From 7b970111af4def51db0c829c32953cfdd66104de Mon Sep 17 00:00:00 2001 From: Sangjoon Bob Lee Date: Thu, 30 Jul 2026 20:05:05 -0700 Subject: [PATCH] docs: drop contents rail, cap nav at 16rem, add docs design rules --- docs/_config.yml | 6 ++-- docs/_static/custom.css | 30 +++++++++++++++---- docs/_static/toc-toggle.js | 38 ----------------------- docs/_toc.yml | 2 ++ docs/maintainer/docs-design.md | 55 ++++++++++++++++++++++++++++++++++ 5 files changed, 85 insertions(+), 46 deletions(-) delete mode 100644 docs/_static/toc-toggle.js create mode 100644 docs/maintainer/docs-design.md diff --git a/docs/_config.yml b/docs/_config.yml index 0392e3f4..6939cb8f 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -58,9 +58,10 @@ sphinx: - Quartz suppress_warnings: - "etoc.toctree" - # In-page Contents sidebar + # No in-page Contents sidebar: the pages showcase wide interactive + # widgets, so the article column gets every horizontal pixel. html_theme_options: - secondary_sidebar_items: ["page-toc"] + secondary_sidebar_items: [] html_static_path: - "_static" html_extra_path: @@ -68,7 +69,6 @@ sphinx: html_css_files: - custom.css html_js_files: - - toc-toggle.js # Keeps the mobile hamburger wired across sphinx theme drift; the file # is idempotent so double-inclusion via _static auto-add is harmless. - nav-toggle-fix.js diff --git a/docs/_static/custom.css b/docs/_static/custom.css index fd5a451a..80ebf203 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,5 +1,15 @@ -/* Interactive widgets are wide. Give the article the full page width and let - any still-wider output scroll horizontally instead of being clipped. */ +/* Interactive widgets are wide. Give the article the full page width, drop the + right-hand in-page "Contents" sidebar, and let any still-wider output scroll + horizontally instead of being clipped. */ + +/* Remove the secondary (right) table-of-contents sidebar. Deliberate: the + pages showcase wide interactive widgets, so every horizontal pixel goes to + the article column. Do not reintroduce a page-toc rail. */ +.bd-sidebar-secondary, +.bd-toc, +div.bd-sidebar-secondary { + display: none !important; +} /* Use the full available width for the page and article columns. */ .bd-page-width, @@ -9,10 +19,20 @@ max-width: 100% !important; } -/* Contents sidebar toggle */ +/* Left navigation: fixed 16rem width on desktop — it must NOT scale + proportionally with the viewport (the theme's default is a percentage, so + big monitors waste pixels on nav that belong to widgets). The collapse + offset is overridden IN LOCKSTEP with the width: if they ever disagree, + the collapsed state drags the whole article off-screen (burned twice). + Mobile (<960px) keeps the theme's off-canvas drawer untouched. */ @media (min-width: 960px) { - html.toc-hidden .bd-sidebar-secondary { - display: none !important; + .bd-sidebar-primary { + width: 16rem; + max-width: 16rem; + flex: 0 0 16rem; + } + .bd-sidebar-primary.pst-sidebar-hidden { + margin-left: -16rem; } } diff --git a/docs/_static/toc-toggle.js b/docs/_static/toc-toggle.js deleted file mode 100644 index e7ac9a98..00000000 --- a/docs/_static/toc-toggle.js +++ /dev/null @@ -1,38 +0,0 @@ -// Contents sidebar toggle -(function () { - const KEY = "quantem-docs-hide-toc"; - - let hidden = false; - try { - hidden = localStorage.getItem(KEY) === "1"; - } catch (e) {} - if (hidden) { - document.documentElement.classList.add("toc-hidden"); - } - - document.addEventListener("DOMContentLoaded", function () { - const sidebar = document.querySelector(".bd-sidebar-secondary"); - if (!sidebar) return; - - const button = document.createElement("button"); - button.className = "btn btn-sm toc-toggle-button"; - button.type = "button"; - button.title = "Show or hide the contents sidebar"; - button.setAttribute("aria-label", "Show or hide the contents sidebar"); - button.innerHTML = ''; - button.addEventListener("click", function () { - const nowHidden = !document.documentElement.classList.contains("toc-hidden"); - document.documentElement.classList.toggle("toc-hidden", nowHidden); - try { - localStorage.setItem(KEY, nowHidden ? "1" : "0"); - } catch (e) {} - }); - - const header = document.querySelector(".article-header-buttons"); - if (header) { - header.appendChild(button); - } else { - sidebar.prepend(button); - } - }); -})(); diff --git a/docs/_toc.yml b/docs/_toc.yml index 8167a6d6..1627b269 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -78,6 +78,8 @@ parts: - file: maintainer/index title: Maintainer guide sections: + - file: maintainer/docs-design + title: Docs design rules - file: changelog title: Changelog - file: maintainer/widget-release diff --git a/docs/maintainer/docs-design.md b/docs/maintainer/docs-design.md new file mode 100644 index 00000000..8b0a0777 --- /dev/null +++ b/docs/maintainer/docs-design.md @@ -0,0 +1,55 @@ +# Docs Design Rules + +Non-negotiable layout rules for this docs site. They exist because each one +was broken at least once and reached the published site. Fix forward from the +existing design — do not reinvent it during theme bumps or reworks. + +## Widgets get the horizontal pixels + +The pages exist to showcase wide interactive widgets. Every layout decision +gives spare width to the article column, not to chrome. + +- **No right-hand "Contents" (page-toc) sidebar. Ever.** + `docs/_static/custom.css` hides `.bd-sidebar-secondary`, and + `docs/_config.yml` sets `secondary_sidebar_items: []`. A "hideable + contents" rework reintroduced it once (2026-07-30) and was reverted the + same day. Do not add a page-toc rail, a toc toggle button, or a + `toc-toggle.js` back. +- **Left navigation is fixed at 16rem on desktop — never proportional.** + The theme's default sidebar width is a percentage of the viewport, so big + monitors silently spend hundreds of pixels on nav. `custom.css` pins + `width / max-width / flex-basis` to `16rem` at `min-width: 960px`. + +## Width and collapse offset move in lockstep + +If the sidebar's laid-out width and the theme's collapsed offset disagree, +the whole article is dragged off-screen by the difference (shipped broken +twice: −25px on phones, −116px on desktops). `custom.css` therefore overrides +`.pst-sidebar-hidden { margin-left: -16rem; }` right next to the 16rem width. +Change one, change both. Below 960px the theme's off-canvas drawer is left +completely alone. + +## The mobile hamburger must survive theme drift + +Both sphinx themes wire the drawer to `document.querySelector('.primary-toggle')` +— the first match — and newer pydata themes render an extra hidden button +first, killing the visible hamburger. Two defenses, keep both: + +- `docs/_static/nav-toggle-fix.js` forwards clicks from unwired toggle + buttons to the wired one (idempotent, safe to double-load). +- `scripts/check_docs_nav_toggle.py` runs in the docs workflow after every + build and fails the deploy when a page has multiple toggles without the + shim. + +## Verify locally before any push + +CI is never the first build. Before pushing docs changes: + +1. `scripts/docs_preview.sh` (full build + no-store server on port 8767); + for CSS-only tweaks, `--no-build` and copy the asset into + `docs/_build/html/_static/`. +2. Drive the built pages at phone (375/420), laptop (~1500), and large + desktop (~1900) widths — with the left sidebar **both expanded and + collapsed**, and the phone drawer opened and closed. +3. `python scripts/check_docs_nav_toggle.py docs/_build/html` must pass, and + built pages must contain zero `img.quantem-static-fallback` elements.