/CLAUDE.md
CLAUDE.md at /CLAUDE.md
Path: CLAUDE.md
Zudo Design Token Panel
Documentation site built with zudo-doc — a zfb-based documentation framework with MDX, Tailwind CSS v4, and Preact islands. This project is intentionally minimal: one config file (zfb.config.ts) plus markdown content — layout, chrome, and islands all ship from @takazudo/zudo-doc in node_modules.
Tech Stack
zfb — documentation build framework
MDX — content format, authored under
src/content/Tailwind CSS v4 — compiled by zfb's embedded Tailwind engine (no
@tailwindcss/viteplugin, notailwindcssdependency);src/importsstyles/ global. css tailwindcss/preflight+tailwindcss/utilitiesand zfb's internal resolver serves bothPreact — for interactive islands only (with compat mode for React API)
zfb semantic highlighting — native build-time fenced-code rendering plus lazy
@takazudo/zfb-md-wasmfor HtmlPreview; both emithi-*classes resolved through--zd-syntax-*design tokens@takazudo/zudo-doc — the package that owns everything: layout, chrome, islands, default
@themedesign tokens, and (viapackageOwnedRoutes, on by default) the doc routes themselves
Commands
pnpm dev— runs the zfb dev server (port 4321) and the doc-history API server (port 4322) concurrently viarun-p(pnpm dev:zfb/pnpm dev:historyindividually)pnpm dev:network— same, but zfb binds--host 0.0.0.0for LAN access (pnpm dev:zfb:networkindividually); the doc-history server stays loopback-only and LAN clients reach it through zfb's/dev proxydoc- history/ * Trusted networks only: this also serves your git doc-history — including UNPUBLISHED local commits — to anyone on the LAN via the
/proxydoc- history/ * run-pswallows trailing args, so other zfb flags don't forward throughpnpm dev— pass them directly instead:pnpm run dev:zfb -- <flags>pnpm build— static HTML export todist/pnpm check— TypeScript type checkingpnpm preview— serve the builtdist/
Key Directories
zfb.config.ts # THE one config file — zudoDoc({ ...only fields you chose })
pages/
├── index.tsx # 1-line re-export of the package home route
└── docs/[[...slug]].tsx # self-contained doc-route stub (required for `pnpm dev`)
[locale]/docs/[[...slug]].tsx # same, for non-default locales
src/
├── chrome-bindings.tsx # optional typed primary chrome / named header / MDX bindings
├── content/
│ └── docs/ # MDX content (this project's showcase docs)
│ └── docs-ja/ # Japanese MDX content (mirrors docs/)
└── styles/
└── global.css # @import chain + a token-override slot — that's it Everything else — layout, header, sidebar, footer, doc chrome, islands, and the default design tokens — lives in node_modules/@takazudo/zudo-doc. For supported markup replacement, create src/ with defineChromeBindings, set chromeBindingsModule, and use the primary Header / Footer / Sidebar / Toc / Breadcrumb / DocPager slots or the named headerRightComponents registry. The generated default, locale, and doc-history route shapes already consume the same binding object; do not fork a route stub for presentational customization. npx zudo-doc eject <component> only copies source: heed its primary, nested-chrome, or content-layer remediation before expecting the copy to render. Settings you didn't set explicitly in zfb.config.ts use the package's documented defaults — hover zudoDoc's ZudoDocConfig argument in your editor to see every field and its @default.
zdtp ↔ zudo-doc relationship
The doc/ workspace intentionally consumes the pinned npm release of @takazudo/zdtp; never force-link it to packages/zdtp. The pin governs which panel build the site runs — the embedded panel widget and the three-site demo split below — not what the documentation prose may describe. Doc content is free to document main-branch panel behavior ahead of the pinned release; that split is stated publicly in the note at the top of getting-, which this section cross-references rather than restates: read the two together as one rule, not two that can be read as contradicting each other.
This is a deliberate three-site split, kept separate because of the honesty problem tracked in #593: doc/ answers what can be installed from the pinned npm release, examples/minimal/ runs the workspace build as the smallest wiring that works, and playground/ runs the workspace build at full size, including the real vendored zudo-doc PanelConfig and prose pages. Do not make either workspace demo consume the pinned doc/ dependency, or make doc/ consume the workspace package, to make their versions appear consistent.
Use the root playground/ workspace to exercise unpublished panel changes in a real zfb consumer. Its default manifest covers the panel's control kinds, while ?manifest=zudo-doc uses the real zudo-doc PanelConfig vendored by scripts/ (the S17 vendor script). The generated file records the source @takazudo/zudo-doc version so drift is visible.
Verifying an unpublished panel in the real doc site
The committed doc/ workspace remains pinned to the published panel release. To inspect an unpublished panel build in the real zudo-doc consumer, run this from the repository root:
bash scripts/doc-with-local-panel.shThe script builds and packs packages/zdtp, copies the doc source into a temporary directory, and installs that scratch site with a file override for the packed panel. It prints the local panel version, then runs the scratch site's pnpm dev; open the printed URL and activate the design-token-panel header trigger. The terminal output includes the exact local package version being served (the fixed window.zdtp API itself intentionally exposes only show, hide, and toggle). The temporary directory, workspace override, install lock, and generated build output are removed when the dev command exits. The committed doc/ and root lockfile are never modified.
The override belongs in the temporary pnpm-workspace.yaml rather than a package-level pnpm field because pnpm 11 no longer reads that package.json configuration. The script also verifies that the scratch site resolved the packed panel version and that the panel and zudo-doc share one Preact installation. A mismatch is a peer/bootstrap spike blocker: capture its logs in the PR and ship only the scheduled drift re-exam until the dependency boundary is resolved; do not force a package or lockfile change.
The informational consumer-smoke job in . repeats the packed-panel override, builds the scratch doc, serves its static output, and uses Chromium to open one doc page, activate the header trigger, assert the real zudo-doc panel tabs are mounted, and reject console or page errors. The scheduled . workflow installs the latest zudo-doc for the consumer-manifest contract check. Its five-example matrix is manual-dispatch-only and informational while those public examples still pin older panel APIs; failures open or update one deduplicated issue per job.
Content Conventions
Frontmatter
Required:
title(string)Optional:
description,sidebar_position(number),categorySidebar order is driven by
sidebar_position
Admonitions
Available in all MDX files without imports, via directive syntax: :::note, :::tip, :::info, :::warning, :::danger, :::caution, :::details. Each accepts an optional bracketed title: :::note[Custom Title].
Docusaurus-style {title="..."} is NOT supported. MDX parses the braces as a JS expression, so it either fails the build with ReferenceError: title is not defined or is silently ignored. Always use the bracketed form.
Headings
Do NOT use h1 (#) in doc content — the page title from frontmatter is rendered as h1. Start content headings from h2 (##).
Built-in MDX components
@takazudo/zudo-doc ships a few globally-available MDX components — usable in any .mdx file with no import. The seeded getting- already uses one:
<CategoryNav category="..." />— a card-grid list of the pages in a docs category (this is the one seeded intogetting-).started/ index. mdx <CategoryTreeNav category="..." />— the same listing as a compact nested tree, better for deeper hierarchies.<SiteTreeNavDemo />— a full-site documentation tree (the MDX-available wrapper of theSiteTreeNavisland).
Admonitions (above), tabbed content (<Tabs> / <TabItem>, <CodeGroup>), and block math (<MathBlock>) work the same way — no import. Full reference: https:
i18n
English (default):
/— content indocs/ . . . src/content/ docs/ Japanese:
/— content inja/ docs/ . . . src/content/ docs- ja/ Japanese docs should mirror the English directory structure
Both
pages/docs/[[...slug]].tsxandpages/[locale]/docs/[[...slug]].tsxare self-contained doc-route stubs shipped by the generator — required sopnpm devdoesn't 404 on doc pages (a zfb dev-mode limitation on package-injected dynamic routes). Don't delete them.
Enabled Features
search — Full-text search via Pagefind
claudeResources — Auto-generated docs for Claude Code resources
designTokenPanel — Interactive tabbed panel for tweaking spacing, font, size, and color tokens
sidebarResizer — Draggable sidebar width
sidebarToggle — Show/hide desktop sidebar
versioning — Multi-version documentation support
docHistory — Document edit history
llmsTxt — Generates llms.txt for LLM consumption
changelog — Per-version EN/JA pages under
src/are the source of truth; the docs build generatescontent/ docs*/ changelog/ .from the English pages, so do not edit that package file directly. / packages/ zdtp/ CHANGELOG. md