|
|
|
|
|
|
|
|
|
|
|
|
|
|
class SidebarManager {
|
|
|
constructor() {
|
|
|
this.sidebar = null;
|
|
|
this.toggleBtn = null;
|
|
|
this.overlay = null;
|
|
|
this.isCollapsed = false;
|
|
|
this.isMobile = window.innerWidth <= 1024;
|
|
|
|
|
|
this.init();
|
|
|
}
|
|
|
|
|
|
init() {
|
|
|
|
|
|
if (document.readyState === 'loading') {
|
|
|
document.addEventListener('DOMContentLoaded', () => this.setup());
|
|
|
} else {
|
|
|
this.setup();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
setup() {
|
|
|
this.sidebar = document.getElementById('sidebar-modern') || document.querySelector('.sidebar-modern');
|
|
|
this.toggleBtn = document.getElementById('sidebar-collapse-btn');
|
|
|
this.overlay = document.getElementById('sidebar-overlay-modern') || document.querySelector('.sidebar-overlay-modern');
|
|
|
|
|
|
if (!this.sidebar) {
|
|
|
console.warn('Sidebar not found');
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
|
|
|
this.loadState();
|
|
|
|
|
|
|
|
|
this.setupEventListeners();
|
|
|
|
|
|
|
|
|
this.handleResize();
|
|
|
}
|
|
|
|
|
|
setupEventListeners() {
|
|
|
|
|
|
if (this.toggleBtn) {
|
|
|
this.toggleBtn.addEventListener('click', () => this.toggle());
|
|
|
}
|
|
|
|
|
|
|
|
|
if (this.overlay) {
|
|
|
this.overlay.addEventListener('click', () => this.close());
|
|
|
}
|
|
|
|
|
|
|
|
|
window.addEventListener('resize', () => this.handleResize());
|
|
|
|
|
|
|
|
|
document.addEventListener('keydown', (e) => {
|
|
|
if (e.key === 'Escape' && this.isMobile && this.sidebar.classList.contains('open')) {
|
|
|
this.close();
|
|
|
}
|
|
|
});
|
|
|
|
|
|
|
|
|
const navLinks = this.sidebar.querySelectorAll('.nav-link-modern');
|
|
|
navLinks.forEach(link => {
|
|
|
link.addEventListener('click', () => {
|
|
|
if (this.isMobile) {
|
|
|
this.close();
|
|
|
}
|
|
|
});
|
|
|
});
|
|
|
|
|
|
|
|
|
this.setActivePage();
|
|
|
}
|
|
|
|
|
|
toggle() {
|
|
|
if (this.isMobile) {
|
|
|
|
|
|
this.sidebar.classList.toggle('open');
|
|
|
this.overlay?.classList.toggle('active');
|
|
|
} else {
|
|
|
|
|
|
this.isCollapsed = !this.isCollapsed;
|
|
|
this.sidebar.classList.toggle('collapsed');
|
|
|
this.saveState();
|
|
|
|
|
|
|
|
|
window.dispatchEvent(new CustomEvent('sidebar-toggle', {
|
|
|
detail: { collapsed: this.isCollapsed }
|
|
|
}));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
open() {
|
|
|
if (this.isMobile) {
|
|
|
this.sidebar.classList.add('open');
|
|
|
this.overlay?.classList.add('active');
|
|
|
document.body.style.overflow = 'hidden';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
close() {
|
|
|
if (this.isMobile) {
|
|
|
this.sidebar.classList.remove('open');
|
|
|
this.overlay?.classList.remove('active');
|
|
|
document.body.style.overflow = '';
|
|
|
}
|
|
|
}
|
|
|
|
|
|
collapse() {
|
|
|
if (!this.isMobile && !this.isCollapsed) {
|
|
|
this.isCollapsed = true;
|
|
|
this.sidebar.classList.add('collapsed');
|
|
|
this.saveState();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
expand() {
|
|
|
if (!this.isMobile && this.isCollapsed) {
|
|
|
this.isCollapsed = false;
|
|
|
this.sidebar.classList.remove('collapsed');
|
|
|
this.saveState();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
handleResize() {
|
|
|
const wasMobile = this.isMobile;
|
|
|
this.isMobile = window.innerWidth <= 1024;
|
|
|
|
|
|
|
|
|
if (wasMobile !== this.isMobile) {
|
|
|
|
|
|
if (!this.isMobile) {
|
|
|
this.sidebar.classList.remove('open');
|
|
|
this.overlay?.classList.remove('active');
|
|
|
document.body.style.overflow = '';
|
|
|
|
|
|
|
|
|
if (this.isCollapsed) {
|
|
|
this.sidebar.classList.add('collapsed');
|
|
|
}
|
|
|
} else {
|
|
|
|
|
|
this.sidebar.classList.remove('collapsed');
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
setActivePage() {
|
|
|
|
|
|
const path = window.location.pathname;
|
|
|
const pageName = this.getPageNameFromPath(path);
|
|
|
|
|
|
if (!pageName) return;
|
|
|
|
|
|
|
|
|
const navLinks = this.sidebar.querySelectorAll('.nav-link-modern');
|
|
|
navLinks.forEach(link => {
|
|
|
link.classList.remove('active');
|
|
|
link.removeAttribute('aria-current');
|
|
|
});
|
|
|
|
|
|
|
|
|
const activeLink = this.sidebar.querySelector(`[data-page="${pageName}"]`);
|
|
|
if (activeLink) {
|
|
|
activeLink.classList.add('active');
|
|
|
activeLink.setAttribute('aria-current', 'page');
|
|
|
}
|
|
|
}
|
|
|
|
|
|
getPageNameFromPath(path) {
|
|
|
|
|
|
|
|
|
const match = path.match(/\/pages\/([^\/]+)\//);
|
|
|
return match ? match[1] : null;
|
|
|
}
|
|
|
|
|
|
saveState() {
|
|
|
try {
|
|
|
localStorage.setItem('sidebar_collapsed', JSON.stringify(this.isCollapsed));
|
|
|
} catch (error) {
|
|
|
console.warn('Failed to save sidebar state:', error);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
loadState() {
|
|
|
try {
|
|
|
const saved = localStorage.getItem('sidebar_collapsed');
|
|
|
if (saved !== null) {
|
|
|
this.isCollapsed = JSON.parse(saved);
|
|
|
if (this.isCollapsed && !this.isMobile) {
|
|
|
this.sidebar.classList.add('collapsed');
|
|
|
}
|
|
|
}
|
|
|
} catch (error) {
|
|
|
console.warn('Failed to load sidebar state:', error);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
getState() {
|
|
|
return {
|
|
|
isCollapsed: this.isCollapsed,
|
|
|
isMobile: this.isMobile,
|
|
|
isOpen: this.sidebar?.classList.contains('open') || false
|
|
|
};
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
const sidebarManager = new SidebarManager();
|
|
|
|
|
|
|
|
|
if (typeof module !== 'undefined' && module.exports) {
|
|
|
module.exports = sidebarManager;
|
|
|
}
|
|
|
|
|
|
export default sidebarManager;
|
|
|
|
|
|
|