Skip to content

Commit 273a302

Browse files
committed
rustdoc: enforce BODY_MIN constraint on sidebar resize
1 parent 210c88f commit 273a302

File tree

4 files changed

+155
-17
lines changed

4 files changed

+155
-17
lines changed

src/librustdoc/html/static/css/rustdoc.css

+12-7
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99
:root {
1010
--nav-sub-mobile-padding: 8px;
1111
--search-typename-width: 6.75rem;
12+
/* DEFAULT_SIDEBAR_WIDTH
13+
see main.js for information on these values
14+
and on the RUSTDOC_MOBILE_BREAKPOINT */
15+
--desktop-sidebar-width: 200px;
16+
--src-sidebar-width: 300px;
1217
}
1318

1419
/* See FiraSans-LICENSE.txt for the Fira Sans license. */
@@ -383,7 +388,7 @@ img {
383388

384389
.sidebar {
385390
font-size: 0.875rem;
386-
flex: 0 0 var(--desktop-sidebar-width, 200px);
391+
flex: 0 0 var(--desktop-sidebar-width);
387392
overflow-y: scroll;
388393
overscroll-behavior: contain;
389394
position: sticky;
@@ -414,7 +419,7 @@ img {
414419
position: absolute;
415420
height: 100%;
416421
/* make sure there's a 1px gap between the scrollbar and resize handle */
417-
left: calc(var(--desktop-sidebar-width, 200px) + 1px);
422+
left: calc(var(--desktop-sidebar-width) + 1px);
418423
}
419424

420425
.rustdoc.src .sidebar-resizer {
@@ -426,7 +431,7 @@ img {
426431
.src-sidebar-expanded .rustdoc.src .sidebar-resizer {
427432
/* for src sidebar, gap is already provided by 1px border on sidebar itself, so place resizer
428433
to right of it */
429-
left: var(--src-sidebar-width, 300px);
434+
left: var(--src-sidebar-width);
430435
}
431436

432437
.sidebar-resizing {
@@ -448,7 +453,7 @@ img {
448453
margin: 0;
449454
/* when active or hovered, place resizer glow on top of the sidebar (right next to, or even
450455
on top of, the scrollbar) */
451-
left: var(--desktop-sidebar-width, 200px);
456+
left: var(--desktop-sidebar-width);
452457
border-left: solid 1px var(--sidebar-resizer-hover);
453458
}
454459

@@ -457,7 +462,7 @@ img {
457462
.src-sidebar-expanded .rustdoc.src .sidebar-resizer:focus,
458463
.src-sidebar-expanded .rustdoc.src .sidebar-resizer.active {
459464
/* when active or hovered, place resizer glow on top of the normal src sidebar border */
460-
left: calc(var(--src-sidebar-width, 300px) - 1px);
465+
left: calc(var(--src-sidebar-width) - 1px);
461466
}
462467

463468
@media (pointer: coarse) {
@@ -497,7 +502,7 @@ img {
497502

498503
.src-sidebar-expanded .src .sidebar {
499504
overflow-y: auto;
500-
flex-basis: var(--src-sidebar-width, 300px);
505+
flex-basis: var(--src-sidebar-width);
501506
}
502507

503508
.src-sidebar-expanded .src .sidebar > *:not(#src-sidebar-toggle) {
@@ -1806,7 +1811,7 @@ However, it's not needed with smaller screen width because the doc/code block is
18061811
/*
18071812
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
18081813
If you update this line, then you also need to update the line with the same warning
1809-
in src-script.js
1814+
in src-script.js and main.js
18101815
*/
18111816
@media (max-width: 700px) {
18121817
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,

src/librustdoc/html/static/js/main.js

+105-8
Original file line numberDiff line numberDiff line change
@@ -1273,8 +1273,49 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
12731273
searchState.setup();
12741274
}());
12751275

1276-
// This section handles sidebar resizing
1276+
// Hide, show, and resize the sidebar
1277+
//
1278+
// The body class and CSS variable are initially set up in storage.js,
1279+
// but in this file, we implement:
1280+
//
1281+
// * the show sidebar button, which appears if the sidebar is hidden
1282+
// and, by clicking on it, will bring it back
1283+
// * the sidebar resize handle, which appears only on large viewports
1284+
// with a [fine precision pointer] to allow the user to change
1285+
// the size of the sidebar
1286+
//
1287+
// [fine precision pointer]: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer
12771288
(function() {
1289+
// 100 is the size of the logo
1290+
// don't let the sidebar get smaller than that, or it'll get squished
1291+
const SIDEBAR_MIN = 100;
1292+
// Don't let the sidebar get bigger than this
1293+
const SIDEBAR_MAX = 500;
1294+
// Don't let the body (including the gutter) get smaller than this
1295+
//
1296+
// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
1297+
// Acceptable values for BODY_MIN are constrained by the mobile breakpoint
1298+
// (which is the minimum size of the whole page where the sidebar exists)
1299+
// and the default sidebar width:
1300+
//
1301+
// BODY_MIN <= RUSTDOC_MOBILE_BREAKPOINT - DEFAULT_SIDEBAR_WIDTH
1302+
//
1303+
// At the time of this writing, the DEFAULT_SIDEBAR_WIDTH on src pages is
1304+
// 300px, and the RUSTDOC_MOBILE_BREAKPOINT is 700px, so BODY_MIN must be
1305+
// at most 400px. Otherwise, it would start out at the default size, then
1306+
// grabbing the resize handle would suddenly cause it to jank to
1307+
// its contraint-generated maximum.
1308+
const BODY_MIN = 400;
1309+
// At half-way past the minimum size, vanish the sidebar entirely
1310+
const SIDEBAR_VANISH_THRESHOLD = SIDEBAR_MIN / 2;
1311+
1312+
// Toolbar button to show the sidebar.
1313+
//
1314+
// On small, "mobile-sized" viewports, it's not persistent and it
1315+
// can only be activated by going into Settings and hiding the nav bar.
1316+
// On larger, "desktop-sized" viewports (though that includes many
1317+
// tablets), it's fixed-position, appears in the left side margin,
1318+
// and it can be activated by resizing the sidebar into nothing.
12781319
const sidebarButton = document.getElementById("sidebar-button");
12791320
if (sidebarButton) {
12801321
sidebarButton.addEventListener("click", e => {
@@ -1283,13 +1324,38 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
12831324
e.preventDefault();
12841325
});
12851326
}
1327+
1328+
// Pointer capture.
1329+
//
1330+
// Resizing is a single-pointer gesture. Any secondary pointer is ignored
12861331
let currentPointerId = null;
1332+
1333+
// "Desired" sidebar size.
1334+
//
1335+
// This is stashed here for window resizing. If the sidebar gets
1336+
// shrunk to maintain BODY_MIN, and then the user grows the window again,
1337+
// it gets the sidebar to restore its size.
1338+
let desiredSidebarSize = null;
1339+
1340+
// If this page has no sidebar at all, bail out.
12871341
const resizer = document.querySelector(".sidebar-resizer");
12881342
const sidebar = document.querySelector(".sidebar");
12891343
if (!resizer || !sidebar) {
12901344
return;
12911345
}
1346+
1347+
// src page and docs page use different variables, because the contents of
1348+
// the sidebar are so different that it's reasonable to thing the user
1349+
// would want them to have different sizes
12921350
const isSrcPage = hasClass(document.body, "src");
1351+
1352+
// Call this function to hide the sidebar when using the resize handle
1353+
//
1354+
// This function also nulls out the sidebar width CSS variable and setting,
1355+
// causing it to return to its default. This does not happen if you do it
1356+
// from settings.js, which uses a separate function. It's done here because
1357+
// the minimum sidebar size is rather uncomfortable, and it must pass
1358+
// through that size when using the shrink-to-nothing gesture.
12931359
function hideSidebar() {
12941360
if (isSrcPage) {
12951361
window.rustdocCloseSourceSidebar();
@@ -1302,6 +1368,13 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13021368
document.documentElement.style.removeProperty("--desktop-sidebar-width");
13031369
}
13041370
}
1371+
1372+
// Call this function to show the sidebar from the resize handle.
1373+
// On docs pages, this can only happen if the user has grabbed the resize
1374+
// handle, shrunk the sidebar down to nothing, and then pulls back into
1375+
// the visible range without releasing it. You can, however, grab the
1376+
// resize handle on a source page with the sidebar closed, because it
1377+
// remains visible all the time on there.
13051378
function showSidebar() {
13061379
if (isSrcPage) {
13071380
window.rustdocShowSourceSidebar();
@@ -1310,6 +1383,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13101383
updateLocalStorage("hide-sidebar", "false");
13111384
}
13121385
}
1386+
1387+
// Call this to set the correct CSS variable and setting.
1388+
// This function doesn't enforce size constraints. Do that before calling it!
13131389
function changeSidebarSize(size) {
13141390
if (isSrcPage) {
13151391
updateLocalStorage("src-sidebar-width", size);
@@ -1319,34 +1395,54 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13191395
document.documentElement.style.setProperty("--desktop-sidebar-width", size + "px");
13201396
}
13211397
}
1398+
1399+
// Check if the sidebar is hidden. Since src pages and doc pages have
1400+
// different settings, this function has to check that.
13221401
function isSidebarHidden() {
13231402
return isSrcPage ?
13241403
!hasClass(document.documentElement, "src-sidebar-expanded") :
13251404
hasClass(document.documentElement, "hide-sidebar");
13261405
}
1406+
1407+
// Respond to the resize handle event.
1408+
// This function enforces size constraints, and implements the
1409+
// shrink-to-nothing gesture based on thresholds defined above.
13271410
function resize(e) {
13281411
if (currentPointerId === null || currentPointerId !== e.pointerId) {
13291412
return;
13301413
}
13311414
e.preventDefault();
13321415
const pos = e.clientX - sidebar.offsetLeft - 3;
1333-
if (pos < 50) {
1416+
if (pos < SIDEBAR_VANISH_THRESHOLD) {
13341417
hideSidebar();
1335-
} else if (pos >= 100) {
1336-
// 100 is the size of the logo
1337-
// don't let the sidebar get smaller than that, or it'll get squished
1418+
} else if (pos >= SIDEBAR_MIN) {
13381419
if (isSidebarHidden()) {
13391420
showSidebar();
13401421
}
1341-
// don't let the sidebar get wider than 500
1342-
changeSidebarSize(Math.min(pos, window.innerWidth - 100, 500));
1422+
// don't let the sidebar get wider than SIDEBAR_MAX, or the body narrower
1423+
// than BODY_MIN
1424+
const constrainedPos = Math.min(pos, window.innerWidth - BODY_MIN, SIDEBAR_MAX);
1425+
changeSidebarSize(constrainedPos);
1426+
desiredSidebarSize = constrainedPos;
13431427
}
13441428
}
1429+
// Respond to the window resize event.
1430+
window.addEventListener("resize", () => {
1431+
stopResize();
1432+
if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
1433+
changeSidebarSize(window.innerWidth - BODY_MIN);
1434+
} else if (desiredSidebarSize !== null && desiredSidebarSize > SIDEBAR_MIN) {
1435+
changeSidebarSize(desiredSidebarSize);
1436+
}
1437+
});
13451438
function stopResize(e) {
13461439
if (currentPointerId === null) {
13471440
return;
13481441
}
1349-
e.preventDefault();
1442+
if (e) {
1443+
e.preventDefault();
1444+
}
1445+
desiredSidebarSize = sidebar.getBoundingClientRect().width;
13501446
removeClass(resizer, "active");
13511447
window.removeEventListener("pointermove", resize, false);
13521448
window.removeEventListener("pointerup", stopResize, false);
@@ -1376,6 +1472,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
13761472
window.addEventListener("pointerup", stopResize, false);
13771473
addClass(resizer, "active");
13781474
addClass(document.documentElement, "sidebar-resizing");
1475+
desiredSidebarSize = null;
13791476
}
13801477
resizer.addEventListener("pointerdown", initResize, false);
13811478
}());

src/librustdoc/html/static/js/storage.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -196,18 +196,21 @@ if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
196196

197197
updateTheme();
198198

199+
// Hide, show, and resize the sidebar at page load time
200+
//
201+
// This needs to be done here because this JS is render-blocking,
202+
// so that the sidebar doesn't "jump" after appearing on screen.
203+
// The user interaction to change this is set up in main.js.
199204
if (getSettingValue("source-sidebar-show") === "true") {
200205
// At this point in page load, `document.body` is not available yet.
201206
// Set a class on the `<html>` element instead.
202207
addClass(document.documentElement, "src-sidebar-expanded");
203208
}
204-
205209
if (getSettingValue("hide-sidebar") === "true") {
206210
// At this point in page load, `document.body` is not available yet.
207211
// Set a class on the `<html>` element instead.
208212
addClass(document.documentElement, "hide-sidebar");
209213
}
210-
211214
function updateSidebarWidth() {
212215
const desktopSidebarWidth = getSettingValue("desktop-sidebar-width");
213216
if (desktopSidebarWidth && desktopSidebarWidth !== "null") {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Checks sidebar resizing
2+
go-to: "file://" + |DOC_PATH| + "/test_docs/index.html"
3+
set-window-size: (1280, 600)
4+
wait-for-property: (".sidebar", {"clientWidth": 200}, [NEAR])
5+
6+
// resize past maximum (don't grow past 500)
7+
drag-and-drop: ((205, 100), (600, 100))
8+
wait-for-property: (".sidebar", {"clientWidth": 500}, [NEAR])
9+
10+
// make the window small enough that the sidebar has to shrink
11+
set-window-size: (750, 600)
12+
wait-for-property: (".sidebar", {"clientWidth": 350}, [NEAR])
13+
14+
// grow the window again to make the sidebar bigger
15+
set-window-size: (1280, 600)
16+
wait-for-property: (".sidebar", {"clientWidth": 500}, [NEAR])
17+
18+
// make the window small enough that the sidebar has to shrink
19+
set-window-size: (750, 600)
20+
wait-for-property: (".sidebar", {"clientWidth": 350}, [NEAR])
21+
22+
// grow the window again to make the sidebar bigger
23+
set-window-size: (1280, 600)
24+
wait-for-property: (".sidebar", {"clientWidth": 500}, [NEAR])
25+
26+
// shrink back down again, then reload the page
27+
// the "desired size" is a bit of remembered implicit state,
28+
// and rustdoc tries to minimize things like this
29+
set-window-size: (800, 600)
30+
wait-for-property: (".sidebar", {"clientWidth": 400}, [NEAR])
31+
reload:
32+
set-window-size: (1280, 600)
33+
wait-for-property: (".sidebar", {"clientWidth": 400}, [NEAR])

0 commit comments

Comments
 (0)