feat(toc): ✨ add folding TOC elements for more compact TOC table
This commit is contained in:
parent
da25a786d1
commit
9870967093
3 changed files with 77 additions and 14 deletions
|
@ -165,8 +165,11 @@ a:hover {
|
|||
margin-right: 2rem;
|
||||
}
|
||||
|
||||
:target {
|
||||
scroll-margin-top: 6rem;
|
||||
:target, html, body {
|
||||
scroll-margin-top: 140px;
|
||||
}
|
||||
:target {
|
||||
outline: 1px solid var(--highlight_1);
|
||||
}
|
||||
|
||||
#main_content_flexbox {
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
color: var(--toc-fg) !important;
|
||||
}
|
||||
|
||||
& .active {
|
||||
& .active > a {
|
||||
background-color: var(--toc-bg);
|
||||
border-bottom: 1px solid var(--highlight_1);
|
||||
|
||||
|
@ -57,4 +57,11 @@
|
|||
margin-bottom: 0.2em;
|
||||
transition: all 1s;
|
||||
}
|
||||
|
||||
& .toc_collapsing {
|
||||
display: none;
|
||||
}
|
||||
& li:is(:has(.active),.active) > ol > .toc_collapsing {
|
||||
display: block;
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ let tocId = "toc";
|
|||
|
||||
const TOC_IDENTIFIER = "toc";
|
||||
const TOC_MAIN_CONTENT_ID = "#content_article"
|
||||
const TOC_TOP_PIXEL_MARGIN = 300;
|
||||
const TOC_TOP_PIXEL_MARGIN = 150;
|
||||
|
||||
class TocTracker {
|
||||
known_heading_elements = [];
|
||||
|
@ -49,14 +49,25 @@ class TocTracker {
|
|||
throw Error("A `main` tag section is required to query headings from.");
|
||||
}
|
||||
|
||||
let headings = main.querySelectorAll("h1, h2, h3, h4, h5, h6");
|
||||
let headings = main.querySelectorAll("h1, h2, h3, h4, h5, h6, li strong");
|
||||
headings.forEach((heading, index) => {
|
||||
const heading_level = parseInt(heading.tagName.slice(-1));
|
||||
let heading_level = parseInt(heading.tagName.slice(-1));
|
||||
let heading_collapsed = false;
|
||||
|
||||
let heading_name = heading.innerHTML;
|
||||
|
||||
if(heading.tagName == 'STRONG') {
|
||||
heading_level = -1;
|
||||
heading_collapsed = true;
|
||||
|
||||
heading = heading.closest('li');
|
||||
}
|
||||
|
||||
this.known_heading_elements.push({
|
||||
level: heading_level,
|
||||
name: heading.innerHTML,
|
||||
name: heading_name,
|
||||
dom: heading,
|
||||
collapse: heading_collapsed
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -65,6 +76,23 @@ class TocTracker {
|
|||
this.known_heading_elements.sort((a, b) => {
|
||||
return a.dom.getBoundingClientRect().y
|
||||
- b.dom.getBoundingClientRect().y;
|
||||
});
|
||||
|
||||
let lastHeadingLevel = 0;
|
||||
this.known_heading_elements.forEach((element) => {
|
||||
if(element.level == -1) {
|
||||
let extra_depth = 0;
|
||||
let current_dom = element.dom;
|
||||
while(current_dom.tagName != 'ARTICLE') {
|
||||
if((current_dom.tagName == 'OL') || (current_dom.tagName == 'UL'))
|
||||
extra_depth += 1;
|
||||
|
||||
current_dom = current_dom.parentElement.closest('ol,ul,article');
|
||||
}
|
||||
element.level = lastHeadingLevel+extra_depth;
|
||||
}
|
||||
else
|
||||
lastHeadingLevel = element.level;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -192,7 +220,7 @@ class TocNavBarUpdater {
|
|||
let newNode = document.createElement('li');
|
||||
|
||||
const pathURL = location.pathname + '#' + pathItem.id + location.search;
|
||||
newNode.innerHTML = "<a href=" + pathURL + "> #<sub>" + pathItem.level + '</sub>' + pathItem.name + '</a>'
|
||||
newNode.innerHTML = "<a hx-boost=false href=" + pathURL + "> #<sub>" + pathItem.level + '</sub>' + pathItem.name + '</a>'
|
||||
|
||||
this.navbar_dom.appendChild(newNode);
|
||||
this.added_navbar_elements.push(newNode);
|
||||
|
@ -224,17 +252,37 @@ class TocSidemenu {
|
|||
}
|
||||
|
||||
_generateSidebar() {
|
||||
this.toc_tracker.known_heading_elements.forEach(element => {
|
||||
let new_element = document.createElement('li');
|
||||
let toc_stack = [this.sidebar_dom];
|
||||
let last_added_li = null;
|
||||
|
||||
this.toc_tracker.known_heading_elements.forEach(element => {
|
||||
while(element.level > toc_stack.length) {
|
||||
if(!last_added_li) {
|
||||
last_added_li = document.createElement('li');
|
||||
toc_stack[toc_stack.length-1].appendChild(last_added_li);
|
||||
}
|
||||
|
||||
let new_ol = document.createElement('ol');
|
||||
last_added_li.appendChild(new_ol);
|
||||
last_added_li = false;
|
||||
toc_stack.push(new_ol);
|
||||
}
|
||||
while(element.level < toc_stack.length)
|
||||
toc_stack.pop();
|
||||
|
||||
|
||||
let new_element = document.createElement('li');
|
||||
last_added_li = new_element;
|
||||
|
||||
const pathURL = location.pathname + '#' + element.id + location.search;
|
||||
|
||||
new_element.style = "padding-left: " + element.level * 0.8 + "em";
|
||||
new_element.innerHTML = "<a href=" + pathURL + ">" + element.name + "</a>";
|
||||
new_element.innerHTML = "<a hx-boost=false style=\"padding-left: " + element.level * 0.8 + "em\" href=" + pathURL + ">" + element.name + "</a>";
|
||||
if(element.collapse)
|
||||
new_element.classList.add('toc_collapsing');
|
||||
|
||||
this.sidebar_elements[element.id] = new_element;
|
||||
|
||||
this.sidebar_dom.appendChild(new_element);
|
||||
toc_stack[toc_stack.length-1].appendChild(new_element);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -251,13 +299,18 @@ class TocSidemenu {
|
|||
if(this.currently_active_entry) {
|
||||
this.currently_active_entry.classList.remove('active');
|
||||
}
|
||||
Object.values(this.sidebar_elements).forEach((entry) => entry.classList.remove('contains_active'));
|
||||
|
||||
let active_entry = this.sidebar_elements[entry.dom.id];
|
||||
active_entry.classList.add('active');
|
||||
this.currently_active_entry = active_entry;
|
||||
|
||||
entry.path.forEach((path_piece) => this.sidebar_elements[path_piece.id].classList.add('contains_active'));
|
||||
}
|
||||
}
|
||||
|
||||
let tracker = new TocTracker();
|
||||
let navbar_updater = new TocNavBarUpdater(tracker);
|
||||
let sidebar_updater = new TocSidemenu(tracker);
|
||||
let sidebar_updater = new TocSidemenu(tracker);
|
||||
|
||||
document.addEventListener('DOMContentLoaded', (event) => tracker.reloadHeadings());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue