// SPDX-License-Identifier: MIT // The field's Responses menu: every response window at once — new, tile, cascade, call home, clear, close all — and // the settings they share (text size, where answers go, open filling the screen). Each window also fills the screen // on a double-click of its header (⤢), and shrinks back on another (or Esc). import { useEffect, useRef, useState } from 'react'; import { useUIF } from './UIFContext'; import { responseSettings, type ResponseSettings } from '../core/responseSettings'; export function ResponsesMenu() { const { outputs } = useUIF(); const [open, setOpen] = useState(false); const [s, setS] = useState(responseSettings.get()); const ref = useRef(null); useEffect(() => responseSettings.subscribe(setS), []); useEffect(() => { if (!open) return; const onDown = (e: PointerEvent) => { if (!ref.current?.contains(e.target as Node)) setOpen(false); }; document.addEventListener('pointerdown', onDown); return () => document.removeEventListener('pointerdown', onDown); }, [open]); const list = outputs.list(); const n = list.length; const active = list.find(o => o.id === outputs.activeId); const act = (f: () => void) => () => { f(); setOpen(false); }; const set = (c: Partial) => responseSettings.set(c); const item = (label: string, hint: string, f: () => void, disabled = false, danger = false) => ( ); return (
{open && (
e.key === 'Escape' && setOpen(false)}>
Response windows · {n} open
{item('New window', 'spawn', () => { const id = outputs.spawn(); if (s.openMaximized) outputs.maximize(id, true); })} {item('Tile', 'fill the screen, side by side', () => outputs.tile(), n === 0)} {item('Cascade', 'stacked, a step apart', () => outputs.cascade(), n === 0)} {item('Call all home', 'back beside the field', () => outputs.callHome('all'), n === 0)} {item(active?.maximized ? 'Shrink back' : 'Fill the screen', active ? `the active one: ${active.title}` : 'no active window', () => active && outputs.maximize(active.id), !active)} {item('Clear all', 'empty every window', () => outputs.clearAll(), n === 0)} {item('Close all', `${n} window${n === 1 ? '' : 's'}`, () => outputs.closeAll(), n === 0, true)}
Settings
Text {(['s', 'm', 'l', 'xl'] as const).map(k => ( ))}
Answers
double-click a window's header: fill the screen / shrink back · Esc shrinks · T mode: close all, tile, cascade, max
)}
); }