This commit is contained in:
2025-11-16 18:01:30 +01:00
commit 858003cb0b
26 changed files with 4712 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
// Sidebar Component
export class Sidebar {
constructor() {
this.sidebar = document.getElementById('sidebar');
this.resizeHandle = document.getElementById('resizeHandle');
this.menuToggle = null;
this.isResizing = false;
this.startX = 0;
this.startWidth = 0;
this.init();
}
init() {
this.createMenuToggle();
this.setupResize();
this.setupMobileBehavior();
}
createMenuToggle() {
// Create mobile menu toggle button
this.menuToggle = document.createElement('button');
this.menuToggle.className = 'mobile-menu-toggle';
this.menuToggle.innerHTML = '☰';
this.menuToggle.setAttribute('aria-label', 'Toggle menu');
this.menuToggle.addEventListener('click', (e) => {
e.stopPropagation();
this.toggleMobile();
});
// Create overlay for mobile
this.overlay = document.createElement('div');
this.overlay.className = 'sidebar-overlay';
this.overlay.addEventListener('click', () => this.closeMobile());
// Insert at the beginning of body
document.body.insertBefore(this.menuToggle, document.body.firstChild);
document.body.appendChild(this.overlay);
}
setupResize() {
if (!this.resizeHandle || !this.sidebar) return;
this.resizeHandle.addEventListener('mousedown', (e) => {
if (window.innerWidth <= 768) return; // Disable resize on mobile
this.isResizing = true;
this.startX = e.clientX;
this.startWidth = parseInt(window.getComputedStyle(this.sidebar).width, 10);
document.addEventListener('mousemove', this.handleResize.bind(this));
document.addEventListener('mouseup', this.stopResize.bind(this));
e.preventDefault();
});
}
handleResize(e) {
if (!this.isResizing) return;
const width = this.startWidth + e.clientX - this.startX;
const minWidth = 200;
const maxWidth = 600;
if (width >= minWidth && width <= maxWidth) {
this.sidebar.style.width = `${width}px`;
document.documentElement.style.setProperty('--sidebar-width', `${width}px`);
}
}
stopResize() {
this.isResizing = false;
document.removeEventListener('mousemove', this.handleResize);
document.removeEventListener('mouseup', this.stopResize);
}
setupMobileBehavior() {
// Close sidebar on window resize if switching to desktop
window.addEventListener('resize', () => {
if (window.innerWidth > 768) {
this.closeMobile();
}
});
// Close sidebar when clicking on module items or search button on mobile
if (this.sidebar) {
this.sidebar.addEventListener('click', (e) => {
if (window.innerWidth <= 768) {
// Close if clicking on interactive elements (but not the toggle itself)
if (e.target.closest('.module-item') ||
e.target.closest('.search-btn') ||
e.target.closest('.nav-tab')) {
// Small delay to allow the click to register
setTimeout(() => this.closeMobile(), 100);
}
}
});
}
}
toggleMobile() {
const isOpen = this.sidebar?.classList.contains('open');
if (isOpen) {
this.closeMobile();
} else {
this.openMobile();
}
}
openMobile() {
this.sidebar?.classList.add('open');
if (this.overlay) {
this.overlay.classList.add('active');
}
// Prevent body scroll when sidebar is open
document.body.style.overflow = 'hidden';
}
closeMobile() {
this.sidebar?.classList.remove('open');
if (this.overlay) {
this.overlay.classList.remove('active');
}
// Restore body scroll
document.body.style.overflow = '';
}
}