Skip to content

Sidebar improvements #2666

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

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
65 changes: 37 additions & 28 deletions src/front-end/js/book.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS */
/* global default_theme, default_dark_theme, default_light_theme, hljs, ClipboardJS, mdBook */

// Fix back button cache problem
window.onunload = function() { };
Expand Down Expand Up @@ -523,34 +523,28 @@ aria-label="Show hidden lines"></button>';
const sidebarResizeHandle = document.getElementById('sidebar-resize-handle');
let firstContact = null;

function showSidebar() {
body.classList.remove('sidebar-hidden');
body.classList.add('sidebar-visible');
function setSidebarVisibility(isVisible) {
body.classList.toggle('sidebar-hidden', !isVisible);
body.classList.toggle('sidebar-visible', isVisible);
Array.from(sidebarLinks).forEach(function(link) {
link.setAttribute('tabIndex', 0);
link.setAttribute('tabIndex', isVisible ? 0 : -1);
});
sidebarToggleButton.setAttribute('aria-expanded', true);
sidebar.setAttribute('aria-hidden', false);
try {
localStorage.setItem('mdbook-sidebar', 'visible');
} catch (e) {
// Ignore error.
}
sidebarToggleButton.setAttribute('aria-expanded', isVisible);
sidebar.setAttribute('aria-hidden', !isVisible);

// We use sessionStorage for the sidebar visibility setting, as we want it to be
// specific to the current browser window and tab (since different windows can have
// different sizes), unlike the theme which is a global preference (ie. if you want
// a dark theme, you probably want it on all your windows)
mdBook.setConfig('sidebar', isVisible ? 'visible' : 'hidden', sessionStorage);
}

function showSidebar() {
setSidebarVisibility(true);
}

function hideSidebar() {
body.classList.remove('sidebar-visible');
body.classList.add('sidebar-hidden');
Array.from(sidebarLinks).forEach(function(link) {
link.setAttribute('tabIndex', -1);
});
sidebarToggleButton.setAttribute('aria-expanded', false);
sidebar.setAttribute('aria-hidden', true);
try {
localStorage.setItem('mdbook-sidebar', 'hidden');
} catch (e) {
// Ignore error.
}
setSidebarVisibility(false);
}

// Toggle sidebar
Expand All @@ -569,21 +563,36 @@ aria-label="Show hidden lines"></button>';

sidebarResizeHandle.addEventListener('mousedown', initResize, false);

function initResize() {
let startClientX;
let startSidebarWidth;
function initResize(e) {
window.addEventListener('mousemove', resize, false);
window.addEventListener('mouseup', stopResize, false);

body.classList.add('sidebar-resizing');

startClientX = e.clientX;
startSidebarWidth = parseInt(
getComputedStyle(document.body)
.getPropertyValue('--sidebar-width')
?.replace(/px$/, ''),
10,
);
}

function resize(e) {
let pos = e.clientX - sidebar.offsetLeft;
const pos = e.clientX - sidebar.offsetLeft;
if (pos < 20) {
hideSidebar();
} else {
if (body.classList.contains('sidebar-hidden')) {
showSidebar();
}
pos = Math.min(pos, window.innerWidth - 100);
document.documentElement.style.setProperty('--sidebar-width', pos + 'px');
const sidebarWidth = startSidebarWidth +
Math.min(e.clientX, window.innerWidth - 100) -
startClientX;
mdBook.setConfig('sidebarWidth', sidebarWidth, sessionStorage);
document.documentElement.style.setProperty('--sidebar-width', sidebarWidth + 'px');
}
}
//on mouseup remove windows functions mousemove & mouseup
Expand Down
95 changes: 64 additions & 31 deletions src/front-end/templates/index.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -64,50 +64,83 @@
</head>
<body>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">

if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
<script>
// First declare the global constants needed everywhere, outside of the function wrapper
// TODO refactoring: maybe all variables that are currently global could be moved to a single global object (window.mdBook) to avoid cluttering the global namespace?
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
const html = document.documentElement;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");


// Global “namespace” object to keep some of our helper functions and utils
const mdBook = {
getConfig(key, storage = localStorage) {
const fullKey = "mdbook-" + key;
try {
return storage.getItem(fullKey);
} catch(e) {
// It can only be a security exception (if the user has disabled cookies/storage)
// TODO: we could warn the user that we won’t be able to persist their settings, but maybe it would be better to do it only if/when they try to change them? (ie when they try to hide or show the sidebar, or change the theme)
return null;
}

if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
},

setConfig(key, value, storage = localStorage) {
const fullKey = 'mdbook-' + key;
try {
storage.setItem(fullKey, value);
} catch (e) {
// Ignore error.
// It can only be a security exception (if the user has disabled cookies/storage)
// TODO: maybe display some warning to the user that the setting they are trying
// to change will not be kept across page changes/reloads because they disabled
// storage for this site/origin?
}
} catch (e) { }
</script>
},
};


(function(){

// Set the theme before any content is loaded, prevents flash

let theme = mdBook.getConfig('theme');
// Work around some values being stored in localStorage wrapped in quotes
// Probably for legacy reasons?
if(theme && theme.startsWith('"')) {
theme = theme.replace(/^"|"$/g, "");
mdBook.setConfig('theme', theme);
}
theme = theme ?? default_theme;

<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('{{ default_theme }}')
html.classList.add(theme);
html.classList.add("js");
</script>

<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
// Hide / unhide sidebar before it is displayed, and restore its width if it was manually resized

<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
let sidebar = mdBook.getConfig("sidebar", sessionStorage);
if(!sidebar) {
// No value, this must be the first time this page is open.
// By default, show or hide the sidebar depending on the window width.
sidebar = (document.body.clientWidth >= 1080) ? "visible" : "hidden";
// Then we need to *store* the visibility of the sidebar, because without that, if the user resized the window then navigated to another page, the sidebar visibility could change unexpectedly
mdBook.setConfig('sidebar', sidebar, sessionStorage);
}

sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>

// We need parseInt() because storage only stores strings
let sidebarWidth = parseInt(mdBook.getConfig("sidebarWidth", sessionStorage), 10);
if(sidebarWidth && Number.isFinite(sidebarWidth)) {
document.documentElement.style.setProperty('--sidebar-width', Math.min(sidebarWidth, window.innerWidth - 100) + 'px');
}

})();</script>

<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
Expand Down
Loading