// Void 2.0 SPA bootstrap. Mounts chrome (sidebar/topbar/rightrail) and // delegates the #main panel to a view module based on the current route. // Views are loaded dynamically so a missing view never breaks the shell. import { api } from './api.js'; import { route, current, navigate } from './router.js'; import { renderSidebar } from './components/sidebar.js'; import { renderTopbar } from './components/topbar.js'; import { renderRightrail } from './components/rightrail.js'; import { emit } from './state.js'; import { el, mount } from './dom.js'; import { attachDropzone } from './components/dropzone.js'; const VIEWS = { home: () => import('./views/home.js'), space: () => import('./views/space.js'), project: () => import('./views/project.js'), page: () => import('./views/page.js'), ref: () => import('./views/reference.js'), resource: () => import('./views/resource.js'), search: () => import('./views/search.js'), inbox: () => import('./views/inbox.js'), 'sacred-valley': () => import('./views/sacred_valley.js'), jobs: () => import('./views/jobs.js') }; async function renderView(ctx) { const main = document.getElementById('main'); const loader = VIEWS[ctx.name] || VIEWS.home; try { const mod = await loader(); await mod.render(main, ctx); } catch (e) { console.error('view render failed', e); mount(main, el('h1', { class: 'view-h1' }, 'Something went wrong'), el('p', { class: 'view-sub' }, 'View failed to load. Check console for details.'), el('pre', {}, String(e && e.stack || e)) ); } } async function pollPending() { try { const rows = await api.get('/api/pending-changes'); emit('pending-count', rows.length); } catch (e) { if (e.status === 403) emit('pending-count', 0); } } async function init() { if (!api.hasToken()) { try { await api.get('/api/spaces'); } catch { /* api wrapper opens the modal on 401 */ } } renderTopbar(document.getElementById('topbar')); renderSidebar(document.getElementById('sidebar')); renderRightrail(document.getElementById('rightrail')); attachDropzone(document.getElementById('main')); route(renderView); pollPending(); setInterval(pollPending, 15000); } window.addEventListener('DOMContentLoaded', init); window.voidNav = navigate; // dev convenience: window.voidNav('/space/abc')