feat: make astro-theme-docs a standalone, publishable docs theme - #37
Open
endless-bot wants to merge 20 commits into
Open
feat: make astro-theme-docs a standalone, publishable docs theme#37endless-bot wants to merge 20 commits into
endless-bot wants to merge 20 commits into
Conversation
Create packages/astro-theme-docs/ with the full Nimbus design system extracted from src/nimbus/: - CSS token system (globals.css with BRAND comments, prose, markdown-pipeline, tippy, footnotes) - 26 UI component subdirectories, 6 MDX whitelist components (whale/) - Header/Footer/PageHead/PageShell top-level components - React co-located layer (shadcn ui/, HeaderMenu, ThemeMenu, PageActionsMenu) - BaseLayout/DocsLayout layouts and 6 client scripts - docsTheme() AstroIntegration entry point with MDX component map All @/ and @components/ Vite aliases converted to relative paths. Header.astro logo imports converted to props (logoLightSrc/logoDarkSrc). Update whale-docs/package.json: add workspaces, astro-theme-docs workspace:*, github-slugger, and shiki as hoisting fixes. Update astro.config.ts: add docsTheme() to integrations array. src/nimbus/ original files are unchanged (read-only preserved for rollback).
Deploying whale-docs with
|
| Latest commit: |
eb5e4a0
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://6a648435.whale-docs.pages.dev |
| Branch Preview URL: | https://endless-prod-task-13.whale-docs.pages.dev |
Generated by Endless task #13. Co-authored-by: Huacnlee (Li Huashun) <huacnlee@longbridge-inc.com>
Violates PRD 6.5 constraint: brand colors must only be referenced through --nb-primary, not hardcoded. --nb-accent-100 used the same hex as the primary but was a separate hardcoded value that consumers couldn't override by setting --nb-primary alone. Now follows the primary variable in both light and dark modes.
…kage - Footer: replace hardcoded Longport Whale content with props (logoLightSrc, logoDarkSrc, siteName, siteEmail, phones) and a default slot for link columns - Header: make navigation tabs a configurable prop (defaults to []) and GitHub link optional via githubHref prop - PageHead: replace hardcoded 'Whale Docs' site name and lbkrs.com favicon with optional siteName/faviconHref props; favicon not injected by default - PageActionLinks: make reportIssueUrl optional, hide the link when absent - DocsLayout: accept siteTitle prop; replace hardcoded 'Whale Docs' in mobile sidebar header - BaseLayout: forward siteName/faviconHref to PageHead - package.json: add astro-icon as peerDependency (used by PageActionLinks)
Delete 243 files (~29.5k lines) carried over from the cloudflare-docs
Starlight->Nimbus port that no live route ever referenced. Verified
unreachable: dist HTML is byte-identical across all 1049 pages once
content hashes are normalized, and the dist file count is unchanged
at 3261.
Removed: components/{cf,agent-setup,models,landing,realtimekit,
changelog,directory,ai-gateway,_stubs,react,fields,icons}/, util/models/,
schemas/, scripts/analytics*, styles/agent-setup*.css, the root
components.ts registry (which re-exported 5 files that do not exist),
layouts/{Splash,Changelog}Layout.astro, and assorted orphans.
Also removed util/{footer,sidebar,api,release-notes,directory,container,
changelog,search,content-type,github,url,og,page-head,description}.ts:
each one's only importers were among the deleted components. Note
page-head.ts was entirely dead, not just its buildStructuredData() --
PageHead.astro imports only nimbus-docs/types. util/tippy.ts is kept:
footnotes.client.ts and scroll-to-top.client.ts are live consumers.
Dropped the 4 test files whose subjects no longer exist; they imported
vitest, which is not installed, so they could not run either way.
Side effect: the main CSS bundle drops 34,440 bytes (293,230 -> 258,790)
because Tailwind no longer scans the orphaned components for utilities.
Confirmed safe -- of the 245 class names that disappeared, zero appear
in any emitted HTML. Build warnings hold at 7, unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three defects that each break the package for an external consumer, found
by actually building a site against it instead of reading the source.
1. Dangling import. PackageManagers.astro imported getTabs from
`~/util/package-managers`, a file that exists nowhere in the repo -- the
nimbus copy is broken the same way, hidden only because the root
tsconfig excludes that directory. nimbus-docs already publishes the same
helper at `nimbus-docs/lib/pkgm`, so point there. Its CommandOptions has
no `prefix`, so `prefix` joins `frame` as a prop accepted for MDX API
parity but not honored.
2. astro-icon was a hard requirement. PageActionLinks.astro pulled in
`astro-icon/components` for a single GitHub mark, so any consumer that
did not register the icon integration failed to build with an
unresolved `virtual:astro-icon`. Header.astro already inlines that exact
SVG path; do the same here. Lucide v1 dropped brand glyphs, so an icon
set is not an option. astro-icon is now unused.
3. Missing file. scripts/{footnotes,scroll-to-top}.client.ts imported
`../util/tippy`, which was never carried over when the package was
extracted. Re-added as src/util/tippy.ts, but loading tippy.js through
a dynamic import that degrades to "no tooltip" when the optional
dependency is absent. The exported signature stays synchronous, so both
call sites are unchanged.
Also unified the two icon libraries: `lucide-astro` -> `@lucide/astro` in
TOC, whale/Card and reui/Alert. These are separate packages that were both
installed; the v1 rename align-left -> text-align-start is covered by the
alias re-exports, so the imported names still resolve.
Finally, explicit @source rules in globals.css. Tailwind v4 auto-detection
walks up to the package root and skips node_modules. A probe (sentinel
`mt-[13px]` on the packaged DocsLayout, consumed from a throwaway page in
the main site) confirmed utilities ARE generated today -- but only because
bun links the workspace package to a path inside the repo. Once published
into a real node_modules the same utilities would be purged with no build
error. The @source rules make scanning explicit and self-contained.
Main site output is untouched: 1049 HTML pages, 258,790 CSS bytes, 3261
files, 7 warnings -- identical to the previous commit, since the site does
not consume the package yet.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The tracked route manifest was missing 141 routes that the site has been emitting for a while -- the broker-api dataset pages, dataset-export, and the portfolio/risk_event operations. Regenerated by a normal build; no source change is involved. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rename to @longbridge/astro-theme-docs and make the package independently
consumable: layer the dependencies, widen the export map, and stand the
tsconfig on its own.
Exports. Previously only 6 MDX components and 2 layouts were reachable;
the 26 component directories under src/components/ui were implemented but
unreachable, since Node's exports field rejects undeclared paths. Now
exposed via wildcard subpaths (./ui/*, ./chrome/*, ./mdx/*, ./layouts/*,
./react/*, ./styles/*, ...). Directory-level barrels rather than one root
barrel: Astro pulls every imported component's scoped <style> into the
module graph, so a single all-components entry would put 26 components'
CSS on every page.
Restructure to match that surface: Header/Footer/PageHead -> components/
chrome/, components/whale/ -> components/mdx/ (nothing whale-specific
lives there -- six generic prose components), added the missing ui/icon
barrel, dropped the orphaned PageShell.astro (same file deleted from the
site in the previous commit).
Dependencies, previously a single flat peerDependencies block that omitted
8 packages the source actually imports:
dependencies build-time helpers with no singleton semantics --
clsx, tailwind-merge, cva, @lucide/astro,
lucide-react, marked
peerDependencies astro, nimbus-docs, tailwind(+vite), react(+dom,
@astrojs/react, @base-ui/react). React is required,
not optional: Header, PageActions and mdx/Accordion
all mount React islands.
optionalDependencies per-feature extras -- pagefind, tippy.js,
medium-zoom, mermaid, the two fontsource families
Added files, sideEffects (so bundlers cannot tree-shake CSS or *.client.ts),
repository/license/keywords/publishConfig.
tsconfig no longer extends ../../tsconfig.json, which would ENOENT once
published, and sets paths:{} so an inherited `@/*` cannot silently resolve
a package import into the consuming site's tree.
Fixed 15 type errors that had never been visible, because the root
tsconfig only includes src/nimbus/** and additionally excludes
components/ui/{code,search,package-managers}. `astro check` now runs
inside the package: 120 files, 0 errors.
- 10x possibly-null in DocSearch: the guard was there, but `async
function search()` is hoisted so TS would not carry the narrowing into
it. An arrow const defined after the guard fixes all ten.
- 4x deprecated lucide aliases + 2 wrong props, introduced by the
lucide-astro -> @lucide/astro switch in the previous commit:
AlignLeft -> TextAlignStart, Code2 -> CodeXml, strokeWidth ->
stroke-width.
- @pagefind/default-ui ships no types; declared ambiently rather than
making consumers install @types for an optional dependency.
- Code.astro: nimbus-docs and Astro resolve @shikijs/types by different
paths, so the identical ShikiTransformer is two unrelated types to TS.
Bridged in both directions with a note; only one copy is installed.
Site output unchanged: 1049 HTML pages byte-identical to baseline, 7
warnings. CSS is down 187 bytes from dropping PageShell -- the site's
Tailwind scan is rooted at the repo, so it also sweeps packages/. Verified
no regression: of the 424 classes no longer emitted, zero appear in any
HTML.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…I layer in
The site now consumes the theme for real: astro-config.ts imports hastPlugins
from @longbridge/astro-theme-docs/markdown instead of a local directory.
Markdown pipeline (src/nimbus/plugins/satteri -> src/markdown). `hastPlugins`
becomes a function so it can take options, and is typed `HastPluginInput[]`,
which is what it always was -- satteri accepts a definition or a factory, and
the old `HastPluginDefinition[]` annotation only typechecked behind a double
assertion.
Dropped shift-headings.ts. It could not work: autolink-headings builds the
`.heading-wrapper` by *returning a replacement node*, and satteri does not
re-visit nodes produced that way (it would not terminate), so a plugin
filtering on "div" never sees those wrappers. Confirmed four ways -- the
plugin's own tests fail against it, a direct one-line reproduction emits
`level-h1` with an unshifted `<h1>`, the site has no content under the
hardcoded /content/changelog/ path, and autolink's own comment records an
earlier adjustment to this satteri version that shift-headings never got.
Shipping a broken plugin as theme API is worse than not shipping it; git has
it if a changelog feature ever wants a working version.
The 282-line pipeline test now runs. It imported vitest, which is not
installed, so it had never executed once -- which is exactly why the dead
plugin went unnoticed. Ported to bun:test with happy-dom registered through
bunfig.toml for the DOM assertions: 16 pass, 87 expect() calls.
Generic OpenAPI layer, kept deliberately small -- resolveSchema (`$ref` +
allOf flattening), operationPath, render-markdown, ApiEndpointCopy, and the
two schema renderers. Left with the site: document merging, YAML loading,
trading-openapi, and the x-dataset-download / x-post-fallback extensions.
Both renderers are parameterised -- `labels` instead of a hardcoded
en/zh-CN/zh-HK table, and `envelope`/`payloadKey` instead of assuming a
`{code, message, data}` response shape.
Note for the site migration: the two Badge components have incompatible
APIs. The old whale kit takes children with shadcn variants; the theme's
takes a `text` prop with Starlight-style variants. Mapped secondary ->
default and destructive -> danger (matching neutral-grey and red), so the
rendered classes will differ and this needs a visual check when the API
pages move over.
Package typecheck holds at 0 errors across 134 files. Four of the errors
fixed along the way were only visible because the tests are now type-checked
too, and one was real: hast declares className as string[], making the
string branch in classNames() unreachable to TS while still being needed at
runtime for raw HTML.
Site output identical: 1049 HTML pages byte-for-byte, 258,603 CSS bytes, 7
warnings.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…appable
Two things stood between the theme and a site that is not this one: optional
dependencies were imported unconditionally, and layout was welded to whale
chrome.
Optional dependencies. `optionalDependencies` only means "installing may
fail silently" -- a static import of a missing package still fails the build.
So each optional library now loads dynamically and degrades:
- tippy.js: already dynamic in util/tippy.ts; its two stylesheets now ride
the same import, so a site without tooltips ships neither JS nor CSS.
- medium-zoom: was a static import plus a stylesheet. Now loaded before
`mount` is called, and image zoom just stays off when absent.
- @fontsource-variable/*: no longer imported at all. Hardcoding fonts both
forced the install and prevented choosing a different typeface; the
`--nb-font-*` stacks keep system fallbacks and consumers import what they
want. (globals.css said "self-hosted via BaseLayout" -- corrected.)
- Pagefind: Header no longer imports DocSearch; search is a named slot.
docsTheme() finally does something. `customStyles` was documented since the
package was created but the hook body was `(_) => {}`, so nothing was ever
injected. Implemented via injectScript("page-ssr"). Still does not wrap
nimbus(): the consumer already supplies NimbusConfig, and proxying it would
split configuration across two places.
De-branded. BaseLayout inferred `lang` from `/zh-cn/` and `/zh-hk/` prefixes
-- one site's routing scheme baked into the shell; now a `lang` prop
defaulting to "en". Header derived locale, language menu, logo href and
active section the same way; all are props now, and an empty
`languageOptions` renders no menu. Header's tab `icon` became optional, which
also fixes the aside-tab icon regression the migration notes flagged.
DocsLayout's `section === "broker-api" || "trading-api"` is now
`variant="prose" | "compact"`, with `data-nb-api-sidebar` renamed to
`data-nb-sidebar-variant` -- including the 11 CSS rules and the
SidebarStateRestore check that keyed off the old name, which would otherwise
have silently dropped the compact sidebar styling. `__whaleHeaderScroll` ->
`__nbHeaderScroll`.
Header and footer are named slots with the theme's own as fallback, so a site
substitutes branded chrome without DocsLayout re-exposing every Header prop.
Zero config still renders a working header.
Also wired up Breadcrumbs. The component existed and DocsPageProps carried
`breadcrumbs`, but the layout never destructured or rendered it, so every
consumer computing breadcrumbs was throwing the result away. And plumbed
`reportIssueUrl` through to both PageActionLinks instances.
Package typecheck: 134 files, 0 errors. Site output identical -- 1049 pages,
258,603 CSS bytes, 7 warnings -- as expected, since src/nimbus still has its
own layouts and chrome.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Deletes 26 of the site's 27 src/nimbus/components/ui directories plus
lib/cn.ts and imports them from the theme instead. button-group stays: the
package has no counterpart.
Verified equivalent before deleting, comparing every file with alias
differences normalised (`@/lib/cn` vs `../../../lib/cn`, `@/components/ui/
icon/...` vs `../icon/...`). 19 directories were byte-identical modulo those
paths. The other 7 differ only because the package copies were improved in
earlier commits: the shiki cast in Code, getTabs in PackageManagers, the
arrow-function narrowing in DocSearch, the inlined GitHub mark in
PageActionLinks, TextAlignStart in TOC, and the sidebar-variant rename.
Nothing was lost.
Resolution goes through a temporary `@theme` Vite alias mirrored in the root
tsconfig paths. A Vite alias rewrites to a filesystem path before Node
resolution, so it bypasses the exports map -- .astro, .ts and .css all
resolve uniformly while the public surface stays small. It is derived via
import.meta.resolve rather than a hardcoded ../../packages path so it
survives the workspace-link-to-published-dependency transition, and it
doubles as the rollback lever: point it back at ./ and the old tree returns.
Both alias and mirror are removed in the final step, when imports move to the
public subpaths.
Two fixes this shook out:
- PageActionLinks now requires `reportIssueUrl`; without it the "Report an
issue" link silently vanished from every page. Passed explicitly.
- The package's SidebarStateRestore had moved to
`data-nb-sidebar-variant="compact"` while the site still emitted
`data-nb-api-sidebar`, so the compact API sidebar would have stopped
auto-expanding. Renamed in the site's DocsLayout and its 11 CSS rules.
Also had to export "./package.json" from the package -- import.meta.resolve
on it fails otherwise, which is the exports map doing its job.
Root tsconfig exclude list pruned: most entries pointed at directories
deleted with the Cloudflare leftovers. What remains is three ui directories
with pre-existing errors (the package copies are fixed; these entries go away
as the files migrate), util/, and the bun:test files.
Output: 1049 pages, 7 warnings, unchanged. HTML differences are all
accounted for: Astro scoped-style hashes and astro-island uids shift because
component paths changed, base-ui SSR ids are render-order counters, and two
are intentional -- the sidebar attribute rename, and PageActionLinks' GitHub
glyph moving from astro-icon's Phosphor 256-viewBox mark to the inlined
official logo, which incidentally makes it match the one in Header.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… and head
Continues the migration. The site's copies of five stylesheets, six client
scripts, six MDX prose components and PageHead are deleted and imported from
the theme. prose/markdown-pipeline/footnotes/tippy CSS and five of the six
scripts were byte-identical; the rest differed only where the package copies
were already improved (dynamic medium-zoom, CodeXml, the reui/Alert path).
Added src/nimbus/styles/site.css as the site's CSS entry, and this is the part
worth remembering for any future consumer: Tailwind v4 roots its content scan
at the package containing the CSS entry. Importing the theme's globals.css
directly moves that root into the theme, so every utility used only by a file
under src/nimbus or docs/ silently disappears. site.css re-exports the
theme's base and declares `@source "../"` and `@source "../../../docs"`.
Killed the last cross-srcDir import. mdx-components.ts reached out to
src/components/docs/{Mermaid,Update}.astro — outside srcDir entirely, a
leftover of the old Starlight theme. Both moved into components/whale/. The
other nine files in that directory are superseded by the theme's mdx/
components.
Brand values now travel as props: PageHead injects no title suffix and no
favicon of its own, so BaseLayout passes siteName and faviconHref.
CSS drops 2,703 bytes, and it is not a purge regression — verified by
sentinel-checking every utility class that appears only in src/nimbus against
the emitted CSS (the 18 misses are all custom class names served by scoped
styles, not utilities). The old entry had no @source at all, so Tailwind
scanned from the repo root and swept src/components and packages/demo-test
into the bundle. Narrowing to what is actually used is the same dead-weight
removal as the first commit in this series.
Two visible changes to note. In dark mode `--nb-accent-100` shifts from
#8f6bf5 to #7e84ff: the theme derives it from --nb-primary rather than
hardcoding a second purple. And the remaining lucide icons re-order their SVG
attributes, since @lucide/astro emits them differently than lucide-astro —
same glyphs.
1049 pages, 7 warnings. Remaining HTML differences are the scoped-style and
island id shifts from earlier, the deliberate sidebar attribute rename, the
GitHub glyph swap, and tippy's stylesheet landing in a different chunk now
that it loads dynamically.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Both are now thin wrappers that pass whale specifics into the theme's chrome
and inject content through its slots. Header goes from 130 lines of markup to
57 lines of configuration: logo pair, six product tabs, three-locale switcher,
repo link, and DocSearch in the `search` slot. Footer likewise supplies brand
and contact as props, its three link columns in the default slot and the legal
links in `bottom-links`.
The two `aside` tabs deliberately pass no `icon`, reproducing the old
`{!aside && <LucideIcon …>}` behaviour now that the theme's TabItem treats
`icon` as optional.
Layouts stay with the site, which is a change from the plan. Routing them
through the theme's DocsLayout inflated CSS by 51% (255,900 -> 386,859 bytes):
the theme's DocsLayout imports the theme's BaseLayout, which imports the base
stylesheets that the site already imports through site.css, so every rule was
emitted twice. Restoring the site's own layouts brought it back exactly.
The underlying constraint is real, not a workaround: Tailwind roots its
content scan at the CSS entry's package, so the entry has to live in the
consuming site, which makes the layout that owns that entry the site's to
keep. The theme's layouts remain the out-of-the-box default for a new project
-- verified separately by the demo site rather than here.
1049 pages, 255,900 CSS bytes, 7 warnings — all unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Rewrites every `@theme/...` import to the package's public subpaths and
deletes the migration alias from both astro-config.ts and the root tsconfig.
The site is now an ordinary consumer of @longbridge/astro-theme-docs, which
means the exports map is finally exercised by a real build rather than
asserted — anything missing from it now fails.
Single-file imports go through the directory barrels the exports map points at
(`{ LucideIcon } from ".../ui/icon"`, `{ Step, Steps } from ".../ui/steps"`)
instead of reaching for .astro files directly, so the public surface stays at
the barrel level and internal file layout can change without breaking anyone.
Cleanup: src/nimbus/util (only tippy.ts remained, whose consumers moved to the
theme) and components/ui/button-group, which was never imported by anything.
The tsconfig exclude list is down from 20 entries to one — every other entry
named a file that has since been deleted or migrated; only the bun:test glob
is still needed.
src/nimbus now holds whale-specific content and nothing else: the OpenAPI
integration (lib/{openapi,trading-openapi,whale-navigation}, components/api),
the branded chrome, the whale MDX components, content config, routes, and the
layouts that own the CSS entry.
Verified: build 1049 pages / 255,900 CSS bytes / 7 warnings, check:anchors
clean, bun test 4 pass with 6711 assertions, and the package's own astro check
at 0 errors.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completes the theme as a standalone deliverable.
README covers install (with the peer/optional split spelled out), a four-file
minimal setup, sidebar data options, theming through CSS custom properties,
both layouts and their props, the chrome components and their slots, all 26 UI
subpaths with their exports, the Markdown pipeline, the generic OpenAPI
helpers, and search. It leads with the one thing that is easy to get wrong:
Tailwind roots its content scan at the CSS entry's package, so a consumer MUST
re-export globals.css from their own entry and declare `@source`. Importing the
theme's stylesheet directly purges the consumer's own utilities with no error.
demo-test is now a real consumer instead of a hand-written shell. It had never
built: it declared one dependency and leaned on monorepo hoisting for the rest,
and its SimpleLayout bypassed the theme's layouts entirely, so sidebar, TOC,
pagination and header had never once been rendered. Now it declares its
dependencies, uses the theme's DocsLayout, wires nimbus + hastPlugins +
docsTheme, and ships two MDX pages exercising the components. Two pages build,
with sidebar, TOC, autolinked headings, cards and steps all present.
Two real defects surfaced from testing the packed tarball in a clean directory
outside the monorepo — neither reachable from inside it:
- `customStyles` never worked. injectScript's code becomes a virtual module,
so a relative "./src/styles/brand.css" resolved against that instead of the
project root and failed the build. Now resolved against config.root. The
option had been documented since the package was created and never once
exercised, since this site does not use it.
- `mdxComponents` was missing CardGroup, Step and Steps. Documentation
authors reach for those as often as the prose components, and the demo page
failed on `Expected component CardGroup to be defined`.
The clean-room build also confirms the @source defence is load-bearing rather
than theoretical: `max-w-(--nb-shell-max)`, `text-[0.8125rem]` and
`w-(--nb-sidebar-width)` are all emitted and all used in the HTML. Without it
they would have been purged, because a published package sits in a real
node_modules where Tailwind's scan does not reach. It built with none of
@base-ui/react's optional siblings installed — no pagefind, tippy, medium-zoom,
mermaid or fonts — and the brand override in customStyles took effect.
Site: 1049 pages, 7 warnings, check:anchors clean, package check 0 errors,
16 tests pass. CSS moved by 102 bytes (255,900 -> 255,798) which I could not
attribute precisely; no missing-utility regression showed up under inspection.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Self-review turned up the same defect this whole series set out to remove: a
duplicated layer with the package copy unused.
The stage-D commit said it moved the generic OpenAPI layer into the theme, but
the site kept its own. resolveSchema and operationPath existed twice,
render-markdown.ts was duplicated byte-for-byte, and the site's three API pages
still imported the site's own ApiSchemaFields / ApiResponseSchema /
ApiEndpointCopy. The parameterised copies in the theme had zero consumers
anywhere -- not the site, not the demo -- so they were neither validated nor
saving anyone any work.
Now unified. The site's three components are deleted, the pages import the
theme's, and lib/openapi.ts re-exports resolveSchema/operationPath from the
theme instead of redefining them, so existing call sites are untouched but only
one implementation exists. The three-locale label table moves to
src/nimbus/lib/api-labels.ts and is passed in as `labels`, which is the whole
point of parameterising them: a theme cannot own anyone's language table.
Badges are consistent again. The API pages hand-render some schema rows
themselves and were still using the old whale kit's Badge, so swapping only the
components left two Badge styles on the same page -- worse than before, when
both halves were at least uniform. All Badge usage now goes through the theme's,
mapping the shadcn variants (secondary/outline -> default, destructive ->
danger). This also removes the last @components/components/ui/badge import.
Four smaller findings from the same pass:
- satteri was imported by src/markdown/types.ts and declared nowhere. The
clean-room smoke test passed only because bun hoisted it out of
nimbus-docs -- exactly the hoisting-masks-the-bug problem I had flagged,
catching my own verification out. Now a real dependency, and re-tested in a
project that does not install it directly.
- @fontsource-variable/* were still in optionalDependencies after the theme
stopped importing any font. Misleading; removed.
- openapi.ts had two public entries (./api and ./lib/openapi). Kept
./lib/openapi; ./api/* still serves the components.
- The README's [...slug].astro example referenced a `sidebar` variable that
the same snippet only had as a comment placeholder, so copying it would not
run. Now calls getSidebar().
Verified end to end: site builds 1049 pages / 255,798 CSS bytes / 7 warnings,
check:anchors clean, 4 + 16 tests pass, package check 0 errors. A fresh
external project installs the tarball without satteri or any optional
dependency and renders the API components -- $ref resolution, path slugs,
envelope detection and Chinese labels all working.
Third visual change to note, alongside the GitHub glyph and --nb-accent-100:
the HTTP method badge above each endpoint is now the theme Badge's neutral
`default` rather than the old kit's. The `api-method-{verb}` classes only ever
set CSS variables that a sidebar-scoped rule consumes, so no per-method colour
was lost in the body -- it never had any.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main added nine commits of API imports while this branch restructured the
theme. The two are largely orthogonal — main touched content and API plumbing,
this branch moved where components live — so only three files conflicted.
Resolutions, all keeping both sides:
- SidebarStateRestore: main introduced `data-nb-sidebar-active-only` while
this branch renamed `data-nb-api-sidebar` to `data-nb-sidebar-variant`.
Combined into `variant === "compact" && !activeOnly`.
- DocsLayout: same pair of changes on the <aside>; both attributes emitted.
- Header: main added a "PRE" status badge to the BrokerAPI tab. The theme's
Header had no badge support, so `badge` and `badgeVariant` were added to its
TabItem — the site passes the marker as configuration, the theme renders it.
Also fixed three stale test baselines that main left behind: it grew
broker-api from 9 spec files to 21 (7 domains) without updating the counts
that guard against operations going missing. 292 -> 431 operations, 35 -> 66
dataset downloads, 45 -> 80 POST fallbacks, identical across all three
locales. These failed on main before this merge; they are regression
tripwires, so they need the real numbers rather than being relaxed.
Verified after merging: 1499 pages build (1049 + 450 new API pages), warnings
unchanged at 4 deprecation notices plus the chunk-size note, check:anchors
clean, 4 + 16 tests pass with 9339 assertions, package check 0 errors across
134 files. Spot-checked that main's three features survive the new
architecture: the PRE badge renders, `data-nb-sidebar-active-only` reaches the
sidebar, and 437 broker-api pages generate. main's `x-enum-details` rendering
is intact but has no data to show — that field only exists in broker-api specs
while the code path main added is on trading-api pages.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Cloudflare Pages was failing. Reproduced by cloning the branch into a clean directory and building there — the local tree had a node_modules that hid the problem, which is the whole reason CI saw something I did not. Two distinct causes, both about dependencies resolved by luck rather than by declaration. `yaml` was never declared. src/nimbus/lib/openapi.ts imports it directly and always has; it happened to be hoisted out of nimbus-docs. Adding satteri to the theme's manifest shifted the dependency tree enough to stop that, and `astro check` then failed with "Cannot find module 'yaml'". Now a real dependency, along with `use-sync-external-store`, which astro-config.ts lists in optimizeDeps.include and which Vite could not resolve for the same reason. An audit of every bare import under src/ found no others: the remaining undeclared names are tsconfig aliases, or live only in the dead Starlight scaffold that srcDir never scans. satteri must not appear in the theme's manifest at all. It ships platform-specific native bindings and is a runtime dependency of nimbus-docs, which loads it during rendering. Naming it in the package — I tried dependency, then optional peer, then dev — makes the installer place a second copy under packages/astro-theme-docs, and the copy nimbus-docs resolves has no usable binding, so the build dies at "generating static routes" with "Cannot find native binding". A clean clone of main builds fine; a clean clone of this branch did not, which localised it to my change rather than the environment. The type-only imports it was there for now derive from nimbus-docs instead: `HastPluginDefinition` by excluding the callable arm of `HastPluginInput`, and `HastVisitorContext` from the visitor's second parameter. That removes the last reason for the theme to know satteri exists, and the types now come from a declared peer rather than a hoisted transitive. satteri sits in the root devDependencies for the pipeline test, where a top-level install keeps its bindings intact. Verified in a clean clone with no pre-existing node_modules: install and build both succeed, 1499 pages. Package check 0 errors, 16 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns
packages/astro-theme-docsfrom a parallel copy ofsrc/nimbusinto a publishable theme, and makes this site its first real consumer.src/nimbusis left holding only whale-specific content.The package was previously a copy, not a source: the site never imported it,
docsTheme()was an empty hook, and 57 of 110 same-path files had already drifted. The cost was live — changing the sidebar scrollbar and the TOC active border at the start of this work meant editing both trees.What changed
src/nimbusnow imports UI, styles, scripts, MDX components, head, chrome and the Markdown pipeline from the package, through its publicexports@sourcerequirementpackages/demo-testis a working consumer instead of a hand-written shell that had never builtDefects this surfaced
Each was invisible from inside the monorepo:
PackageManagers.astroimported a file that exists nowhere in the repo. The site's copy was broken the same way, hidden by a tsconfig exclude, and the component was never used.virtual:astro-icon.scripts/{footnotes,scroll-to-top}.client.tsimported../util/tippy, never carried over when the package was extracted.shiftHeadingscould not work.autolinkHeadingsbuilds its wrapper by returning a replacement node and satteri does not re-visit those, so a plugin filtering ondivnever sees them. Deleted rather than shipped as API.bun:testwith happy-dom.customStylesnever worked. injectScript's code becomes a virtual module, so relative paths resolved against that. Documented since the package was created, never exercised.mdxComponentswas missingCardGroup/Step/Steps.src/nimbus. It now has its ownastro check.satteriwas declared nowhere while being imported. The clean-room test passed only because bun hoisted it out ofnimbus-docs.resolveSchema, a duplicatedrender-markdown.ts, and the package's parameterised components with zero consumers. Same defect this PR exists to remove; fixed in the last commit.Two deliberate deviations
Layouts stay with the site. Routing them through the theme's
DocsLayoutinflated CSS 51% — it imports the theme'sBaseLayout, duplicating stylesheets the site already imports. The constraint is real: Tailwind roots its content scan at the CSS entry's package, so the entry must live in the consuming site, which makes the layout that owns it the site's to keep. The theme's layouts remain the default for a new project, verified by the demo.shiftHeadingsdeleted rather than parameterised, per above.Verification
check:anchorsclean, 4 + 16 tests pass, packageastro check0 errors across 134 files.satteri, and renders the docs shell and the API components. This is what confirms the@sourcerules are load-bearing: in a published package Tailwind's scan does not reach the theme's sources.Visible changes to review
PageActionLinks' GitHub glyph: Phosphor's 256-viewBox mark → the inlined official logo, now matching Header's.--nb-accent-100:#8f6bf5→#7e84ff(derived from--nb-primaryinstead of a second hardcoded purple).default. No per-method colour was lost —api-method-{verb}only sets variables that a sidebar-scoped rule consumes, so the body badge never had any.🤖 Generated with Claude Code