From 3b0cd2e68a386abfc1f7114c201ae1201632022a Mon Sep 17 00:00:00 2001 From: moose-lab Date: Thu, 4 Jun 2026 16:30:24 +0800 Subject: [PATCH] feat: expose seekersai site architecture --- .../2026-06-04-seekersai-site-architecture.md | 419 ++++++++++++++++++ src/App.test.tsx | 99 ++++- src/components/landing/LandingNav.tsx | 205 +++++++-- src/components/landing/LandingSections.tsx | 75 +++- src/components/marketing/MarketingPage.tsx | 119 ++++- src/styles/app.css | 113 ++++- 6 files changed, 969 insertions(+), 61 deletions(-) create mode 100644 docs/plans/2026-06-04-seekersai-site-architecture.md diff --git a/docs/plans/2026-06-04-seekersai-site-architecture.md b/docs/plans/2026-06-04-seekersai-site-architecture.md new file mode 100644 index 0000000..95c13db --- /dev/null +++ b/docs/plans/2026-06-04-seekersai-site-architecture.md @@ -0,0 +1,419 @@ +# SeekersAI.com Landing Site Architecture Plan + +Date: 2026-06-04 +Scope: QuickFork public landing site at `https://seekersai.com` +Skill basis: `site-architecture` + +## Planning Summary + +QuickFork is a hybrid SaaS and content-led launch site. It is no longer only a homepage landing page: the current public crawl surface already includes product-intent pages, use-case pages, resources, a free tool, a template, examples, comparison pages, support/legal pages, `llms.txt`, and `pricing.md`. + +The architecture goal is to keep the homepage as the conversion and product-studio hub, while making the published growth pages discoverable through clear navigation, hub-and-spoke internal links, and stable URL patterns. + +### Business Context + +- Product: QuickFork turns a GitHub repository into a launch-ready story and shareable marketing asset package. +- Primary audience: open-source maintainers, AI project builders, DevRel teams, founders, product marketers, and design leads. +- Primary conversion: paste a GitHub repository URL and generate a free repo brief or launch package. +- Secondary conversions: sign up, inspect examples, request a checklist/template, request a full launch package, or contact the team. +- Evidence constraint: pages must avoid invented metrics, customer logos, pricing claims, or proof points that are not backed by repository evidence or explicit user input. + +### Current State + +- Site type: existing hybrid SaaS plus content/growth site. +- Current canonical production domain: `https://seekersai.com`. +- Current live checks on 2026-06-04: `/`, `/sitemap.xml`, and `/llms.txt` return HTTP 200 from Vercel. +- Existing source of truth for crawlable marketing URLs: `src/marketing/link-catalog.ts`. +- Existing sitemap output: `public/sitemap.xml`. +- Existing homepage navigation: Product dropdown to page anchors, Pricing anchor, sign-in/sign-up through `UserMenu`. +- Existing footer navigation: Contact, Help, Privacy, Terms. +- Existing page-level internal linking: `MarketingPage` renders up to 3 related routes based on funnel stage or buyer stage. + +### Architecture Gaps + +- Header navigation does not expose published growth page clusters such as use cases, resources, tools, examples, or comparisons. +- Footer does not expose the current product, resource, example, compare, `llms.txt`, or `pricing.md` crawl surfaces. +- Parent cluster URLs such as `/product`, `/resources`, `/examples`, and `/compare` are conceptual in the URL structure but do not currently behave as explicit HTML hub pages. +- `/pricing.md` is crawlable, while the visible header uses `/#pricing`; this is acceptable while pricing is not finalized, but it should be made intentional. +- Contact intent routes are tracked in the link catalog as draft bottom-funnel routes, but `contactLink` matching currently only runs for `/contact` with query params. The architecture should preserve those URLs as draft conversion routes rather than listing them as crawlable pages. + +## Recommended Information Architecture + +Use a moderate 2 to 3 level structure: + +- L0: Homepage and product studio entry. +- L1: Product, Use Cases, Resources, Tools, Examples, Compare, Support. +- L2: Individual intent pages under each cluster. + +Keep existing URLs stable. Do not rename published pages unless redirects are added. + +## Page Hierarchy + +```text +Homepage (/) +|-- Product cluster +| |-- GitHub repo to launch package (/product/github-repo-to-launch-package) +| |-- Source-backed launch assets (/product/source-backed-launch-assets) +| |-- Cold-start launch materials (/product/cold-start-launch-materials) +| |-- GitHub repo launch materials map (/product/github-repo-launch-materials-map) +| |-- README marketing cards (/product/readme-marketing-cards) +| |-- GitHub repo visual explainer (/product/github-repo-visual-explainer) +| |-- GitHub repo to launch deck (/product/github-repo-to-launch-deck) +| |-- GitHub repo to product outreach (/product/github-repo-to-product-outreach) +| `-- Repository launch package pilot (/product/repository-launch-package-pilot) +|-- Use cases +| |-- Open-source launch (/use-cases/open-source-launch) +| |-- AI project launch (/use-cases/ai-project-launch) +| `-- DevRel launch workflow (/use-cases/devrel-launch-workflow) +|-- Resources +| |-- Open-source launch checklist (/resources/open-source-launch-checklist) +| |-- GitHub project marketing card guide (/resources/github-project-marketing-card-guide) +| |-- GitHub repo launch demand map (/resources/github-repo-launch-demand-map) +| `-- README cover prompt guide (/resources/readme-cover-prompt-guide) +|-- Tools +| `-- GitHub repo launch readiness score (/tools/github-repo-launch-readiness-score) +|-- Templates +| `-- GitHub launch announcement (/templates/github-launch-announcement) +|-- Examples +| |-- QwenLM FlashQLA launch card (/examples/qwenlm-flashqla-launch-card) +| `-- DeepSeek TWVP launch card (/examples/deepseek-twvp-launch-card) +|-- Compare +| |-- ChatGPT open-source launch copy (/compare/chatgpt-open-source-launch-copy) +| `-- Canva README banner generator (/compare/canva-readme-banner-generator) +|-- Contact and conversion routes +| |-- Contact (/contact) +| |-- Demo intent (/contact?intent=demo) +| |-- Partnership intent (/contact?intent=partnership) +| `-- Launch package intent (/contact?intent=launch-package) +|-- Support +| `-- Help (/help) +|-- Legal +| |-- Privacy (/privacy) +| `-- Terms (/terms) +|-- AI and crawler assets +| |-- LLMs file (/llms.txt) +| |-- Pricing markdown (/pricing.md) +| |-- Robots (/robots.txt) +| `-- Sitemap (/sitemap.xml) +|-- Authentication +| |-- Sign in (/sign-in) +| `-- Sign up (/sign-up) +``` + +## Visual Sitemap + +```mermaid +graph TD + HOME["Homepage / Studio"] + + subgraph Header_Nav["Recommended Header Nav"] + NAV_PRODUCT["Product"] + NAV_USECASES["Use Cases"] + NAV_RESOURCES["Resources"] + NAV_EXAMPLES["Examples"] + NAV_PRICING["Pricing"] + NAV_CTA["Generate free repo brief"] + end + + subgraph Product["Product Intent Pages"] + P1["Repo to launch package"] + P2["Source-backed launch assets"] + P3["Cold-start launch materials"] + P4["Launch materials map"] + P5["README marketing cards"] + P6["Visual explainer"] + P7["Launch deck"] + P8["Product outreach"] + P9["Launch package pilot"] + end + + subgraph UseCases["Use Cases"] + U1["Open-source launch"] + U2["AI project launch"] + U3["DevRel launch workflow"] + end + + subgraph Resources["Resources and Tools"] + R1["Open-source checklist"] + R2["Marketing card guide"] + R3["Launch demand map"] + R4["README cover prompt guide"] + T1["Launch readiness score"] + TM1["Launch announcement template"] + end + + subgraph Proof["Examples and Comparisons"] + E1["FlashQLA example"] + E2["DeepSeek TWVP example"] + C1["ChatGPT comparison"] + C2["Canva comparison"] + end + + subgraph Support["Footer and Utility"] + CONTACT["Contact"] + HELP["Help"] + PRIVACY["Privacy"] + TERMS["Terms"] + LLMS["llms.txt"] + PRICING_MD["pricing.md"] + end + + HOME --> NAV_PRODUCT + HOME --> NAV_USECASES + HOME --> NAV_RESOURCES + HOME --> NAV_EXAMPLES + HOME --> NAV_PRICING + HOME --> NAV_CTA + + NAV_PRODUCT --> P1 + NAV_PRODUCT --> P2 + NAV_PRODUCT --> P3 + NAV_PRODUCT --> P4 + NAV_PRODUCT --> P9 + + NAV_USECASES --> U1 + NAV_USECASES --> U2 + NAV_USECASES --> U3 + + NAV_RESOURCES --> R1 + NAV_RESOURCES --> R2 + NAV_RESOURCES --> R3 + NAV_RESOURCES --> R4 + NAV_RESOURCES --> T1 + NAV_RESOURCES --> TM1 + + NAV_EXAMPLES --> E1 + NAV_EXAMPLES --> E2 + NAV_EXAMPLES --> C1 + NAV_EXAMPLES --> C2 + + P1 --> U1 + P1 --> R1 + P1 --> T1 + P2 --> R2 + P3 --> R3 + P4 --> U2 + P6 --> E1 + P7 --> TM1 + P8 --> P9 + P9 --> CONTACT + + U1 --> P1 + U2 --> P3 + U3 --> P4 + + R1 --> P1 + R2 --> P5 + R3 --> P4 + R4 --> P6 + T1 --> P9 + TM1 --> P7 + + E1 --> P6 + E2 --> P6 + C1 --> P2 + C2 --> P5 +``` + +## URL Map + +| Page | URL | Parent | Nav Location | Priority | +| --- | --- | --- | --- | --- | +| Homepage and studio | `/` | none | Header logo, CTA target | High | +| GitHub repo to launch package | `/product/github-repo-to-launch-package` | Product | Header Product menu | High | +| Source-backed launch assets | `/product/source-backed-launch-assets` | Product | Header Product menu | High | +| Cold-start launch materials | `/product/cold-start-launch-materials` | Product | Header Product menu | High | +| GitHub repo launch materials map | `/product/github-repo-launch-materials-map` | Product | Header Product menu | High | +| README marketing cards | `/product/readme-marketing-cards` | Product | Product menu or related links | Medium | +| GitHub repo visual explainer | `/product/github-repo-visual-explainer` | Product | Product menu or examples cross-link | Medium | +| GitHub repo to launch deck | `/product/github-repo-to-launch-deck` | Product | Product menu or template cross-link | Medium | +| GitHub repo to product outreach | `/product/github-repo-to-product-outreach` | Product | Product menu or pilot cross-link | Medium | +| Repository launch package pilot | `/product/repository-launch-package-pilot` | Product | Header Product menu, footer Product | High | +| Open-source launch | `/use-cases/open-source-launch` | Use Cases | Header Use Cases menu | High | +| AI project launch | `/use-cases/ai-project-launch` | Use Cases | Header Use Cases menu | High | +| DevRel launch workflow | `/use-cases/devrel-launch-workflow` | Use Cases | Header Use Cases menu | Medium | +| Open-source launch checklist | `/resources/open-source-launch-checklist` | Resources | Header Resources menu | High | +| GitHub project marketing card guide | `/resources/github-project-marketing-card-guide` | Resources | Header Resources menu | High | +| GitHub repo launch demand map | `/resources/github-repo-launch-demand-map` | Resources | Header Resources menu | High | +| README cover prompt guide | `/resources/readme-cover-prompt-guide` | Resources | Header Resources menu | Medium | +| GitHub repo launch readiness score | `/tools/github-repo-launch-readiness-score` | Tools | Header Resources menu | High | +| GitHub launch announcement | `/templates/github-launch-announcement` | Templates | Header Resources menu | Medium | +| QwenLM FlashQLA launch card | `/examples/qwenlm-flashqla-launch-card` | Examples | Header Examples menu | Medium | +| DeepSeek TWVP launch card | `/examples/deepseek-twvp-launch-card` | Examples | Header Examples menu | Medium | +| ChatGPT open-source launch copy | `/compare/chatgpt-open-source-launch-copy` | Compare | Header Examples menu, footer Compare | Medium | +| Canva README banner generator | `/compare/canva-readme-banner-generator` | Compare | Header Examples menu, footer Compare | Medium | +| Contact | `/contact` | Contact | Footer, CTA fallback | High | +| Demo intent | `/contact?intent=demo` | Contact | CTA only, not sitemap | Medium | +| Partnership intent | `/contact?intent=partnership` | Contact | CTA only, not sitemap | Medium | +| Launch package intent | `/contact?intent=launch-package` | Contact | CTA only, not sitemap | High | +| Help Center | `/help` | Support | Footer | Medium | +| Privacy | `/privacy` | Legal | Footer | Required | +| Terms | `/terms` | Legal | Footer | Required | +| LLMs file | `/llms.txt` | AI discovery | Footer utility, crawler asset | Medium | +| Pricing markdown | `/pricing.md` | AI discovery | Footer utility, crawler asset | Medium | +| Sign in | `/sign-in` | Auth | User menu | Medium | +| Sign up | `/sign-up` | Auth | Header CTA/User menu | High | + +## Navigation Spec + +### Header + +Recommended header order: + +1. Brand logo to `/`. +2. Product mega menu. +3. Use Cases menu. +4. Resources menu. +5. Examples menu. +6. Pricing link to `/#pricing` while pricing is not finalized. +7. Right CTA: `Generate free repo brief` to `/#studio`. +8. Auth state: `Sign in` or account menu. + +Recommended Product menu: + +- Studio - `/#studio` +- Repo to launch package - `/product/github-repo-to-launch-package` +- Source-backed launch assets - `/product/source-backed-launch-assets` +- Cold-start launch materials - `/product/cold-start-launch-materials` +- Launch materials map - `/product/github-repo-launch-materials-map` +- Launch package pilot - `/product/repository-launch-package-pilot` + +Recommended Use Cases menu: + +- Open-source launch - `/use-cases/open-source-launch` +- AI project launch - `/use-cases/ai-project-launch` +- DevRel launch workflow - `/use-cases/devrel-launch-workflow` + +Recommended Resources menu: + +- Open-source launch checklist - `/resources/open-source-launch-checklist` +- Marketing card guide - `/resources/github-project-marketing-card-guide` +- Launch demand map - `/resources/github-repo-launch-demand-map` +- README cover prompt guide - `/resources/readme-cover-prompt-guide` +- Launch readiness score - `/tools/github-repo-launch-readiness-score` +- Launch announcement template - `/templates/github-launch-announcement` + +Recommended Examples menu: + +- QwenLM FlashQLA launch card - `/examples/qwenlm-flashqla-launch-card` +- DeepSeek TWVP launch card - `/examples/deepseek-twvp-launch-card` +- ChatGPT comparison - `/compare/chatgpt-open-source-launch-copy` +- Canva comparison - `/compare/canva-readme-banner-generator` + +### Footer + +Recommended footer columns: + +| Column | Links | +| --- | --- | +| Product | Studio, repo to launch package, source-backed launch assets, cold-start launch materials, launch package pilot | +| Use Cases | Open-source launch, AI project launch, DevRel launch workflow | +| Resources | Checklist, marketing card guide, launch demand map, readiness score, template | +| Examples | FlashQLA, DeepSeek TWVP, ChatGPT comparison, Canva comparison | +| Support | Contact, Help, Sign in, Sign up | +| Legal and AI Discovery | Privacy, Terms, `llms.txt`, `pricing.md`, `sitemap.xml` | + +### Breadcrumbs + +Add breadcrumbs to HTML marketing pages after hub pages are implemented, or add visual breadcrumb labels immediately without requiring parent hub pages. + +Recommended breadcrumb patterns: + +- `Home > Product > GitHub repo to launch package` +- `Home > Use Cases > AI project launch` +- `Home > Resources > Open-source launch checklist` +- `Home > Tools > GitHub repo launch readiness score` +- `Home > Examples > QwenLM FlashQLA launch card` +- `Home > Compare > ChatGPT open-source launch copy` + +Do not add breadcrumbs to `robots.txt`, `sitemap.xml`, `llms.txt`, or `pricing.md`. + +## Internal Linking Plan + +### Hub Pages + +Near-term: use homepage sections, header menus, footer columns, and related-route cards as the functional hubs. + +Medium-term: add explicit HTML hub pages when the site is ready for more browse traffic: + +- `/product` - explain repo-to-launch package categories and link to all product-intent pages. +- `/use-cases` - map personas to launch jobs. +- `/resources` - collect guides, checklist, tool, and template. +- `/examples` - collect generated project examples. +- `/compare` - collect alternative and objection pages. + +If hub pages are added later, update `src/marketing/link-catalog.ts`, `public/sitemap.xml`, `public/llms.txt`, and `src/seo/public-growth.test.ts`. + +### Recommended Cross-Links + +| Source page | Link targets | Anchor intent | +| --- | --- | --- | +| `/` | Product pages, use cases, readiness score, examples, launch package pilot | Move visitors from studio promise to specific intent pages | +| `/product/github-repo-to-launch-package` | `/use-cases/open-source-launch`, `/resources/open-source-launch-checklist`, `/tools/github-repo-launch-readiness-score` | Define package, qualify readiness, show open-source launch workflow | +| `/product/source-backed-launch-assets` | `/resources/github-project-marketing-card-guide`, `/compare/chatgpt-open-source-launch-copy`, `/product/repository-launch-package-pilot` | Reinforce evidence boundary and bottom-funnel pilot | +| `/product/cold-start-launch-materials` | `/resources/github-repo-launch-demand-map`, `/use-cases/ai-project-launch`, `/product/github-repo-launch-materials-map` | Connect cold-start pain to materials mapping | +| `/product/github-repo-launch-materials-map` | `/use-cases/devrel-launch-workflow`, `/templates/github-launch-announcement`, `/product/github-repo-to-product-outreach` | Move from planning map to channels | +| `/product/readme-marketing-cards` | `/resources/readme-cover-prompt-guide`, `/compare/canva-readme-banner-generator`, `/examples/qwenlm-flashqla-launch-card` | Pair visual asset intent with prompt and comparison proof | +| `/product/github-repo-visual-explainer` | `/examples/qwenlm-flashqla-launch-card`, `/examples/deepseek-twvp-launch-card`, `/resources/github-project-marketing-card-guide` | Connect visual explainer to examples | +| `/product/github-repo-to-launch-deck` | `/templates/github-launch-announcement`, `/resources/github-repo-launch-demand-map`, `/contact?intent=launch-package` | Convert deck intent to package help | +| `/product/github-repo-to-product-outreach` | `/product/repository-launch-package-pilot`, `/contact?intent=demo`, `/resources/github-repo-launch-demand-map` | Move outreach intent toward qualified contact | +| `/tools/github-repo-launch-readiness-score` | `/product/repository-launch-package-pilot`, `/product/cold-start-launch-materials`, `/resources/open-source-launch-checklist` | Turn readiness diagnosis into next action | +| Examples | Related product page, relevant resource, studio CTA | Turn proof into generation | +| Compare pages | Relevant product page, example page, studio CTA | Convert alternative search into QuickFork action | + +### Link Rules + +- Every crawlable marketing page should have at least one header or footer path plus related links. +- Related cards should prefer one same-stage page, one adjacent-stage page, and one conversion page. +- Anchor text should describe the target, for example `source-backed launch assets`, not `read more`. +- Do not list draft contact intent URLs in the XML sitemap until they are intended as crawlable landing pages. +- Keep canonical URLs free of UTM parameters. UTM variants belong to distributed links only. +- Use `/#studio` for free generation CTAs and `/contact?intent=launch-package` for paid or founder-led service CTAs. + +## URL Policy + +- Preserve existing published paths. +- Use lowercase slugs and hyphens. +- Keep cluster parents plural where they already exist: `/use-cases`, `/resources`, `/tools`, `/templates`, `/examples`, `/compare`. +- Keep `/product/{slug}` singular because the current catalog already uses it. +- Do not switch `/product` to `/products` without redirects and test updates. +- Keep `/pricing.md` as an AI/crawler-readable pricing context while pricing remains unsettled. +- If public pricing becomes validated, add `/pricing` as an HTML page and keep `/pricing.md` as a machine-readable companion, with internal links explaining both. + +## Implementation Phases + +### Phase 1: Navigation Exposure + +Goal: make the existing published pages discoverable without changing URLs. + +- Expand `LandingNav` into product, use-case, resource, and examples menus. +- Expand `LandingFooter` into grouped columns. +- Keep `/#pricing` in the header, but add `pricing.md` only in footer utility or AI discovery links. +- Add tests that assert key published routes appear in header/footer output. + +### Phase 2: Internal Link Strength + +Goal: make the existing crawlable pages function as coherent clusters. + +- Replace the generic related-route logic with a curated internal-link map for the highest-priority pages. +- Add breadcrumbs or breadcrumb-like route labels to marketing pages. +- Add a regression test that verifies every `sitemapMarketingLinks` path has at least one planned inbound link from header, footer, homepage, or curated related links. + +### Phase 3: Hub Pages + +Goal: add browseable parent pages once the current route set needs scalable navigation. + +- Add `/product`, `/use-cases`, `/resources`, `/examples`, and `/compare` hub pages. +- Add hub pages to `link-catalog`, sitemap, `llms.txt`, and tests. +- Update breadcrumbs to point to real parent pages. +- Add redirects only if any published URL changes. No published URL changes are recommended now. + +## Acceptance Criteria + +- Homepage remains the first conversion surface and studio entry point. +- Header contains 4 to 7 primary navigation items plus a right-side CTA. +- Footer exposes all major public clusters and required legal/support links. +- Every crawlable marketing page has at least one inbound internal link outside the sitemap. +- `src/marketing/link-catalog.ts`, `public/sitemap.xml`, `public/llms.txt`, and `src/seo/public-growth.test.ts` stay synchronized. +- No page claims customer counts, adoption, ranking, revenue, exact pricing, or benchmark outcomes without evidence. +- Live smoke checks for `/`, `/sitemap.xml`, and `/llms.txt` return 200 before calling the architecture implementation shipped. diff --git a/src/App.test.tsx b/src/App.test.tsx index 3f8b97e..88cc1a7 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -37,7 +37,10 @@ describe("App", () => { expect(screen.getByRole("navigation", { name: /primary/i })).toBeInTheDocument(); expect(screen.getByRole("link", { name: /quickfork home/i })).toBeInTheDocument(); expect(screen.getByRole("link", { name: /product/i })).toHaveAttribute("href", "#studio"); - expect(screen.getByRole("link", { name: /pricing/i })).toHaveAttribute("href", "#pricing"); + expect(within(screen.getByRole("navigation", { name: /primary/i })).getByRole("link", { name: /pricing/i })).toHaveAttribute( + "href", + "#pricing", + ); const footerNav = screen.getByRole("navigation", { name: /footer/i }); expect(within(footerNav).getByRole("link", { name: /^contact$/i })).toHaveAttribute("href", "/contact"); expect(within(footerNav).getByRole("link", { name: /^help$/i })).toHaveAttribute("href", "/help"); @@ -94,6 +97,90 @@ describe("App", () => { expect(screen.getByRole("heading", { name: /From GitHub URL to multilingual launch package/i })).toBeInTheDocument(); }, 10000); + it("exposes the published growth architecture through header and footer navigation", () => { + render(); + + const primaryNav = screen.getByRole("navigation", { name: /primary/i }); + expect(within(primaryNav).getByRole("link", { name: /^product/i })).toHaveAttribute("href", "#studio"); + expect(within(primaryNav).getByRole("link", { name: /^use cases/i })).toHaveAttribute( + "href", + "/use-cases/open-source-launch", + ); + expect(within(primaryNav).getByRole("link", { name: /^resources/i })).toHaveAttribute( + "href", + "/resources/open-source-launch-checklist", + ); + expect(within(primaryNav).getByRole("link", { name: /^examples/i })).toHaveAttribute( + "href", + "/examples/qwenlm-flashqla-launch-card", + ); + expect(within(primaryNav).getByRole("link", { name: /generate free repo brief/i })).toHaveAttribute("href", "#studio"); + + const productMenu = screen.getByLabelText(/quickfork product menu/i); + expect(within(productMenu).getByRole("link", { name: /repo to launch package/i })).toHaveAttribute( + "href", + "/product/github-repo-to-launch-package", + ); + expect(within(productMenu).getByRole("link", { name: /source-backed launch assets/i })).toHaveAttribute( + "href", + "/product/source-backed-launch-assets", + ); + expect(within(productMenu).getByRole("link", { name: /launch package pilot/i })).toHaveAttribute( + "href", + "/product/repository-launch-package-pilot", + ); + + const resourcesMenu = screen.getByLabelText(/quickfork resources menu/i); + expect(within(resourcesMenu).getByRole("link", { name: /launch readiness score/i })).toHaveAttribute( + "href", + "/tools/github-repo-launch-readiness-score", + ); + expect(within(resourcesMenu).getByRole("link", { name: /launch announcement template/i })).toHaveAttribute( + "href", + "/templates/github-launch-announcement", + ); + + const footerNav = screen.getByRole("navigation", { name: /footer/i }); + expect(within(footerNav).getByRole("heading", { name: /^product$/i })).toBeInTheDocument(); + expect(within(footerNav).getByRole("heading", { name: /^resources$/i })).toBeInTheDocument(); + expect(within(footerNav).getByRole("heading", { name: /^legal and ai discovery$/i })).toBeInTheDocument(); + expect(within(footerNav).getByRole("link", { name: /repo to launch package/i })).toHaveAttribute( + "href", + "/product/github-repo-to-launch-package", + ); + expect(within(footerNav).getByRole("link", { name: /launch demand map/i })).toHaveAttribute( + "href", + "/resources/github-repo-launch-demand-map", + ); + expect(within(footerNav).getByRole("link", { name: /^llms\.txt$/i })).toHaveAttribute("href", "/llms.txt"); + expect(within(footerNav).getByRole("link", { name: /^pricing\.md$/i })).toHaveAttribute("href", "/pricing.md"); + }); + + it("renders marketing breadcrumbs and curated related routes for high-priority pages", () => { + window.history.replaceState({}, "", "/product/github-repo-to-launch-package"); + + render(); + + const breadcrumbs = screen.getByRole("navigation", { name: /breadcrumb/i }); + expect(within(breadcrumbs).getByRole("link", { name: /^home$/i })).toHaveAttribute("href", "/"); + expect(within(breadcrumbs).getByText(/^Product$/i)).toBeInTheDocument(); + expect(within(breadcrumbs).getByText(/GitHub Repo To Launch Package/i)).toBeInTheDocument(); + + const relatedRoutes = screen.getByRole("region", { name: /related routes/i }); + expect(within(relatedRoutes).getByRole("link", { name: /^use case: open source launch$/i })).toHaveAttribute( + "href", + "/use-cases/open-source-launch", + ); + expect(within(relatedRoutes).getByRole("link", { name: /^resource: open source launch checklist$/i })).toHaveAttribute( + "href", + "/resources/open-source-launch-checklist", + ); + expect(within(relatedRoutes).getByRole("link", { name: /^tool: github repo launch readiness score$/i })).toHaveAttribute( + "href", + "/tools/github-repo-launch-readiness-score", + ); + }); + it("keeps the generator studio inside the redesigned frontend", () => { render(); @@ -1120,7 +1207,10 @@ describe("App", () => { expect(screen.getByRole("heading", { name: /help center/i })).toBeInTheDocument(); expect(screen.getByRole("link", { name: /quickfork home/i })).toHaveAttribute("href", "/#hero"); expect(screen.getByRole("link", { name: /product/i })).toHaveAttribute("href", "/#studio"); - expect(screen.getByRole("link", { name: /pricing/i })).toHaveAttribute("href", "/#pricing"); + expect(within(screen.getByRole("navigation", { name: /primary/i })).getByRole("link", { name: /pricing/i })).toHaveAttribute( + "href", + "/#pricing", + ); expect(screen.getByRole("link", { name: /contact the team/i })).toHaveAttribute("href", "/contact"); expect(document.title).toBe("Help Center | QuickFork"); expect(document.querySelector('link[rel="canonical"]')).toHaveAttribute("href", "https://seekersai.com/help"); @@ -1617,7 +1707,8 @@ describe("App", () => { it("shows auth state controls in the top navigation", () => { render(); - expect(screen.getByRole("link", { name: /sign in/i })).toHaveAttribute("href", "/sign-in"); - expect(screen.getByRole("link", { name: /sign up/i })).toHaveAttribute("href", "/sign-up"); + const banner = screen.getByRole("banner"); + expect(within(banner).getByRole("link", { name: /sign in/i })).toHaveAttribute("href", "/sign-in"); + expect(within(banner).getByRole("link", { name: /sign up/i })).toHaveAttribute("href", "/sign-up"); }); }); diff --git a/src/components/landing/LandingNav.tsx b/src/components/landing/LandingNav.tsx index 9096030..a87e100 100644 --- a/src/components/landing/LandingNav.tsx +++ b/src/components/landing/LandingNav.tsx @@ -1,24 +1,152 @@ -import { ChevronDown, Layers3, PanelTop, Sparkles } from "lucide-react"; +import { BookOpen, ChevronDown, FileText, Layers3, PanelTop, Route, Search, Sparkles, Target } from "lucide-react"; import { UserMenu } from "../auth/UserMenu"; -const productMenuItems = [ +const navMenus = [ { + label: "Product", href: "#studio", - icon: PanelTop, - title: "Studio", - description: "Generate the QuickFork launch package", + ariaLabel: "Product, open QuickFork product studio", + menuLabel: "QuickFork product menu", + items: [ + { + href: "#studio", + icon: PanelTop, + title: "Studio", + description: "Generate the QuickFork launch package", + }, + { + href: "/product/github-repo-to-launch-package", + icon: Route, + title: "Repo to launch package", + description: "Source-backed story, copy, and visuals", + }, + { + href: "/product/source-backed-launch-assets", + icon: Target, + title: "Source-backed launch assets", + description: "Keep generated claims reviewable", + }, + { + href: "/product/cold-start-launch-materials", + icon: Sparkles, + title: "Cold-start launch materials", + description: "README, social, deck, and outreach drafts", + }, + { + href: "/product/github-repo-launch-materials-map", + icon: Layers3, + title: "Launch materials map", + description: "Plan every launch artifact by evidence", + }, + { + href: "/product/repository-launch-package-pilot", + icon: FileText, + title: "Launch package pilot", + description: "Request a fuller founder-led package", + }, + ], }, { - href: "#how-to", - icon: Layers3, - title: "Launch Flow", - description: "From GitHub repo to output package", + label: "Use Cases", + href: "/use-cases/open-source-launch", + ariaLabel: "Use Cases, browse QuickFork launch use cases", + menuLabel: "QuickFork use cases menu", + items: [ + { + href: "/use-cases/open-source-launch", + icon: BookOpen, + title: "Open-source launch", + description: "Package a public repository for launch", + }, + { + href: "/use-cases/ai-project-launch", + icon: Sparkles, + title: "AI project launch", + description: "Explain AI repos for builders and users", + }, + { + href: "/use-cases/devrel-launch-workflow", + icon: Route, + title: "DevRel launch workflow", + description: "Repeat launch prep across many projects", + }, + ], }, { - href: "#features", - icon: Sparkles, - title: "Prompt System", - description: "Copy, layout, and visual prompt planning", + label: "Resources", + href: "/resources/open-source-launch-checklist", + ariaLabel: "Resources, browse QuickFork launch resources", + menuLabel: "QuickFork resources menu", + items: [ + { + href: "/resources/open-source-launch-checklist", + icon: FileText, + title: "Open-source launch checklist", + description: "Review launch basics before publishing", + }, + { + href: "/resources/github-project-marketing-card-guide", + icon: BookOpen, + title: "Marketing card guide", + description: "Turn a repo into a visual card", + }, + { + href: "/resources/github-repo-launch-demand-map", + icon: Search, + title: "Launch demand map", + description: "Prioritize launch pages and assets", + }, + { + href: "/resources/readme-cover-prompt-guide", + icon: Sparkles, + title: "README cover prompt guide", + description: "Prompt safer README launch visuals", + }, + { + href: "/tools/github-repo-launch-readiness-score", + icon: Target, + title: "Launch readiness score", + description: "Score what the repo needs next", + }, + { + href: "/templates/github-launch-announcement", + icon: FileText, + title: "Launch announcement template", + description: "Draft a launch post from source evidence", + }, + ], + }, + { + label: "Examples", + href: "/examples/qwenlm-flashqla-launch-card", + ariaLabel: "Examples, browse QuickFork examples and comparisons", + menuLabel: "QuickFork examples menu", + items: [ + { + href: "/examples/qwenlm-flashqla-launch-card", + icon: PanelTop, + title: "QwenLM FlashQLA launch card", + description: "A source-backed launch example", + }, + { + href: "/examples/deepseek-twvp-launch-card", + icon: PanelTop, + title: "DeepSeek TWVP launch card", + description: "A visual primitive project example", + }, + { + href: "/compare/chatgpt-open-source-launch-copy", + icon: Search, + title: "ChatGPT comparison", + description: "Compare generic chat to repo evidence", + }, + { + href: "/compare/canva-readme-banner-generator", + icon: Search, + title: "Canva comparison", + description: "Compare visual tools to source-backed assets", + }, + ], }, ]; @@ -35,32 +163,37 @@ export function LandingNav() { QuickFork
@@ -73,3 +206,7 @@ export function LandingNav() { function getLandingAnchorHref(hash: string) { return window.location.pathname === "/" ? hash : `/${hash}`; } + +function getNavHref(href: string) { + return href.startsWith("#") ? getLandingAnchorHref(href) : href; +} diff --git a/src/components/landing/LandingSections.tsx b/src/components/landing/LandingSections.tsx index def0cbc..31b1c19 100644 --- a/src/components/landing/LandingSections.tsx +++ b/src/components/landing/LandingSections.tsx @@ -221,6 +221,65 @@ export function ClosingCTA() { } export function LandingFooter() { + const footerGroups = [ + { + title: "Product", + links: [ + { href: "/#studio", label: "Studio" }, + { href: "/product/github-repo-to-launch-package", label: "Repo to launch package" }, + { href: "/product/source-backed-launch-assets", label: "Source-backed launch assets" }, + { href: "/product/cold-start-launch-materials", label: "Cold-start launch materials" }, + { href: "/product/repository-launch-package-pilot", label: "Launch package pilot" }, + ], + }, + { + title: "Use Cases", + links: [ + { href: "/use-cases/open-source-launch", label: "Open-source launch" }, + { href: "/use-cases/ai-project-launch", label: "AI project launch" }, + { href: "/use-cases/devrel-launch-workflow", label: "DevRel launch workflow" }, + ], + }, + { + title: "Resources", + links: [ + { href: "/resources/open-source-launch-checklist", label: "Checklist" }, + { href: "/resources/github-project-marketing-card-guide", label: "Marketing card guide" }, + { href: "/resources/github-repo-launch-demand-map", label: "Launch demand map" }, + { href: "/tools/github-repo-launch-readiness-score", label: "Readiness score" }, + { href: "/templates/github-launch-announcement", label: "Launch template" }, + ], + }, + { + title: "Examples", + links: [ + { href: "/examples/qwenlm-flashqla-launch-card", label: "FlashQLA" }, + { href: "/examples/deepseek-twvp-launch-card", label: "DeepSeek TWVP" }, + { href: "/compare/chatgpt-open-source-launch-copy", label: "ChatGPT comparison" }, + { href: "/compare/canva-readme-banner-generator", label: "Canva comparison" }, + ], + }, + { + title: "Support", + links: [ + { href: "/contact", label: "Contact" }, + { href: "/help", label: "Help" }, + { href: "/sign-in", label: "Sign in" }, + { href: "/sign-up", label: "Sign up" }, + ], + }, + { + title: "Legal and AI Discovery", + links: [ + { href: "/privacy", label: "Privacy" }, + { href: "/terms", label: "Terms" }, + { href: "/llms.txt", label: "llms.txt" }, + { href: "/pricing.md", label: "pricing.md" }, + { href: "/sitemap.xml", label: "sitemap.xml" }, + ], + }, + ]; + return (
@@ -228,10 +287,18 @@ export function LandingFooter() { Source-backed launch assets for public repositories.
); diff --git a/src/components/marketing/MarketingPage.tsx b/src/components/marketing/MarketingPage.tsx index 759daa8..2fd3bd0 100644 --- a/src/components/marketing/MarketingPage.tsx +++ b/src/components/marketing/MarketingPage.tsx @@ -4,7 +4,7 @@ import { useEffect } from "react"; import { LandingFooter } from "../landing/LandingSections"; import { LandingNav } from "../landing/LandingNav"; import { trackEvent } from "../../lib/analytics"; -import { marketingPageLinks, type MarketingLink } from "../../marketing/link-catalog"; +import { marketingPageLinks, type MarketingLink, type MarketingPageType } from "../../marketing/link-catalog"; import { formatMarketingLabel, getMarketingPageDescription, @@ -82,6 +82,7 @@ export function MarketingPage({ link }: MarketingPageProps) {
+
@@ -357,14 +358,19 @@ export function MarketingPage({ link }: MarketingPageProps) { ) : null} {relatedLinks.length > 0 ? ( -
+
Related routes
{relatedLinks.map((relatedLink) => ( - + {getMarketingPageTypeLabel(relatedLink)} {formatMarketingLabel(relatedLink.primaryKeyword)} {getMarketingPrimaryCtaLabel(relatedLink)} @@ -379,6 +385,18 @@ export function MarketingPage({ link }: MarketingPageProps) { ); } +function MarketingBreadcrumbs({ link }: { link: MarketingLink }) { + return ( + + ); +} + function applyRouteMetadata(link: MarketingLink) { const previousTitle = document.title; const descriptionMeta = getOrCreateMetaDescription(); @@ -455,12 +473,107 @@ function applyMarketingSchema(link: MarketingLink) { } function getRelatedLinks(currentLink: MarketingLink) { + const curatedSlugs = curatedRelatedLinkSlugs[currentLink.slug]; + + if (curatedSlugs) { + return curatedSlugs + .map((slug) => marketingPageLinks.find((link) => link.slug === slug)) + .filter((link): link is MarketingLink => Boolean(link)); + } + return marketingPageLinks .filter((link) => link.slug !== currentLink.slug) .filter((link) => link.funnelStage === currentLink.funnelStage || link.buyerStage === currentLink.buyerStage) .slice(0, 3); } +const curatedRelatedLinkSlugs: Record = { + "github-repo-to-launch-package": [ + "open-source-launch", + "open-source-launch-checklist", + "github-repo-launch-readiness-score", + ], + "source-backed-launch-assets": [ + "github-project-marketing-card-guide", + "chatgpt-open-source-launch-copy", + "repository-launch-package-pilot", + ], + "cold-start-launch-materials": [ + "github-repo-launch-demand-map", + "ai-project-launch", + "github-repo-launch-materials-map", + ], + "github-repo-launch-materials-map": [ + "devrel-launch-workflow", + "github-launch-announcement", + "github-repo-to-product-outreach", + ], + "readme-marketing-cards": [ + "readme-cover-prompt-guide", + "canva-readme-banner-generator", + "qwenlm-flashqla-launch-card", + ], + "github-repo-visual-explainer": [ + "qwenlm-flashqla-launch-card", + "deepseek-twvp-launch-card", + "github-project-marketing-card-guide", + ], + "github-repo-to-launch-deck": [ + "github-launch-announcement", + "github-repo-launch-demand-map", + "repository-launch-package-pilot", + ], + "github-repo-to-product-outreach": [ + "repository-launch-package-pilot", + "github-repo-launch-demand-map", + "source-backed-launch-assets", + ], + "github-repo-launch-readiness-score": [ + "repository-launch-package-pilot", + "cold-start-launch-materials", + "open-source-launch-checklist", + ], + "qwenlm-flashqla-launch-card": [ + "github-repo-visual-explainer", + "github-project-marketing-card-guide", + "github-repo-to-launch-package", + ], + "deepseek-twvp-launch-card": [ + "github-repo-visual-explainer", + "source-backed-launch-assets", + "ai-project-launch", + ], + "chatgpt-open-source-launch-copy": [ + "source-backed-launch-assets", + "qwenlm-flashqla-launch-card", + "github-repo-to-launch-package", + ], + "canva-readme-banner-generator": [ + "readme-marketing-cards", + "readme-cover-prompt-guide", + "qwenlm-flashqla-launch-card", + ], +}; + +function getMarketingParentLabel(pageType: MarketingPageType) { + const parentLabels: Record = { + product: "Product", + use_case: "Use Cases", + resource: "Resources", + tool: "Tools", + template: "Templates", + example: "Examples", + compare: "Compare", + contact: "Contact", + }; + + return parentLabels[pageType]; +} + +function getMarketingBreadcrumbLabel(link: MarketingLink) { + return getMarketingPageTitle(link).replace(/\s+\|\s+QuickFork$/, ""); +} + function getResourceType(link: MarketingLink) { if (link.slug.includes("checklist")) return "checklist"; if (link.slug.includes("template") || link.slug.includes("prompt")) return "template"; diff --git a/src/styles/app.css b/src/styles/app.css index 9edfa3c..6b1961e 100644 --- a/src/styles/app.css +++ b/src/styles/app.css @@ -142,6 +142,11 @@ blockquote { position: relative; } +.productNavItem:last-of-type .productMenu { + right: 0; + left: auto; +} + .navLink { min-height: 36px; display: inline-flex; @@ -174,6 +179,12 @@ blockquote { padding-inline: 12px; } +.navBriefLink { + border-color: var(--dark); + color: #ffffff; + background: var(--dark); +} + .productChevron { transition: transform 160ms ease; } @@ -189,6 +200,13 @@ blockquote { outline-offset: 2px; } +.navBriefLink:hover, +.navBriefLink:focus-visible { + border-color: var(--dark); + color: #ffffff; + background: #191936; +} + .productNavItem:hover .productChevron, .productNavItem:focus-within .productChevron { transform: rotate(180deg); @@ -2331,13 +2349,12 @@ blockquote { } .footer { - min-height: 112px; border-top: 1px solid var(--border); display: grid; - grid-template-columns: minmax(0, 1fr) auto; - align-items: center; - justify-content: space-between; - gap: 24px; + grid-template-columns: minmax(220px, 0.7fr) minmax(0, 1.7fr); + align-items: start; + gap: 32px; + padding: 34px 0; color: var(--muted); font-size: 11px; font-weight: 650; @@ -2363,27 +2380,49 @@ blockquote { } .footerNav { - display: flex; - flex-wrap: wrap; - justify-content: flex-end; - gap: 8px; + display: grid; + grid-template-columns: repeat(3, minmax(140px, 1fr)); + gap: 22px 20px; +} + +.footerGroup { + display: grid; + gap: 10px; + align-content: start; +} + +.footerGroup h2 { + color: var(--fg); + font: 700 12px/1 var(--font-mono); + letter-spacing: 0; + text-transform: uppercase; +} + +.footerGroup div { + display: grid; + gap: 6px; } .footerNav a { - min-height: 38px; + min-height: 28px; border: 1px solid transparent; border-radius: 4px; display: inline-flex; align-items: center; - padding: 0 10px; + justify-self: start; + padding: 0; color: var(--muted); + font-size: 13px; + font-weight: 550; + line-height: 1.25; + text-transform: none; } .footerNav a:hover, .footerNav a:focus-visible { - border-color: var(--border); color: var(--fg); - background: #ffffff; + text-decoration: underline; + text-underline-offset: 3px; } .secondaryHero, @@ -2500,6 +2539,7 @@ blockquote { } .marketingHeroSection, +.marketingBreadcrumbs, .marketingBodySection, .marketingGrowthSection, .marketingCaptureSection, @@ -2508,8 +2548,36 @@ blockquote { margin: 0 auto; } +.marketingBreadcrumbs { + padding-top: 34px; + display: flex; + flex-wrap: wrap; + gap: 8px; + align-items: center; + color: var(--muted); + font: 650 12px/1.4 var(--font-mono); + text-transform: uppercase; +} + +.marketingBreadcrumbs a { + color: var(--fg); +} + +.marketingBreadcrumbs a:hover, +.marketingBreadcrumbs a:focus-visible { + text-decoration: underline; + text-underline-offset: 3px; +} + +.marketingBreadcrumbs span[aria-current="page"] { + overflow: hidden; + text-overflow: ellipsis; + color: var(--fg); + white-space: nowrap; +} + .marketingHeroSection { - padding: 92px 0 64px; + padding: 44px 0 64px; } .marketingHeroGrid { @@ -3261,6 +3329,7 @@ blockquote { .studioSection, .closing, .marketingHeroSection, + .marketingBreadcrumbs, .marketingBodySection, .marketingGrowthSection, .marketingCaptureSection, @@ -3285,7 +3354,8 @@ blockquote { justify-self: start; width: 100%; gap: 8px; - overflow: visible; + overflow-x: auto; + scrollbar-width: none; } .productNavItem { @@ -3503,6 +3573,17 @@ blockquote { } .footerNav { - justify-content: flex-start; + grid-template-columns: repeat(2, minmax(0, 1fr)); + width: 100%; + } +} + +@media (max-width: 520px) { + .footerNav { + grid-template-columns: 1fr; + } + + .marketingBreadcrumbs span[aria-current="page"] { + white-space: normal; } }