// Collapsible chrome controller: left sidebar + right companion rail. // Desktop → panels shrink the grid (state persisted). Narrow/portrait → panels // become off-canvas drawers over the main area with a scrim; closed by default. // // State lives as classes on #shell: `sidebar-collapsed` / `rail-collapsed`. // rightrail.js also toggles `rail-collapsed` (its own strip) + the same key, so // a MutationObserver keeps the scrim in sync no matter who toggles. const SB_KEY = 'void_sidebar_collapsed'; const RAIL_KEY = 'void_rail_collapsed'; const shell = () => document.getElementById('shell'); const isNarrow = () => window.matchMedia('(max-width: 860px)').matches; function syncScrim() { const s = shell(); if (!s) return; const anyOpen = isNarrow() && (!s.classList.contains('sidebar-collapsed') || !s.classList.contains('rail-collapsed')); document.body.classList.toggle('drawer-open', anyOpen); } export function toggleSidebar() { const s = shell(); const opening = s.classList.contains('sidebar-collapsed'); s.classList.toggle('sidebar-collapsed'); if (opening && isNarrow()) s.classList.add('rail-collapsed'); // one drawer at a time if (!isNarrow()) localStorage.setItem(SB_KEY, String(!opening)); } export function toggleRail() { const s = shell(); const opening = s.classList.contains('rail-collapsed'); s.classList.toggle('rail-collapsed'); if (opening && isNarrow()) s.classList.add('sidebar-collapsed'); localStorage.setItem(RAIL_KEY, String(!opening)); } function closeDrawers() { shell().classList.add('sidebar-collapsed', 'rail-collapsed'); } export function initChrome() { const s = shell(); if (!s) return; if (!document.getElementById('scrim')) { const scrim = document.createElement('div'); scrim.id = 'scrim'; scrim.addEventListener('click', closeDrawers); document.body.appendChild(scrim); } // Initial state. if (isNarrow()) { s.classList.add('sidebar-collapsed', 'rail-collapsed'); // drawers closed on phones/portrait } else if (localStorage.getItem(SB_KEY) === 'true') { s.classList.add('sidebar-collapsed'); // restore desktop preference (rail handled by rightrail.js) } // Keep the scrim correct whenever shell classes change (covers rightrail's own toggle). new MutationObserver(syncScrim).observe(s, { attributes: true, attributeFilter: ['class'] }); // Crossing the breakpoint: collapse to a sane default for the new mode. let wasNarrow = isNarrow(); window.addEventListener('resize', () => { const narrow = isNarrow(); if (narrow === wasNarrow) return; wasNarrow = narrow; if (narrow) closeDrawers(); else s.classList.remove('sidebar-collapsed'); // show the sidebar again on desktop syncScrim(); }); syncScrim(); }