Astro Theme & Site Rendering
- theme/src/lib/bundle.ts
- PageEntry
- IndexManifest
- NavGroup
- ParsedPage
- theme/src/scripts/site.ts
- theme/src/components/GraphExplorer.svelte
- theme/src/layouts/BaseLayout.astro
- theme/src/pages/pages/[slug].astro
Relevant source files · 6
The theme/ directory is the Astro site that turns an astrolabe wiki bundle — a directory of markdown pages plus index.json and version.json produced by the wiki writer — into a static, browsable website. It is deliberately thin: all rendering happens at build time from plain files, and the browser only ever receives static markup that a small client script enhances with the design system's widget bundle. Nothing in bundle.ts ships to the browser; it exists purely for getStaticPaths and frontmatter code Design note.
Reading the bundle at build time
Everything the theme knows about the wiki comes from theme/src/lib/bundle.ts. The bundle location is resolved from the BUNDLE_DIR environment variable (defaulting to ../bundle) by bundleDir() bundleDir, and readIndex() parses index.json into an IndexManifest — the repo identity, generation metadata, and the canonical ordered list of PageEntry records readIndex. Each PageEntry carries the slug, title, type (overview | reference | guide), scope, documented symbols, citation count, and verification status PageEntry; the verification badge on every rendered page comes straight from this field.
Two derived helpers drive the site chrome. navGroups() builds the sidebar structure: overview pages sit at the top level, every other type becomes a numbered group (2 Reference → 2.1 …), ordered by the fixed TYPE_ORDER of overview, reference, guide navGroups. And readRepo() recovers repository identity in a slightly clever way: the bundle has no repository URL of its own, so readRepo scans the rendered pages for the first source-host blob citation link (GitHub /blob/<ref>/ or GitLab /-/blob/<ref>/), extracts owner, name, and host from it, and caches the result readRepo.
Markdown rendering
theme/src/lib/markdown.ts turns each bundle page's markdown into HTML at build time. parsePage handles frontmatter with gray-matter, body with marked, and produces a ParsedPage: frontmatter data, rendered HTML, h2/h3 headings in document order (for the "On this page" column), and the list of SourceFiles cited by the page ParsedPage. A link-rewrite pass maps bundle-relative targets onto site routes — <slug>.md becomes /pages/<slug>/, src/<path> becomes /src/<path>, while http(s), mailto, and absolute links pass through unchanged rewriteHref. The renderer emits the design system's own markup conventions — heading ids matching what Astrolabe.Prose.slug would produce, code fences as CodeBlock figures, mermaid fences as MermaidViewer figures — so the statically rendered ToC and client enhancement agree Rendered markup.
The page frame
BaseLayout.astro is the frame every page renders into: sticky SiteHeader, left SiteNav, article, and right-hand ToC, all static markup that design/bundle.js enhances on load Layout overview. It pulls the manifest, repo info, and version info from bundle.ts, builds the nav from navGroups, and nests h3 headings under their preceding h2 for the ToC Layout data assembly. Three notable details:
- An inline script applies the stored theme (
astrolabe:themein localStorage, with a one-time migration from the oldastrolabe-themekey) before first paint, falling back toprefers-color-scheme/ contrast media queries — the inline equivalent ofAstrolabe.ThemeSelector.init()theme initialization script. - The header wires up the search button (
data-al-search, revealed once the Pagefind index answers), the version and theme selector mounts (data-al-version,data-al-theme), and a breadcrumb built from the repo info recovered byreadRepoHeader actions. - The
<article>carriesdata-pagefind-bodyonly whenindexedis set, so only wiki pages enter the search index Article element. - The nav's Resources section is conditional on bundle contents: the "Symbol graph" link only appears when
graph.jsonexists, checked withhasFileNav resources.
Page routes
theme/src/pages/pages/[slug].astro is the route that renders every wiki page. Its getStaticPaths lists the bundle's pages/*.md files and runs each through parsePage, passing slug, frontmatter data, HTML, headings, and cited sources as props getStaticPaths. The template then renders the page header — title, type and scope badges, a verification badge driven by the manifest's verification field, and symbol chips — followed by a collapsible "Relevant source files" list built from the cited SourceFiles, with line ranges rendered en-dash-separated and capped at four entries per file Page metadata and source list. Finally it injects the rendered HTML and computes prev/next links from the manifest's canonical order (overview first, then scope order), falling back to the index page when there is no previous page Prev/next nav.
A separate theme/src/pages/graph.astro renders the interactive symbol graph using GraphExplorer.svelte as a full-width island — the only Svelte component in the theme — while ordinary pages remain pure static HTML GraphExplorer usage.
Client-side enhancement
theme/src/scripts/site.ts is the single client entry point. It runs after BaseLayout has loaded the design system's bundle as a classic script, reads site metadata out of the al-site JSON element the layout serialized, and then runs three steps: A.enhance() wires up all the design system's [data-al-*] widgets, mountVersions() mounts the version selector, and mountDiagrams() lazily loads Mermaid Enhancement entry point.
The version selector is resilient to how the site was deployed: it tries fetch('/versions.json') (assembled by the deploy pipeline for multi-version sites), normalizes both the design system's Version shape and a legacy shape through toVersion, and — when there is no versions file — synthesizes a single entry from the bundle's own commit and tag so the SHA is always visible mountVersions. Diagram mounting is lazy by design: it only queries figure.al-diagram[data-al-mermaid] elements, returns early when there are none, and dynamically imports the mermaid package just for those pages; on failure the figures stay unmounted so the raw Mermaid source remains readable mountDiagrams.
Relationships
graph TD
subgraph "Bundle (build input)"
IDX["index.json"]
PAGES["pages/*.md"]
VERSION["version.json"]
end
subgraph "theme build time"
BUNDLE["`theme/src/lib/bundle.ts`"]
MARKDOWN["`theme/src/lib/markdown.ts`"]
SLUG["`theme/src/pages/pages/[slug].astro`"]
GRAPH["`theme/src/pages/graph.astro`"]
LAYOUT["`theme/src/layouts/BaseLayout.astro`"]
end
subgraph "client"
SITE["`theme/src/scripts/site.ts`"]
DESIGN["design/bundle.js (window.Astrolabe)"]
EXPLORER["`theme/src/components/GraphExplorer.svelte`"]
end
IDX --> BUNDLE
VERSION --> BUNDLE
BUNDLE --> LAYOUT
PAGES --> MARKDOWN
MARKDOWN --> SLUG
SLUG --> LAYOUT
LAYOUT --> SITE
SITE --> DESIGN
GRAPH --> LAYOUT
GRAPH --> EXPLORERReference
| Symbol | Kind | What it does | Location |
|---|---|---|---|
bundle.ts |
file | Build-time readers for the bundle directory (index, version, repo, nav) | theme/src/lib/bundle.ts |
PageEntry |
interface | One wiki page's manifest record: slug, title, type, scope, symbols, verification | theme/src/lib/bundle.ts |
IndexManifest |
interface | Root of index.json: repo identity, generation metadata, ordered pages |
theme/src/lib/bundle.ts |
NavGroup |
interface | Sidebar entry: numbered page or labeled group with numbered children | theme/src/lib/bundle.ts |
ParsedPage |
interface | Result of rendering one page: data, HTML, headings, cited source files | theme/src/lib/markdown.ts |
site.ts |
file | Client entry: A.enhance(), version selector, lazy Mermaid mounting |
theme/src/scripts/site.ts |
GraphExplorer.svelte |
file | Interactive symbol graph island, mounted by the graph page | theme/src/components/GraphExplorer.svelte |
BaseLayout.astro |
file | Site frame: header, nav, article, ToC, theme bootstrapping | theme/src/layouts/BaseLayout.astro |
[slug].astro |
file | Wiki page route: static paths, page metadata, source list, prev/next | theme/src/pages/pages/[slug].astro |
Generated by astrolabe from commit ecc180b3 (tag 0.4.0).