feat: migrate landing to Astro#5
Conversation
Full replacement of static HTML landing with the Astro + Starlight codebase from rtk-ai/rtk-landing. Keeps CNAME www.rtk-ai.app (moved from root to public/CNAME per Astro convention). - Brings full docs pipeline (clones rtk/develop at build time) - Build-time GitHub stats sync (stars, forks, version) + daily cron - Starlight docs under /guide/ - Dark-only design system + CSS custom properties Post-merge: switch GitHub Pages source to "GitHub Actions" (see PR body). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Migrates the RTK landing site from static HTML to an Astro 5 + Starlight codebase, adding a build-time docs pipeline, client-side search, and GitHub Pages deployment via Actions.
Changes:
- Rebuild the landing/product pages in Astro, with a shared layout, global styles, and small client scripts (reveal/copy/slideshow/search/i18n).
- Add Starlight docs integration with a build-time pipeline that clones/copies docs and generates a search index.
- Add GitHub Actions workflow for Pages deploy + scheduled rebuilds; move static assets/SEO files (CNAME/robots) under
public/.
Reviewed changes
Copilot reviewed 60 out of 94 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| tsconfig.json | Adds Astro strict TS config and @/* path alias. |
| tailwind.config.mjs | Tailwind theme wired to CSS tokens + typography plugin. |
| src/styles/starlight-overrides.css | Maps Starlight tokens to RTK dark theme + docs styling tweaks. |
| src/styles/global.css | Global design tokens + resets for dark-only UI. |
| src/scripts/slideshow.ts | Landing demo slideshow behavior (tabs/dots/arrows/autoplay/keyboard). |
| src/scripts/search.ts | Client-side Cmd+K modal search implementation + rendering. |
| src/scripts/reveal.ts | IntersectionObserver-based scroll reveal with stagger. |
| src/scripts/copy.ts | Copy-to-clipboard behavior for install buttons. |
| src/pages/vox/index.astro | New Vox product page (Astro) using shared layout. |
| src/pages/rss.xml.ts | RSS endpoint backed by a local entries list. |
| src/pages/index.astro | New landing homepage composed from section components + JSON-LD graph. |
| src/pages/404.astro | New 404 page in Astro (replaces static 404.html). |
| src/layouts/Layout.astro | Base HTML shell: meta/OG/canonical + JSON-LD injection. |
| src/data/search-index.ts | Static search entries merged with generated docs search entries. |
| src/data/rss-entries.ts | Manual RSS entries source. |
| src/content/config.ts | Adds a Starlight loader-based docs collection definition. |
| src/content.config.ts | Adds an alternate docs collection definition (duplicate config). |
| src/components/starlight/Header.astro | Starlight header override (uses global header + SearchModal). |
| src/components/starlight/Head.astro | Starlight head override adding BreadcrumbList JSON-LD. |
| src/components/starlight/Footer.astro | Starlight footer override that portals global footer to body. |
| src/components/landing/ToolComparison.astro | Landing “tool comparison” section content. |
| src/components/landing/ShareGain.astro | “Paste rtk gain → share” section + client parsing/sharing logic. |
| src/components/landing/Proof.astro | Proof section with screenshots and copy. |
| src/components/landing/ProductNav.astro | Product-page nav + mobile drawer. |
| src/components/landing/Problem.astro | Problem section cards. |
| src/components/landing/Nav.astro | Landing nav with links, search trigger, and language switcher. |
| src/components/landing/LandingFooter.astro | Full landing footer with GitHub version fetch. |
| src/components/landing/Install.astro | Install section with copy buttons. |
| src/components/landing/Hero.astro | Hero section with GitHub stats fetch + terminal demo markup. |
| src/components/landing/DemoSlideshow.astro | Demo slideshow markup (before/after examples). |
| src/components/landing/Cta.astro | CTA section + social share links. |
| src/components/landing/CloudWaitlist.astro | Waitlist form + client submission/count fetch. |
| src/components/global/SearchModal.astro | Global search modal markup + bootstrapping. |
| src/components/global/I18nScript.astro | Client i18n application via data-i18n attributes. |
| src/components/global/Header.astro | Docs header to visually match landing nav + search trigger. |
| src/components/global/Footer.astro | Global footer component used site-wide and by Starlight override. |
| public/robots.txt | Moves robots.txt under public/ and updates directives. |
| public/favicon.svg | Adds site favicon SVG. |
| public/CNAME | Moves CNAME under public/ (Astro convention). |
| scripts/prepare-docs.mjs | Build-time docs copy pipeline + anchor map generation. |
| scripts/build-search-index.mjs | Build-time docs search entries generator. |
| plugins/remark-docs-links.mjs | Remark plugin rewriting relative .md links to site routes. |
| package.json | Adds Astro/Starlight/Tailwind deps + build/dev scripts. |
| astro.config.mjs | Astro/Starlight config: site, redirects, custom CSS/components, remark plugin. |
| README.md | New repo documentation for Astro/Starlight setup and pipeline. |
| CLAUDE.md | Updated contributor instructions for Claude Code usage in this repo. |
| CHANGELOG.md | Adds changelog for site changes. |
| .gitignore | Updates ignores for Astro build output + generated docs/search artifacts. |
| .github/workflows/deploy.yml | Adds GitHub Pages build/deploy workflow + schedule/dispatch triggers. |
| .claude/settings.json | Adds a PostToolUse hook reminder for RSS updates. |
| .claude/commands/update-rss.md | Adds a Claude slash command for RSS updates. |
| .claude/commands/prepare-docs.md | Adds a Claude slash command for regenerating docs. |
| .claude/CLAUDE.md | Adds Claude-specific repo instructions (duplicate of root guidance). |
| sitemap.xml | Removes legacy static sitemap. |
| robots.txt | Removes legacy root-level robots.txt. |
| CNAME | Removes legacy root-level CNAME. |
| 404.html | Removes legacy static 404 page. |
| assets/illustrations/PROMPTS.md | Removes illustration prompt guide file. |
| assets/icm/web-overview.png | Adds ICM asset (binary). |
| assets/icm/web-health.png | Adds ICM asset (binary). |
| assets/icm/web-graph-3d.png | Adds ICM asset (binary). |
| assets/icm/tui-overview.png | Adds ICM asset (binary). |
| apple-touch-icon.png | Adds Apple touch icon (binary). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "hooks": [ | ||
| { | ||
| "type": "command", | ||
| "command": "input=$(cat); echo \"$input\" | grep -q 'git push' && printf '\\n⚠️ [RSS] Pushed to landing. New release or content? Update src/data/rss-entries.ts\\n Types: release | new_page | new_doc | new_feature | performance\\n File: /Users/florianbruniaux/Sites/rtk-ai/rtk-landing/src/data/rss-entries.ts\\n' || true" |
There was a problem hiding this comment.
This hook message hardcodes an absolute local filesystem path (/Users/.../src/data/rss-entries.ts), which will be incorrect for other contributors and leaks a machine-specific path into the repo. Consider making the message path relative (or omit it) so the hook is portable.
| "command": "input=$(cat); echo \"$input\" | grep -q 'git push' && printf '\\n⚠️ [RSS] Pushed to landing. New release or content? Update src/data/rss-entries.ts\\n Types: release | new_page | new_doc | new_feature | performance\\n File: /Users/florianbruniaux/Sites/rtk-ai/rtk-landing/src/data/rss-entries.ts\\n' || true" | |
| "command": "input=$(cat); echo \"$input\" | grep -q 'git push' && printf '\\n⚠️ [RSS] Pushed to landing. New release or content? Update src/data/rss-entries.ts\\n Types: release | new_page | new_doc | new_feature | performance\\n File: src/data/rss-entries.ts\\n' || true" |
|
|
||
| on: | ||
| push: | ||
| branches: ["main"] |
There was a problem hiding this comment.
Workflow is configured to deploy on pushes to main, but the PR description and several links in the repo still refer to master. If the default branch is master, deployments won’t run. Consider switching the trigger to master (or include both master and main) to match the repository’s actual default branch and the post-merge instructions.
| branches: ["main"] | |
| branches: ["main", "master"] |
| <a href="/docs/guide/" class="footer-link">Docs</a> | ||
| <a href="/icm/" class="footer-link">ICM</a> | ||
| <a href="/vox/" class="footer-link">Vox</a> |
There was a problem hiding this comment.
This footer link uses /docs/guide/, but the configured docs base is /guide/. As-is, it will 404 because only /docs is redirected in astro.config.mjs. Update to /guide/.
| <a href="/" class="btn-primary">Back to home</a> | ||
| <a href="/docs/guide/" class="btn-secondary">Browse docs</a> | ||
| </div> |
There was a problem hiding this comment.
The 404 page links to /docs/guide/, but docs live under /guide/. Update the href (or add redirects for /docs/guide/*) so the button doesn't send users to a 404 from the 404 page.
| /** Convert a .md filename to a Starlight slug path */ | ||
| function mdToSlug(href) { | ||
| // Strip ./ ../ prefix, keep the filename | ||
| const clean = href.replace(/^\.\.?\//, '') | ||
| // Lowercase, strip .md | ||
| const slug = clean.replace(/\.md$/, '').toLowerCase() | ||
| return `/docs/guide/${slug}/` | ||
| } |
There was a problem hiding this comment.
This plugin rewrites relative doc links to /docs/guide/..., but the site’s docs base path is /guide/. That will produce broken links (no redirect for /docs/guide/*). Update the rewrite base to /guide/ and also handle index.md so links like ./index.md map to /guide/<dir>/ (not /guide/<dir>/index/).
| User-agent: Google-Extended | ||
| Allow: / | ||
|
|
||
| Sitemap: https://www.rtk-ai.app/sitemap-index.xml |
There was a problem hiding this comment.
robots.txt references https://www.rtk-ai.app/sitemap-index.xml, but this repo doesn’t generate or ship that file (no public/sitemap-index.xml and no sitemap integration configured). Either add sitemap generation (e.g., @astrojs/sitemap) and ensure the URL matches the generated filename, or update/remove this Sitemap directive.
| function getPageUrl(relPath) { | ||
| const withoutExt = relPath.replace(/\.md$/, '') | ||
| const normalized = withoutExt.replace(/\\/g, '/') | ||
| return `/guide/${normalized}/` | ||
| } |
There was a problem hiding this comment.
getPageUrl() returns /guide/<path>/ but does not normalize index.md to its directory route. This will produce incorrect search result URLs like /guide/foo/index/#... (and root /guide/index/). Strip a trailing /index segment when building the page URL.
| import { defineCollection } from 'astro:content' | ||
| import { docsLoader } from '@astrojs/starlight/loaders' | ||
| import { docsSchema } from '@astrojs/starlight/schema' | ||
|
|
||
| export const collections = { | ||
| docs: defineCollection({ | ||
| loader: docsLoader(), | ||
| schema: docsSchema(), | ||
| }), | ||
| } |
There was a problem hiding this comment.
Both src/content/config.ts and src/content.config.ts define collections. Astro/Starlight expects a single content config file; having two is ambiguous and can lead to the wrong one being picked up (or future maintenance errors). Remove the unused one and consolidate into the location required by your Astro/Starlight version (and ensure it uses the Starlight docsLoader() if needed).
| import { defineCollection } from 'astro:content' | ||
| import { docsSchema } from '@astrojs/starlight/schema' | ||
|
|
||
| export const collections = { | ||
| docs: defineCollection({ | ||
| type: 'content', | ||
| schema: docsSchema(), | ||
| }), | ||
| } |
There was a problem hiding this comment.
This repository includes two competing content config files (src/content/config.ts and src/content.config.ts). Keep only one source of truth for collections to avoid docs content not loading correctly depending on which file Astro recognizes.
| html { | ||
| scroll-behavior: smooth; | ||
| overflow-x: hidden; | ||
| } |
There was a problem hiding this comment.
Setting scroll-behavior: smooth unconditionally can violate prefers-reduced-motion expectations. Consider wrapping it in a @media (prefers-reduced-motion: no-preference) block and leaving the default behavior otherwise.
Summary
🚨 Required post-merge action (site down until done)
Do this immediately after merging:
Test plan
Follow-ups (separate PRs)
🤖 Generated with Claude Code