mirror of
https://github.com/hanzo-docs/docs.git
synced 2026-10-24 20:09:02 +00:00
452 lines
25 KiB
Markdown
452 lines
25 KiB
Markdown
# Hanzo Docs Framework
|
|
|
|
Fork of [Hanzo Docs](https://github.com/hanzoai/docs) with all packages renamed to `@hanzo/docs-*` namespace.
|
|
|
|
## How this ships
|
|
|
|
**Runbook: [`RELEASE.md`](./RELEASE.md).** One lane:
|
|
|
|
push -> github.com/hanzo-docs/docs origin; GitHub Actions is OFF here
|
|
-> git.hanzo.ai/hanzoai/docs a pull mirror; sync + dispatch (RELEASE.md)
|
|
.github/workflows/deploy.yml the forge reads this directory natively
|
|
-> pnpm build --filter=docs NEXT_EXPORT=1 -> apps/docs/out
|
|
-> hanzoai/ci .github/actions/site Sites project `docs`
|
|
-> s3://hanzo-sites/hanzo/docs what docs.hanzo.ai serves
|
|
|
|
The host is a route, not a workload: `Host(docs.hanzo.ai)` -> Middleware
|
|
`docs-static` -> that S3 prefix, declared in hanzoai/universe
|
|
`charts/app/values/hanzo/static-sites.yaml`. Nothing is pinned and nothing rolls;
|
|
the publish IS the deploy.
|
|
|
|
The other workflows in `.github/workflows/` run on the same forge: `lint.yml` and
|
|
`test.yml` on pull requests, `release.yml` on push (the npm packages),
|
|
`sync-zen-pricing.yml` daily, `deploy-cloud.yml` for `apps/cloud` (Sites project
|
|
`hanzo-cloud`), and eight `deploy-*-docs.yml` that still `wrangler pages deploy`
|
|
their app. Each wrangler one is the ONLY deploy of its host, so it stays until
|
|
that host has a Sites project: give the app `output: 'export'`, publish a slug,
|
|
move the DNS, delete the workflow.
|
|
|
|
**The image lane is cold.** `ghcr.io/hanzoai/docs`, the root `Dockerfile`,
|
|
`hanzo.yml`'s `images:` and the `docs` app in universe served this host before
|
|
the Sites plane did. The pod still runs and no router names it. Building or
|
|
pinning it publishes nothing.
|
|
|
|
**The export gate is in `scripts/check-export.sh`**, which the deploy runs on
|
|
`apps/docs/out` and the Dockerfile runs in its build stage. This site fails by
|
|
exporting nothing — a valid layer, a valid image, a 404 — and `apps/<app>/
|
|
export.require` names the sections that must not silently vanish (`docs/studio/`
|
|
is a submodule; a checkout that does not recurse drops it while page count and
|
|
nav stay green).
|
|
|
|
|
|
## Canonical model — the one way to do docs
|
|
|
|
Full ADR: `apps/docs/content/docs/contributing/docs-architecture.mdx` (rendered
|
|
at docs.hanzo.ai/docs/contributing/docs-architecture). Summary:
|
|
|
|
- **docs.hanzo.ai is the hub.** ONE Fumadocs build (`apps/docs`) → ONE Sites
|
|
project `docs`. The federated per-section deploy is **retired** (stale
|
|
origins 530'd). Do not reintroduce per-section builds.
|
|
- **IA is two levels of separator, and one word each.** The ROOT sidebar
|
|
(`content/docs/meta.json`) is nine sections a developer walks in order — Get
|
|
started · Concepts · Capabilities · Reference · Build with · Surfaces ·
|
|
Programs · Integrate · Open source. Inside Capabilities
|
|
(`content/docs/openapi/meta.json`, generated) is the second level: the nine
|
|
DOMAINS — Identity & Trust · Intelligence · Data · Streams · Observability ·
|
|
Commerce · Platform · Applications · Chain — from `apps/docs/openapi-specs/
|
|
capabilities.yaml`, which is tracked HERE and is the one editorial decision
|
|
left in this repo. Both levels are icon-bearing separators
|
|
(`---[Icon]Name---`, resolved by `lucideIconsPlugin`), NOT folder moves —
|
|
files stay flat so URLs/openapi back-links don't break.
|
|
**Counts are never written twice.** How many capabilities there are is a fact
|
|
about cloud's document, printed by the generator on `/docs/openapi`; authored
|
|
prose links to it rather than restating a number that goes stale the next time
|
|
cloud ships. `check-capabilities` is what holds the taxonomy, the document and
|
|
the pages to one set.
|
|
**No stutter.** A folder's own `index.mdx` is already its landing page — the
|
|
tree builder resolves it before it reads `pages`. Naming `index` in `pages`
|
|
demotes the page to a child of the folder carrying the folder's own name, so
|
|
the sidebar reads `Agents > Agents`; 191 folders named it and 188 of them
|
|
carried the same title, so that is how many rows said it twice. Same rule one
|
|
level down: a folder wrapping exactly ONE page is a folder that should not
|
|
exist, which is why a single-tool MCP product is published as a page and not a
|
|
directory. **API reference and
|
|
SDKs are separated surfaces** (`/docs/openapi`, `/docs/sdks`) reached via the
|
|
top nav (`lib/nav.ts`), deliberately NOT in the root
|
|
sidebar descent. The landing (`app/(landing)/page.tsx` — its own route group,
|
|
because it carries the docs chrome from `components/shell.tsx` while
|
|
`(home)` keeps the marketing chrome for /blog) + docs home
|
|
(`content/docs/index.mdx`) lead with the decentralized spine ("the AI cloud
|
|
you can run yourself"); `content/docs/network.mdx` = self-host/hanzo.network,
|
|
`content/docs/architecture/philosophy.mdx` = the engineering pedagogy. Landing
|
|
breadth stats trace to real sources: the domains from `capabilities.yaml` and
|
|
the capability count from cloud's document, 157 models
|
|
(`ai/conf/models.yaml`), 706 connectors (`cloud/clients/automations/catalog/
|
|
catalog.json`), 6 SDK langs (`openapi/CLAUDE.md`). Count from data, never invent.
|
|
- **One canonical home per doc.** Content enters the single build via exactly one
|
|
of three orthogonal mechanisms, chosen by *kind*:
|
|
1. **Authored** (first-party prose) → MDX under `content/docs/<section>/`.
|
|
Small/core sections live in-repo; team-owned sections live in a
|
|
`hanzo-docs/<team>` content repo mounted as a **git submodule** at
|
|
`content/docs/<team>/`. Exemplar: `hanzo-docs/studio-docs` → `content/docs/studio/`.
|
|
2. **Generated** (never hand-written, `.gitignore`d) → API reference from
|
|
`hanzoai/cloud`'s `openapi.yaml` at the release `openapi-specs/.spec-lock`
|
|
pins, via `scripts/sync-openapi.sh` + `scripts/gen-openapi-pages.ts`
|
|
(source-derived: an endpoint's sentence is written next to its handler and
|
|
travels here unaltered); SDK reference from the ZAP SDK generator into
|
|
`content/docs/sdks/<lang>/`. Every reader of the document goes through
|
|
`scripts/openapi-doc.ts`, which owns the path — no script names the file.
|
|
A generated MDX **fragment** is the third shape here, for a fact an authored
|
|
page needs mid-sentence: `scripts/gen-key-types.ts` writes
|
|
`generated/key-types.mdx` and `content/docs/api-keys.mdx` pulls it in with
|
|
`<include>`. It sits outside `content/` because source.config globs
|
|
`**/*.mdx` there and would give a fragment its own URL — and the path is
|
|
relative to the INCLUDING file, so from `content/docs/` it is
|
|
`../../generated/`. One directory short renders the page body empty with
|
|
the frontmatter and chrome intact, which looks like a working page.
|
|
3. **Ported** (upstream OSS, mirrored with attribution, **tracked**) →
|
|
`content/docs/projects/<upstream>/`. Port, don't re-author. Carry upstream
|
|
LICENSE + NOTICE. GPL stays GPL. This is a committed snapshot, not build
|
|
output: `scripts/sync-project-docs.ts` refreshes it on demand
|
|
(`pnpm --filter docs sync:projects`) and you read the diff before it ships,
|
|
the same contract `openapi-specs/` has. It used to be BOTH — gitignored and
|
|
re-mirrored by every build, so a build rewrote 965 committed files, put 298
|
|
repos' docs on disk that production never had, and died on 54 imports
|
|
(`@site/...`) no alias resolves. The builder alone skipped the sync, which
|
|
meant the command a person runs and the command that ships the site
|
|
compiled different sites.
|
|
- **Repos:** `hanzo-docs/docs` = framework + hub (canonical; `hanzoai/docs`
|
|
redirects here). `hanzo-docs/<team>` = authored content only, NO framework.
|
|
`hanzoai/cloud` `openapi.yaml` = the API source of truth; `hanzoai/openapi`'s
|
|
`hanzo.yaml` was a projection of it on its own clock and this repo no longer
|
|
reads it. All docs live in the `hanzo-docs`
|
|
org: the hub at `hanzo-docs/docs`, each team's content at `hanzo-docs/<team>`.
|
|
- **Standalone vs hub:** default is a hub section. Standalone deploy only if ALL
|
|
of: ≈150+ pages or fast OSS-upstream churn, independent versioning, direct
|
|
audience. Standalone runs its own copy of this framework; the hub links out,
|
|
never copies.
|
|
- **Serving:** the Sites plane — `s3://hanzo-sites/hanzo/docs`, served by the
|
|
ingress staticFiles middleware on `Host(docs.hanzo.ai)`. The sibling hosts
|
|
below are still CF Pages `hanzo-docs` (token from KMS, never hard-coded). No
|
|
nginx/caddy, and no pod for a static export.
|
|
|
|
**Known dedup debt (rollout, not done):** the `apps/*-docs` legacy apps
|
|
(base-docs, bootnode-docs, bot-docs, cloud, dev-docs, dns-docs, flow, gui-docs,
|
|
insights-docs, platform, pulsar-docs, spec, tasks-docs, team, visor, zen-docs,
|
|
zt-docs) predate the unified `content/docs/` model — migrate their content into
|
|
`content/docs/<section>/` (or a `hanzo-docs/<team>` submodule) then archive the
|
|
app.
|
|
|
|
## Two build guards, and why prose needs them
|
|
|
|
`scripts/pre-build.ts` ends with two checks that fail the build. Both exist for
|
|
the same reason: a generated page cannot be wrong about the API, an authored one
|
|
can, and a reader cannot tell which kind of page they are on.
|
|
|
|
- **`check-endpoints.ts`** — no page may name a `/v1/…` route on `api.hanzo.ai`
|
|
that the document does not serve.
|
|
- **`check-keys.ts`** — no page may spell an API key a way cloud does not mint,
|
|
and `api-keys.mdx` must teach every class the document carries. Both
|
|
directions, so renaming, adding or removing a key class in cloud stops the
|
|
build here instead of publishing a stale page.
|
|
|
|
The key classes come from `Document.keys` (`openapi-doc.ts`), read out of the
|
|
`/v1/keys` prose — cloud's own Go doc comments, lifted by zipdoc. `secretKey(doc)`
|
|
is the one accessor generators use for "the key a server presents"; three of them
|
|
had it as a literal, which is how three GENERATED pages came to teach `hk-`.
|
|
|
|
**What was wrong:** docs.hanzo.ai documented three key types — `hk-` "API Key",
|
|
`sk-` "Secret Key", `hz-` "Widget Key". Cloud mints two (`cloud.APIKeyPrefixes`:
|
|
`pk-`, `sk-`) and refuses anything else, so a reader's first call failed asking
|
|
for a key nobody can issue. `hk-`/`hz-` were on 149 files. Note the shape of the
|
|
mistake: `sk-` was *present* and *described wrongly* (as an org-level provider
|
|
credential; it resolves to the USER), so a find-and-replace would have left the
|
|
page confidently wrong. Cloud's `apps/platform/secretshape.go` still lists `hk-`
|
|
in its secret-DETECTION table — harmless, it only scans, but it is where the
|
|
invention came from.
|
|
|
|
## Kai section and Jev parity
|
|
|
|
`content/docs/kai/` is Kai's section: concepts, questions, patterns, a cookbook,
|
|
SDKs, agents, limits and Kai-native programs. `guides/migrate/jev.mdx` moves a
|
|
Jev integration over and maps every Jev asset to its Kai page.
|
|
|
|
- **`parity/jev.yaml`** (repo root) lists every public Jev asset — each
|
|
docs.typesafe.ai page, TypeSafe's SDK surface and skill, the community apps
|
|
and examples — with the Kai page that answers it or `none:` and why.
|
|
`apps/docs/scripts/parity.test.ts` fails when a listed page stops existing; it
|
|
runs in `pnpm test` and before the build in `.hanzo/workflows/deploy.yml`.
|
|
- **Every output block on a Kai page is a program's stdout.** The line before
|
|
the fence is `{/* out: <lang>/<file> [args] */}`: `python/` files live in
|
|
hanzoai/python-sdk `pkg/hanzo-kai/examples/`, `ts/` in hanzo-js/kai
|
|
`examples/`; `sh/` (a curl) and `typesafe/` (TypeSafe's own SDK with
|
|
`TYPESAFE_BASE_URL=https://api.hanzo.ai`) are printed whole on their page.
|
|
Re-run the program to change the block; never edit a block by hand.
|
|
- **`$` in prose is `\$`.** remark-math reads a `$…$` pair as math.
|
|
|
|
## Branch Convention
|
|
|
|
- **`main`** — Production branch. A push here builds the export and publishes it
|
|
to the Sites plane, so landing on `main` IS publishing (`RELEASE.md`). All
|
|
Hanzo work lands here.
|
|
- **`dev`** — Tracks upstream `Hanzo Docs/dev`. Used for upstream sync merges only.
|
|
- **`upstream`** remote — points to `hanzoai/docs`
|
|
|
|
## Architecture
|
|
|
|
pnpm workspace monorepo with turbo. Two apps, 24 packages, 24 examples.
|
|
|
|
```
|
|
~/work/hanzo/docs/
|
|
├── apps/
|
|
│ ├── docs/ # Main docs site (hanzoai.github.io/docs)
|
|
│ └── zap-docs/ # Zap protocol docs
|
|
├── packages/
|
|
│ ├── core/ # @hanzo/docs-core - source loading, search, i18n
|
|
│ ├── mdx/ # @hanzo/docs-mdx - MDX processing, collections
|
|
│ ├── base-ui/ # @hanzo/docs-base-ui - headless UI (@base-ui/react)
|
|
│ ├── radix-ui/ # @hanzo/docs-ui - full UI with Radix primitives
|
|
│ ├── openapi/ # @hanzo/docs-openapi - OpenAPI docs generation
|
|
│ ├── typescript/ # @hanzo/docs-typescript - auto type tables
|
|
│ ├── twoslash/ # @hanzo/docs-twoslash - TypeScript code hints
|
|
│ ├── cli/ # @hanzo/docs-cli - scaffolding & customization
|
|
│ ├── story/ # @hanzo/docs-story - component stories
|
|
│ ├── tailwind/ # @hanzo/docs-tailwind - Tailwind CSS utils
|
|
│ ├── press/ # @hanzo/docs-press - minimal setup
|
|
│ ├── hanzo-docs/ # @hanzo/docs - unified wrapper re-exporting all
|
|
│ ├── content-collections/ # @hanzo/docs-content-collections
|
|
│ ├── mdx-remote/ # @hanzo/docs-mdx-remote - remote MDX
|
|
│ ├── obsidian/ # @hanzo/docs-obsidian - Obsidian vault adapter
|
|
│ ├── python/ # @hanzo/docs-python - Python docgen
|
|
│ ├── doc-gen/ # @hanzo/docs-docgen - doc generation
|
|
│ ├── create-app/ # @hanzo/docs-create-app - project scaffolding
|
|
│ ├── create-app-versions/ # version tracking for create-app
|
|
│ ├── shared/ # shared utilities
|
|
│ ├── stf/ # @hanzo/docs-stf (upstream dependency)
|
|
│ ├── mdx-runtime/ # @hanzo/mdx-runtime
|
|
│ ├── eslint-config-custom/ # shared ESLint config
|
|
│ └── tsconfig/ # shared TypeScript config
|
|
└── examples/ # 24 example apps (Next.js, Astro, React Router, etc.)
|
|
```
|
|
|
|
## Package Naming Convention
|
|
|
|
One brand: every workspace package publishes under `@hanzo/docs-*`. The
|
|
rename rule (applied when merging from the upstream fork) drops the upstream
|
|
prefix and re-scopes to `@hanzo/docs-`:
|
|
|
|
- `<basename>` (unscoped upstream) → `@hanzo/docs-<basename>`
|
|
- `@<scope>/<basename>` (scoped upstream) → `@hanzo/docs-<basename>`
|
|
|
|
Canonical workspace packages and their paths:
|
|
|
|
| Hanzo name | Path |
|
|
|------------|------|
|
|
| `@hanzo/docs-core` | packages/core |
|
|
| `@hanzo/docs-mdx` | packages/mdx |
|
|
| `@hanzo/docs-ui` | packages/radix-ui |
|
|
| `@hanzo/docs-base-ui` | packages/base-ui |
|
|
| `@hanzo/docs-openapi` | packages/openapi |
|
|
| `@hanzo/docs-preview` | packages/preview |
|
|
| `@hanzo/docs-typescript` | packages/typescript |
|
|
| `@hanzo/docs-twoslash` | packages/twoslash |
|
|
| `@hanzo/docs-cli` | packages/cli |
|
|
| `@hanzo/docs-story` | packages/story |
|
|
| `@hanzo/docs-tailwind` | packages/tailwind |
|
|
| `@hanzo/docs-language` | packages/language |
|
|
| `@hanzo/docs-local-md` | packages/local-md |
|
|
| `@hanzo/docs-sanity` | packages/sanity |
|
|
| `@hanzo/docs-vite` | packages/vite |
|
|
| `@hanzo/docs-basehub` | packages/basehub |
|
|
| `@hanzo/docs-mdx-remote` | packages/mdx-remote |
|
|
| `@hanzo/docs-stf` | packages/stf |
|
|
| `@hanzo/create-docs` | packages/create-app |
|
|
| `@hanzo/docs-create-versions` | packages/create-app-versions |
|
|
|
|
**Important**: `packages/radix-ui` publishes as `@hanzo/docs-ui` (Radix
|
|
variant). The `base-ui` variant (`@hanzo/docs-base-ui`) uses `@base-ui/react`
|
|
instead of Radix.
|
|
|
|
**External deps kept verbatim** (real upstream npm packages, NOT renamed):
|
|
`fuma-cli`, `fuma-content`, `@fumari/json-schema-ts`, and the third-party
|
|
search adapters (typesense / trieve) documented under `apps/docs`.
|
|
|
|
## Upstream Sync
|
|
|
|
Remote `upstream` points to the upstream fork. Local `dev` tracks `upstream/dev`.
|
|
|
|
To merge upstream changes:
|
|
|
|
```bash
|
|
git checkout dev && git pull upstream dev
|
|
git checkout -b merge-upstream-YYYY-MM-DD main
|
|
git merge dev
|
|
# Resolve conflicts, then re-apply the package rename (table above)
|
|
# Merge into main when ready
|
|
```
|
|
|
|
After merge, re-apply the rename with the canonical script
|
|
(`scripts/rebrand-packages.mjs` — masks the external KEEP-list, then maps
|
|
each upstream name to its `@hanzo/docs-*` form).
|
|
|
|
## Key Patterns
|
|
|
|
### Source Config (`source.config.ts`)
|
|
```typescript
|
|
import { defineConfig, defineDocs } from '@hanzo/docs-mdx/config';
|
|
```
|
|
|
|
### Source Loader (`lib/source.ts`)
|
|
```typescript
|
|
import { docs } from '@/.source';
|
|
import { loader } from '@hanzo/docs-core/source';
|
|
|
|
export const source = loader({
|
|
baseUrl: '/docs',
|
|
source: docs.toHanzoDocsSource(), // API name kept from upstream
|
|
});
|
|
```
|
|
|
|
### The chrome is @hanzo/gui (apps/docs)
|
|
|
|
Every docs page sits in `components/shell.tsx`: the rail (`rail.tsx` — brand,
|
|
search, `tree.tsx`, account and theme at the foot), and a column holding the bar
|
|
(`bar.tsx`) and the page (`page.tsx` — breadcrumb, title, description, the
|
|
"Use agent" menu `agent.tsx`, body, previous/next; `toc.tsx` beside it). All of
|
|
it is gui stacks and text on theme tokens; no class names.
|
|
|
|
- **Widths are media props, never JS.** `$max-md`, `$xl` compile to CSS media
|
|
rules, so the markup a phone hydrates is the markup the export wrote. Rail
|
|
264px, bar 56px, article 880px with the outline 240px beside it from 1280px;
|
|
below 768px the rail is a Sheet opened from the bar.
|
|
- **First paint is styled with no script.** gui emits each component's atomic
|
|
rules as `<style precedence>` during SSR, React hoists them, and `<html>` ships
|
|
`t_dark`. Check it: render any page with JavaScript off.
|
|
- **One theme authority: `t_dark`/`t_light` on `<html>`.** gui's
|
|
`NextThemeProvider` (`@hanzogui/next-theme`) writes it before paint and
|
|
`<Hanzo theme>` follows it (`app/provider.tsx`). The only CSS that reads it is
|
|
`color-scheme` in `app/global.css`, which is what picks the code palette.
|
|
- **Muted text is `lib/ink.ts`.** gui's grey ramp is not symmetric (light step 10
|
|
is #333), so muted names step 10 dark / 9 light. Chrome text measures >= 7.5:1
|
|
in both themes.
|
|
- **gui v5 is shorthand-only.** `bg p px items justify rounded minW maxH t z`
|
|
exist; `w`/`h` do NOT (use `width`/`height`) — an unknown prop is dropped
|
|
silently and the box takes its content's size.
|
|
- **One title per page.** The header prints the frontmatter `title`;
|
|
`lib/remark-title.ts` drops a body's leading `# heading`.
|
|
- **Page bodies are gui too.** MDX hands each markdown tag to
|
|
`components/mdx.tsx`; blocks are spaced by `Body`'s gap, never their own
|
|
margins, so a list inside a callout keeps its own rhythm. Running text sets
|
|
`whiteSpace: normal` (gui text keeps whitespace, markdown hard-wraps). Tables
|
|
keep the browser's table layout through `style.display`. Code tokens carry
|
|
`color: light-dark(…)` (`lib/shiki.ts`), so `color-scheme` picks the palette
|
|
and no stylesheet knows the theme. Steps are the `Steps`/`Step` parts
|
|
(`lib/remark-parts.ts` renames remark-steps' marked divs).
|
|
- **The tree narrows by path, not address.** `lib/tree.tsx` resolves an
|
|
operation page (not in the tree) to its product page, so the rail opens the
|
|
reference it belongs to.
|
|
|
|
## Build
|
|
|
|
```bash
|
|
pnpm install # Install deps
|
|
pnpm build # Build all packages + apps
|
|
pnpm dev # Dev server
|
|
|
|
# Individual packages
|
|
pnpm build --filter @hanzo/docs-core
|
|
pnpm build --filter @hanzo/docs-ui
|
|
```
|
|
|
|
Build tool: `tsdown` (all packages except `hanzo-docs` wrapper which uses `tsup`).
|
|
|
|
## Compatibility
|
|
|
|
- Next.js 15-16+ with App Router
|
|
- React 19+
|
|
- `apps/docs` renders no Tailwind; the framework packages still ship it ("Moving onto @hanzo/gui")
|
|
- pnpm 10+
|
|
|
|
## Moving onto @hanzo/gui — the plan
|
|
|
|
House rule: `@hanzo/gui` is the only UI framework (it renders on web, iOS and
|
|
Android; Tailwind classes and Radix/Base UI are DOM-only). docs.hanzo.ai is being
|
|
moved onto it in four phases, each shipped to main when verified live.
|
|
|
|
**Inventory of what docs.hanzo.ai renders** (Tailwind's own scanner, counting only
|
|
tokens Tailwind would emit CSS for, in class contexts; `content/docs/projects/**`
|
|
excluded — it is upstream's):
|
|
|
|
| Area | Tailwind tokens / files | Radix files | Base UI files |
|
|
|---|---|---|---|
|
|
| `apps/docs` app+components+lib, before phase 1 | 2,189 / 52 | 2 | 0 |
|
|
| `apps/docs` after phase 1 | 1,906 / 37 | 2 | 0 |
|
|
| `apps/docs` after phase 3 | 0 / 0 | 0 | 0 |
|
|
| `packages/base-ui` (@hanzo/docs-base-ui) | 2,774 / 76 | 0 | 10 |
|
|
| `packages/radix-ui` (@hanzo/docs-ui, via openapi/twoslash/typescript) | 2,568 / 71 | 9 | 0 |
|
|
| `packages/openapi` | 794 / 23 | 3 | 0 |
|
|
| `packages/story` / `twoslash` | 212 / 4, 3 / 1 | 1, 1 | 0 |
|
|
| authored MDX (`content/docs`, mostly code samples) | 63 / 56 | 0 | 0 |
|
|
|
|
Plus the CSS: `app/global.css` imports `tailwindcss`, the base-ui, openapi,
|
|
story and twoslash presets, and `tailwindcss-animate`.
|
|
|
|
**What replaces what.** Layout, rail, bar, outline and page header: our own gui
|
|
stacks (done). Drawer: `@hanzo/ui` Sheet. Menus: `@hanzo/ui` DropdownMenu.
|
|
Folds: plain state + gui stacks. Icons: `@hanzogui/lucide-icons-2`. Theme:
|
|
`@hanzogui/next-theme`. Tree/TOC logic stays in `@hanzo/docs-core` (headless).
|
|
|
|
| Phase | Scope | Replaces | Status |
|
|
|---|---|---|---|
|
|
| 1 | Chrome on every page: rail, tree, bar, outline, page header, search trigger, account, theme | base-ui `DocsLayout`/`DocsPage`/sidebar/toc, next-themes, the corner dock | shipped (f11eb49dc2) |
|
|
| 2 | Page bodies: markdown's elements (`components/mdx/prose.tsx`), the parts content names — Callout, Cards, Tabs, Steps, Accordion, Files, code blocks and code tabs (`blocks.tsx`, `tabs.tsx`, `code.tsx`) — and `Example`; content imports none of them; ported and studio pages reach them through the `parts` aliases in next.config | Tailwind typography, base-ui MDX components, shiki.css, the HoverCard link preview (a `title` now) | shipped |
|
|
| 3 | App pages and app parts: landing (on the theme now, no forced dark), hero, product sections, provider strip, catalogs, search (`search.tsx` + `finder.tsx`, ⌘K), feedback (a real `docs.feedback` event, not a console stub), 404, blog (in the shell, on the page frame), sign-in screens | base-ui search dialog, `RootProvider`, HomeLayout, the registry build and the dead preview / AI-search / API-page modules | shipped |
|
|
| 4 | The build: `app/global.css` is plain CSS (faces, ground, `color-scheme`, the shell footer); no `@import 'tailwindcss'`, no presets, no `postcss.config.mjs`; `apps/docs` no longer depends on `tailwindcss`, `@tailwindcss/postcss`, `tailwindcss-animate`, `tailwind-merge`, `class-variance-authority`, any `@radix-ui/*`, `@hanzo/docs-base-ui`, `@hanzo/docs-ui`, `lucide-react`, or the build plugins that emitted their parts (twoslash, auto type table, ts2js) | — | shipped |
|
|
|
|
**No framework package was deleted, because none is dead.** `packages/base-ui`,
|
|
`radix-ui`, `tailwind`, `story`, `twoslash`, `typescript`, `openapi` and the
|
|
`packages/gui` stub each still have consumers in `apps/*`, `examples/*` or the
|
|
`@hanzo/docs` wrapper. They leave when those apps move onto the gui parts in
|
|
`apps/docs/components/` — lift those into a package first, so every docs app
|
|
renders one set.
|
|
|
|
**Known gap in @hanzo/ui (8.27.18):** its `.d.ts` augments `@hanzogui/web`
|
|
without depending on it, so in this workspace the augmentation lands on the
|
|
hoisted 8.1.1 copy while `@hanzo/gui` 8.3.5 uses 8.3.5 — every gui shorthand
|
|
fails typecheck here (runtime is correct; `ignoreBuildErrors` is on). The fix is
|
|
@hanzo/ui declaring `@hanzogui/web`/`core` as dependencies of the same train.
|
|
|
|
**Out of scope when counting:** `content/docs/projects/**` is a snapshot of
|
|
upstream repos. The Java/Spring IAM guide uses Bootstrap in a Thymeleaf template
|
|
and the IAM login-customization guide uses its own `<style>` blocks — not Tailwind.
|
|
|
|
**`@zenlm/ui` ships classes that style nothing** (`packages/zenlm-ui`: Tailwind
|
|
utilities, no CSS, no Tailwind dep); `apps/zen-docs` pins the published tarball.
|
|
Converting it to gui style props fixes it by construction.
|
|
|
|
### Baseline when touching this repo
|
|
|
|
`pnpm types:check` is **not green and never was**: 50 of 72 tasks fail at rest.
|
|
`npx vitest run` is 13 failed / 203 passed. Judge a change by the *delta* against
|
|
those sets, not by a clean run you will never get. And `docs#types:check` failing
|
|
tells you nothing about whether a page renders — MDX compile errors do not surface
|
|
in tsc. `zen5.mdx` typechecked clean while the loader skipped the entire page
|
|
(`<50ms` in a table parses as a JSX tag; fence such values in backticks). Run the
|
|
app and look at it.
|
|
|
|
`remark-math` is on, so two `$` in one paragraph or list item typeset the text
|
|
between them as math: `migrate/stripe.mdx`'s "floor $1 and ceiling $5,000"
|
|
renders as KaTeX on the live site. Write each amount as `\$0.021` where a
|
|
paragraph holds two; a table cell, a code span and frontmatter are each their
|
|
own context and need no escape.
|
|
|
|
## Landing Apps (Moved Out)
|
|
|
|
Landing page apps were moved to their ecosystem repos:
|
|
- Hanzo apps → `~/work/hanzo/apps/`
|
|
- Lux apps → `~/work/lux/apps/`
|
|
- Zoo apps → `~/work/zoo/apps/`
|
|
|
|
`apps/zap-docs` and `apps/liquid` are gone; their deploy workflows were deleted
|
|
because they built directories that do not exist. See `apps/` for what is here.
|