124 lines
3.6 KiB
JavaScript
124 lines
3.6 KiB
JavaScript
// 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 = '';
|
|
}
|
|
}
|
|
|