100 lines
3.9 KiB
JavaScript
100 lines
3.9 KiB
JavaScript
(function () {
|
|
const nav = document.getElementById('sidebar-nav');
|
|
const wrap = document.getElementById('sidebar-nav-wrap');
|
|
const track = document.getElementById('sb-track');
|
|
const thumb = document.getElementById('sb-thumb');
|
|
if (!nav || !track || !thumb || !wrap) return;
|
|
let isDragging = false;
|
|
function show() { track.style.opacity = '1'; }
|
|
function hide() { if (!isDragging) track.style.opacity = '0'; }
|
|
function update() {
|
|
const sh = nav.scrollHeight, ch = nav.clientHeight;
|
|
if (sh <= ch) { track.style.display = 'none'; return; }
|
|
track.style.display = 'block'; track.style.opacity = '1';
|
|
const st = nav.scrollTop, th = Math.max((ch / sh) * ch, 24);
|
|
const maxTop = ch - th, ratio = sh > ch ? st / (sh - ch) : 0;
|
|
thumb.style.height = th + 'px'; thumb.style.top = (ratio * maxTop) + 'px';
|
|
}
|
|
const observer = new MutationObserver(function () {
|
|
update(); setTimeout(function () {
|
|
update();
|
|
if (nav.scrollHeight > nav.clientHeight) { track.style.display = 'block'; track.style.opacity = '1'; }
|
|
}, 350);
|
|
});
|
|
observer.observe(nav, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
|
|
nav.addEventListener('scroll', update); window.addEventListener('resize', update);
|
|
wrap.addEventListener('mouseenter', function () { show(); update(); });
|
|
wrap.addEventListener('mouseleave', hide);
|
|
thumb.addEventListener('mousedown', function (e) {
|
|
e.preventDefault(); isDragging = true; track.style.opacity = '1';
|
|
document.body.style.cursor = 'pointer'; document.body.style.userSelect = 'none';
|
|
function onMove(ev) {
|
|
if (!isDragging) return;
|
|
const rect = track.getBoundingClientRect();
|
|
nav.scrollTop = ((ev.clientY - rect.top) / rect.height) * (nav.scrollHeight - nav.clientHeight);
|
|
}
|
|
function onUp() {
|
|
isDragging = false; document.body.style.cursor = ''; document.body.style.userSelect = '';
|
|
document.removeEventListener('mousemove', onMove); document.removeEventListener('mouseup', onUp);
|
|
}
|
|
document.addEventListener('mousemove', onMove); document.addEventListener('mouseup', onUp);
|
|
});
|
|
update(); setTimeout(update, 300);
|
|
|
|
nav.querySelectorAll('.submenu-group:not(.open) > .submenu-body').forEach(function (b) {
|
|
b.style.maxHeight = '0px';
|
|
});
|
|
|
|
function setBodyHeight(group) {
|
|
const body = group.querySelector(':scope > .submenu-body');
|
|
if (!body) return;
|
|
if (group.classList.contains('open')) {
|
|
body.style.maxHeight = body.scrollHeight + 'px';
|
|
} else {
|
|
body.style.maxHeight = '0px';
|
|
}
|
|
}
|
|
|
|
nav.addEventListener('transitionend', function (e) {
|
|
if (!e.target.classList || !e.target.classList.contains('submenu-body')) return;
|
|
if (e.propertyName !== 'max-height') return;
|
|
if (e.target.style.maxHeight !== '0px') {
|
|
e.target.style.maxHeight = 'none';
|
|
}
|
|
});
|
|
|
|
nav.addEventListener('click', function (e) {
|
|
const head = e.target.closest('.submenu-head');
|
|
if (!head) return;
|
|
const group = head.parentElement;
|
|
if (group && group.classList.contains('submenu-group')) {
|
|
group.classList.toggle('open');
|
|
setBodyHeight(group);
|
|
update();
|
|
}
|
|
});
|
|
|
|
function activateCurrent() {
|
|
const currentPage = window.location.pathname.split('/').pop();
|
|
if (!currentPage) return;
|
|
const activeLink = nav.querySelector('a[href="' + currentPage + '"]');
|
|
if (!activeLink) return;
|
|
activeLink.classList.add('active');
|
|
let node = activeLink.parentElement;
|
|
while (node && node !== nav) {
|
|
if (node.classList && node.classList.contains('submenu-group')) {
|
|
node.classList.add('open');
|
|
setBodyHeight(node);
|
|
}
|
|
node = node.parentElement;
|
|
}
|
|
update();
|
|
requestAnimationFrame(function () { activeLink.scrollIntoView({ block: 'nearest' }); });
|
|
}
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', activateCurrent);
|
|
} else {
|
|
activateCurrent();
|
|
}
|
|
})();
|