Skip to content
File

Blob: worker/src/client/exhibit/board/board-node.tsx

typescript71 lines
1import type { Hardware } from '@/shared/contracts/hardware.ts';
2import { CoreMeter } from './core-meter.tsx';
3import type { RGB } from '@/shared/contracts/robot.ts';
4import { anchors } from '@/client/exhibit/diagram/diagram-model.ts';
5import type { ExplanationTrigger } from '@/client/exhibit/diagram/diagram-model.ts';
6import { BoardIllustration, ledColor } from './board-illustration.tsx';
7 
8export function BoardNode({
9 led,
10 cpu,
11 expanded,
12 onSelect,
13}: { led?: RGB; cpu?: Hardware['cpuBusyBps'] } & ExplanationTrigger) {
14 const color = ledColor(led),
15 known = !!led;
16 const ledOn = known && led!.some((value) => value > 0);
17 return (
18 <section
19 data-anchor={anchors.board}
20 className="relative z-1 grid w-full grid-cols-[104px_1fr] gap-x-4 self-center sm:grid-cols-[145px_1fr] sm:gap-x-6 lg:block lg:max-w-[260px] lg:px-1"
21 aria-labelledby="board-title"
22 >
23 <button
24 className="col-start-2 mt-3 flex w-full items-center gap-2.5 self-end text-left [&_h2]:text-lg [&_h2]:font-medium [&_h2]:tracking-tight sm:[&_h2]:text-[22px]"
25 onClick={(event) => onSelect(event.currentTarget)}
26 aria-haspopup="dialog"
27 aria-expanded={expanded}
28 aria-controls={expanded ? 'signal-detail' : undefined}
29 >
30 <h2 id="board-title">ESP32-S3</h2>
31 <span className="text-sm text-muted" aria-hidden="true">
32 ↗
33 </span>
34 </button>
35 <p className="col-start-2 mt-1 font-mono text-[8px] text-muted sm:text-[9px]">N32R16V</p>
36 <div className="col-start-1 row-start-1 row-end-5 mt-4 lg:mx-auto lg:mb-4">
37 <div className="mx-auto w-[100px] max-w-full sm:w-[125px] lg:w-[183px]">
38 <BoardIllustration led={led} />
39 <div
40 className="mt-1 grid grid-cols-2 px-[16%] text-center font-mono text-[9px] text-muted"
41 aria-label="Board connectors, left to right"
42 >
43 <span>UART</span>
44 <span>USB</span>
45 </div>
46 </div>
47 <div className="mt-2 flex items-center justify-center gap-1.5 text-center text-[9px] leading-relaxed text-muted lg:text-[10px]">
48 <span
49 className="status-dot inline-block size-1.5 shrink-0 rounded-full"
50 style={{ background: color }}
51 />
52 {known ? (ledOn ? 'Reported LED color' : 'LED is off') : 'Waiting for LED state'}
53 </div>
54 </div>
55 <div className="col-start-2 mt-3 self-start lg:mt-0">
56 <div className="border-t border-line py-2">
57 <CoreMeter core={0} task="Wi-Fi · str0m radio" busyBps={cpu?.[0]} />
58 <CoreMeter core={1} task="Opus decode → live FFT" busyBps={cpu?.[1]} />
59 </div>
60 <p className="mt-3 text-[10px] leading-relaxed text-muted">
61 <span className="block font-mono text-[8px] tracking-wide">EITHER CORE</span>
62 <span className="mt-1 block text-[11px] text-ink">HTTPS signaling</span>
63 </p>
64 </div>
65 <span className="col-start-2 mt-3 block text-[10px] leading-relaxed text-muted lg:mt-4">
66 USB power · Wi-Fi streams
67 </span>
68 </section>
69 );
70}