Skip to content

feat(docs): AI-ready docs UX, full-body search, pm tabs, and content overhaul - #507

Merged
Brooooooklyn merged 4 commits into
mainfrom
feat/docs-ux-polish
Jul 29, 2026
Merged

feat(docs): AI-ready docs UX, full-body search, pm tabs, and content overhaul#507
Brooooooklyn merged 4 commits into
mainfrom
feat/docs-ux-polish

Conversation

@Brooooooklyn

Copy link
Copy Markdown
Member

Summary

Research-driven polish of the whole docs site (4 parallel audits: content & IA, napi-rs feature coverage, UX/frontend code, external best practices — research doc included at docs/superpowers/specs/2026-07-28-docs-polish-research.md), followed by a Codex adversarial review whose 8 findings were each verified against the code and fixed in this branch.

AI-era affordances

  • Copy-page dropdown on every docs page: Copy as Markdown · View as Markdown · Open in ChatGPT · Open in Claude (the raw .md twins were already served — now reachable from the UI).
  • /llms-full.txt per locale (full-docs bundle for agents); llms.txt is now linked from the footer.

Search

  • Full body + code indexing: build-time /search-index.<locale>.json, lazy-fetched on first ⌘K (replaces title/headings-only in-bundle index).
  • Results grouped by sidebar section with matched-heading / body-snippet sub-rows and #anchor navigation. Slugs replicate markdown-it-anchor exactly (verified against the real compiler: underscores kept, inline HTML dropped, CJK percent-encoded, {#custom-id} honored, -1/-2 dedup).

UX

  • Synced package-manager tabs (::: pm): CSS-only switching with per-bar radio groups (keyboard/ARIA correct), group-local :has(), JS cross-bar sync + localStorage persistence; live on getting-started + simple-package in all 3 locales.
  • Branded 404 (worker notFound serves the static /404.html); /docs, /blog, /changelog section roots 301 to their first page instead of bare-404ing.
  • PageMeta row: last-updated date + contributor avatars (per-locale git history, gravatar fallback) + 👍/👎 feedback links prefilling GitHub issues + /edit/main edit links.
  • Mobile "On this page" collapsible; Radix focus-trapped drawer (fix: overlay no longer intercepts taps); sidebar active-item scroll-into-view; skip-link focus fix; copy-code button visible on touch/keyboard; localized TOC/theme chrome; "help translate" CTA.
  • Deploy CI uses fetch-depth: 0 so git-derived page metadata is real.

Content (EN)

  • Rewritten v2→v3 migration guide (H1, grammar, TL;DR breaking-changes table, step-by-step; fixes triples.defaults key name).
  • New pages: Custom async runtime (async-runtime feature + AsyncRuntime SPI + napi-async-runtime crate, with an unload-safe example that joins workers before shutdown returns) · Web Streams (+AsyncBlock/AsyncBlockBuilder, with_dispose documented as success-path) · Examples index.
  • Newly documented: type_tag, Either3..Either26, HandleScope/EscapableHandleScope, @napi-rs/wasm-runtime, namespaces.
  • De-duplicated function type tables, consolidated dts-header docs to one canonical page, runnable examples for CLI leaf pages, beginner-ordered concepts sidebar, release guide surfaced in the beginner path.

Translations (cn + pt-BR)

  • async-fn, function, promise, async-task, exports re-synced from ~30–67% to full parity with the updated English pages (code blocks byte-identical, heading structure matched).

Verification

  • 422/422 tests pass (42 files), incl. new coverage: slug renderer-parity, pm-tabs transform, search-index builder, lastmod contributors.
  • yarn build green; artifacts confirmed in dist/client (search-index ×3, llms-full ×3, 404.html, sitemap, llms.txt).
  • Dev-server smoke: pm-tabs render + defaults, copy-page button, last-updated row, /docs → 301, cn PromiseRaw translation live.
  • Codex adversarial review run on the diff: all 8 findings (drawer z-order, unsafe runtime example, with_dispose claim, search slugs/body cap, en-only lastmod + shallow CI, desktop-hidden PageMeta, radio-group a11y, triples.default) verified and fixed here.

Deferred (intentionally)

  • v2↔v3 version switcher (out of scope per maintainer), in-browser playground (needs a Rust toolchain in-container), docs MCP server (needs hosting; /llms-full.txt covers the agent use case for now).

…overhaul

Research-driven polish across the whole docs site (research doc:
docs/superpowers/specs/2026-07-28-docs-polish-research.md), followed by a
Codex adversarial review whose 8 verified findings are all fixed here.

Site / UX:
- Copy-page dropdown on every docs page: Copy as Markdown, View .md,
  Open in ChatGPT / Claude (raw .md twins were already served, now surfaced).
- /llms-full.txt per locale (full-docs bundle); llms.txt linked in footer.
- Full-body + code Cmd-K search: build-time /search-index.<locale>.json
  (lazy-fetched), grouped results with matched-heading/snippet sub-rows and
  anchor navigation. Slugs replicate markdown-it-anchor exactly (underscores,
  inline-HTML dropping, CJK encoding, {#custom-id}, -1/-2 dedup).
- Synced package-manager tabs (::: pm) with per-bar radio groups (keyboard/
  ARIA-correct), group-local :has() CSS, JS cross-bar sync + persistence.
- Branded static 404.html (worker notFound serves it); /docs /blog
  /changelog section roots 301 to their first page.
- PageMeta row: last-updated + contributor avatars (per-locale git history,
  gravatar fallback) + thumbs feedback links + /edit/main edit links.
- Mobile: "On this page" collapsible, Radix focus-trapped drawer (fixed
  z-order so the overlay no longer intercepts taps), sidebar active-item
  scroll-into-view, skip-link focus fix, copy-code button visible on
  touch/keyboard, localized TOC/theme chrome, translate CTA on the
  not-translated banner.
- Deploy CI checks out full history (fetch-depth: 0) so lastmod data is real.

Content (EN):
- Rewrite the v2 -> v3 migration guide (H1, grammar, TL;DR table, steps);
  fix triples.defaults key name.
- New pages: Custom async runtime (feature + AsyncRuntime SPI +
  napi-async-runtime crate, with an unload-safe example), Web Streams
  (+AsyncBlock/AsyncBlockBuilder), Examples index.
- Document type_tag, Either3..Either26, HandleScope/EscapableHandleScope,
  @napi-rs/wasm-runtime, namespaces; correct with_dispose to success-path.
- De-duplicate function type tables, consolidate dts-header docs, runnable
  examples for CLI leaf pages, beginner-ordered concepts sidebar, release
  guide surfaced in the beginner path, misc correctness fixes.

Translations (cn + pt-BR):
- Re-sync async-fn, function, promise, async-task, exports to full parity
  with the updated English pages (code blocks byte-identical).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0fd7eb2a92

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/build-search-index.mjs Outdated
Comment thread components/docs/SearchDialog.tsx
Addresses review feedback on #507:

- build-search-index: fall back to the frontmatter `title:` when a page has
  no H1 (cn/pt-BR env + migration-guide pages emitted blank, unmatchable
  result rows). Verified: 0 blank titles in all 3 locales.
- SearchDialog: consolidate ranked results by group label (one CommandGroup
  per label) via a pure groupSearchResults in lib/docs/search-index —
  adjacency-only grouping produced duplicate React keys on interleaved
  rankings. Covered by unit tests.
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Both review comments addressed in 896426f (each verified against the code before fixing):

  1. Blank titles — confirmed: cn/pt-BR env + v2-v3-migration-guide lack H1s, so the full index emitted empty titles. pageTitle now falls back to the frontmatter title:. Rebuilt index shows 0 blank titles in all 3 locales; unit tests added.
  2. Duplicate group keys — confirmed: adjacency-only grouping emitted multiple same-label groups. Grouping is now a pure groupSearchResults that consolidates by label (one group per label, first-appearance order), with unit tests.

427/427 tests pass, build green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 896426fda2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/build-search-index.mjs Outdated
Comment thread scripts/build-search-index.mjs Outdated
Comment thread components/docs/SearchDialog.tsx Outdated
…ack sections

Addresses the second round of review feedback on #507 (each verified against
the actual @void/md compiler before fixing):

- headingText/markdownToPlainText: extract inline code spans BEFORE stripping
  HTML, so `PromiseRaw<'env, T>` keeps its generic (renderer anchor:
  promiseraw%3C'env%2C-t%3E) while genuine inline HTML (Promise<T>) is still
  dropped. Fence markers are removed before the code-span split.
- Strip the byte-0 <script> island block before frontmatter everywhere
  (markdownToPlainText, pageTitle, pageDescription) and tolerate leading
  blank lines: script-first pages (webassembly, announce-v2/v3) no longer
  leak YAML into the searchable body and now get title + description.
- SearchDialog fallback (metadata index, e.g. vite dev): derive the result
  section from the locale-stripped leaf, so cn/pt-BR fallback entries group
  under Docs/Blog instead of a literal locale-code group.
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Second review round addressed in b079b4f — all three verified against the actual @void/md compiler before fixing:

  1. Generics in code-span headings — confirmed: our indexer produced promiseraw where the renderer emits promiseraw%3C'env%2C-t%3E. Code spans are now extracted before the HTML strip; emitted index matches the renderer exactly (verified in the built JSON).
  2. Script-first pages — confirmed: webassembly/announce-v2/v3 leaked YAML into the searchable body and lost their structured description. Script block is now stripped before frontmatter everywhere (blank-line tolerant); emitted entry has correct title/description and prose-first body.
  3. Fallback locale sections — confirmed: vite dev (build-only index) grouped cn/pt-BR results under a literal locale-code label. Section now derives from the locale-stripped leaf.

432/432 tests pass, build green.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b079b4f88c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread pages/en/docs/concepts/streams.md
Comment thread pages/en/docs/concepts/streams.md
Comment thread components/docs/SearchDialog.tsx Outdated
Comment thread components/docs/PageActions.tsx
Comment thread scripts/build-search-index.mjs Outdated
…ile TOC width

Third round of review feedback on #507 (all verified first):

- streams: add `use napi_derive::napi;` to the standalone lib.rs examples
  (bindgen_prelude does not re-export the proc macro — the docs' own class/
  threadsafe-function pages already follow this convention) and import
  `createReadStream` from node:fs in the index.mjs example.
- pageTitle: run the H1 through the same inline-markup extraction as
  headings — titles like `\`Reference\` / \`WeakReference\`` no longer
  display backticks in the dialog.
- SearchDialog: render CommandEmpty only after the index fetch resolves, so
  "No results found" no longer flashes next to the loading row.
- PageActions/DocsLayout: stretch the island wrapper to the column width
  ([&>div]:w-full + w-full root), so the mobile "On this page" <details>
  spans the main column instead of shrink-to-fit right-aligned.
@Brooooooklyn

Copy link
Copy Markdown
Member Author

Third review round addressed in dc2a906 — all five verified before fixing:

  1. streams #[napi] import — confirmed: bindgen_prelude does not re-export the macro (the example crate gets it via #[macro_use] extern crate napi_derive at its root). Added use napi_derive::napi; to all three standalone examples, matching the class/threadsafe-function pages' convention.
  2. createReadStream import — confirmed; added import { createReadStream } from 'node:fs'.
  3. Empty state during load — confirmed; CommandEmpty now renders only after the fetch resolves.
  4. Mobile TOC width — confirmed: the shrink-to-fit chain was slot flex-item → island wrapper → root. Stretched both the island wrapper ([&>div]:w-full) and the root (w-full); the copy button stays end-aligned.
  5. Backtick titles — confirmed in the emitted JSON (\Reference` / `WeakReference`). pageTitle` now strips inline markup; emitted titles are clean.

433/433 tests pass, build green.

@Brooooooklyn
Brooooooklyn merged commit 9f284d7 into main Jul 29, 2026
2 checks passed
@Brooooooklyn
Brooooooklyn deleted the feat/docs-ux-polish branch July 29, 2026 15:43

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc2a906028

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

.map((part) =>
part.length >= 2 && part.startsWith('`') && part.endsWith('`')
? part.slice(1, -1)
: part.replace(/<[^>]+>/g, ' ').replace(/(\*\*|~~|\*)/g, ' '),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve fenced code while stripping HTML

The inline-code split does not protect fenced code because the fence markers were already removed, so every code sample passes through the HTML-tag regex. Generic types such as Box<dyn AsyncRuntimeGuard + '_> disappear from the new async-runtime index, and a comparison such as if n <= 1 can make the regex consume multiple lines through the next >, removing intervening identifiers from full-body search. Unlike the repaired inline-span case, this is fresh evidence from fenced regions; preserve fence contents separately or restrict HTML removal to prose.

Useful? React with 👍 / 👎.

Comment on lines +172 to +173
#[napi]
pub async fn sleep_then_add(a: u32, b: u32, sleep_ms: u32) -> u32 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Import the attribute macro in the runtime example

Copying this standalone lib.rs example fails because #[napi] is not in scope: the snippet only uses the fully qualified #[napi_derive::module_init] attribute and imports no napi_derive::napi macro. Import the macro or write this attribute as #[napi_derive::napi] so the documented example compiles.

Useful? React with 👍 / 👎.

Comment on lines +100 to +102
<a
href="/llms.txt"
className="transition-colors hover:text-primary"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep footer links in the active locale

On Chinese and Portuguese pages, this hardcoded link always opens the English /llms.txt, despite the build emitting /cn/llms.txt and /pt-BR/llms.txt; the new Docs link is similarly hardcoded to the English route. This affects both localized landing pages and localized docs/blog layouts, so the footer needs route-locale-aware targets without also enabling the landing-only language control.

Useful? React with 👍 / 👎.

Brooooooklyn added a commit that referenced this pull request Jul 30, 2026
The scroll-into-view effect (from #507) unconditionally scrolled the active
sidebar item to 1/3 from the top on every page mount. Since navigation is a
full page load, the whole sidebar visibly jumped after EVERY nav click —
even when the clicked item was already on screen (reported as a layout
shift).

Use nearest-edge semantics instead: only adjust scrollTop when the active
item is outside the visible area (48px margin), bringing it just into view.
An already-visible item leaves the scroll position untouched, so clicking
between visible pages no longer shifts anything. Deep links into long
sidebars still reveal the active item. Also skips the adjustment when the
item has no box (inside a collapsed group).
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