diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index dfad1ab10dbe0..dbd78ea0dc97c 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -2013,6 +2013,7 @@ fn init_id_map() -> FxHashMap, usize> {
map.insert("themeStyle".into(), 1);
map.insert("settings-menu".into(), 1);
map.insert("help-button".into(), 1);
+ map.insert("sidebar-button".into(), 1);
map.insert("main-content".into(), 1);
map.insert("toggle-all-docs".into(), 1);
map.insert("all-types".into(), 1);
diff --git a/src/librustdoc/html/static/css/noscript.css b/src/librustdoc/html/static/css/noscript.css
index fe0cf6dc8cc75..390e812772a70 100644
--- a/src/librustdoc/html/static/css/noscript.css
+++ b/src/librustdoc/html/static/css/noscript.css
@@ -9,7 +9,7 @@ rules.
margin-left: 0 !important;
}
-#copy-path {
+#copy-path, #sidebar-button, .sidebar-resizer {
/* It requires JS to work so no need to display it in this case. */
display: none;
}
@@ -132,6 +132,8 @@ nav.sub {
--scrape-example-help-hover-color: #000;
--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+ --sidebar-resizer-hover: hsl(207, 90%, 66%);
+ --sidebar-resizer-active: hsl(207, 90%, 54%);
}
/* End theme: light */
@@ -238,6 +240,8 @@ nav.sub {
--scrape-example-help-hover-color: #fff;
--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+ --sidebar-resizer-hover: hsl(207, 30%, 54%);
+ --sidebar-resizer-active: hsl(207, 90%, 54%);
}
/* End theme: dark */
}
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 6e61969a8c190..6e673aa77c5c8 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -9,6 +9,11 @@
:root {
--nav-sub-mobile-padding: 8px;
--search-typename-width: 6.75rem;
+ /* DEFAULT_SIDEBAR_WIDTH
+ see main.js for information on these values
+ and on the RUSTDOC_MOBILE_BREAKPOINT */
+ --desktop-sidebar-width: 200px;
+ --src-sidebar-width: 300px;
}
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -383,13 +388,15 @@ img {
.sidebar {
font-size: 0.875rem;
- flex: 0 0 200px;
+ flex: 0 0 var(--desktop-sidebar-width);
+ width: var(--desktop-sidebar-width);
overflow-y: scroll;
overscroll-behavior: contain;
position: sticky;
height: 100vh;
top: 0;
left: 0;
+ z-index: 100;
}
.rustdoc.src .sidebar {
@@ -398,7 +405,95 @@ img {
overflow-x: hidden;
/* The sidebar is by default hidden */
overflow-y: hidden;
- z-index: 1;
+}
+
+.hide-sidebar .sidebar,
+.hide-sidebar .sidebar-resizer {
+ display: none;
+}
+
+.sidebar-resizer {
+ touch-action: none;
+ width: 9px;
+ cursor: col-resize;
+ z-index: 200;
+ position: fixed;
+ height: 100%;
+ /* make sure there's a 1px gap between the scrollbar and resize handle */
+ left: calc(var(--desktop-sidebar-width) + 1px);
+}
+
+.rustdoc.src .sidebar-resizer {
+ /* when closed, place resizer glow on top of the normal src sidebar border (no need to worry
+ about sidebar) */
+ left: 49px;
+}
+
+.src-sidebar-expanded .rustdoc.src .sidebar-resizer {
+ /* for src sidebar, gap is already provided by 1px border on sidebar itself, so place resizer
+ to right of it */
+ left: var(--src-sidebar-width);
+}
+
+.sidebar-resizing {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.sidebar-resizing * {
+ cursor: col-resize !important;
+}
+
+.sidebar-resizing .sidebar {
+ position: fixed;
+ z-index: 100;
+}
+.sidebar-resizing > body {
+ padding-left: var(--resizing-sidebar-width);
+}
+
+.sidebar-resizer:hover,
+.sidebar-resizer:active,
+.sidebar-resizer:focus,
+.sidebar-resizer.active {
+ width: 10px;
+ margin: 0;
+ /* when active or hovered, place resizer glow on top of the sidebar (right next to, or even
+ on top of, the scrollbar) */
+ left: var(--desktop-sidebar-width);
+ border-left: solid 1px var(--sidebar-resizer-hover);
+}
+
+.src-sidebar-expanded .rustdoc.src .sidebar-resizer:hover,
+.src-sidebar-expanded .rustdoc.src .sidebar-resizer:active,
+.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,
+.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active {
+ /* when active or hovered, place resizer glow on top of the normal src sidebar border */
+ left: calc(var(--src-sidebar-width) - 1px);
+}
+
+@media (pointer: coarse) {
+ .sidebar-resizer {
+ /* too easy to hit the resizer while trying to hit the [-] toggle */
+ display: none !important;
+ }
+}
+
+.sidebar-resizer.active {
+ /* make the resize tool bigger when actually resizing, to avoid :hover styles on other stuff
+ while resizing */
+ padding: 0 140px;
+ width: 2px;
+ margin-left: -140px;
+ border-left: none;
+}
+.sidebar-resizer.active:before {
+ border-left: solid 2px var(--sidebar-resizer-active);
+ display: block;
+ height: 100%;
+ content: "";
}
.sidebar, .mobile-topbar, .sidebar-menu-toggle,
@@ -416,7 +511,8 @@ img {
.src-sidebar-expanded .src .sidebar {
overflow-y: auto;
- flex-basis: 300px;
+ flex-basis: var(--src-sidebar-width);
+ width: var(--src-sidebar-width);
}
.src-sidebar-expanded .src .sidebar > *:not(#src-sidebar-toggle) {
@@ -477,6 +573,7 @@ ul.block, .block li {
display: block;
padding: 0.25rem; /* 4px */
margin-left: -0.25rem;
+ margin-right: 0.25rem;
}
.sidebar h2 {
@@ -775,7 +872,7 @@ h2.section-header > .anchor {
text-decoration: underline;
}
-.crate.block a.current { font-weight: 500; }
+.crate.block li.current a { font-weight: 500; }
/* In most contexts we use `overflow-wrap: anywhere` to ensure that we can wrap
as much as needed on mobile (see
@@ -1478,7 +1575,20 @@ a.tooltip:hover::after {
margin-left: 4px;
display: flex;
}
-#settings-menu > a, #help-button > a {
+#sidebar-button {
+ display: none;
+}
+.hide-sidebar #sidebar-button {
+ display: flex;
+ margin-right: 4px;
+ position: fixed;
+ left: 6px;
+ height: 34px;
+ width: 34px;
+ background-color: var(--main-background-color);
+ z-index: 1;
+}
+#settings-menu > a, #help-button > a, #sidebar-button > a {
display: flex;
align-items: center;
justify-content: center;
@@ -1493,10 +1603,21 @@ a.tooltip:hover::after {
}
#settings-menu > a:hover, #settings-menu > a:focus,
-#help-button > a:hover, #help-button > a:focus {
+#help-button > a:hover, #help-button > a:focus,
+#sidebar-button > a:hover, #sidebar-button > a:focus {
border-color: var(--settings-button-border-focus);
}
+#sidebar-button > a:before {
+ content: url('data:image/svg+xml,');
+ width: 22px;
+ height: 22px;
+}
+
#copy-path {
color: var(--copy-path-button-color);
background: var(--main-background-color);
@@ -1711,7 +1832,7 @@ However, it's not needed with smaller screen width because the doc/code block is
/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
If you update this line, then you also need to update the line with the same warning
-in src-script.js
+in src-script.js and main.js
*/
@media (max-width: 700px) {
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
@@ -1722,6 +1843,10 @@ in src-script.js
scroll-margin-top: 45px;
}
+ .hide-sidebar #sidebar-button {
+ position: static;
+ }
+
.rustdoc {
/* Sidebar should overlay main content, rather than pushing main content to the right.
Turn off `display: flex` on the body element. */
@@ -1750,7 +1875,8 @@ in src-script.js
/* Hide the logo and item name from the sidebar. Those are displayed
in the mobile-topbar instead. */
.sidebar .logo-container,
- .sidebar .location {
+ .sidebar .location,
+ .sidebar-resizer {
display: none;
}
@@ -1818,6 +1944,10 @@ in src-script.js
top: 0;
}
+ .hide-sidebar .mobile-topbar {
+ display: none;
+ }
+
.sidebar-menu-toggle {
width: 45px;
/* Rare exception to specifying font sizes in rem. Since this is acting
@@ -1827,6 +1957,10 @@ in src-script.js
color: var(--main-color);
}
+ .hide-sidebar .sidebar-menu-toggle {
+ display: none;
+ }
+
.sidebar-elems {
margin-top: 1em;
}
@@ -1870,6 +2004,17 @@ in src-script.js
display: none;
}
+ /* sidebar button becomes topbar button */
+ #sidebar-button > a:before {
+ content: url('data:image/svg+xml,');
+ width: 22px;
+ height: 22px;
+ }
+
/* Display an alternating layout on tablets and phones */
.item-table, .item-row, .item-table > li, .item-table > li > div,
.search-results > a, .search-results > a > div {
@@ -2274,6 +2419,8 @@ in src-script.js
--scrape-example-help-hover-color: #000;
--scrape-example-code-wrapper-background-start: rgba(255, 255, 255, 1);
--scrape-example-code-wrapper-background-end: rgba(255, 255, 255, 0);
+ --sidebar-resizer-hover: hsl(207, 90%, 66%);
+ --sidebar-resizer-active: hsl(207, 90%, 54%);
}
/* End theme: light */
@@ -2379,6 +2526,8 @@ in src-script.js
--scrape-example-help-hover-color: #fff;
--scrape-example-code-wrapper-background-start: rgba(53, 53, 53, 1);
--scrape-example-code-wrapper-background-end: rgba(53, 53, 53, 0);
+ --sidebar-resizer-hover: hsl(207, 30%, 54%);
+ --sidebar-resizer-active: hsl(207, 90%, 54%);
}
/* End theme: dark */
@@ -2488,6 +2637,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
--scrape-example-help-hover-color: #fff;
--scrape-example-code-wrapper-background-start: rgba(15, 20, 25, 1);
--scrape-example-code-wrapper-background-end: rgba(15, 20, 25, 0);
+ --sidebar-resizer-hover: hsl(34, 50%, 33%);
+ --sidebar-resizer-active: hsl(34, 100%, 66%);
}
:root[data-theme="ayu"] h1,
@@ -2519,6 +2670,7 @@ Original by Dempfi (https://github.com/dempfi/ayu)
}
:root[data-theme="ayu"] .sidebar .current,
+:root[data-theme="ayu"] .sidebar .current a,
:root[data-theme="ayu"] .sidebar a:hover,
:root[data-theme="ayu"] #src-sidebar div.files > a:hover,
:root[data-theme="ayu"] details.dir-entry summary:hover,
@@ -2569,7 +2721,8 @@ Original by Dempfi (https://github.com/dempfi/ayu)
border-bottom: 1px solid rgba(242, 151, 24, 0.3);
}
-:root[data-theme="ayu"] #settings-menu > a img {
+:root[data-theme="ayu"] #settings-menu > a img,
+:root[data-theme="ayu"] #sidebar-button > a:before {
filter: invert(100);
}
/* End theme: ayu */
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index d613997cd7ff5..63ab56053af9f 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1,5 +1,5 @@
// Local js definitions:
-/* global addClass, getSettingValue, hasClass, searchState */
+/* global addClass, getSettingValue, hasClass, searchState, updateLocalStorage */
/* global onEach, onEachLazy, removeClass, getVar */
"use strict";
@@ -495,7 +495,7 @@ function preLoadCss(cssUrl) {
}
const link = document.createElement("a");
link.href = path;
- if (link.href === current_page) {
+ if (path === current_page) {
link.className = "current";
}
link.textContent = name;
@@ -857,12 +857,12 @@ function preLoadCss(cssUrl) {
for (const crate of window.ALL_CRATES) {
const link = document.createElement("a");
link.href = window.rootPath + crate + "/index.html";
- if (window.rootPath !== "./" && crate === window.currentCrate) {
- link.className = "current";
- }
link.textContent = crate;
const li = document.createElement("li");
+ if (window.rootPath !== "./" && crate === window.currentCrate) {
+ li.className = "current";
+ }
li.appendChild(link);
ul.appendChild(li);
}
@@ -1473,6 +1473,264 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
searchState.setup();
}());
+// Hide, show, and resize the sidebar
+//
+// The body class and CSS variable are initially set up in storage.js,
+// but in this file, we implement:
+//
+// * the show sidebar button, which appears if the sidebar is hidden
+// and, by clicking on it, will bring it back
+// * the sidebar resize handle, which appears only on large viewports
+// with a [fine precision pointer] to allow the user to change
+// the size of the sidebar
+//
+// [fine precision pointer]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer
+(function() {
+ // 100 is the size of the logo
+ // don't let the sidebar get smaller than that, or it'll get squished
+ const SIDEBAR_MIN = 100;
+ // Don't let the sidebar get bigger than this
+ const SIDEBAR_MAX = 500;
+ // Don't let the body (including the gutter) get smaller than this
+ //
+ // WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
+ // Acceptable values for BODY_MIN are constrained by the mobile breakpoint
+ // (which is the minimum size of the whole page where the sidebar exists)
+ // and the default sidebar width:
+ //
+ // BODY_MIN <= RUSTDOC_MOBILE_BREAKPOINT - DEFAULT_SIDEBAR_WIDTH
+ //
+ // At the time of this writing, the DEFAULT_SIDEBAR_WIDTH on src pages is
+ // 300px, and the RUSTDOC_MOBILE_BREAKPOINT is 700px, so BODY_MIN must be
+ // at most 400px. Otherwise, it would start out at the default size, then
+ // grabbing the resize handle would suddenly cause it to jank to
+ // its contraint-generated maximum.
+ const RUSTDOC_MOBILE_BREAKPOINT = 700;
+ const BODY_MIN = 400;
+ // At half-way past the minimum size, vanish the sidebar entirely
+ const SIDEBAR_VANISH_THRESHOLD = SIDEBAR_MIN / 2;
+
+ // Toolbar button to show the sidebar.
+ //
+ // On small, "mobile-sized" viewports, it's not persistent and it
+ // can only be activated by going into Settings and hiding the nav bar.
+ // On larger, "desktop-sized" viewports (though that includes many
+ // tablets), it's fixed-position, appears in the left side margin,
+ // and it can be activated by resizing the sidebar into nothing.
+ const sidebarButton = document.getElementById("sidebar-button");
+ if (sidebarButton) {
+ sidebarButton.addEventListener("click", e => {
+ removeClass(document.documentElement, "hide-sidebar");
+ updateLocalStorage("hide-sidebar", "false");
+ e.preventDefault();
+ });
+ }
+
+ // Pointer capture.
+ //
+ // Resizing is a single-pointer gesture. Any secondary pointer is ignored
+ let currentPointerId = null;
+
+ // "Desired" sidebar size.
+ //
+ // This is stashed here for window resizing. If the sidebar gets
+ // shrunk to maintain BODY_MIN, and then the user grows the window again,
+ // it gets the sidebar to restore its size.
+ let desiredSidebarSize = null;
+
+ // Sidebar resize debouncer.
+ //
+ // The sidebar itself is resized instantly, but the body HTML can be too
+ // big for that, causing reflow jank. To reduce this, we queue up a separate
+ // animation frame and throttle it.
+ let pendingSidebarResizingFrame = false;
+
+ // If this page has no sidebar at all, bail out.
+ const resizer = document.querySelector(".sidebar-resizer");
+ const sidebar = document.querySelector(".sidebar");
+ if (!resizer || !sidebar) {
+ return;
+ }
+
+ // src page and docs page use different variables, because the contents of
+ // the sidebar are so different that it's reasonable to thing the user
+ // would want them to have different sizes
+ const isSrcPage = hasClass(document.body, "src");
+
+ // Call this function to hide the sidebar when using the resize handle
+ //
+ // This function also nulls out the sidebar width CSS variable and setting,
+ // causing it to return to its default. This does not happen if you do it
+ // from settings.js, which uses a separate function. It's done here because
+ // the minimum sidebar size is rather uncomfortable, and it must pass
+ // through that size when using the shrink-to-nothing gesture.
+ function hideSidebar() {
+ if (isSrcPage) {
+ window.rustdocCloseSourceSidebar();
+ updateLocalStorage("src-sidebar-width", null);
+ // [RUSTDOCIMPL] CSS variable fast path
+ //
+ // The sidebar width variable is attached to the element by
+ // storage.js, because the sidebar and resizer don't exist yet.
+ // But the resize code, in `resize()`, sets the property on the
+ // sidebar and resizer elements (which are the only elements that
+ // use the variable) to avoid recalculating CSS on the entire
+ // document on every frame.
+ //
+ // So, to clear it, we need to clear all three.
+ document.documentElement.style.removeProperty("--src-sidebar-width");
+ sidebar.style.removeProperty("--src-sidebar-width");
+ resizer.style.removeProperty("--src-sidebar-width");
+ } else {
+ addClass(document.documentElement, "hide-sidebar");
+ updateLocalStorage("hide-sidebar", "true");
+ updateLocalStorage("desktop-sidebar-width", null);
+ document.documentElement.style.removeProperty("--desktop-sidebar-width");
+ sidebar.style.removeProperty("--desktop-sidebar-width");
+ resizer.style.removeProperty("--desktop-sidebar-width");
+ }
+ }
+
+ // Call this function to show the sidebar from the resize handle.
+ // On docs pages, this can only happen if the user has grabbed the resize
+ // handle, shrunk the sidebar down to nothing, and then pulls back into
+ // the visible range without releasing it. You can, however, grab the
+ // resize handle on a source page with the sidebar closed, because it
+ // remains visible all the time on there.
+ function showSidebar() {
+ if (isSrcPage) {
+ window.rustdocShowSourceSidebar();
+ } else {
+ removeClass(document.documentElement, "hide-sidebar");
+ updateLocalStorage("hide-sidebar", "false");
+ }
+ }
+
+ /**
+ * Call this to set the correct CSS variable and setting.
+ * This function doesn't enforce size constraints. Do that before calling it!
+ *
+ * @param {number} size - CSS px width of the sidebar.
+ */
+ function changeSidebarSize(size) {
+ if (isSrcPage) {
+ updateLocalStorage("src-sidebar-width", size);
+ // [RUSTDOCIMPL] CSS variable fast path
+ //
+ // While this property is set on the HTML element at load time,
+ // because the sidebar isn't actually loaded yet,
+ // we scope this update to the sidebar to avoid hitting a slow
+ // path in WebKit.
+ sidebar.style.setProperty("--src-sidebar-width", size + "px");
+ resizer.style.setProperty("--src-sidebar-width", size + "px");
+ } else {
+ updateLocalStorage("desktop-sidebar-width", size);
+ sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
+ resizer.style.setProperty("--desktop-sidebar-width", size + "px");
+ }
+ }
+
+ // Check if the sidebar is hidden. Since src pages and doc pages have
+ // different settings, this function has to check that.
+ function isSidebarHidden() {
+ return isSrcPage ?
+ !hasClass(document.documentElement, "src-sidebar-expanded") :
+ hasClass(document.documentElement, "hide-sidebar");
+ }
+
+ // Respond to the resize handle event.
+ // This function enforces size constraints, and implements the
+ // shrink-to-nothing gesture based on thresholds defined above.
+ function resize(e) {
+ if (currentPointerId === null || currentPointerId !== e.pointerId) {
+ return;
+ }
+ e.preventDefault();
+ const pos = e.clientX - sidebar.offsetLeft - 3;
+ if (pos < SIDEBAR_VANISH_THRESHOLD) {
+ hideSidebar();
+ } else if (pos >= SIDEBAR_MIN) {
+ if (isSidebarHidden()) {
+ showSidebar();
+ }
+ // don't let the sidebar get wider than SIDEBAR_MAX, or the body narrower
+ // than BODY_MIN
+ const constrainedPos = Math.min(pos, window.innerWidth - BODY_MIN, SIDEBAR_MAX);
+ changeSidebarSize(constrainedPos);
+ desiredSidebarSize = constrainedPos;
+ if (pendingSidebarResizingFrame !== false) {
+ clearTimeout(pendingSidebarResizingFrame);
+ }
+ pendingSidebarResizingFrame = setTimeout(() => {
+ if (currentPointerId === null || pendingSidebarResizingFrame === false) {
+ return;
+ }
+ pendingSidebarResizingFrame = false;
+ document.documentElement.style.setProperty(
+ "--resizing-sidebar-width",
+ desiredSidebarSize + "px"
+ );
+ }, 100);
+ }
+ }
+ // Respond to the window resize event.
+ window.addEventListener("resize", () => {
+ if (window.innerWidth < RUSTDOC_MOBILE_BREAKPOINT) {
+ return;
+ }
+ stopResize();
+ if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
+ changeSidebarSize(window.innerWidth - BODY_MIN);
+ } else if (desiredSidebarSize !== null && desiredSidebarSize > SIDEBAR_MIN) {
+ changeSidebarSize(desiredSidebarSize);
+ }
+ });
+ function stopResize(e) {
+ if (currentPointerId === null) {
+ return;
+ }
+ if (e) {
+ e.preventDefault();
+ }
+ desiredSidebarSize = sidebar.getBoundingClientRect().width;
+ removeClass(resizer, "active");
+ window.removeEventListener("pointermove", resize, false);
+ window.removeEventListener("pointerup", stopResize, false);
+ removeClass(document.documentElement, "sidebar-resizing");
+ document.documentElement.style.removeProperty( "--resizing-sidebar-width");
+ if (resizer.releasePointerCapture) {
+ resizer.releasePointerCapture(currentPointerId);
+ currentPointerId = null;
+ }
+ }
+ function initResize(e) {
+ if (currentPointerId !== null || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
+ return;
+ }
+ if (resizer.setPointerCapture) {
+ resizer.setPointerCapture(e.pointerId);
+ if (!resizer.hasPointerCapture(e.pointerId)) {
+ // unable to capture pointer; something else has it
+ // on iOS, this usually means you long-clicked a link instead
+ resizer.releasePointerCapture(e.pointerId);
+ return;
+ }
+ currentPointerId = e.pointerId;
+ }
+ e.preventDefault();
+ window.addEventListener("pointermove", resize, false);
+ window.addEventListener("pointercancel", stopResize, false);
+ window.addEventListener("pointerup", stopResize, false);
+ addClass(resizer, "active");
+ addClass(document.documentElement, "sidebar-resizing");
+ const pos = e.clientX - sidebar.offsetLeft - 3;
+ document.documentElement.style.setProperty( "--resizing-sidebar-width", pos + "px");
+ desiredSidebarSize = null;
+ }
+ resizer.addEventListener("pointerdown", initResize, false);
+}());
+
+// This section handles the copy button that appears next to the path breadcrumbs
(function() {
let reset_button_timeout = null;
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 70a2825265ec1..2b42fbebb803d 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -29,6 +29,13 @@
window.rustdoc_remove_line_numbers_from_examples();
}
break;
+ case "hide-sidebar":
+ if (value === true) {
+ addClass(document.documentElement, "hide-sidebar");
+ } else {
+ removeClass(document.documentElement, "hide-sidebar");
+ }
+ break;
}
}
@@ -186,6 +193,11 @@
"js_name": "line-numbers",
"default": false,
},
+ {
+ "name": "Hide persistent navigation bar",
+ "js_name": "hide-sidebar",
+ "default": false,
+ },
{
"name": "Disable keyboard shortcuts",
"js_name": "disable-shortcuts",
@@ -216,6 +228,13 @@
function displaySettings() {
settingsMenu.style.display = "";
+ onEachLazy(settingsMenu.querySelectorAll("input[type='checkbox']"), el => {
+ const val = getSettingValue(el.id);
+ const checked = val === "true";
+ if (checked !== el.checked && val !== null) {
+ el.checked = checked;
+ }
+ });
}
function settingsBlurHandler(event) {
diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js
index 27b5cf1e2aef3..bbb0527a8331c 100644
--- a/src/librustdoc/html/static/js/src-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -71,16 +71,31 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
return hasFoundFile;
}
+let toggleLabel;
+
+function getToggleLabel() {
+ toggleLabel = toggleLabel || document.querySelector("#src-sidebar-toggle button");
+ return toggleLabel;
+}
+
+window.rustdocCloseSourceSidebar = () => {
+ removeClass(document.documentElement, "src-sidebar-expanded");
+ getToggleLabel().innerText = ">";
+ updateLocalStorage("source-sidebar-show", "false");
+};
+
+window.rustdocShowSourceSidebar = () => {
+ addClass(document.documentElement, "src-sidebar-expanded");
+ getToggleLabel().innerText = "<";
+ updateLocalStorage("source-sidebar-show", "true");
+};
+
function toggleSidebar() {
const child = this.parentNode.children[0];
if (child.innerText === ">") {
- addClass(document.documentElement, "src-sidebar-expanded");
- child.innerText = "<";
- updateLocalStorage("source-sidebar-show", "true");
+ window.rustdocShowSourceSidebar();
} else {
- removeClass(document.documentElement, "src-sidebar-expanded");
- child.innerText = ">";
- updateLocalStorage("source-sidebar-show", "false");
+ window.rustdocCloseSourceSidebar();
}
}
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index 37250ba5a1fda..ac9c6f377b82a 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -183,11 +183,38 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
updateTheme();
+// Hide, show, and resize the sidebar at page load time
+//
+// This needs to be done here because this JS is render-blocking,
+// so that the sidebar doesn't "jump" after appearing on screen.
+// The user interaction to change this is set up in main.js.
if (getSettingValue("source-sidebar-show") === "true") {
// At this point in page load, `document.body` is not available yet.
// Set a class on the `` element instead.
addClass(document.documentElement, "src-sidebar-expanded");
}
+if (getSettingValue("hide-sidebar") === "true") {
+ // At this point in page load, `document.body` is not available yet.
+ // Set a class on the `` element instead.
+ addClass(document.documentElement, "hide-sidebar");
+}
+function updateSidebarWidth() {
+ const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
+ if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
+ document.documentElement.style.setProperty(
+ "--desktop-sidebar-width",
+ desktopSidebarWidth + "px"
+ );
+ }
+ const srcSidebarWidth = getSettingValue("src-sidebar-width");
+ if (srcSidebarWidth && srcSidebarWidth !== "null") {
+ document.documentElement.style.setProperty(
+ "--src-sidebar-width",
+ srcSidebarWidth + "px"
+ );
+ }
+}
+updateSidebarWidth();
// If we navigate away (for example to a settings page), and then use the back or
// forward button to get back to a page, the theme may have changed in the meantime.
@@ -201,5 +228,6 @@ if (getSettingValue("source-sidebar-show") === "true") {
window.addEventListener("pageshow", ev => {
if (ev.persisted) {
setTimeout(updateTheme, 0);
+ setTimeout(updateSidebarWidth, 0);
}
});
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index 3f6147bb916fd..60ca5660c0205 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -114,6 +114,7 @@