Skip to content

Commit

Permalink
Rollup merge of rust-lang#115660 - notriddle:notriddle/sidebar-resize…
Browse files Browse the repository at this point in the history
…, r=GuillaumeGomez

rustdoc: allow resizing the sidebar / hiding the top bar

Fixes rust-lang#97306

Preview: http://notriddle.com/rustdoc-html-demo-4/sidebar-resize/std/index.html

![image](https://github.com/rust-lang/rust/assets/1593513/a2f40ea2-0436-4e44-99e8-d160dab2a680)

## Summary

This feature adds:

1. A checkbox to the Settings popover to hide the persistent navigation bar (the sidebar on large viewports and the top bar on small ones).
2. On large viewports, it adds a resize handle to the persistent sidebar. Resizing it into nothing is equivalent to turning off the persistent navigation bar checkbox in Settings.
3. If the navigation bar is hidden, a toolbar button to the left of the search appears. Clicking it brings the navigation bar back.

## Motivation

While "mobile mode" is definitely a good default, it's not the only reason people have wanted to hide the sidebar:

* Some people use tiling window managers, and don't like rustdoc's current breakpoints. Changing the breakpoints might help with that, but there's no perfect solution, because there's a gap between "huge screen" and "smartphone" where reasonable people can disagree about whether it makes sense for the sidebar to be on-screen. rust-lang#97306

* Some people ask for ways to reduce on-screen clutter because it makes it easier to focus. There's not a media query for that (and if there was, privacy-conscious users would turn it off). rust-lang#59829

This feature is designed to avoid these problems. Resizing the sidebar especially helps, because it provides a way to hide the sidebar without adding a new top-level button (which would add clutter), and it provides a way to make rustdoc play nicer in complex, custom screen layouts.

## Guide and Reference-level explanation

On a desktop or laptop with a mouse, resize the sidebar by dragging its right edge.

On any browser, including mobile phones, the sticky top bar or side bar can be hidden from the Settings area (the button with the cog wheel, next to the search bar). When it's hidden, a convenient button will appear on the search bar's left.

## Drawbacks

This adds more JavaScript code to the render blocking area.

## Rationale and alternatives

The most obvious way to allow people to hide the sidebar would have been to let them "manually enter mobile mode." The upside is that it's a feature we already have. The downside is that it's actually really hard to come up with a terse description. Is it:

* A Setting that forces desktop viewers to always have the mobile-style top bar? If so, how do we label it? Should it be visible on mobile, and, if so, does it just not do anything?
* A persistent hide/show sidebar button, present on desktop, just like on mobile? That's clutter that I'd like to avoid.

## Prior art

* The new file browser in GitHub uses a similar divider with a mouse-over indicator
* mdBook and macOS Finder both allow you to resize the sidebar to nothing as a gesture to hide it
* https://www.nngroup.com/articles/drag-drop/

## Future possibilities

https://rust-lang.zulipchat.com/#narrow/stream/266220-rustdoc/topic/Table.20of.20contents proposes a new, second sidebar (a table of contents). How should it fit in with this feature? Should it be resizeable? Hideable? Can it be accessed on mobile?
  • Loading branch information
GuillaumeGomez authored Dec 15, 2023
2 parents ec0008a + fd9f1a7 commit f8b9269
Show file tree
Hide file tree
Showing 17 changed files with 625 additions and 30 deletions.
1 change: 1 addition & 0 deletions src/librustdoc/html/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, 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);
Expand Down
6 changes: 5 additions & 1 deletion src/librustdoc/html/static/css/noscript.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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 */
}
171 changes: 162 additions & 9 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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 {
Expand All @@ -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,
Expand All @@ -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) {
Expand Down Expand Up @@ -477,6 +573,7 @@ ul.block, .block li {
display: block;
padding: 0.25rem; /* 4px */
margin-left: -0.25rem;
margin-right: 0.25rem;
}

.sidebar h2 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 22" \
fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m7.6121 3v16 M5.375 7.625h-2 m2 3h-2 m2 3h-2" stroke-width="1.25"/></svg>');
width: 22px;
height: 22px;
}

#copy-path {
color: var(--copy-path-button-color);
background: var(--main-background-color);
Expand Down Expand Up @@ -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,
Expand All @@ -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. */
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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
Expand All @@ -1827,6 +1957,10 @@ in src-script.js
color: var(--main-color);
}

.hide-sidebar .sidebar-menu-toggle {
display: none;
}

.sidebar-elems {
margin-top: 1em;
}
Expand Down Expand Up @@ -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,<svg xmlns="http://www.w3.org/2000/svg" \
viewBox="0 0 22 22" fill="none" stroke="black">\
<rect x="1" y="1" width="20" height="20" ry="1.5" stroke-width="1.5"/>\
<circle cx="4.375" cy="4.375" r="1" stroke-width=".75"/>\
<path d="m3 7.375h16m0-3h-4" stroke-width="1.25"/></svg>');
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 {
Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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 */

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 */
Expand Down
Loading

0 comments on commit f8b9269

Please sign in to comment.