import { useRef, useState } from 'react'; import { playbackView } from '@/client/radio/playback.ts'; import type { SessionState, SignalBuffer } from '@/client/radio/session-state.ts'; import type { RadioActions } from '@/client/radio/use-radio.ts'; import { Login } from '@/client/ui/login.tsx'; import { BoardNode } from './board/board-node.tsx'; import { AudioPanel } from './audio/audio-panel.tsx'; import { SpectrumPanel } from './spectrum/spectrum-panel.tsx'; import { ControlsPanel } from './controls/controls-panel.tsx'; import { SignalPopover } from './details/signal-popover.tsx'; import { SfuNode } from './diagram/sfu-node.tsx'; import { Wires } from './diagram/wires.tsx'; import { BRANCHES, branchStyles } from './diagram/diagram-model.ts'; import type { ExplanationTrigger, Selection, SignalDetails } from './diagram/diagram-model.ts'; /** Adapts the radio snapshot to the exhibit; panels receive only their own data and actions. */ export function Exhibit({ state, signal, actions, }: { state: SessionState; signal: SignalBuffer; actions: RadioActions; }) { const diagramRef = useRef(null); const [details, setDetails] = useState(null); const selected = details?.selection ?? null; const select = (selection: Selection, anchor: HTMLButtonElement) => setDetails((previous) => previous?.selection === selection && previous.anchor === anchor ? null : { selection, anchor }, ); const connected = state.phase === 'connected'; const playback = playbackView(state); const error = state.issues.connection ?? state.issues.control ?? state.issues.status ?? state.issues.heartbeat; const active = { audio: connected && state.audio.at > 0 && state.now - state.audio.at < 3000, spectrum: connected && signal.at > 0 && state.now - signal.at < 1200, robot: connected && state.telemetryAt > 0 && state.now - state.telemetryAt < 3000, }; const explanation = (selection: Selection): ExplanationTrigger => ({ expanded: selected === selection, onSelect: (anchor) => select(selection, anchor), }); const held = connected && !!state.viewerId && state.room.controller === state.viewerId; return ( <> {state.auth === 'required' ? : null}
{BRANCHES.map((branch) => ( ))}

{state.message}

{state.received.toLocaleString()} telemetry ยท {state.spectrumCount.toLocaleString()}{' '} spectrum
{error ? (

{error}

) : null} setDetails(null)} /> ); }