Skip to content
File

Blob: worker/src/client/exhibit/controls/led-controls.tsx

typescript53 lines
1import type { CSSProperties } from 'react';
2import type { RGB } from '@/shared/contracts/robot.ts';
3 
4const colors: { name: string; rgb: RGB; display: string }[] = [
5 { name: 'coral', rgb: [32, 3, 0], display: '#db704f' },
6 { name: 'amber', rgb: [28, 18, 0], display: '#c89535' },
7 { name: 'green', rgb: [0, 24, 5], display: '#4b9471' },
8 { name: 'turquoise', rgb: [0, 24, 24], display: 'oklch(0.63 0.085 195)' },
9 { name: 'blue', rgb: [0, 10, 32], display: '#548abb' },
10 { name: 'violet', rgb: [18, 0, 32], display: 'oklch(0.61 0.105 305)' },
11 { name: 'rose', rgb: [32, 0, 12], display: 'oklch(0.65 0.105 350)' },
12 { name: 'off', rgb: [0, 0, 0], display: '#e5e5dd' },
13];
14 
15export function LedControls({
16 led,
17 disabled,
18 pending,
19 onChange,
20}: {
21 led?: RGB;
22 disabled: boolean;
23 pending: boolean;
24 onChange: (rgb: RGB) => void;
25}) {
26 return (
27 <fieldset
28 className="mt-3 mb-1 min-w-0 border-0 p-0 [&_legend]:font-mono [&_legend]:text-[9px] [&_legend]:tracking-wide [&_legend]:text-muted"
29 disabled={disabled}
30 >
31 <legend>ONBOARD LED · GPIO38</legend>
32 <div className="mt-2 grid w-fit grid-cols-4 gap-1 [&_button]:flex [&_button]:size-11 [&_button]:items-center [&_button]:justify-center [&_button]:rounded-md [&_button]:border [&_button]:border-transparent [&_button]:p-1 [&_button]:text-xl [&_button[aria-pressed=true]]:border-ink [&_button>span]:size-6 [&_button>span]:rounded-full [&_button>span]:bg-(--swatch) [&_button>span]:ring-1 [&_button>span]:ring-inset [&_button>span]:ring-ink/10">
33 {colors.map((color) => (
34 <button
35 type="button"
36 key={color.name}
37 aria-label={color.name === 'off' ? 'Turn LED off' : `Set LED to ${color.name}`}
38 aria-disabled={disabled || pending}
39 aria-pressed={led?.join(',') === color.rgb.join(',')}
40 data-rgb={color.rgb.join(',')}
41 style={{ '--swatch': color.display } as CSSProperties}
42 onClick={() => {
43 if (!disabled && !pending) onChange(color.rgb);
44 }}
45 >
46 {color.name === 'off' ? '○' : <span aria-hidden="true" />}
47 </button>
48 ))}
49 </div>
50 </fieldset>
51 );
52}