// The sheet of the simulation. What Java opens as a window of its own — a // computer's desktop, a switch's or home router's table, the data exchange — // opens here as the dashboard's sheet does (its AppSheet), not as a window in // the window: over the surface, below the toolbar (the mode buttons stay in // reach), with a head — icon, title, who else has it open, ×. One at a time: // it covers the surface, so another is opened once it is closed. // // Beyond the dashboard's sheet: „Durchsichtig“ lets the network show through // the sheet (the cables light up while one types a ping), the sheet still // takes the pointer. The choice is the person's, kept in this browser. import { useCallback, useState, type ReactNode } from "react"; import { useTranslate } from "../i18n/i18n.js"; import { WindowWatchers } from "../remote/PresenceMarks.js"; import type { PresenceUser } from "../remote/presence.js"; /** What every sheet of the simulation gets from the editor: where it begins, whether it is see-through, how it closes, who else has it open. */ export interface SheetFrame { /** Its top edge in the editor's area: below the toolbar. */ readonly top: number; readonly seeThrough: boolean; readonly onSeeThrough: (on: boolean) => void; readonly onClose: () => void; /** Who else in the project has it open (plan §7.4). */ readonly watchers?: readonly PresenceUser[] | undefined; } export interface SimulationSheetProps { readonly frame: SheetFrame; readonly title: string; readonly icon?: string; /** Marks for what it shows (`data-desktop`, `data-viewer`, `data-capture`). */ readonly attributes: Readonly>; readonly className?: string; readonly children: ReactNode; } export function SimulationSheet({ frame, title, icon, attributes, className, children, }: SimulationSheetProps) { const t = useTranslate(); return (
{icon === undefined ? null : }

{title}

{children}
); } /** Two overlapping squares, the front one half filled: something showing through. */ function SeeThroughIcon() { return ( ); } const SEE_THROUGH_KEY = "filius.sheetSeeThrough"; /** „Durchsichtig“, remembered in this browser; storage that is not there (a private window, blocked) only forgets it. */ export function useSeeThrough(): [boolean, (on: boolean) => void] { const [on, setOn] = useState(() => { try { return window.localStorage.getItem(SEE_THROUGH_KEY) === "true"; } catch { return false; } }); const change = useCallback((next: boolean) => { setOn(next); try { window.localStorage.setItem(SEE_THROUGH_KEY, String(next)); } catch { // Not kept; it still holds for this page. } }, []); return [on, change]; }