Skip to content

Navigation Menu

Sign in
Sign up

Docsite Architecture

Cindy Zhang edited this page Aug 11, 2026 · 7 revisions

Docsite Architecture

The Astryx docsite lives at astryx.atmeta.com (the Vercel deployment at xds-sandbox.vercel.app serves the same site) and is a Next.js 15 app that renders documentation from generated registries. All content originates from .doc.mjs files colocated with source code — there is no separate CMS or markdown content directory.


Quick Reference

What Where
Docsite app apps/docsite/
Data generation script apps/docsite/scripts/generate-data.mjs
Generated registries apps/docsite/src/generated/ (gitignored, built at dev/build time)
Component docs source packages/core/src/<Component>/<Name>.doc.mjs
Reference docs source packages/cli/assets/docs/<topic>.doc.mjs
Example blocks source packages/cli/assets/templates/blocks/components/<Name>/
Page templates source packages/cli/templates/pages/<slug>/
Doc type definitions @astryxdesign/cli/authoring (packages/cli/authoring/)
Shell / sidebar nav apps/docsite/src/components/DocsShell.tsx
Deployment Vercel (auto-deploy on push to main)

Page Types

1. Home / Overview

URL: /

What it shows: Hero section, package grid (libraries + themes), and foundations card grid.

Data source: packageRegistry, componentRegistry (count), docsRegistry (foundations topics), themeRegistry (live theme previews).

Code: apps/docsite/src/app/(docs)/page.tsx


2. Component Detail

URL pattern: /components/[name]

What it shows: Two tabs — Overview (showcase preview, usage description, import path, best practices, examples) and Playground (interactive preview with live prop controls).

Data source:

  • Component metadata → componentRegistry (from packages/core/src/<Dir>/<Name>.doc.mjs)
  • Showcase preview → showcaseRegistry (from packages/cli/assets/templates/blocks/components/<Name>/<Name>Showcase.tsx)
  • Example blocks → exampleRegistry (from non-showcase .doc.mjs + .tsx pairs in the blocks directory)
  • Package info → packageRegistry

Code:

  • Route: apps/docsite/src/app/(docs)/components/[name]/page.tsx
  • Client component: apps/docsite/src/components/component-detail/ComponentDetailClient.tsx
  • Sub-components: apps/docsite/src/components/component-detail/ (PropsTable, BestPractices, ExampleBlock, ShowcasePreview, InteractivePreview, HookSignature, PlaygroundPropsTable)

3. Package Page

URL pattern: /packages/[name]

What it shows: Adapts based on package type:

  • Component package (@astryxdesign/core): heading + grouped component grid with preview cards
  • Theme package (@astryxdesign/theme-*): live theme preview with install steps
  • Other (@astryxdesign/cli): README rendered as markdown

Data source: packageRegistry, groupedComponentRegistry, themeRegistry

Code: apps/docsite/src/app/(docs)/packages/[name]/page.tsx


4. Doc Topic (Guides & Foundations)

URL pattern: /docs/[topic]

What it shows: Long-form reference documentation. Two rendering modes:

  • Token topics (color, elevation, motion, shape, spacing, typography, tokens): rendered via TokensDocView with live token tables
  • Other docs (principles, styling, theme, getting-started): rendered via ReferenceDocView with prose/code/table/list blocks

Data source: docsRegistry (from packages/cli/assets/docs/<topic>.doc.mjs)

Code:

  • Route: apps/docsite/src/app/(docs)/docs/[topic]/page.tsx
  • Token view: apps/docsite/src/components/docs/TokensDocView.tsx
  • Reference view: apps/docsite/src/components/docs/ReferenceDocView.tsx
  • Block renderer: apps/docsite/src/components/docs/ContentBlockRenderer.tsx

5. Changelog

URL: /changelog

What it shows: Aggregated changelogs from all non-private packages, with component name cross-referencing for linking.

Data source: packageRegistry (the changelog field, read from packages/<name>/CHANGELOG.md), componentRegistry (component names for linking)

Code: apps/docsite/src/app/(docs)/changelog/page.tsx, apps/docsite/src/components/ChangelogView.tsx


6. Templates (Gallery)

URL: /templates

What it shows: Tabbed gallery of templates, themes, and component showcases with hover-overlay cards.

Data source: templateRegistry, blockRegistry (showcases), themeRegistry, packageRegistry

Code: apps/docsite/src/app/(site)/templates/page.tsx


7. Template Viewer

URL pattern: /templates/[slug]

What it shows: Individual template preview (WIP — currently shows title + description).

Data source: templateRegistry

Code: apps/docsite/src/app/craft/templates/[slug]/page.tsx


8. Theme Editor

URL: /craft/theme

What it shows: Live theme customization (WIP — placeholder page).

Code: apps/docsite/src/app/craft/theme/page.tsx


9. Playground

URL: /playground

What it shows: Full-page Monaco code editor with live preview iframe. Users write TSX and see it rendered.

Data source: Component scope generated by scripts/generate-playground-types.mjs

Code: apps/docsite/src/app/playground/page.tsx, apps/docsite/src/app/playground/PlaygroundClient.tsx


Data Pipeline

How data gets generated

Source files (.doc.mjs) → generate-data.mjs → src/generated/*.ts → Next.js pages

The script runs automatically before dev and build (via predev / prebuild in package.json). You can also run it manually:

cd apps/docsite
node apps/docsite/scripts/generate-data.mjs

Generated Registries

Registry File Sources Contains
packageRegistry packageRegistry.ts packages/*/package.json + README + CHANGELOG Package metadata, versions, descriptions
componentRegistry componentRegistry.ts packages/core/src/*/*.doc.mjs Full component docs: props, usage, theming, keywords
groupedComponentRegistry groupedComponentRegistry.ts Derived from componentRegistry Nav-ready grouped/sorted component lists
blockRegistry blockRegistry.ts packages/cli/assets/templates/blocks/**/*.doc.mjs Example blocks with source code
showcaseRegistry showcaseRegistry.ts Subset of blocks where isShowcase: true Dynamic imports for showcase previews
exampleRegistry exampleRegistry.ts Subset of blocks where isShowcase: false Dynamic imports + source for example blocks
templateRegistry templateRegistry.ts packages/cli/templates/pages/*/template.doc.mjs Page template metadata
docsRegistry docsRegistry.ts packages/cli/assets/docs/*.doc.mjs Full doc topics with sections and content blocks
themeRegistry themeRegistry.ts Theme packages installed in docsite Live theme objects for preview rendering

Package discovery

Packages are auto-discovered from the root package.json workspaces field. Only packages/* directories are included (not apps/* or internal/*). Private packages and packages not installed in the docsite's dependencies are filtered out.


Data Structures

ComponentEntry (componentRegistry)

interface ComponentEntry {
 name: string; // "Button", "useToast"
 moduleName: string; // "Button", "useToast"
 directory: string; // "Button", "hooks"
 group: string | null; // Grouping label for nav (e.g. "Button")
 description: string; // From usage.description
 keywords: string[]; // Search terms
 hidden: boolean; // Excluded from nav if true
 parentDoc: string | null; // Parent component for sub-components/hooks
 props: PropDoc[]; // Prop documentation
 usage: UsageDoc | null; // Best practices, anatomy, features
 theming: ThemingDoc | null; // CSS class targets, vars
 params: HookParamDoc[] | null; // Hook parameters (null for components)
 returns: HookReturnDoc[] | null; // Hook return (null for components)
 playground: { defaults: Record<string, unknown> } | null;
}

DocTopic (docsRegistry)

interface DocTopic {
 topic: string; // URL slug: "tokens", "getting-started"
 title: string; // Display title
 description: string; // Short description
 category: string | null; // "guide" | "foundations" | null
 sections: DocSection[]; // Array of {title, content: ContentBlock[]}
}

ContentBlock types

type ContentBlock =
 | { type: 'prose'; text: string }
 | { type: 'code'; lang: string; code: string; label?: string }
 | { type: 'table'; headers: string[]; rows: string[][] }
 | { type: 'list'; style: 'ordered' | 'unordered' | 'do' | 'dont'; items: string[] }

BlockEntry (blockRegistry)

interface BlockEntry {
 dirName: string; // File basename
 name: string; // Display name
 description: string;
 exampleFor: string; // Component name this example belongs to
 isShowcase: boolean; // Hero preview vs. inline example
 aspectRatio: number; // For card thumbnails
 componentsUsed: string[];
 category: string; // Path like "components/Button"
 source: string; // Raw TSX source
}

Navigation Structure

The sidebar navigation is built in DocsShell.tsx from the generated registries. Here's the mapping:

Nav Section Data Source How Items Are Derived
Home Hardcoded Single link to /
What's New Hardcoded Single link to /changelog
Guide docsRegistry Topics with category === 'guide', sorted alphabetically
Guide → Foundations docsRegistry Topics with category === 'foundations', "tokens" pinned first, rest alphabetical
Libraries packageRegistry Non-theme packages, filtered to non-private + installed in docsite
Themes packageRegistry Packages where name includes theme-, uses displayName
Components groupedComponentRegistry Grouped items from @astryxdesign/core (see grouping logic below)
Utilities groupedComponentRegistry Hooks/utilities separated from main component list

Component Grouping Logic

The generateGroupedComponentRegistry function in generate-data.mjs groups components for the nav sidebar:

  1. Utilities bucket — components with group === 'Utilities' or standalone hooks in the hooks/ directory
  2. Explicit groups — components with a group field in their .doc.mjs
  3. Directory-based groups — hooks without parentDoc that live in a non-hooks directory are grouped by directory name
  4. Parent-child groups — hooks with a parentDoc field are nested under their parent component
  5. Ungrouped — everything else appears as standalone nav items

Groups with a single item render as a plain entry. Groups with multiple items render as a collapsible section.

Adding a new nav category

To add a new doc topic category (beyond guide and foundations):

  1. Add category: 'your-category' to the .doc.mjs file in packages/cli/assets/docs/
  2. In DocsShell.tsx, add filtering logic: const yourTopics = docTopics.filter(d => d.category === 'your-category')
  3. Add a new <SideNavSection> or nested <SideNavItem> for the section
  4. Add active-state detection for the new category

Authoring Documentation

Adding a new component doc

  1. Create packages/core/src/<ComponentDir>/<Name>.doc.mjs
  2. Export a docs object typed as ComponentDoc (from @astryxdesign/cli/authoring)
  3. Run node apps/docsite/scripts/generate-data.mjs to regenerate registries
  4. The component automatically appears in nav and at /components/<Name>

Adding a showcase preview

  1. Create packages/cli/assets/templates/blocks/components/<Name>/<Name>Showcase.doc.mjs with isShowcase: true and exampleFor: '<Name>'
  2. Create the matching <Name>Showcase.tsx with a default export
  3. Regenerate data — the showcase appears on the component's Overview tab

Adding an example block

  1. Create packages/cli/assets/templates/blocks/components/<Name>/<ExampleName>.doc.mjs with isShowcase: false and exampleFor: '<Name>'
  2. Create the matching .tsx file with a default export
  3. Regenerate — the example appears in the component's "Examples" section

Adding a reference doc

  1. Create packages/cli/docs/<topic>.doc.mjs
  2. Export a docs object typed as ReferenceDoc
  3. Set category: 'guide' or category: 'foundations' to control nav placement
  4. Regenerate — the topic appears in the sidebar under its category

Hiding a component from nav

Set hidden: true in the component's .doc.mjs. It won't appear in the sidebar but the page still exists at /components/<Name>.


Development

cd apps/docsite
pnpm install
pnpm dev # Runs generate + next dev

The predev script auto-regenerates data. After changing any .doc.mjs file, restart the dev server or manually run:

node apps/docsite/scripts/generate-data.mjs

Testing

pnpm test # Runs data extraction tests

Tests live in apps/docsite/src/__tests__/data-extraction.test.ts and verify the generation pipeline produces valid registries.


Deployment

The docsite deploys to Vercel at xds-sandbox.vercel.app and is served canonically at astryx.atmeta.com. It uses Next.js static export (generateStaticParams) for component and doc pages. The build step runs generate-data.mjs automatically via prebuild.

Clone this wiki locally

AltStyle によって変換されたページ (->オリジナル) /