Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Greptile Summary
This PR redesigns the landing page with new content sections, introduces four use-case pages, centralises all content inside a
max-w-3xlcontainer with decorative side borders, adds structured-data LD+JSON, security headers, prerender config, and a server-side sitemap.Two items worth addressing before merge: all four cards in
Ribbon.vueshare an identicalid(navigation-top-left-bottom-right), producing duplicate DOM IDs; and--font-sans/--font-monowere moved out of@theme staticinto:root, which may cause Tailwind v4 to stop recognising them as design tokens and fall back to system fonts.Confidence Score: 4/5
Important Files Changed
Flowchart
%%{init: {'theme': 'neutral'}}%% flowchart TD A[default.vue layout] --> B[Navigation.vue fixed bottom navbar] A --> C[main slot max-w-3xl centred] A --> D[Footer.vue] C --> E[pages/index.vue Hero + sections + Ribbon] C --> F[pages/roadmap.vue] C --> G[pages/blog/index.vue] C --> H[pages/blog/slug.vue] E --> I[components/Hero.vue] E --> J["components/Ribbon.vue — duplicate IDs"] J --> K[usecases/real-time-pipelines] J --> L[usecases/event-workflows] J --> M[usecases/state-management] J --> N[usecases/business-logic] O[docs.vue layout] --> P[DocsNavigation.vue] O --> Q[main slot max-w-3xl centred] Q --> R[pages/docs/index.vue] Q --> S[pages/docs/slug.vue] T[nuxt.config.ts prerender + SEO] --> U["server/routes/sitemap.xml.ts static routes only"] T --> V["public/robots.txt conflicts with server route"]Comments Outside Diff (5)
nuxt.config.ts, line 2648-2652 (link)Setting a static
canonicalhref tohttps://slung.techin the globalapp.headconfig injects<link rel="canonical" href="https://slung.tech">on every page — including/blog/my-post,/docs/getting-started, etc. Search engines will interpret this as every page being a duplicate of the homepage, causing all non-root pages to be deindexed in favour of/. No individual page in this PR overrides this link viauseHead.Either remove this global canonical and set it per-page (using
useHeadoruseSeoMetawith the dynamicroute.fullPath), or dynamically compute the href:public/site.webmanifest, line 2921-2935 (link)screenshotskey in web manifestThe
screenshotsarray is declared twice at the top level of the JSON object (once at line ~2843 and again here). The JSON spec treats duplicate keys as undefined behaviour; most parsers silently use the last value, dropping the first declaration entirely. This means theform_factor: "narrow"andform_factor: "wide"entries from the first block are lost. Remove the duplicate declaration and merge any unique entries into a single array.nuxt.config.ts, line 2716-2735 (link)SearchActiontargets a non-existent/searchrouteThe
WebSiteJSON-LD schema includes aSearchActionwithurlTemplate: "https://slung.tech/search?q={search_term_string}". No/searchpage exists in this codebase, so Google's Sitelinks search box feature won't work and any crawler that follows the template will hit a 404. Either remove thepotentialActionblock or implement the search page first.app/composables/useOpenGraph.ts, line 663 (link)datePublishedalways reflects the current timedatePublished: new Date().toISOString()is evaluated at render time, so every server-side render reports the page as published right now. For blog posts this is semantically wrong — search engines expectdatePublishedto be the original publication date anddateModifiedfor updates. The composable already receives its parameters at call-site, sodatePublishedshould be an explicit parameter with a sensible fallback only when unavailable.app/components/Ribbon.vue, line 562-591 (link)The four entries in the useCases array all carry the same id value. The template forwards this as both the element id attribute and the v-for key, so every rendered NuxtLink gets an identical id (invalid HTML — only the first is reachable via getElementById) and Vue will warn about duplicate keys, which can cause incorrect virtual-DOM patching. Each item needs a distinct id value.
Reviews (3): Last reviewed commit: "fix: more" | Re-trigger Greptile