Skip to content

feat(website): align the docs index with the control plane - #923

Merged
blove merged 1 commit into
mainfrom
blove/docs-index-control-plane
Sep 1, 2026
Merged

feat(website): align the docs index with the control plane#923
blove merged 1 commit into
mainfrom
blove/docs-index-control-plane

Conversation

@blove

@blove blove commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

/docs was 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 reads Docs / Overview, the picker reads Choose a library.

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 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.

Renderjson-render

The library is called json-render 85 times across docs content, on the marketing page, and on the /docs card. Render existed 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/render and the URL stays /docs/render/. Marketing surfaces keep Render — that's about the /render product page, a separate decision.

Two drifts found while building this

  • The page and the drawer named the page differently. page.tsx passed pageTitle="Overview"; Nav resolves the drawer's title independently and got "Documentation". Same page, two names, depending on viewport width. Both now read a shared DOCS_INDEX_TITLE.
  • A loose e2e assertion. getByText('Render') passed on a substring of json-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, so hasText on 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, because getAllByText is 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 forcing max-w-3xl onto the body.

Design spec: docs/superpowers/specs/2026-09-01-docs-index-control-plane-design.md.

🤖 Generated with Claude Code

/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>
@vercel

vercel Bot commented Sep 1, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
threadplane Ready Ready Preview Sep 1, 2026 5:17am UTC

Request Review

@blove
blove enabled auto-merge (squash) September 1, 2026 05:15

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Automated approval: this PR received an intelligent (AI) code review. See the review comments on this PR.

@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Claude finished @blove's task in 0s —— View job


I'll analyze this and get back to you.

@blove
blove merged commit 69c2d54 into main Sep 1, 2026
24 checks passed
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>
@blove
blove deleted the blove/docs-index-control-plane branch September 1, 2026 18:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant