fix(website): give library-neutral docs pages an honest control plane - #920
Merged
Conversation
Records the design for /docs/choosing-an-adapter and the control plane's missing "no library selected" state. Also records that one of the two follow-ups behind this work was already fixed by #892, and that /docs is a landing page rather than a page missing its shell. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
On /docs/choosing-an-adapter the mobile drawer's Scope card read "LangGraph / Getting Started / Documentation" — three fabrications in the one card whose job is saying where you are. Nav derives the library from the second path segment, which on that URL is "choosing-an-adapter"; getLibraryConfig returns undefined and the code fell back to 'langgraph', so the drawer showed LangGraph's picker and its whole section tree. The cause is that the control plane had no "no library selected" state, so every caller had to invent one. Adds it: - activeLibrary is now LibraryId | null through DocsControlPlane and DocsNavigation. Neutral pages show "Docs / <page>" in Scope, a "Choose a library" picker with nothing checked, and no section tree. - Nav stops defaulting to langgraph and resolves special-page titles, which corrects the drawer on every library-neutral route. /docs/choosing-an-adapter was also bespoke, and that drift is what produced the rest of its symptoms. It now uses the same shell as every other docs page, which: - gives it the control plane it never had, - deletes an empty hero Section that opened a measured 144px gap above the H1 and whose empty div was the target of aria-labelledby, leaving the section with no accessible name, - replaces ~60 duplicated lines of MDX pipeline with MdxRenderer. MdxRenderer's library/section/slug/title props were accepted and never read — four of the website's lint warnings. Dropped. The blog route was passing library="langgraph" for blog posts, which only ever looked harmless because the value was discarded. /docs keeps its landing-page treatment; it is the front door, not a page missing its shell. 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 04:23
Contributor
blove
added a commit
that referenced
this pull request
Sep 1, 2026
/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>
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.
Picks up the two follow-ups from #911. Re-checking them against
mainfirst changed both, so this PR is not quite what those notes described.One follow-up was already done
"There is no docs nav below
lg" is fixed — #892 added a mobile drawer. That note was taken against the pre-#892 tree."
/docshas no control plane" is not a defect./docsis a designed landing page — "Start building with Threadplane", pick-your-backend cards. It's the front door; a sidebar would damage it. Left alone.What the re-check found instead
On
/docs/choosing-an-adapterat 375px, the drawer's Scope card read:Three fabrications in the one card whose job is telling you where you are.
Nav.tsxderives the library frompathParts[1]— here"choosing-an-adapter", not a library — sogetLibraryConfig()returned undefined and the code fell back to'langgraph'. The drawer then showed LangGraph's picker, LangGraph's entire section tree, and a title of "Documentation".The failure mode is silence: it renders something plausible.
Root cause: the control plane had no "no library selected" state, so every caller had to invent one.
The fix
activeLibrarybecomesLibraryId | nullthroughDocsControlPlaneandDocsNavigation. Neutral pages getDocs / <page>in Scope, aChoose a librarypicker with nothing checked, and no section tree.Navstops defaulting and resolves special-page titles — correcting the drawer on every library-neutral route, not just this one./docs/choosing-an-adapter, mobileLangGraph / Getting Started / DocumentationDocs / Choosing an adapterLangGraphChoose a libraryThe page was also bespoke
That drift produced the rest of its symptoms. It now uses the same shell as every other docs page, which:
Sectionthat opened a measured 144px gap above the H1, and whose empty<div>was the target ofaria-labelledby— leaving the section with no accessible name at all;MdxRenderer.MdxRenderer'slibrary/section/slug/titleprops were accepted and never read — four of the website's lint warnings. Dropped. The blog route was passinglibrary="langgraph"for blog posts, which only ever looked harmless because the value was discarded.Testing
404 tests pass, 0 lint errors, production build green.
Nav.spec.tsx→'does not invent a library on a library-neutral docs page'is the one that matters — it fails againstmainwithexpected <span></span> to be null, catching the fabricated LangGraph. The existing'shows truthful scope and collapsed environment defaults'doubles as the regression guard that real library pages are untouched; verified in the browser too (LangGraph / Guides / Streaming, picker and tree intact).Design spec:
docs/superpowers/specs/2026-09-01-docs-library-neutral-pages-design.md.🤖 Generated with Claude Code