diff --git a/doc/doc-support/package.nix b/doc/doc-support/package.nix index 466beb204425..f2c37df39132 100644 --- a/doc/doc-support/package.nix +++ b/doc/doc-support/package.nix @@ -73,6 +73,7 @@ stdenvNoCC.mkDerivation ( ../anchor.min.js ../manpage-urls.json ../redirects.json + ../nav.json ] ); }; @@ -117,6 +118,7 @@ stdenvNoCC.mkDerivation ( --script ./anchor.min.js \ --script ./anchor-use.js \ --sidebar-depth 3 \ + --nav ./nav.json \ manual.md \ out/index.html diff --git a/doc/nav.json b/doc/nav.json new file mode 100644 index 000000000000..15d4926421cf --- /dev/null +++ b/doc/nav.json @@ -0,0 +1,3 @@ +{ + "open": [] +} diff --git a/doc/style.css b/doc/style.css index 90517caf4948..ac052c81511c 100644 --- a/doc/style.css +++ b/doc/style.css @@ -131,6 +131,32 @@ body { padding-left: 1rem; padding-right: 1rem; } + + /* + See: https://developer.mozilla.org/en-US/docs/Web/API/Popover_API + + - :popover-open pseudo-class matches a popover element when it is in the showing state + - ::backdrop full-screen element placed directly behind popover + */ + nav.toc-sidebar:popover-open { + position: fixed; + inset: 0 auto 0 0; + width: min(20rem, 85vw); + height: 100dvh; + max-height: none; + margin: 0; + padding: 1rem; + overflow-y: auto; + overscroll-behavior: contain; + background: var(--background); + border: 0; + border-right: 0.0625rem solid #d8d8d8; + box-shadow: 0 0 1.5rem rgb(0 0 0 / 0.35); + } + + nav.toc-sidebar::backdrop { + background: rgb(0 0 0 / 0.5); + } } a { @@ -486,9 +512,25 @@ div.appendix .variablelist .term { nav.toc-sidebar { height: 100%; - overflow-y: none; padding: 0 1rem 2rem; - border-bottom: 0.0625rem solid #d8d8d8; +} + +/* menu button, shown on mobile, hidden on desktop */ +.toc-toggle { + display: inline-flex; + align-items: center; + margin: 0.75rem 0 0; + padding: 0.4rem 0.8rem; + border: 0.0625rem solid #d8d8d8; + border-radius: 0.25rem; + background: var(--background); + color: var(--main-text-color); + font: inherit; + cursor: pointer; + position: fixed; + top: 0.5rem; + left: 0.8rem; + z-index: 2; } nav.toc-sidebar .toc { @@ -533,14 +575,25 @@ nav.toc-sidebar summary { } nav.toc-sidebar { + /* un-pop the drawer */ + display: block; + position: static; + inset: auto; + /* */ + margin: 0; grid-column: 1; grid-row: 2; max-height: none; overflow-y: auto; - border-bottom: none; + border: none; border-right: 0.0625rem solid #d8d8d8; } + /* Hide the toggle button on desktop */ + .toc-toggle { + display: none; + } + main.content { grid-column: 1 / -1; grid-row: 2; diff --git a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py index 902b365d8b5f..11d247320d68 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py @@ -264,6 +264,7 @@ class HTMLParameters(NamedTuple): # structural depth of the navigation sidebar tree sidebar_depth: int media_dir: Path + sidebar_open: frozenset[str] = frozenset() class ManualHTMLRenderer(RendererMixin, HTMLRenderer): _base_path: Path @@ -367,6 +368,20 @@ class ManualHTMLRenderer(RendererMixin, HTMLRenderer): file.write(self._redirects.get_redirect_script(toc.target.path)) scripts.append(f'./{redirects_name}') + # Register a close handler + # Without this the popover can still be closed by clicking outside of it + # It handles auto-closing when the user clicks a href. + close_menu_js = """ + document.addEventListener("DOMContentLoaded", () => { + const nav = document.getElementById("manual-toc"); + nav?.addEventListener("click", (e) => { + if (e.target.closest("a[href]") && nav.matches(":popover-open")) { + nav.hidePopover(); + } + }); + }); + """ + return "\n".join([ '', '' for script in scripts)), + f"", f' ', f' ' if home.target.href() else "", f' {up_link}{prev_link}{next_link}', ' ', '
', + # See: https://developer.mozilla.org/en-US/docs/Web/API/Popover_API + # Supported by most browsers since 2023, full support since Jan 2025 + (' ') if sidebar else "", nav_html, - f' ' if sidebar else "", + f' ' if sidebar else "", '