Skip to content

Commit 2492405

Browse files
committed
Improved TOC
1 parent ba983ac commit 2492405

3 files changed

Lines changed: 92 additions & 0 deletions

File tree

_includes/head/meta-static.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@
1414
<meta name="application-name" content="{{ site.title }}" />
1515

1616
<meta name="generator" content="Hydejack v9.2.1" />
17+
<script src="{{ '/assets/js/toc-enhance.js' | relative_url }}" defer></script>

_sass/my-style.scss

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,33 @@ body.dark-mode {
8181
vertical-align: baseline;
8282
border-radius: 0.25rem;
8383
}
84+
85+
/* TOC sidebar enhancements */
86+
#markdown-toc {
87+
transition: box-shadow 0.15s ease, transform 0.15s ease;
88+
}
89+
90+
.toc-sentinel {
91+
width: 1px;
92+
height: 1px;
93+
display: block;
94+
}
95+
96+
/* Only affix TOC on screens wide enough (86em = --break-point-5) */
97+
@media (min-width: 86em) {
98+
#markdown-toc.affix {
99+
position: fixed;
100+
top: 1rem;
101+
right: 1rem;
102+
width: 18rem;
103+
max-height: calc(100vh - 2rem);
104+
overflow: auto;
105+
box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
106+
background: inherit;
107+
z-index: 40;
108+
}
109+
}
110+
111+
#markdown-toc a {
112+
transition: color 0.12s ease, font-weight 0.12s ease;
113+
}

assets/js/toc-enhance.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/* Enhanced TOC behavior: affix, active-section highlighting, and auto-scroll */
2+
(function () {
3+
function safeId(href) { return href && href.charAt(0) === '#' ? href.slice(1) : null }
4+
document.addEventListener('DOMContentLoaded', function () {
5+
var toc = document.getElementById('markdown-toc');
6+
if (!toc) return;
7+
// sentinel to toggle affix class when TOC scrolls past top
8+
var sentinel = document.createElement('div');
9+
sentinel.className = 'toc-sentinel';
10+
toc.parentNode.insertBefore(sentinel, toc);
11+
var sentObs = new IntersectionObserver(function (entries) {
12+
entries.forEach(function (e) {
13+
if (!e.isIntersecting) toc.classList.add('affix'); else toc.classList.remove('affix');
14+
});
15+
}, { root: null, threshold: 0, rootMargin: '-1px 0px 0px 0px' });
16+
sentObs.observe(sentinel);
17+
18+
var links = Array.from(toc.querySelectorAll('a[href^="#"]'));
19+
var targets = links.map(function (a) { return document.getElementById(safeId(a.getAttribute('href'))) }).filter(Boolean);
20+
if (targets.length === 0) return;
21+
22+
var offsets = new Map();
23+
var visible = new Set();
24+
var first = true;
25+
var tocContainsOverscroll = getComputedStyle(toc).overscrollBehaviorY === 'contain';
26+
27+
function setActive(activeEl) {
28+
links.forEach(function (a) { a.style.fontWeight = '' });
29+
if (!activeEl) return;
30+
var selector = 'a[href="#' + activeEl.id + '"]';
31+
var link = toc.querySelector(selector);
32+
if (link) {
33+
link.style.fontWeight = 'bold';
34+
if (tocContainsOverscroll) {
35+
clearTimeout(link.__tocScrollTimer);
36+
link.__tocScrollTimer = setTimeout(function () {
37+
if (toc.classList.contains('affix')) link.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });
38+
}, 100);
39+
}
40+
}
41+
}
42+
43+
var observer = new IntersectionObserver(function (entries) {
44+
if (first) {
45+
targets.forEach(function (t) { offsets.set(t, t.getBoundingClientRect().top + window.pageYOffset); });
46+
first = false;
47+
}
48+
entries.forEach(function (entry) {
49+
var el = entry.target;
50+
if (entry.isIntersecting) visible.add(el); else visible.delete(el);
51+
});
52+
if (visible.size === 0) { setActive(null); return; }
53+
var active = null;
54+
visible.forEach(function (el) { if (!active || offsets.get(el) < offsets.get(active)) active = el; });
55+
setActive(active);
56+
}, { root: null, threshold: [0, 0.1, 0.5, 1] });
57+
58+
targets.forEach(function (t) { observer.observe(t) });
59+
window.addEventListener('unload', function () { observer.disconnect(); sentObs.disconnect(); });
60+
});
61+
})();

0 commit comments

Comments
 (0)