Feat/design alignment - #151
Merged
Merged
Conversation
Need. Every value a consumer can put in `search.provider` should do what it says. Problem. It offered three and only two worked. `titles` rendered a search box that could never return a result: the route emitted `/_docs/search.json`, but nothing in the runtime ever read it, and the index itself was only titles, descriptions and headings with no body text. `devProvider` was read by nothing at all. Solution. `provider` narrows to `pagefind | none`, `devProvider` goes, and the route goes with them.
Need. Readers search the prose of every page, not just its title. Problem. The package was instrumented for Pagefind and never wired to it. `Prose.astro` already stamped `data-pagefind-body` and `search.provider` already defaulted to `pagefind`, but nothing built an index. `astro-pagefind` exists to do exactly this, and we cannot use it: it ships TypeScript rather than JavaScript. A consumer importing it in `astro.config.mjs` gets it compiled by Astro. We import it from code that is already built and running in Node, and Node does not compile TypeScript inside `node_modules`. Solution. A small integration of our own, added by `autoIntegrations` when `search.provider` is `pagefind`. It runs in `astro:build:done`, the first hook where every page exists on disk, and every failure throws so a broken index fails the build rather than shipping dead search. `pagefind` is a plain dependency, not a peer: a consumer should get working search from the four lines of config it already writes.
Need. A search result should say what the page is and where it sits, without opening it. Problem. The index carried only the title. Nothing published the section, and a page with no `description` fell back to Pagefind's excerpt, which is chosen for the query and so usually starts mid-clause. Solution. Three keys, all from data that already exists: `title` from the heading, `crumbs` from `breadcrumbsFor` so the trail is the authored `_group.yaml` labels at any depth, and `description` from frontmatter, falling back to the first paragraph of prose. The fallback is indexed, never rendered.
Need. A reader reaches any page from anywhere, by keyboard or by tap.
Problem. There was no search UI, and the header's `search` slot could not be
filled
Solution. A modal over a dimmed page, opened by click, ⌘K or /. Composed from
Equality's exported `Dialog` and `Command` primitives, so `packages/ui` stays
untouched
Results are flat and in Pagefind's order, five at a time. An earlier version
grouped them by section, which reordered the ranking we adopted Pagefind for;
the section is a breadcrumb on each row instead.
Three lines are load-bearing and commented where they sit:
`shouldFilter={false}`, because cmdk would re-filter what Pagefind ranked;
`client:only`, because a server-rendered trigger would never wake up; and a
`showSearch` prop rather than slot fallback, because Astro registers a named
slot at compile time, so a forwarded slot always counts as filled.
Co-authored-by: Henry Wilkinson <henry@wilkinson.graphics>
Baseline for feedback. Six areas, built from nineteen logged decisions in .anchor.local/living-docs/decisions.md, slug design-alignment. - Header: brand renders the EQTY mark, inverted for light mode; 69px from the board; edges move to border-raised, which is the token Gov Studio pairs with a raised fill; utility controls go bare at every width. - Sidebar: rows take Equality's house list recipe with Gov Studio's height cap and weight. Selected state is the board's node 2014:2145, an opaque lilac-700 to lilac-900 gradient. Opaque rather than alpha over brand-primary, whose contrast inverts between themes. - Search: the same selected treatment, so the two agree. - Page header: the breadcrumb renders at last. The trail was already computed on every page and thrown away into the search index. It shows ancestors only; the index keeps the page, because a result row needs it to identify itself. - Mobile: a navigation drawer on the Popover API. Below lg the sidebar was display:none with no replacement, so a phone could only navigate by search. Closes a live accessibility defect. headerLink.icon is optional, Equality's Icon is Lucide-backed and ships no brand marks, and the label was hidden below sm, so equality.eqtylab.io renders a 16x12px link with no accessible name. Configured links move into the drawer, where their labels show. Verified: root build green at 68 pages, check-no-utilities clean, 33 unit tests, 196 browser tests across five device profiles, lint and format clean. Not verified on real hardware. Browser tests live in .local/, which .gitignore covers, so they are not in this commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Need. A reader should see what the site is and which product it documents. Problem. The header showed only the logo, and `replacesTitle` hid the site name. Below lg it swapped to a cropped mark, on a premise about width that measurement disproved. Solution. Full wordmark at every width, then a constant "Docs" label. The product name heads the sidebar. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. The configured header links want icons, and the demo's only link is GitHub. Problem. `icon` took a Lucide name, and Lucide ships no brand marks. So the GitHub link rendered no icon, and below sm, with its label hidden, no accessible name either. Solution. `icon` also takes a path to an SVG in the consumer's `public/`, rendered the same way as the logo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. Changing theme is rare and low-stakes. It should cost one press. Problem. The dropdown cost two, and made the reader open a menu and read three options to make a choice that hardly matters. As a modal Radix menu it also died on iOS. Solution. One button cycling System, Light, Dark, with the current state on its face. Nothing to open, nothing to think through and select. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. The sidebar is the most-used surface here, and it should look like the design system it documents. Problem. It was styled from the Governance Studio board: a gradient selected row, a shadow, a row height cap, none of which Equality ships. It read as a third language beside the search palette and the theme menu. Solution. Rows take Equality's dropdown item, the rail takes the Separator's colour, and the current page holds the hover recipe, which search now shares. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. A reader scrolling a long page should see where they are. Problem. The scroll-spy watched a narrow band, so nothing was marked at load or between two headings. The rail was broken into dashes and its nesting had no connector. Solution. The active heading is the last one above the reading line. The rail is continuous, curves in and out of each nested level, and carries a lit segment that travels along it as you scroll. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. Documentation is mostly body text, so block spacing is most of the page. Problem. Blocks sat 8px apart while lines inside a paragraph sat 28px apart, so consecutive paragraphs read as one. Headings sat the same distance above and below, marking nothing. Solution. One scale: 12 / 16 / 32 / 48 / 64. A heading binds tighter to the text it owns than paragraphs bind to each other. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. A reader who finishes a page needs somewhere to go next, and a way to fix what they just read. Problem. The page stopped at its last line, 40px from the bottom. `footer.editUrl`, `footer.showPrevNext` and `prevNextFor` were all built and none of them rendered. Solution. Previous and next links, then a quiet row with "Edit this page". Space separates it rather than a rule, and every page now ends with 128px of runway. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need: comments that warn you off a change, and nothing else. Problem: those sat among comments describing what the code does. Solution: the descriptions are gone, the warnings are one line each. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Need: to try search locally before shipping a page. Problem: Pagefind writes its index into dist, and astro dev never serves dist, so the palette 404'd and asked for the build you had just run. Solution: in dev, a request under /pagefind/ is read straight from dist on disk. Results describe the last build; rebuild while dev runs and the next search sees it. Reverses 748ba55, which had dev refuse to search rather than answer from the last build. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Need: to know in dev that the page you are editing is not in the index. Problem: those last-build results look exactly like current ones. Solution: a footer says so in dev; it compiles out of production. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Baseline for feedback. Six areas, built from nineteen logged decisions in .anchor.local/living-docs/decisions.md, slug design-alignment. - Header: brand renders the EQTY mark, inverted for light mode; 69px from the board; edges move to border-raised, which is the token Gov Studio pairs with a raised fill; utility controls go bare at every width. - Sidebar: rows take Equality's house list recipe with Gov Studio's height cap and weight. Selected state is the board's node 2014:2145, an opaque lilac-700 to lilac-900 gradient. Opaque rather than alpha over brand-primary, whose contrast inverts between themes. - Search: the same selected treatment, so the two agree. - Page header: the breadcrumb renders at last. The trail was already computed on every page and thrown away into the search index. It shows ancestors only; the index keeps the page, because a result row needs it to identify itself. - Mobile: a navigation drawer on the Popover API. Below lg the sidebar was display:none with no replacement, so a phone could only navigate by search. Closes a live accessibility defect. headerLink.icon is optional, Equality's Icon is Lucide-backed and ships no brand marks, and the label was hidden below sm, so equality.eqtylab.io renders a 16x12px link with no accessible name. Configured links move into the drawer, where their labels show. Verified: root build green at 68 pages, check-no-utilities clean, 33 unit tests, 196 browser tests across five device profiles, lint and format clean. Not verified on real hardware. Browser tests live in .local/, which .gitignore covers, so they are not in this commit. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Need. A reader should see what the site is and which product it documents. Problem. The header showed only the logo, and `replacesTitle` hid the site name. Below lg it swapped to a cropped mark, on a premise about width that measurement disproved. Solution. Full wordmark at every width, then a constant "Docs" label. The product name heads the sidebar. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. The configured header links want icons, and the demo's only link is GitHub. Problem. `icon` took a Lucide name, and Lucide ships no brand marks. So the GitHub link rendered no icon, and below sm, with its label hidden, no accessible name either. Solution. `icon` also takes a path to an SVG in the consumer's `public/`, rendered the same way as the logo. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. Changing theme is rare and low-stakes. It should cost one press. Problem. The dropdown cost two, and made the reader open a menu and read three options to make a choice that hardly matters. As a modal Radix menu it also died on iOS. Solution. One button cycling System, Light, Dark, with the current state on its face. Nothing to open, nothing to think through and select. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. The sidebar is the most-used surface here, and it should look like the design system it documents. Problem. It was styled from the Governance Studio board: a gradient selected row, a shadow, a row height cap, none of which Equality ships. It read as a third language beside the search palette and the theme menu. Solution. Rows take Equality's dropdown item, the rail takes the Separator's colour, and the current page holds the hover recipe, which search now shares. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. A reader scrolling a long page should see where they are. Problem. The scroll-spy watched a narrow band, so nothing was marked at load or between two headings. The rail was broken into dashes and its nesting had no connector. Solution. The active heading is the last one above the reading line. The rail is continuous, curves in and out of each nested level, and carries a lit segment that travels along it as you scroll. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. Documentation is mostly body text, so block spacing is most of the page. Problem. Blocks sat 8px apart while lines inside a paragraph sat 28px apart, so consecutive paragraphs read as one. Headings sat the same distance above and below, marking nothing. Solution. One scale: 12 / 16 / 32 / 48 / 64. A heading binds tighter to the text it owns than paragraphs bind to each other. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Need. A reader who finishes a page needs somewhere to go next, and a way to fix what they just read. Problem. The page stopped at its last line, 40px from the bottom. `footer.editUrl`, `footer.showPrevNext` and `prevNextFor` were all built and none of them rendered. Solution. Previous and next links, then a quiet row with "Edit this page". Space separates it rather than a rule, and every page now ends with 128px of runway. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…uality into feat/design-alignment
main's docs work landed alongside the inline-Tailwind conversion. Resolutions: - package.json: kept our 0.3.0 and check:source; took main's scripts/dev.mjs runner and build:dev. - Header/Prose/DocsPage/docs.astro: took ours. main's changes here introduce GlobalSearch, the pagefind meta and `suggested`, all of which this branch already carries. Kept main's note on the breadcrumb trail's shape. - Header.module.css: stays deleted; its rules are inline on Header.astro. - GlobalSearch: took our converted files, then applied main's changes on top - the selected row narrows to a background tint, with no text recolour and no shadow, plus main's reworded comments. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Shrinks99
approved these changes
Sep 21, 2026
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.
Body
The docs site was a vibe code experiment. It worked, but it looked nothing like our brand and
didn't use much of Equality. This branch reskins it by building the design out of some of the
components we ship, and uses that as a test of the system. The gap list it
produced is the point.
What changed:
Ten places still needed hand rolling: no highlight token, no dark values on the
brand colours, collapsible content that cannot start open, no height prop on
CodeBlock. All logged as gaps rather than worked around quietly. Two are oneline fixes in
packages/ui.To check:
pnpm build, thenpnpm devScaffolding
Commits: eight, one concern each, need/problem/solution in each body.
wip(docs): restyle the chrome against the Gov Studio boardfeat(docs): show the product name in the headerchrome/Header.*,styles/chrome.css,config.ts, demo config,eqty-mark.svgfeat(docs): let a header link supply its own SVG iconchrome/LinkIcon.*,chrome/Header.astro,chrome/NavDrawer.astro,config.ts,github.svgfeat(docs): make the theme control a cycling buttonchrome/ThemeToggle.*,chrome/Header.astrofeat(docs): rebuild the sidebar from Equality's own componentschrome/NavTree.*,chrome/NavProduct.*,chrome/Sidebar.astro,chrome/NavDrawer.astro,scripts/eq-nav-*.tsfeat(docs): track the reading position on the table of contentschrome/TableOfContents.*,chrome/TocElbow.astro,chrome/TocList.astro,scripts/eq-toc.tsfix(docs): give prose a single vertical rhythmchrome/Prose.*,styles/prose.cssfeat(docs): end a page with a footer and some runwaychrome/PageFooter.*,routes/docs.astro,layouts/DocsPage.astro.module.css