Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustdoc: sidebar usability improvements #98772

Closed
wants to merge 5 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 35 additions & 29 deletions src/librustdoc/html/static/css/rustdoc.css
Original file line number Diff line number Diff line change
@@ -1370,7 +1370,6 @@ pre.rust {
position: sticky;
top: 0;
left: 0;
cursor: pointer;
font-weight: bold;
font-size: 1.25rem;
border-bottom: 1px solid;
@@ -1391,7 +1390,23 @@ pre.rust {
border-bottom: 1px solid;
margin-bottom: 6px;
}

#sidebar-toggle > button {
background: none;
color: inherit;
cursor: pointer;
text-align: center;
border: none;
outline: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need to set the width here? Also why all these changes?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The essential problem here is that the sidebar toggle element for the source code view is a <div>, rather than a <button>. That's bad, because it won't get reported correctly by accessibility tools, and will also not have a tab position, so you can't get at it with a keyboard.

Fixing that involves making it a <button>, but keeping the appearance the same means having to reset all the default button styles.

/* iOS button gradient: https://stackoverflow.com/q/5438567 */
-webkit-appearance: none;
opacity: 1;
}
#settings-menu, #help-button {
margin-left: 4px;
outline: none;
@@ -1528,38 +1543,19 @@ kbd {
margin-bottom: 1em;
}

div.children {
padding-left: 27px;
display: none;
}
div.name {
details.dir-entry > summary {
margin: 0 0 0 13px;
list-style-position: outside;
cursor: pointer;
position: relative;
margin-left: 16px;
}
div.files > a {
display: block;
padding: 0 3px;
}
div.files > a:hover, div.name:hover {
background-color: #a14b4b;

details.dir-entry div.folders, details.dir-entry div.files {
padding-left: 27px;
}
div.name.expand + .children {

details.dir-entry a {
display: block;
}
div.name::before {
content: "\25B6";
padding-left: 4px;
font-size: 0.625rem;
position: absolute;
left: -16px;
top: 4px;
}
div.name.expand::before {
transform: rotate(90deg);
left: -15px;
top: 2px;
}

/* The hideme class is used on summary tags that contain a span with
placeholder text shown only when the toggle is closed. For instance,
@@ -1683,6 +1679,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {

/* Media Queries */

/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY;
If you update this line, then you also need to update the line with the same warning
in storage.js plus the media query with (max-width: 700px)
*/
@media (min-width: 701px) {
/* In case there is no documentation before a code block, we need to add some margin at the top
to prevent an overlay between the "collapse toggle" and the information tooltip.
@@ -1703,6 +1704,11 @@ details.rustdoc-toggle[open] > summary.hideme::after {
}
}

/*
WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
If you update this line, then you also need to update the line with the same warning
in storage.js plus the media query with (min-width: 701px)
*/
@media (max-width: 700px) {
/* When linking to an item with an `id` (for instance, by clicking a link in the sidebar,
or visiting a URL with a fragment like `#method.new`, we don't want the item to be obscured
5 changes: 3 additions & 2 deletions src/librustdoc/html/static/css/themes/ayu.css
Original file line number Diff line number Diff line change
@@ -620,7 +620,7 @@ kbd {
#sidebar-toggle {
background-color: #14191f;
}
#sidebar-toggle:hover {
#sidebar-toggle:hover, #sidebar-toggle > button:focus {
background-color: rgba(70, 70, 70, 0.33);
}
#source-sidebar {
@@ -630,7 +630,8 @@ kbd {
color: #fff;
border-bottom-color: #5c6773;
}
#source-sidebar div.files > a:hover, div.name:hover {
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
background-color: #14191f;
color: #ffb44c;
}
5 changes: 3 additions & 2 deletions src/librustdoc/html/static/css/themes/dark.css
Original file line number Diff line number Diff line change
@@ -491,7 +491,7 @@ kbd {
#sidebar-toggle {
background-color: #565656;
}
#sidebar-toggle:hover {
#sidebar-toggle:hover, #sidebar-toggle > button:focus {
background-color: #676767;
}
#source-sidebar {
@@ -500,7 +500,8 @@ kbd {
#source-sidebar > .title {
border-bottom-color: #ccc;
}
#source-sidebar div.files > a:hover, div.name:hover {
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
background-color: #444;
}
#source-sidebar div.files > .selected {
5 changes: 3 additions & 2 deletions src/librustdoc/html/static/css/themes/light.css
Original file line number Diff line number Diff line change
@@ -475,7 +475,7 @@ kbd {
#sidebar-toggle {
background-color: #F5F5F5;
}
#sidebar-toggle:hover {
#sidebar-toggle:hover, #sidebar-toggle > button:focus {
background-color: #E0E0E0;
}
#source-sidebar {
@@ -484,7 +484,8 @@ kbd {
#source-sidebar > .title {
border-bottom-color: #ccc;
}
#source-sidebar div.files > a:hover, div.name:hover {
#source-sidebar div.files > a:hover, details.dir-entry summary:hover,
#source-sidebar div.files > a:focus, details.dir-entry summary:focus {
background-color: #E0E0E0;
}
#source-sidebar div.files > .selected {
46 changes: 42 additions & 4 deletions src/librustdoc/html/static/js/main.js
Original file line number Diff line number Diff line change
@@ -382,8 +382,7 @@ function loadCss(cssFileName) {

function onHashChange(ev) {
// If we're in mobile mode, we should hide the sidebar in any case.
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
hideSidebar();
handleHashes(ev);
}

@@ -764,11 +763,50 @@ function loadCss(cssFileName) {
});
}());

let oldSidebarScrollPosition = null;

function showSidebar() {
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
// This is to keep the scroll position on mobile.
oldSidebarScrollPosition = window.scrollY;
document.body.style.width = `${document.body.offsetWidth}px`;
document.body.style.position = "fixed";
document.body.style.top = `-${oldSidebarScrollPosition}px`;
document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`;
document.querySelector(".mobile-topbar").style.position = "relative";
} else {
oldSidebarScrollPosition = null;
}
const sidebar = document.getElementsByClassName("sidebar")[0];
addClass(sidebar, "shown");
}

function hideSidebar() {
if (oldSidebarScrollPosition !== null) {
// This is to keep the scroll position on mobile.
document.body.style.width = "";
document.body.style.position = "";
document.body.style.top = "";
document.querySelector(".mobile-topbar").style.top = "";
document.querySelector(".mobile-topbar").style.position = "";
// The scroll position is lost when resetting the style, hence why we store it in
// `oldSidebarScrollPosition`.
window.scrollTo(0, oldSidebarScrollPosition);
oldSidebarScrollPosition = null;
}
const sidebar = document.getElementsByClassName("sidebar")[0];
removeClass(sidebar, "shown");
}

window.addEventListener("resize", () => {
if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT &&
oldSidebarScrollPosition !== null) {
// If the user opens the sidebar in "mobile" mode, and then grows the browser window,
// we need to switch away from mobile mode and make the main content area scrollable.
hideSidebar();
}
});

function handleClick(id, f) {
const elem = document.getElementById(id);
if (elem) {
@@ -811,9 +849,9 @@ function loadCss(cssFileName) {
sidebar_menu_toggle.addEventListener("click", () => {
const sidebar = document.getElementsByClassName("sidebar")[0];
if (!hasClass(sidebar, "shown")) {
addClass(sidebar, "shown");
showSidebar();
} else {
removeClass(sidebar, "shown");
hideSidebar();
}
});
}
66 changes: 40 additions & 26 deletions src/librustdoc/html/static/js/source-script.js
Original file line number Diff line number Diff line change
@@ -2,44 +2,44 @@
/* global sourcesIndex */

// Local js definitions:
/* global addClass, getCurrentValue, hasClass, onEachLazy, removeClass, browserSupportsHistoryApi */
/* global addClass, getCurrentValue, onEachLazy, removeClass, browserSupportsHistoryApi */
/* global updateLocalStorage */

"use strict";

(function() {

const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value;
let oldScrollPosition = 0;
let oldScrollPosition = null;

function closeSidebarIfMobile() {
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
updateLocalStorage("source-sidebar-show", "false");
}
}

function createDirEntry(elem, parent, fullPath, hasFoundFile) {
const name = document.createElement("div");
name.className = "name";
const dirEntry = document.createElement("details");
const summary = document.createElement("summary");

dirEntry.className = "dir-entry";

fullPath += elem["name"] + "/";

name.onclick = ev => {
if (hasClass(ev.target, "expand")) {
removeClass(ev.target, "expand");
} else {
addClass(ev.target, "expand");
}
};
name.innerText = elem["name"];
summary.innerText = elem["name"];
dirEntry.appendChild(summary);

const children = document.createElement("div");
children.className = "children";
const folders = document.createElement("div");
folders.className = "folders";
if (elem.dirs) {
for (const dir of elem.dirs) {
if (createDirEntry(dir, folders, fullPath, hasFoundFile)) {
addClass(name, "expand");
dirEntry.open = true;
hasFoundFile = true;
}
}
}
children.appendChild(folders);
dirEntry.appendChild(folders);

const files = document.createElement("div");
files.className = "files";
@@ -48,60 +48,74 @@ function createDirEntry(elem, parent, fullPath, hasFoundFile) {
const file = document.createElement("a");
file.innerText = file_text;
file.href = rootPath + "src/" + fullPath + file_text + ".html";
file.addEventListener("click", closeSidebarIfMobile);
const w = window.location.href.split("#")[0];
if (!hasFoundFile && w === file.href) {
file.className = "selected";
addClass(name, "expand");
dirEntry.open = true;
hasFoundFile = true;
}
files.appendChild(file);
}
}
children.appendChild(files);
parent.appendChild(name);
parent.appendChild(children);
dirEntry.appendChild(files);
parent.appendChild(dirEntry);
return hasFoundFile;
}

function toggleSidebar() {
const child = this.children[0];
const child = this.parentNode.children[0];
if (child.innerText === ">") {
if (window.innerWidth < 701) {
if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) {
// This is to keep the scroll position on mobile.
oldScrollPosition = window.scrollY;
document.body.style.position = "fixed";
document.body.style.top = `-${oldScrollPosition}px`;
} else {
oldScrollPosition = null;
}
addClass(document.documentElement, "source-sidebar-expanded");
child.innerText = "<";
updateLocalStorage("source-sidebar-show", "true");
} else {
if (window.innerWidth < 701) {
if (oldScrollPosition !== null) {
// This is to keep the scroll position on mobile.
document.body.style.position = "";
document.body.style.top = "";
// The scroll position is lost when resetting the style, hence why we store it in
// `oldScroll`.
// `oldScrollPosition`.
window.scrollTo(0, oldScrollPosition);
oldScrollPosition = null;
}
removeClass(document.documentElement, "source-sidebar-expanded");
child.innerText = ">";
updateLocalStorage("source-sidebar-show", "false");
}
}

window.addEventListener("resize", () => {
if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) {
// If the user opens the sidebar in "mobile" mode, and then grows the browser window,
// we need to switch away from mobile mode and make the main content area scrollable.
document.body.style.position = "";
document.body.style.top = "";
window.scrollTo(0, oldScrollPosition);
oldScrollPosition = null;
}
});

function createSidebarToggle() {
const sidebarToggle = document.createElement("div");
sidebarToggle.id = "sidebar-toggle";
sidebarToggle.onclick = toggleSidebar;

const inner = document.createElement("div");
const inner = document.createElement("button");

if (getCurrentValue("source-sidebar-show") === "true") {
inner.innerText = "<";
} else {
inner.innerText = ">";
}
inner.onclick = toggleSidebar;

sidebarToggle.appendChild(inner);
return sidebarToggle;
5 changes: 5 additions & 0 deletions src/librustdoc/html/static/js/storage.js
Original file line number Diff line number Diff line change
@@ -9,6 +9,11 @@ const darkThemes = ["dark", "ayu"];
window.currentTheme = document.getElementById("themeStyle");
window.mainTheme = document.getElementById("mainThemeStyle");

// WARNING: RUSTDOC_MOBILE_BREAKPOINT MEDIA QUERY
// If you update this line, then you also need to update the two media queries with the same
// warning in rustdoc.css
window.RUSTDOC_MOBILE_BREAKPOINT = 701;

const settingsDataset = (function() {
const settingsElement = document.getElementById("default-settings");
if (settingsElement === null) {
Loading