// ============================================ // Sidebar — Tree Navigation Component // ============================================ const Sidebar = { init() { this.renderTree(); this.bindEvents(); this.updateStats(); }, bindEvents() { // Tree node toggles and selection (delegated for dynamic content) Helpers.$('#tree-root').addEventListener('click', (e) => { const header = e.target.closest('.tree-node__header'); if (!header) return; const nodeId = header.dataset.nodeId; const node = MockData.findNodeInHierarchy(nodeId); const isExpanded = Helpers.$('#children-' + nodeId)?.classList.contains('tree-node__children--expanded'); // If camera node clicked, open gallery with filter if (node && node.type === 'camera') { this.openGalleryForCamera(nodeId, node); return; } // Toggle expand/collapse for non-camera nodes this.toggleNode(header); }); }, openGalleryForCamera(nodeId, node) { // Navigate to gallery view App.navigate('gallery'); // Expand parent nodes to show selected camera this.expandToNode(nodeId); // Set active sidebar node Helpers.$$('#tree-root .tree-node__header--active') .forEach(h => h.classList.remove('tree-node__header--active')); Helpers.$(`[data-node-id="${nodeId}"]`)?.classList.add('tree-node__header--active'); // Update breadcrumb const breadcrumb = Helpers.buildBreadcrumb(nodeId); const breadcrumbEl = Helpers.$('#gallery-breadcrumb'); if (breadcrumbEl) breadcrumbEl.textContent = breadcrumb; // Filter gallery by camera if (Gallery && Gallery.filters) { Gallery.filters.camera = node.name; Gallery.filters.category = ''; Gallery.filters.search = ''; // Update select elements const cameraSelect = Helpers.$('#gallery-filter-camera'); if (cameraSelect) cameraSelect.value = node.name; const categorySelect = Helpers.$('#gallery-filter-category'); if (categorySelect) categorySelect.value = ''; Gallery.renderGrid(); } }, expandToNode(nodeId) { // Expand all parent nodes to show the selected camera const parts = nodeId.split('-'); let currentId = parts[0]; for (let i = 1; i < parts.length; i++) { currentId += '-' + parts[i]; const childrenEl = Helpers.$('#children-' + currentId); const toggleEl = Helpers.$(`[data-toggle-for="${currentId}"]`); if (childrenEl && !childrenEl.classList.contains('tree-node__children--expanded')) { childrenEl.classList.add('tree-node__children--expanded'); toggleEl?.classList.add('tree-node__toggle--expanded'); } } }, renderTree() { const root = Helpers.$('#tree-root'); if (!root) return; root.innerHTML = this.buildTreeHTML(MockData.hierarchy); }, buildTreeHTML(nodes, depth = 0) { let html = ''; nodes.forEach(node => { const childCount = node.children ? node.children.length : 0; const imageCount = this.getImageCount(node.id); const hasChildren = childCount > 0; const nodeId = node.id; html += `