- Left sidebar collapses (topbar menu button); rail collapses (topbar button + strip). - <=860px / portrait: sidebar + rail become off-canvas drawers over main with a scrim, closed by default; main goes full-width single-column. - Smooth transitions; crossing the breakpoint resets to a sane default. - New components/chrome.js owns toggle + drawer state. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.1 KiB
JavaScript
57 lines
2.1 KiB
JavaScript
// Topbar: brand, global search (Enter → /search?q=), capture button stub,
|
|
// pending bell with badge, user/agent toggle stub.
|
|
|
|
import { el, mount, clear } from '../dom.js';
|
|
import { navigate } from '../router.js';
|
|
import { on } from '../state.js';
|
|
import { toggleSidebar, toggleRail } from './chrome.js';
|
|
|
|
function captureModal() {
|
|
const root = document.getElementById('modal-root');
|
|
mount(root,
|
|
el('div', { class: 'modal-backdrop', onclick: (e) => { if (e.target.classList.contains('modal-backdrop')) clear(root); } },
|
|
el('div', { class: 'modal' },
|
|
el('h2', {}, 'Universal Capture'),
|
|
el('p', { class: 'muted' },
|
|
'Drag a URL, paste a YouTube link, drop a PDF. ' +
|
|
'Plan 3 wires the capture queue + workers — this surface is here so the UX shape is honest about what is coming.'
|
|
),
|
|
el('div', { class: 'actions' },
|
|
el('button', { class: 'ghost', onclick: () => clear(root) }, 'Close')
|
|
)
|
|
)
|
|
)
|
|
);
|
|
}
|
|
|
|
export function renderTopbar(root) {
|
|
const searchInput = el('input', {
|
|
type: 'text',
|
|
placeholder: 'Search … (Enter to search)',
|
|
onkeydown: (e) => {
|
|
if (e.key === 'Enter' && e.target.value.trim()) {
|
|
navigate('/search?q=' + encodeURIComponent(e.target.value.trim()));
|
|
}
|
|
}
|
|
});
|
|
|
|
const bell = el('button', { class: 'icon-btn', onclick: () => navigate('/inbox') }, 'Inbox');
|
|
|
|
mount(root,
|
|
el('button', { class: 'chrome-toggle', title: 'Toggle menu', onclick: toggleSidebar }, '☰'),
|
|
el('div', { class: 'brand' }, 'VOID'),
|
|
el('button', { class: 'icon-btn', onclick: captureModal }, '+ Capture'),
|
|
el('div', { class: 'topbar-search' }, searchInput),
|
|
el('div', { class: 'topbar-spacer' }),
|
|
bell,
|
|
el('button', { class: 'chrome-toggle', title: 'Toggle companion chat', onclick: toggleRail }, '◆'),
|
|
el('button', { class: 'icon-btn', onclick: () => alert('Agent-switching ships post-Plan-2.') }, 'Owner')
|
|
);
|
|
|
|
on('pending-count', (n) => {
|
|
const old = bell.querySelector('.badge');
|
|
if (old) old.remove();
|
|
if (n > 0) bell.appendChild(el('span', { class: 'badge' }, String(n)));
|
|
});
|
|
}
|