diff --git a/frontend/src/components/AntGeniusPanel.tsx b/frontend/src/components/AntGeniusPanel.tsx index 203b8f0..e0f6fbe 100644 --- a/frontend/src/components/AntGeniusPanel.tsx +++ b/frontend/src/components/AntGeniusPanel.tsx @@ -33,6 +33,37 @@ function pretty(name: string): string { return t.charAt(0).toUpperCase() + t.slice(1).toLowerCase(); } +// PortBtn is defined at MODULE scope on purpose. Defined inside AntGeniusPanel it +// would be a new component *type* on every render, so React would unmount and +// remount every port button each time the panel re-renders — harmless when that's +// rare, but with the CW decoder running the parent re-renders many times a second +// and the buttons were being torn down mid-click (mousedown and mouseup landing on +// different element instances), so antenna changes silently did nothing. +function PortBtn({ port, index, active, tx, onActivate, t }: { + port: 1 | 2; index: number; active: boolean; tx: boolean; + onActivate: (port: number, antenna: number) => void; + t: (key: string, vars?: Record) => string; +}) { + const letter = port === 1 ? 'A' : 'B'; + const cls = tx + ? 'bg-gradient-to-b from-red-500 to-rose-600 text-white border-red-400/50 shadow-[0_0_10px_rgba(244,63,94,0.5)] animate-pulse' + : active + ? (port === 1 + ? 'bg-gradient-to-b from-emerald-400 to-emerald-600 text-white border-emerald-300/60 shadow-[0_0_9px_rgba(16,185,129,0.45)]' + : 'bg-gradient-to-b from-sky-400 to-sky-600 text-white border-sky-300/60 shadow-[0_0_9px_rgba(14,165,233,0.45)]') + : 'bg-card text-muted-foreground border-border hover:bg-muted hover:text-foreground'; + return ( + + ); +} + // AntGeniusPanel — antenna-switch widget for a 4O3A Antenna Genius, styled to // match the app's light theme with soft gradients + glows. Each antenna row has // a port-A button (left) and port-B button (right). Colours: green = selected on @@ -61,27 +92,6 @@ export function AntGeniusPanel({ status, onActivate, onClose, band }: { if (filtered.length > 0) list = filtered; } - const PortBtn = ({ port, index, active, tx }: { port: 1 | 2; index: number; active: boolean; tx: boolean }) => { - const letter = port === 1 ? 'A' : 'B'; - const cls = tx - ? 'bg-gradient-to-b from-red-500 to-rose-600 text-white border-red-400/50 shadow-[0_0_10px_rgba(244,63,94,0.5)] animate-pulse' - : active - ? (port === 1 - ? 'bg-gradient-to-b from-emerald-400 to-emerald-600 text-white border-emerald-300/60 shadow-[0_0_9px_rgba(16,185,129,0.45)]' - : 'bg-gradient-to-b from-sky-400 to-sky-600 text-white border-sky-300/60 shadow-[0_0_9px_rgba(14,165,233,0.45)]') - : 'bg-card text-muted-foreground border-border hover:bg-muted hover:text-foreground'; - return ( - - ); - }; - return (
@@ -124,11 +134,11 @@ export function AntGeniusPanel({ status, onActivate, onClose, band }: { : 'bg-card/70 text-foreground/80 border-border hover:bg-muted/60'; return (
- +
{pretty(a.name)}
- +
); })}