anvilsign in

collin/strudel-claude

pre-demo / src / panel.js
1// The three settings popovers (theme, model, API key) all behave the same way:
2// a chip toggles a panel, clicking outside or pressing Escape closes it, and
3// opening one closes the others. That last part matters now that the model and
4// key panels are anchored side by side in the chat header — they occupy the
5// same strip, so two open at once would stack.
6//
7// Registered panels are tracked here rather than broadcast on the DOM, since
8// they're all bound at startup and never move.
9const panels = [];
10
11/**
12 * Wire a chip to its panel. `onOpen` runs after the panel is shown — use it to
13 * seed fields or move focus.
14 */
15export function bindPanel(button, panel, onOpen) {
16 const toggle = (open) => {
17 panel.hidden = !open;
18 button.setAttribute('aria-expanded', String(open));
19 if (open) onOpen?.();
20 };
21 panels.push(toggle);
22
23 button.addEventListener('click', (e) => {
24 e.stopPropagation();
25 if (button.disabled) return;
26 const open = panel.hidden;
27 closeAll();
28 toggle(open);
29 });
30 // Clicks inside a panel are for the controls in it, not a signal to dismiss.
31 panel.addEventListener('click', (e) => e.stopPropagation());
32}
33
34export function closeAll() {
35 for (const toggle of panels) toggle(false);
36}
37
38document.addEventListener('click', closeAll);
39document.addEventListener('keydown', (e) => {
40 if (e.key === 'Escape') closeAll();
41});