|
| 1 | +--- |
| 2 | +import Default from "@astrojs/starlight/components/Head.astro"; |
| 3 | +
|
| 4 | +const route = Astro.locals.starlightRoute; |
| 5 | +const title = route?.entry?.data?.title ?? ""; |
| 6 | +const description = route?.entry?.data?.description ?? ""; |
| 7 | +const siteUrl = "https://simplestack.dev"; |
| 8 | +const canonicalUrl = new URL(Astro.url.pathname, siteUrl).href; |
| 9 | +
|
| 10 | +// WebSite + Organization schema (all pages) |
| 11 | +const websiteSchema = { |
| 12 | + "@context": "https://schema.org", |
| 13 | + "@type": "WebSite", |
| 14 | + name: "Simple Stack", |
| 15 | + url: siteUrl, |
| 16 | + description: |
| 17 | + "A collection of lightweight, focused tools for Astro and Vite — including a reactive store, scoped IDs, and DOM query utilities.", |
| 18 | + publisher: { |
| 19 | + "@type": "Organization", |
| 20 | + name: "Simple Stack", |
| 21 | + url: siteUrl, |
| 22 | + sameAs: [ |
| 23 | + "https://github.com/bholmesdev/simple-stack", |
| 24 | + "https://wtw.dev/chat", |
| 25 | + ], |
| 26 | + }, |
| 27 | +}; |
| 28 | +
|
| 29 | +// Determine page type from URL pathname |
| 30 | +const pathname = Astro.url.pathname.replace(/^\/|\/$|index\.html$/g, ""); |
| 31 | +const isPackagePage = |
| 32 | + pathname === "store" || pathname === "scope" || pathname === "query"; |
| 33 | +const isHomePage = pathname === ""; |
| 34 | +
|
| 35 | +// SoftwareSourceCode schema for active package pages |
| 36 | +const packageMeta: Record<string, { repo: string; npm: string }> = { |
| 37 | + store: { |
| 38 | + repo: "https://github.com/bholmesdev/simplestack-store", |
| 39 | + npm: "https://www.npmjs.com/package/@simplestack/store", |
| 40 | + }, |
| 41 | + scope: { |
| 42 | + repo: "https://github.com/bholmesdev/simplestack-scope", |
| 43 | + npm: "https://www.npmjs.com/package/vite-plugin-simple-scope", |
| 44 | + }, |
| 45 | + query: { |
| 46 | + repo: "https://github.com/bholmesdev/simplestack-query", |
| 47 | + npm: "https://www.npmjs.com/package/@simplestack/query", |
| 48 | + }, |
| 49 | +}; |
| 50 | +
|
| 51 | +const softwareSchema = isPackagePage |
| 52 | + ? { |
| 53 | + "@context": "https://schema.org", |
| 54 | + "@type": "SoftwareSourceCode", |
| 55 | + name: title, |
| 56 | + description: description, |
| 57 | + url: canonicalUrl, |
| 58 | + codeRepository: packageMeta[pathname]?.repo, |
| 59 | + programmingLanguage: ["TypeScript", "JavaScript"], |
| 60 | + runtimePlatform: "Node.js", |
| 61 | + author: { |
| 62 | + "@type": "Person", |
| 63 | + name: "Ben Holmes", |
| 64 | + url: "https://bholmes.dev", |
| 65 | + }, |
| 66 | + } |
| 67 | + : null; |
| 68 | +
|
| 69 | +// BreadcrumbList schema for non-home pages |
| 70 | +const breadcrumbSchema = !isHomePage |
| 71 | + ? { |
| 72 | + "@context": "https://schema.org", |
| 73 | + "@type": "BreadcrumbList", |
| 74 | + itemListElement: [ |
| 75 | + { |
| 76 | + "@type": "ListItem", |
| 77 | + position: 1, |
| 78 | + name: "Home", |
| 79 | + item: siteUrl, |
| 80 | + }, |
| 81 | + { |
| 82 | + "@type": "ListItem", |
| 83 | + position: 2, |
| 84 | + name: title, |
| 85 | + item: canonicalUrl, |
| 86 | + }, |
| 87 | + ], |
| 88 | + } |
| 89 | + : null; |
| 90 | +
|
| 91 | +const schemas = [websiteSchema, softwareSchema, breadcrumbSchema].filter( |
| 92 | + Boolean, |
| 93 | +); |
| 94 | +--- |
| 95 | + |
| 96 | +<Default {...Astro.props} /> |
| 97 | +{ |
| 98 | + schemas.map((schema) => ( |
| 99 | + <script type="application/ld+json" set:html={JSON.stringify(schema)} /> |
| 100 | + )) |
| 101 | +} |
0 commit comments