Files
basecoat/src/js/sidebar.js
T

110 lines
3.7 KiB
JavaScript
Raw Normal View History

2025-06-12 10:37:19 +08:00
(() => {
2025-06-13 14:14:38 +08:00
// Monkey patching the history API to detect client-side navigation
if (!window.history.__basecoatPatched) {
const originalPushState = window.history.pushState;
window.history.pushState = function(...args) {
originalPushState.apply(this, args);
window.dispatchEvent(new Event('basecoat:locationchange'));
};
const originalReplaceState = window.history.replaceState;
window.history.replaceState = function(...args) {
originalReplaceState.apply(this, args);
window.dispatchEvent(new Event('basecoat:locationchange'));
};
window.history.__basecoatPatched = true;
}
2025-06-12 10:37:19 +08:00
const initSidebar = (sidebarComponent) => {
const initialOpen = sidebarComponent.dataset.initialOpen !== 'false';
const initialMobileOpen = sidebarComponent.dataset.initialMobileOpen === 'true';
const breakpoint = parseInt(sidebarComponent.dataset.breakpoint) || 768;
let open = breakpoint > 0
? (window.innerWidth >= breakpoint ? initialOpen : initialMobileOpen)
: initialOpen;
2025-06-13 14:14:38 +08:00
const updateCurrentPageLinks = () => {
const currentPath = window.location.pathname.replace(/\/$/, '');
sidebarComponent.querySelectorAll('a').forEach(link => {
if (link.hasAttribute('data-ignore-current')) return;
const linkPath = new URL(link.href).pathname.replace(/\/$/, '');
if (linkPath === currentPath) {
link.setAttribute('aria-current', 'page');
} else {
link.removeAttribute('aria-current');
}
});
};
2025-06-12 10:37:19 +08:00
const updateState = () => {
sidebarComponent.setAttribute('aria-hidden', !open);
if (open) {
sidebarComponent.removeAttribute('inert');
} else {
sidebarComponent.setAttribute('inert', '');
}
};
2025-05-02 18:27:45 +08:00
2025-06-12 10:37:19 +08:00
const setState = (state) => {
open = state;
updateState();
};
2025-05-02 18:27:45 +08:00
2025-06-12 10:37:19 +08:00
const sidebarId = sidebarComponent.id;
window.addEventListener('sidebar:open', (e) => {
if (!e.detail?.id || e.detail.id === sidebarId) setState(true);
});
window.addEventListener('sidebar:close', (e) => {
if (!e.detail?.id || e.detail.id === sidebarId) setState(false);
});
window.addEventListener('sidebar:toggle', (e) => {
if (!e.detail?.id || e.detail.id === sidebarId) setState(!open);
});
sidebarComponent.addEventListener('click', (e) => {
2025-06-13 14:14:38 +08:00
const target = e.target;
2025-06-12 10:37:19 +08:00
const nav = sidebarComponent.querySelector('nav');
2025-06-13 14:14:38 +08:00
const isMobile = window.innerWidth < breakpoint;
2025-06-14 16:48:01 +08:00
if (isMobile && (target.closest('a, button') && !target.closest('[data-keep-mobile-sidebar-open]'))) {
2025-06-13 14:14:38 +08:00
if (document.activeElement) document.activeElement.blur();
2025-06-12 10:37:19 +08:00
setState(false);
2025-06-13 14:14:38 +08:00
return;
}
if (target === sidebarComponent || (nav && !nav.contains(target))) {
if (document.activeElement) document.activeElement.blur();
2025-06-12 10:37:19 +08:00
setState(false);
}
});
2025-06-13 14:14:38 +08:00
window.addEventListener('popstate', updateCurrentPageLinks);
window.addEventListener('basecoat:locationchange', updateCurrentPageLinks);
2025-06-12 10:37:19 +08:00
updateState();
2025-06-13 14:14:38 +08:00
updateCurrentPageLinks();
2025-06-12 10:37:19 +08:00
sidebarComponent.dataset.sidebarInitialized = true;
};
document.querySelectorAll('.sidebar:not([data-sidebar-initialized])').forEach(initSidebar);
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === Node.ELEMENT_NODE) {
if (node.matches('.sidebar:not([data-sidebar-initialized])')) {
initSidebar(node);
}
node.querySelectorAll('.sidebar:not([data-sidebar-initialized])').forEach(initSidebar);
}
2025-05-04 15:58:10 +08:00
});
2025-06-12 10:37:19 +08:00
});
});
2025-05-02 18:27:45 +08:00
2025-06-12 10:37:19 +08:00
observer.observe(document.body, { childList: true, subtree: true });
})();