From 2b5ee58b1694d75815aa8aa2488d7cf55b90a639 Mon Sep 17 00:00:00 2001 From: Ben Holmes Date: Wed, 29 Apr 2026 09:16:08 +0000 Subject: [PATCH] docs(www): SEO + AEO audit fixes - Configure site URL (https://simple-stack.dev) and add @astrojs/sitemap so canonical URLs and a sitemap-index.xml are generated at build time. - Add public/robots.txt that allows all crawlers and references the sitemap. - Inject Organization JSON-LD, default Twitter card, og:site_name, and a sensible default robots meta site-wide via Starlight `head`. - Improve home page metadata: better description, OG title/description, and a FAQPage JSON-LD block answering the most common "what is Simple Stack / Simple Store / Simple Scope / Simple Query" questions for AEO. - Mark deprecated docs (Simple Stream and Simple Form) noindex and exclude them from the sitemap so search engines don't surface unmaintained content. Co-Authored-By: Oz --- pnpm-lock.yaml | 3 ++ www/astro.config.mjs | 54 +++++++++++++++++++++++ www/package.json | 1 + www/public/robots.txt | 7 +++ www/src/content/docs/form/client.md | 8 +++- www/src/content/docs/form/index.mdx | 8 +++- www/src/content/docs/form/parse.md | 8 +++- www/src/content/docs/index.mdx | 66 ++++++++++++++++++++++++++--- www/src/content/docs/stream.md | 6 +++ 9 files changed, 153 insertions(+), 8 deletions(-) create mode 100644 www/public/robots.txt diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5657af7..edb731b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -205,6 +205,9 @@ importers: '@astrojs/check': specifier: ^0.9.6 version: 0.9.6(typescript@5.5.4) + '@astrojs/sitemap': + specifier: ^3.6.0 + version: 3.6.0 '@astrojs/starlight': specifier: ^0.37.1 version: 0.37.1(astro@5.16.6) diff --git a/www/astro.config.mjs b/www/astro.config.mjs index 0d7e4c1..13719d8 100644 --- a/www/astro.config.mjs +++ b/www/astro.config.mjs @@ -1,10 +1,56 @@ +import sitemap from "@astrojs/sitemap"; import starlight from "@astrojs/starlight"; import { defineConfig } from "astro/config"; +const SITE_URL = "https://simple-stack.dev"; + +// Site-wide JSON-LD describing the project as an Organization. +// Helps AI engines (ChatGPT, Perplexity, Google AI Overviews) attribute +// citations and disambiguate the brand. +const organizationJsonLd = { + "@context": "https://schema.org", + "@type": "Organization", + name: "Simple Stack", + url: SITE_URL, + logo: `${SITE_URL}/favicon.svg`, + description: + "Simple Stack is a suite of small, focused tools for Astro and modern web frameworks, including Simple Store, Simple Scope, and Simple Query.", + sameAs: [ + "https://github.com/bholmesdev/simple-stack", + "https://wtw.dev/chat", + ], +}; + export default defineConfig({ + site: SITE_URL, + trailingSlash: "ignore", integrations: [ starlight({ title: "Simple Stack 🌱", + description: + "Simple Stack is a suite of small, focused tools for Astro: Simple Store for reactive state, Simple Scope for build-time scoped IDs, and Simple Query for DOM scripting.", + favicon: "/favicon.svg", + head: [ + // Canonical Twitter / OG defaults applied to every page. + { + tag: "meta", + attrs: { name: "twitter:card", content: "summary_large_image" }, + }, + { + tag: "meta", + attrs: { property: "og:site_name", content: "Simple Stack" }, + }, + { + tag: "meta", + attrs: { name: "robots", content: "index, follow, max-image-preview:large" }, + }, + // Organization structured data for AEO / rich results. + { + tag: "script", + attrs: { type: "application/ld+json" }, + content: JSON.stringify(organizationJsonLd), + }, + ], social: [ { icon: "github", @@ -44,5 +90,13 @@ export default defineConfig({ "./src/styles/custom.css", ], }), + sitemap({ + // Keep the sitemap aligned with indexable pages only. The deprecated + // stream and form docs set , + // so they should not be advertised to search engines. + filter: (page) => + !page.startsWith(`${SITE_URL}/stream`) && + !page.startsWith(`${SITE_URL}/form`), + }), ], }); diff --git a/www/package.json b/www/package.json index 8afa5ca..e80a24b 100644 --- a/www/package.json +++ b/www/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "@astrojs/check": "^0.9.6", + "@astrojs/sitemap": "^3.6.0", "@astrojs/starlight": "^0.37.1", "@fontsource/atkinson-hyperlegible": "^5.0.18", "astro": "^5.16.6", diff --git a/www/public/robots.txt b/www/public/robots.txt new file mode 100644 index 0000000..9e976aa --- /dev/null +++ b/www/public/robots.txt @@ -0,0 +1,7 @@ +# https://simple-stack.dev/robots.txt +# Allow all standard search engine and AI crawlers. +User-agent: * +Allow: / + +# Sitemap is generated by @astrojs/sitemap at build time. +Sitemap: https://simple-stack.dev/sitemap-index.xml diff --git a/www/src/content/docs/form/client.md b/www/src/content/docs/form/client.md index 884c722..0077c9b 100644 --- a/www/src/content/docs/form/client.md +++ b/www/src/content/docs/form/client.md @@ -1,8 +1,14 @@ --- -title: Add client validation +title: Add client validation description: Add client validation to your forms sidebar: order: 3 +head: + # Deprecated package: keep the docs accessible but exclude from search engines. + - tag: meta + attrs: + name: robots + content: noindex, follow --- :::caution diff --git a/www/src/content/docs/form/index.mdx b/www/src/content/docs/form/index.mdx index 3e1654e..0fc536d 100644 --- a/www/src/content/docs/form/index.mdx +++ b/www/src/content/docs/form/index.mdx @@ -1,9 +1,15 @@ --- title: Simple form -description: The simple way to validate forms in your fullstack app. +description: The simple way to validate forms in your fullstack app. sidebar: label: Get started order: 1 +head: + # Deprecated package: keep the docs accessible but exclude from search engines. + - tag: meta + attrs: + name: robots + content: noindex, follow --- import { Tabs, TabItem } from '@astrojs/starlight/components'; diff --git a/www/src/content/docs/form/parse.md b/www/src/content/docs/form/parse.md index 35116f9..8d277d9 100644 --- a/www/src/content/docs/form/parse.md +++ b/www/src/content/docs/form/parse.md @@ -1,8 +1,14 @@ --- -title: Parse form requests +title: Parse form requests description: Validate forms server-side sidebar: order: 2 +head: + # Deprecated package: keep the docs accessible but exclude from search engines. + - tag: meta + attrs: + name: robots + content: noindex, follow --- :::caution diff --git a/www/src/content/docs/index.mdx b/www/src/content/docs/index.mdx index 1e6d15c..76faf11 100644 --- a/www/src/content/docs/index.mdx +++ b/www/src/content/docs/index.mdx @@ -1,15 +1,71 @@ --- title: Simple stack 🌱 -description: A suite of tools built for Astro to simplify your workflow. +description: "Simple Stack is a collection of small, focused tools for Astro: Simple Store for reactive state, Simple Scope for build-time scoped IDs, and Simple Query for DOM scripting." tableOfContents: false head: - - tag: title - content: Simple stack 🌱 + - tag: meta + attrs: + property: "og:title" + content: "Simple Stack — small, focused tools for Astro" + - tag: meta + attrs: + property: "og:description" + content: "Simple Store, Simple Scope, and Simple Query: tiny libraries that solve a single use case in Astro and modern web apps." + - tag: script + attrs: + type: "application/ld+json" + content: | + { + "@context": "https://schema.org", + "@type": "FAQPage", + "mainEntity": [ + { + "@type": "Question", + "name": "What is Simple Stack?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Simple Stack is a collection of small, focused libraries for Astro and modern web frameworks. It includes Simple Store for reactive state, Simple Scope for build-time scoped IDs, and Simple Query for DOM scripting in Astro components." + } + }, + { + "@type": "Question", + "name": "What does Simple Store do?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Simple Store is a reactive store that combines the simplicity of signals with selector-style sub-stores you'd find in Zustand or Redux. It supports React, Next.js, and any framework with a Vite-based toolchain." + } + }, + { + "@type": "Question", + "name": "What does Simple Scope do?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Simple Scope is a Vite plugin that generates a stable, scoped ID for the current file at build time, with zero client-side JavaScript. It is useful for form label IDs and querying scoped DOM elements." + } + }, + { + "@type": "Question", + "name": "What does Simple Query do?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Simple Query is an Astro integration that adds a small, jQuery-like API for selecting elements inside an Astro component using data-target attributes, with built-in support for the Signals proposal via signal-polyfill." + } + }, + { + "@type": "Question", + "name": "Which Simple Stack packages are still maintained?", + "acceptedAnswer": { + "@type": "Answer", + "text": "Simple Store, Simple Scope, and Simple Query are actively maintained. Simple Stream and Simple Form are deprecated; Astro's Server Islands and Form Actions cover those use cases natively." + } + } + ] + } --- -A collection of tools I've built to **make web development simpler.** +**Simple Stack is a collection of small, focused libraries for [Astro](https://astro.build) and modern web frameworks.** Each package solves one job well: [Simple Store](/store) for reactive state, [Simple Scope](/scope) for build-time scoped IDs, and [Simple Query](/query) for DOM scripting in Astro components. -To be honest, there isn't a "story" connecting these packages together (I'm no TanStack). But they follow a common theme: solve a simple use case without too many features. +There isn't a "story" connecting these packages together (I'm no TanStack). But they follow a common theme: solve a simple use case without too many features. import { CardGrid, Card, LinkCard } from '@astrojs/starlight/components'; diff --git a/www/src/content/docs/stream.md b/www/src/content/docs/stream.md index 5c734fb..34f8221 100644 --- a/www/src/content/docs/stream.md +++ b/www/src/content/docs/stream.md @@ -1,6 +1,12 @@ --- title: Simple stream 🌊 description: Suspend Astro components with fallback content. Like React Server Components, but Just HTML ™️ +head: + # Deprecated package: keep the docs accessible but exclude from search engines. + - tag: meta + attrs: + name: robots + content: noindex, follow --- :::caution