initial commit
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
(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; // includes leading slash, matches href="/..."
|
||||
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();
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user