"use client"; import { useEffect, useId, useRef, useState, type KeyboardEvent } from "react"; import "./preset-keys.css"; /** * Preset Keys * The station buttons on an old radio, as a radio group. Press one and it * goes down and stays down with a solid clack, the one that was down * springs back up, and the needle sweeps across the dial to the station — * the glow behind the scale dimming while it travels and coming up warm * once it's tuned. */ export type Station = { name: string; short: string; mhz: number }; type Props = { stations: Station[]; defaultIndex?: number; band?: [number, number]; onChange?: (s: Station) => void; theme?: "walnut" | "hifi"; motion?: "full" | "reduced"; className?: string; }; export function PresetKeys({ stations, defaultIndex = 0, band = [88, 108], onChange, theme = "walnut", motion = "full", className = "" }: Props) { const id = useId(); const [sel, setSel] = useState(defaultIndex); const [tuning, setTuning] = useState(false); const refs = useRef<(HTMLButtonElement | null)[]>([]); const timer = useRef(0); const st = stations[sel]; const pos = (st.mhz - band[0]) / (band[1] - band[0]); const choose = (i: number) => { if (i === sel) return; setSel(i); onChange?.(stations[i]); const rm = motion === "reduced" || matchMedia("(prefers-reduced-motion: reduce)").matches; if (rm) return; // While the needle travels the glow dims; it comes back once the station is in. setTuning(true); clearTimeout(timer.current); timer.current = window.setTimeout(() => setTuning(false), 760); }; useEffect(() => () => clearTimeout(timer.current), []); const onKey = (e: KeyboardEvent, i: number) => { const n = stations.length; let to = -1; if (e.key === "ArrowRight" || e.key === "ArrowDown") to = (i + 1) % n; else if (e.key === "ArrowLeft" || e.key === "ArrowUp") to = (i - 1 + n) % n; else if (e.key === "Home") to = 0; else if (e.key === "End") to = n - 1; if (to < 0) return; e.preventDefault(); choose(to); refs.current[to]?.focus(); }; const ticks: number[] = []; for (let f = band[0]; f <= band[1] + 1e-6; f += 0.5) ticks.push(f); return (