Skip to content

Commit 96a1d57

Browse files
committed
ux: auto-scroll active TOC in drawer
1 parent 79dbcff commit 96a1d57

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

docs/_layouts/book.html

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,5 +218,67 @@ <h1>{{ site.title | escape }}</h1>
218218
});
219219
</script>
220220

221+
<script>
222+
// Auto-scroll active TOC into view when opening the drawer.
223+
document.addEventListener('DOMContentLoaded', function() {
224+
var cb = document.getElementById('sidebar-toggle-checkbox');
225+
if (!cb) return;
226+
227+
function normalizePath(p) {
228+
var path = String(p || '').replace(/index\.html$/, '');
229+
if (path.length > 1) {
230+
path = path.replace(/\/+$/, '');
231+
}
232+
return path || '/';
233+
}
234+
235+
function findActiveTocLink() {
236+
var current = normalizePath(window.location.pathname);
237+
var actives = document.querySelectorAll('a.toc-link.active');
238+
if (!actives || actives.length === 0) return null;
239+
240+
for (var i = 0; i < actives.length; i++) {
241+
try {
242+
var a = actives[i];
243+
var pathname = normalizePath(new URL(a.href, window.location.origin).pathname);
244+
if (pathname === current) return a;
245+
} catch (_) {}
246+
}
247+
return actives[0];
248+
}
249+
250+
function ensureActiveTocVisible() {
251+
// If the drawer is closed while we are scheduled, do nothing.
252+
if (!cb.checked) return;
253+
254+
var active = findActiveTocLink();
255+
if (!active) return;
256+
257+
var sidebar = active.closest('.book-sidebar') || document.getElementById('sidebar');
258+
if (!sidebar) return;
259+
260+
try {
261+
var linkRect = active.getBoundingClientRect();
262+
var sidebarRect = sidebar.getBoundingClientRect();
263+
var margin = 8;
264+
var top = sidebarRect.top + margin;
265+
var bottom = sidebarRect.bottom - margin;
266+
// Scroll when any part of the active link is outside the visible bounds.
267+
var outOfView = linkRect.top < top || linkRect.bottom > bottom;
268+
269+
if (outOfView && typeof active.scrollIntoView === 'function') {
270+
active.scrollIntoView({ block: 'center', behavior: 'auto' });
271+
}
272+
} catch (_) {}
273+
}
274+
275+
cb.addEventListener('change', function() {
276+
if (!cb.checked) return;
277+
// Wait a tick for CSS to apply and the sidebar to become visible.
278+
setTimeout(ensureActiveTocVisible, 0);
279+
});
280+
});
281+
</script>
282+
221283
</body>
222284
</html>

0 commit comments

Comments
 (0)