feat(website): align the docs index with the control plane - #923
Merged
Conversation
/docs was the only /docs/* route without the control plane. That was a deliberate call in #920 — it is a designed landing page, and the prose column would flatten its card grids — but the inconsistency reads worse than that risk. It now renders the docs shell with activeLibrary={null}, reusing the library-neutral state from #920. The landing content sits inside docs-shell-body but outside the [slug] route's md:max-w-3xl article measure, so the grids keep their own width: verified still 2-up at 426px on desktop and single-column at 375px. The sidebar picker is kept even though the page's main content is itself a backend picker. #911 removed a duplication of exactly this shape, so to be explicit: that was two statements of the same fact, this is a statement plus a shortcut for a reader who already knows where they are going. Also renames the render library's display label to json-render. It is called that 85 times across docs content, on the marketing page, and on the /docs card; "Render" existed only in docsConfig, feeding the picker, breadcrumbs, structured data and search. With the control plane on this page both labels are on screen at once. The package stays @threadplane/render and the URL stays /docs/render/. Two drifts found while building this: - The page passed pageTitle="Overview" while Nav resolved the drawer's title independently and got "Documentation" — the same page named two ways by viewport width. Both now read a shared DOCS_INDEX_TITLE. - e2e asserted getByText('Render'), which passed on a substring of json-render and would now also pass on the sidebar. It asserts card titles instead, and covers the Chat card again. Every new guard was mutation-tested. The naming test initially passed against a reverted docsConfig: getAllByText is exact-match and the picker menu is closed on mount, so it only ever saw the index card. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
blove
enabled auto-merge (squash)
September 1, 2026 05:15
Contributor
blove
added a commit
that referenced
this pull request
Sep 1, 2026
…ntracts (#926) Two follow-ups from #923. json-render on marketing surfaces --------------------------------- #923 renamed the docs picker label but deliberately left the marketing surfaces. They now agree: the homepage FeatureBlock eyebrow, the footer link, and the three solutions architecture layers all read json-render. Two hazards this surfaced: - The footer derives cta_id from the visible label, so renaming the link would have silently split PostHog's footer_render into a new footer_json_render series. trackFooterCta now takes an optional explicit CtaId and the render link pins the original. - The solutions page maps library name to href through a Record<string, string>. Renaming the data without the key returns undefined and renders the card unlinked — no error, no type failure. solutions-links.spec.ts asserts every layer resolves; mutation-tested by renaming one side only. Style contracts --------------- docs-sidebar-styles.spec.ts guarded two CSS declarations whose loss is invisible to jsdom, but it was a one-off with an inline parser. It is replaced by style-contract.ts plus a registry in style-contracts.spec.ts, so adding a guard is one entry rather than a new file. Seeded with four live rules, each mutation-tested by deleting the declaration and by renaming the selector wholesale: - .docs-sidebar-lib-item-text flex column (the #892 collision) - .docs-sidebar-lib-menu max-height + overflow-y - .docs-control-plane position sticky + align-self - [data-control-plane-pane] overflow-y Writing the registry found a bug in the extracted parser: a CSS comment above a rule lands inside the selector capture, so the exact match never fires and a guarded rule reports as missing. Comments are stripped first. Also removes the DocsSidebar wrapper and its .docs-sidebar rule, dead since #892 moved the docs nav into the control plane — only DocsNavigation is imported, and the sole class usage was inside the dead component. Its comment documented the same align-self hazard now held by the .docs-control-plane contract. Co-authored-by: Claude Opus 5 <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.
/docswas the only/docs/*route without the control plane. That was a deliberate call in #920 — it's a designed landing page and the prose column would flatten its card grids — but the inconsistency reads worse than that risk.The shell, without the prose measure
It now renders the docs shell with
activeLibrary={null}, reusing the library-neutral state from #920. Scope readsDocs / Overview, the picker readsChoose a library.The landing content sits inside
docs-shell-bodybut outside the[slug]route'smd:max-w-3xlarticle measure, so the grids keep their own width. Verified in the browser: still 2-up at 426px per card on desktop, single-column at 375px.The picker stays, deliberately
The page's main content is a backend picker, so the sidebar picker is arguably duplicative — and #911 removed a duplication of exactly this shape. Being explicit that I considered it: that one was two statements of the same fact; this is a statement plus a shortcut for a reader who already knows where they're going.
Render→json-renderThe library is called
json-render85 times across docs content, on the marketing page, and on the/docscard.Renderexisted in exactly one place —docsConfig[].title— feeding the picker, breadcrumbs, structured data and search. With the control plane on this page, both labels are on screen at once.Only the display label changes; the package stays
@threadplane/renderand the URL stays/docs/render/. Marketing surfaces keepRender— that's about the/renderproduct page, a separate decision.Two drifts found while building this
page.tsxpassedpageTitle="Overview";Navresolves the drawer's title independently and got"Documentation". Same page, two names, depending on viewport width. Both now read a sharedDOCS_INDEX_TITLE.getByText('Render')passed on a substring ofjson-render, and once the sidebar landed it would have passed on that too — matching anything but the cards. It now asserts card titles, and covers the Chat card again (whose blurb mentions json-render, sohasTexton the card would have matched two).Testing
421 tests pass, 0 lint errors, production build green — re-run after rebasing onto #922.
Every new guard was mutation-tested, and one didn't survive: the naming test passed against a reverted
docsConfig, becausegetAllByTextis exact-match and the picker menu is closed on mount — it only ever saw the index card. It now opens the menu first. The other two were confirmed by removing the control plane and by forcingmax-w-3xlonto the body.Design spec:
docs/superpowers/specs/2026-09-01-docs-index-control-plane-design.md.🤖 Generated with Claude Code