From 85a0f90f055466895e66ef300fbb32cea326bd61 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 6 Sep 2026 00:53:01 -0500 Subject: [PATCH 1/6] docs: cap the shell width, run the top rule edge to edge On a wide display nothing stopped the layout growing, so the sidebar and the table of contents stayed pinned to the screen edges while the text column sat in the middle. At 2560px that left about 650px of empty space on either side of the text and a long way to travel to reach either sidebar. The shell now stops at 1440px and centers, which leaves the sidebars beside the text instead of at the edges. Below that width nothing changes. The rule under the top bar used to be a border on the navbar plus another on the sidebar header. Both sit inside the shell, so once the shell was centered the rule stopped short of the edges. It is now drawn once, fixed to the viewport, and runs the full width behind them. `width: 100%` is spelled out on the shell because body is a flex container: on its own, `margin-inline: auto` disables the default stretch and the shell shrink-to-fits, which caps the width by accident rather than by intent. Also folds away the duplicate position, width and backdrop-filter declarations that had accumulated in the navbar rule. --- apps/www/src/app/docs/layout.module.css | 33 +++++++++++++++++++ .../www/src/components/docs/navbar.module.css | 14 ++------ .../src/components/docs/sidebar.module.css | 1 - 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/apps/www/src/app/docs/layout.module.css b/apps/www/src/app/docs/layout.module.css index 946033346..aad0a62e6 100644 --- a/apps/www/src/app/docs/layout.module.css +++ b/apps/www/src/app/docs/layout.module.css @@ -1,8 +1,41 @@ +/* + The shell fills the window up to `--docs-shell-max`, then centers itself. + Without the cap the sidebar and the table of contents stay pinned to the + screen edges on a wide display, leaving the text column marooned between two + large empty gaps. + + `width` is set explicitly because body is a flex container: a bare + `margin-inline: auto` would disable the default stretch and leave the shell + shrink-to-fitting, which caps the width by accident rather than by intent. +*/ .container { + --docs-shell-max: 1440px; + display: flex; flex-direction: row; position: relative; + width: 100%; + max-width: var(--docs-shell-max); + margin-inline: auto; } + +/* + The bar across the top of the page is drawn once, here, rather than as a + border on the navbar and the sidebar header. Those two sit inside the centered + shell, so their borders stop at its edges; this one is fixed to the viewport + and runs the full width behind them. +*/ +.container::before { + content: ""; + position: fixed; + top: 50px; + left: 0; + right: 0; + border-top: 0.5px solid var(--rs-color-border-base-primary); + z-index: var(--rs-z-index-portal); + pointer-events: none; +} + .sidebar { height: 100vh; position: sticky; diff --git a/apps/www/src/components/docs/navbar.module.css b/apps/www/src/components/docs/navbar.module.css index 3cae32775..110cdd28e 100644 --- a/apps/www/src/components/docs/navbar.module.css +++ b/apps/www/src/components/docs/navbar.module.css @@ -3,22 +3,14 @@ align-items: center; justify-content: space-between; padding: var(--rs-space-4) var(--rs-space-7); - backdrop-filter: blur(1px); - position: relative; - width: 100%; - box-sizing: border-box; position: sticky; top: 0; - backdrop-filter: blur(1px); - border-bottom: 0.5px solid var(--rs-color-border-base-primary, #e8e8e8); - position: relative; width: 100%; - box-sizing: border-box; - position: sticky; - top: 0; - z-index: var(--rs-z-index-portal); height: 50px; + box-sizing: border-box; + backdrop-filter: blur(1px); background: #fcfcfce6; + z-index: var(--rs-z-index-portal); } [data-theme="dark"] .navbar { diff --git a/apps/www/src/components/docs/sidebar.module.css b/apps/www/src/components/docs/sidebar.module.css index 77aecc645..8a966901a 100644 --- a/apps/www/src/components/docs/sidebar.module.css +++ b/apps/www/src/components/docs/sidebar.module.css @@ -5,7 +5,6 @@ .header { height: 50px; padding: 0 var(--rs-space-5); - border-bottom: 0.5px solid var(--rs-color-border-base-primary); border-radius: 0; margin-bottom: 0; } From aee9e25ec84668d035df93549723cb1b371b6e89 Mon Sep 17 00:00:00 2001 From: Ravi Suhag Date: Sun, 6 Sep 2026 01:04:14 -0500 Subject: [PATCH 2/6] docs: flat table of contents MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The contents rail was a minimap: a column of ticks every 20px, heading labels snapped onto the nearest tick, a two-pass pass to stop labels landing on the same one, and a marker reading out scroll progress to two decimals. Labels only appeared on hover, so at rest it showed a row of ticks and a number. It is now a plain list of the page's headings, indented by level, with the one you are reading marked. Sizes come from the docs typeset — the eyebrow on the label layer, the links at caption size. Two fixes come out of it. Headings gain `scroll-margin-top`, so landing on a #hash no longer parks the heading behind the sticky navbar — that was broken for every deep link, not just ones from this rail. And the rail drops its own click handling in favour of the plain anchor, which gives working middle-click, back button, and copy-link. Active heading is read from scroll position rather than an IntersectionObserver. The reader is at the last heading that has passed under the navbar, which is a question about where the page is scrolled to; an observer answers which headings are on screen and leaves nothing marked whenever a section is taller than the viewport. Net 336 lines lighter. --- .../src/app/docs/[[...slug]]/page.module.css | 15 + apps/www/src/app/docs/[[...slug]]/page.tsx | 24 +- .../components/mdx/mdx-components.module.css | 2 + apps/www/src/components/toc/toc.module.css | 182 +++----- apps/www/src/components/toc/toc.tsx | 417 ++++-------------- 5 files changed, 152 insertions(+), 488 deletions(-) diff --git a/apps/www/src/app/docs/[[...slug]]/page.module.css b/apps/www/src/app/docs/[[...slug]]/page.module.css index 3a724d3dd..9acee770d 100644 --- a/apps/www/src/app/docs/[[...slug]]/page.module.css +++ b/apps/www/src/app/docs/[[...slug]]/page.module.css @@ -38,3 +38,18 @@ letter-spacing: var(--docs-lede-tracking); max-width: 42rem; } + +/* + The rail sits beside the article and stays put while it scrolls. It owns a + fixed width so the text column keeps the same measure on every page, + regardless of how many headings a page has. +*/ +.toc { + flex-shrink: 0; + display: flex; + flex-direction: column; + width: 224px; + height: calc(100vh - 50px); + position: sticky; + top: 50px; +} diff --git a/apps/www/src/app/docs/[[...slug]]/page.tsx b/apps/www/src/app/docs/[[...slug]]/page.tsx index 0b70d3356..b49a82823 100644 --- a/apps/www/src/app/docs/[[...slug]]/page.tsx +++ b/apps/www/src/app/docs/[[...slug]]/page.tsx @@ -64,28 +64,8 @@ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) { -