Skip to content

Commit

Permalink
docs: add a pagetoc to the theme
Browse files Browse the repository at this point in the history
  • Loading branch information
ctron committed Apr 21, 2024
1 parent 8c21e88 commit d09d10f
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 1 deletion.
4 changes: 3 additions & 1 deletion guide/book.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[book]
title = "The `trunk` Guide"
title = "The Trunk Guide"
description = "Documention of Trunk, a web application bundler for Rust"
src = "src"

Expand All @@ -21,7 +21,9 @@ assets_version = "3.0.2" # do not edit: managed by `mdbook-admonish install`
[output.html]
additional-css = [
"./mdbook-admonish.css",
"theme/pagetoc.css"
]
additional-js = [
"theme/pagetoc.js"
]

105 changes: 105 additions & 0 deletions guide/theme/pagetoc.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
:root {
--toc-width: 270px;
--center-content-toc-shift: calc(-1 * var(--toc-width) / 2);
}

.nav-chapters {
/* adjust width of buttons that bring to the previous or the next page */
min-width: 50px;
}

.previous {
/*
adjust the space between the left sidebar or the left side of the screen
and the button that leads to the previous page
*/
margin-left: var(--page-padding);
}

@media only screen {
main {
display: flex;
}

@media (max-width: 1179px) {
.sidebar-hidden .sidetoc {
display: none;
}
}

@media (max-width: 1439px) {
.sidebar-visible .sidetoc {
display: none;
}
}

@media (1180px <= width <= 1439px) {
.sidebar-hidden main {
position: relative;
left: var(--center-content-toc-shift);
}
}

@media (1440px <= width <= 1700px) {
.sidebar-visible main {
position: relative;
left: var(--center-content-toc-shift);
}
}

.content-wrap {
overflow-y: auto;
width: 100%;
}

.sidetoc {
margin-top: 20px;
margin-left: 10px;
margin-right: auto;
}
.pagetoc {
position: fixed;
/* adjust TOC width */
width: var(--toc-width);
height: calc(100vh - var(--menu-bar-height) - 0.67em * 4);
overflow: auto;
}
.pagetoc a {
border-left: 1px solid var(--sidebar-bg);
color: var(--fg) !important;
display: block;
padding-bottom: 5px;
padding-top: 5px;
padding-left: 10px;
text-align: left;
text-decoration: none;
}
.pagetoc a:hover,
.pagetoc a.active {
background: var(--sidebar-bg);
color: var(--sidebar-fg) !important;
}
.pagetoc .active {
background: var(--sidebar-bg);
color: var(--sidebar-fg);
font-weight: bold;
}
.pagetoc .pagetoc-H2 {
padding-left: 20px;
font-size: 90%;
}
.pagetoc .pagetoc-H3 {
padding-left: 40px;
font-size: 90%;
}
.pagetoc .pagetoc-H4 {
padding-left: 60px;
font-size: 90%;
}
}

@media print {
.sidetoc {
display: none;
}
}
138 changes: 138 additions & 0 deletions guide/theme/pagetoc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
function forEach(elems, fun) {
Array.prototype.forEach.call(elems, fun);
}

function getPagetoc(){
const pagetoc = document.getElementsByClassName("pagetoc")[0];

if (pagetoc) {
return pagetoc;
}

return autoCreatePagetoc();
}

function autoCreatePagetoc() {
const main = document.querySelector("#content > main");

const content = document.createElement("div");
content.classList.add("content-wrap");
content.append(...main.childNodes);

main.appendChild(content);

main.insertAdjacentHTML("beforeend", `
<div class="sidetoc">
<nav class="pagetoc"></nav>
</div>
`);

return document.getElementsByClassName("pagetoc")[0]
}

function getPagetocElems() {
return getPagetoc().children;
}

function getHeaders(){
return document.getElementsByClassName("header")
}

// Un-active everything when you click it
function forPagetocElem(fun) {
forEach(getPagetocElems(), fun);
}

function getRect(element) {
return element.getBoundingClientRect();
}

function overflowTop(container, element) {
return getRect(container).top - getRect(element).top;
}

function overflowBottom(container, element) {
return getRect(container).bottom - getRect(element).bottom;
}

var activeHref = location.href;

var updateFunction = function (elem = undefined) {
var id = elem;

if (!id && location.href != activeHref) {
activeHref = location.href;
forPagetocElem(function (el) {
if (el.href === activeHref) {
id = el;
}
});
}

if (!id) {
var elements = getHeaders();
let margin = window.innerHeight / 3;

forEach(elements, function (el, i, arr) {
if (!id && getRect(el).top >= 0) {
if (getRect(el).top < margin) {
id = el;
} else {
id = arr[Math.max(0, i - 1)];
}
}
// a very long last section
// its heading is over the screen
if (!id && i == arr.length - 1) {
id = el
}
});
}

forPagetocElem(function (el) {
el.classList.remove("active");
});

if (!id) return;

forPagetocElem(function (el) {
if (id.href.localeCompare(el.href) == 0) {
el.classList.add("active");
let pagetoc = getPagetoc();
if (overflowTop(pagetoc, el) > 0) {
pagetoc.scrollTop = el.offsetTop;
}
if (overflowBottom(pagetoc, el) < 0) {
pagetoc.scrollTop -= overflowBottom(pagetoc, el);
}
}
});
};

let elements = getHeaders();

if (elements.length > 1) {
// Populate sidebar on load
window.addEventListener("load", function () {
var pagetoc = getPagetoc();
var elements = getHeaders();
forEach(elements, function (el) {
var link = document.createElement("a");
link.appendChild(document.createTextNode(el.text));
link.href = el.hash;
link.classList.add("pagetoc-" + el.parentElement.tagName);
pagetoc.appendChild(link);
link.onclick = function () {
updateFunction(link);
};
});
updateFunction();
});

// Handle active elements on scroll
window.addEventListener("scroll", function () {
updateFunction();
});
} else {
document.getElementsByClassName("sidetoc")[0].remove();
}

0 comments on commit d09d10f

Please sign in to comment.