/** * The SP-404MK2 panel. Presentational: it is told what is lit and reports * presses, holding no state of its own. */ import { panelLabel } from "../domain/format"; import type { ControlId, Entry } from "../domain/types"; import { cx } from "./cx"; import { CONTROL_GROUPS, FX_LEFT, FX_RIGHT, KNOBS, PAD_ROWS } from "./panelLayout"; import styles from "./Panel.module.css"; export interface ScreenText { readonly top: string; readonly right: string; readonly main: string; /** Inverted chips along the bottom of the LCD — the layer's functions. */ readonly chips: readonly string[]; } export interface PanelProps { /** Controls carrying a function on the current layer, and which entries. */ readonly lit: ReadonlyMap; readonly held: readonly ControlId[]; readonly screen: ScreenText; readonly onPress?: (id: ControlId) => void; } interface KeyProps extends Pick { readonly id: ControlId; /** Comes from a CSS module, so possibly undefined. See cx. */ readonly className: string | undefined; } /** Pads print their number, not "PAD 7" — until a layer lights them up. */ const padNumber = (id: ControlId): string | undefined => /^p(\d+)$/.exec(id)?.[1]; function Key({ id, className, lit, held, onPress }: KeyProps) { const entries = lit.get(id); const isHeld = held.includes(id); const isLit = entries !== undefined && entries.length > 0; const number = padNumber(id); return ( ); } export function Panel({ lit, held, screen, onPress }: PanelProps) { const key = { lit, held, ...(onPress ? { onPress } : {}) }; return (
{KNOBS.map((id) => ( ))}
{FX_LEFT.map((id) => ( ))}
{/* The circle sits behind the display and shows only as caps above and below it — no ring around the rectangle. */}
{FX_RIGHT.map((id) => ( ))}
{CONTROL_GROUPS.map((group) => (
{group.leftCaption ? {group.leftCaption} : null}
{group.left.map((id) => ( ))}
{group.rightCaption ? {group.rightCaption} : null}
{group.right.map((id) => ( ))} {group.rightKnob ? ( ) : null}
))}
{PAD_ROWS.map((row) => (
{row.pads.map((id) => ( ))}
))}
); }