From 32854cc98023c9e7eb047ac76ea8cd35efd3af71 Mon Sep 17 00:00:00 2001 From: Denis Kasak Date: Wed, 14 Feb 2024 22:00:35 +0100 Subject: [PATCH] Implement folding for the TOC sidebar --- assets/scss/custom.scss | 95 +++++++++++++++++++++++++++++++++++++++++ static/js/toc.js | 36 +++++++++++++--- 2 files changed, 126 insertions(+), 5 deletions(-) diff --git a/assets/scss/custom.scss b/assets/scss/custom.scss index 7cd0046b..81ded6b5 100644 --- a/assets/scss/custom.scss +++ b/assets/scss/custom.scss @@ -524,3 +524,98 @@ nav.foldable-nav { margin: initial; } } + +// Fix some visual bugs regarding sidebar_menu_foldable / foldable-nav support +// and extend it to ordered lists +nav.foldable-nav { + .with-child ol { + list-style: none; + padding: 0; + margin: 0; + } + + .ol-1 > li { + padding-left: 1.5em; + } + + ol.foldable { + max-height: 0; + overflow: hidden; + } + + input:checked ~ ol.foldable { + max-height: 100vmax; + } + + .ol-1 .with-child > label:before { + display: inline-block; + font-family: inherit; + font-style: normal; + font-variant: normal; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + font-weight: 900; content: "+"; + position: absolute; + left: 0.1em; + padding-left: 0.4em; + padding-right: 0.4em; + font-size: 1em; + color: $gray-900; + transform: unset; + transition: unset; + } + + .ol-1 .with-child > input:checked ~ label:before { + color: $gray-900; + content: "-"; + transform: unset; + transition: unset; + } + + .with-child ol { margin-top: 0.1em; } + + /* Fix bugs and annoyances with unordered lists */ + .ul-1 .with-child > label:before { + font-weight: 900; content: "+"; + font-family: inherit; + transform: unset; + transition: unset; + } + + .ul-1 .with-child > input:checked ~ label:before { + color: $gray-900; + content: "-"; + transform: unset; + transition: unset; + } + +} + +@media (hover: hover) and (pointer: fine) { + nav.foldable-nav { + + .ul-1 .with-child > label:hover:before { + color: $gray-900; + transform: unset; + transition: unset; + } + + .ul-1 .with-child > input:checked ~ label:hover:before { + color: $gray-900; + transform: unset; + transition: unset; + } + + .ol-1 .with-child > label:hover:before { + color: $gray-900; + transform: unset; + transition: unset; + } + + .ol-1 .with-child > input:checked ~ label:hover:before { + color: $gray-900; + transform: unset; + transition: unset; + } + } +} diff --git a/static/js/toc.js b/static/js/toc.js index 6386e40d..4804ef67 100644 --- a/static/js/toc.js +++ b/static/js/toc.js @@ -107,9 +107,10 @@ function makeToc() { // we have to adjust heading IDs to ensure that they are unique const nav = document.createElement("nav"); + nav.classList.add("td-sidebar-nav", "foldable-nav"); nav.id = "TableOfContents"; - const section = makeTocSection(tocTargets, 0); + const section = makeTocSection(tocTargets, 0, 1); nav.appendChild(section.content); // build the TOC and append to it title and content const toc = document.createElement("div"); @@ -130,10 +131,24 @@ function makeToc() { // create a single ToC entry function makeTocEntry(heading) { const li = document.createElement("li"); + li.classList.add("td-sidebar-nav__section-title", "td-sidebar-nav__section"); + + const input = document.createElement("input"); + input.setAttribute("id", `toc-${heading.id}-check`); + input.setAttribute("type", "checkbox"); + const label = document.createElement("label"); + label.setAttribute("for", `toc-${heading.id}-check`); + const a = document.createElement("a"); a.setAttribute("href", `#${heading.id}`); + a.setAttribute("id", `toc-${heading.id}`); + a.classList.add("td-sidebar-link", "td-sidebar-link__page"); a.textContent = heading.textContent; - li.appendChild(a); + + li.appendChild(input); + li.appendChild(label); + label.appendChild(a); + return li; } @@ -142,8 +157,9 @@ Each ToC section is an `
    ` element. ToC entries are `
  1. ` elements and these contain nested ToC sections, whenever we go to the next heading level down. */ -function makeTocSection(headings, index) { +function makeTocSection(headings, index, depth) { const ol = document.createElement("ol"); + ol.classList.add("td-sidebar-nav__section", `ol-${depth}`); let previousHeading = null; let previousLi = null; let i = index; @@ -152,13 +168,20 @@ function makeTocSection(headings, index) { const thisHeading = headings[i]; if (previousHeading && (thisHeading.tagName > previousHeading.tagName)) { // we are going down a heading level, create a new nested section - const section = makeTocSection(headings, i); + const section = makeTocSection(headings, i, depth+1); previousLi.appendChild(section.content); - i = section.index -1; + if (depth >= 1) { + section.content.classList.add("foldable"); + } + previousLi.classList.add("with-child"); + i = section.index - 1; } else if (previousHeading && (previousHeading.tagName > thisHeading.tagName)) { // we have come back up a level, so a section is finished for (let li of lis) { + if (!li.classList.contains("with-child")) { + li.classList.add("without-child"); + } ol.appendChild(li); } return { @@ -174,6 +197,9 @@ function makeTocSection(headings, index) { } } for (let li of lis) { + if (!li.classList.contains("with-child")) { + li.classList.add("without-child"); + } ol.appendChild(li); } return {