at main
1 folder
13 files
Share one top nav across docs and playground (#279)
* Share one top nav across docs, playground, and 404
Docs and the playground carried different chrome: the docs sidebar owned
the wordmark, search, nav links, and theme controls, while the playground
had a bespoke bar with a plain-text title and one "Docs" link. Nothing
carried across but the theme controls.
Both surfaces now render one SiteNav: wordmark, Docs/Playground/Storybook,
search, and the appearance controls. The 404 renders it too, so no surface
is left with its own bar.
The docs move from Fumadocs' docs layout to its notebook layout with
nav.mode 'top', which spans the header full width and starts the sidebar
beneath it. SiteNav is supplied through the layout's header slot, so it
also carries the sidebar collapse and drawer triggers, and the sidebar
footer no longer renders the theme switch.
Below lg the docs hand the destinations to the sidebar, which already
lists them there; surfaces with no sidebar keep them on a second nav row
below md. Below md the appearance controls move behind a disclosure --
they are 230px of pills that cannot share a 320px row with the wordmark,
search, and the sidebar trigger, and letting them wrap made the docs bar
113px tall while the layout still offset content by 56px.
Pre-bundle lucide-react: Fumadocs' search trigger and popover import from
its barrel, which unbundled is ~1750 module requests. Adding that to the
playground, which also loads Monaco, exhausted the browser's connection
pool in dev and the page never hydrated.
* Cover shared navigation behavior
Share one top nav across docs and playground (#279)
* Share one top nav across docs, playground, and 404
Docs and the playground carried different chrome: the docs sidebar owned
the wordmark, search, nav links, and theme controls, while the playground
had a bespoke bar with a plain-text title and one "Docs" link. Nothing
carried across but the theme controls.
Both surfaces now render one SiteNav: wordmark, Docs/Playground/Storybook,
search, and the appearance controls. The 404 renders it too, so no surface
is left with its own bar.
The docs move from Fumadocs' docs layout to its notebook layout with
nav.mode 'top', which spans the header full width and starts the sidebar
beneath it. SiteNav is supplied through the layout's header slot, so it
also carries the sidebar collapse and drawer triggers, and the sidebar
footer no longer renders the theme switch.
Below lg the docs hand the destinations to the sidebar, which already
lists them there; surfaces with no sidebar keep them on a second nav row
below md. Below md the appearance controls move behind a disclosure --
they are 230px of pills that cannot share a 320px row with the wordmark,
search, and the sidebar trigger, and letting them wrap made the docs bar
113px tall while the layout still offset content by 56px.
Pre-bundle lucide-react: Fumadocs' search trigger and popover import from
its barrel, which unbundled is ~1750 module requests. Adding that to the
playground, which also loads Monaco, exhausted the browser's connection
pool in dev and the page never hydrated.
* Cover shared navigation behavior
Share one top nav across docs and playground (#279)
* Share one top nav across docs, playground, and 404
Docs and the playground carried different chrome: the docs sidebar owned
the wordmark, search, nav links, and theme controls, while the playground
had a bespoke bar with a plain-text title and one "Docs" link. Nothing
carried across but the theme controls.
Both surfaces now render one SiteNav: wordmark, Docs/Playground/Storybook,
search, and the appearance controls. The 404 renders it too, so no surface
is left with its own bar.
The docs move from Fumadocs' docs layout to its notebook layout with
nav.mode 'top', which spans the header full width and starts the sidebar
beneath it. SiteNav is supplied through the layout's header slot, so it
also carries the sidebar collapse and drawer triggers, and the sidebar
footer no longer renders the theme switch.
Below lg the docs hand the destinations to the sidebar, which already
lists them there; surfaces with no sidebar keep them on a second nav row
below md. Below md the appearance controls move behind a disclosure --
they are 230px of pills that cannot share a 320px row with the wordmark,
search, and the sidebar trigger, and letting them wrap made the docs bar
113px tall while the layout still offset content by 56px.
Pre-bundle lucide-react: Fumadocs' search trigger and popover import from
its barrel, which unbundled is ~1750 module requests. Adding that to the
playground, which also loads Monaco, exhausted the browser's connection
pool in dev and the page never hydrated.
* Cover shared navigation behavior
Make the checks and tests mean something (#270)
Delete the theme tests that could not fail. validateContrast already
hard-gates text against every surface at 4.5:1 and border.control against
canvas and recessed at 3:1, throwing before any assertion recomputing
those ratios from the emitted CSS could run. Replace each with the honest
statement of the same property: that building the theme does not throw.
The neutral half of the dark subtle-hover test was dead for the same
reason, so keep only the accent pair, which is genuinely ungated.
Drop the loading-skeleton tautology, which asserted a contrast ratio
above 1 immediately after asserting the two colours differ. The real
gate is in loading-skeleton.browser.test.ts, samples the animated pulse
and requires 1.4:1, so it both subsumes and beats the static check.
Drop the migration-era assertions: the hand-written list of 25 removed
tokens, and the hardcoded 128 leaf count, which contract.test.ts already
asserts properly. Derive the count from the contract instead. Drop the
theme test that read the combobox stylesheet source as text and grepped
it for a string.
Make the local and CI checks agree. `pnpm run check` ran check:barrels
but not root formatting; CI ran root formatting but not check:barrels, so
a barrel violation could merge and a docs-only change could pass locally
and fail CI. Adding //#check:format-root to the check task and having CI
run that same task leaves both sides on an identical 28-task graph, with
--affected only ever an additive PR filter. knip stays a separate
unscoped invocation because it is repo-wide.
Run the docs app tests in CI, which nothing did. Four of them failed on
main because the harness rendered ThemeControls as a sibling of the
StoryWrapper that owns the only IconSpritesheetProvider; wrapping
DocsThemeRoot mirrors what __root.tsx actually does. Ignore the docs
failure screenshots, which were written into a tracked path.
Give the token board the coverage check its own comment claims. The
swatch count and the tree builder now both derive from the contract.
Verified by dropping a leaf: 3 unit tests fail and the story fails with
"expected 46 to be 47".
Rebuild the theme identity control and fix the icon collision (#265)
* Replace the docs theme identity select with a matching pill control
The theme identity picker was a raw native <select>, the only native
form control on the docs surface, squeezed to ~200px in the sidebar
footer and truncating "Tactile". Add a text-label segmented toggle
group alongside the existing icon-only one, sharing the same pill
shape, height, and focus treatment as the colour-mode group beside it,
and use it for theme identity in both the sidebar footer and the
playground header.
Also give system colour mode a settings-gear glyph so it no longer
collides with the monitor icon used for the Desktop viewport option.
* Swap the system colour-mode glyph for a half-filled circle
A settings cog reads as "open theme options", not "follow the
operating system" — a misleading glyph, not just an ambiguous one.
Replace it with the conventional split-circle contrast mark (one
half filled, one half outline), which reads as "either of these two,
decided for you". Matches the existing icon set's outline
conventions (24x24 viewBox, currentColor stroke) apart from the
filled half the mark requires.