From 784e71c4aeb00deeb8ae2cdb6fbf07646e0ec0af Mon Sep 17 00:00:00 2001 From: Malware Utkonos Date: Sun, 11 Jan 2026 00:50:49 -0500 Subject: [PATCH] Add css/js to make a collapsible sidebar nav. Fixes #7867 --- .../source/_static/css/sidebar_toggle.css | 52 +++++++++++++++ api-docs/source/_static/js/sidebar_toggle.js | 63 +++++++++++++++++++ api-docs/source/conf.py | 2 + 3 files changed, 117 insertions(+) create mode 100644 api-docs/source/_static/css/sidebar_toggle.css create mode 100644 api-docs/source/_static/js/sidebar_toggle.js diff --git a/api-docs/source/_static/css/sidebar_toggle.css b/api-docs/source/_static/css/sidebar_toggle.css new file mode 100644 index 0000000000..08003c865c --- /dev/null +++ b/api-docs/source/_static/css/sidebar_toggle.css @@ -0,0 +1,52 @@ +/* Toggle button */ +#bn-sidebar-toggle { + position: fixed; + top: 12px; + left: 12px; + z-index: 10000; + + width: 36px; + height: 36px; + + display: inline-flex; + align-items: center; + justify-content: center; + + border: 1px solid rgba(0, 0, 0, 0.25); + border-radius: 6px; + background: #ffffff; + color: #111111; + + font-size: 18px; + line-height: 1; + cursor: pointer; + + /* Avoid stealing too much attention */ + opacity: 0.85; +} + +#bn-sidebar-toggle:hover { + opacity: 1.0; +} + +/* When sidebar is collapsed, reclaim space */ +html.bn-sidebar-collapsed .wy-nav-side { + width: 0 !important; + min-width: 0 !important; + overflow: hidden !important; +} + +html.bn-sidebar-collapsed .wy-side-scroll { + width: 0 !important; + overflow: hidden !important; +} + +/* RTD uses margin-left to make room for the sidebar */ +html.bn-sidebar-collapsed .wy-nav-content-wrap { + margin-left: 0 !important; +} + +/* Optional: ensure content doesn't look overly narrow after reclaiming space */ +html.bn-sidebar-collapsed .wy-nav-content { + max-width: 2000px !important; +} diff --git a/api-docs/source/_static/js/sidebar_toggle.js b/api-docs/source/_static/js/sidebar_toggle.js new file mode 100644 index 0000000000..d72b20b936 --- /dev/null +++ b/api-docs/source/_static/js/sidebar_toggle.js @@ -0,0 +1,63 @@ +(() => { + const STORAGE_KEY = "bn_api_sidebar"; + const CLASS_NAME = "bn-sidebar-collapsed"; + const BUTTON_ID = "bn-sidebar-toggle"; + + function isCollapsed() { + return document.documentElement.classList.contains(CLASS_NAME); + } + + function setCollapsed(collapsed) { + document.documentElement.classList.toggle(CLASS_NAME, collapsed); + try { + localStorage.setItem(STORAGE_KEY, collapsed ? "collapsed" : "expanded"); + } catch (_) { + // ignore storage failures (private mode, policy, etc.) + } + const btn = document.getElementById(BUTTON_ID); + if (btn) { + btn.setAttribute("aria-pressed", collapsed ? "true" : "false"); + btn.title = collapsed ? "Show navigation" : "Hide navigation"; + } + } + + function initialCollapsed() { + try { + const saved = localStorage.getItem(STORAGE_KEY); + if (saved === "collapsed") return true; + if (saved === "expanded") return false; + } catch (_) { + // ignore + } + + // Default: collapse in narrower / split-screen-ish layouts. + return window.matchMedia("(max-width: 1400px)").matches; + } + + function ensureButton() { + if (document.getElementById(BUTTON_ID)) return; + + const btn = document.createElement("button"); + btn.id = BUTTON_ID; + btn.type = "button"; + btn.setAttribute("aria-label", "Toggle navigation"); + btn.setAttribute("aria-pressed", "false"); + btn.textContent = "☰"; + + btn.addEventListener("click", () => setCollapsed(!isCollapsed())); + + // Append to body so it always exists even when the sidebar is collapsed. + document.body.appendChild(btn); + } + + function init() { + ensureButton(); + setCollapsed(initialCollapsed()); + } + + if (document.readyState === "loading") { + document.addEventListener("DOMContentLoaded", init); + } else { + init(); + } +})(); diff --git a/api-docs/source/conf.py b/api-docs/source/conf.py index 06eab1250f..742a39d6f9 100644 --- a/api-docs/source/conf.py +++ b/api-docs/source/conf.py @@ -90,6 +90,8 @@ def fnlist(module): def setup(app): app.add_css_file('css/other.css') + app.add_css_file('css/sidebar_toggle.css') + app.add_js_file('js/sidebar_toggle.js') app.is_parallel_allowed('write') def generaterst():