feat: Winkeyer
This commit is contained in:
@@ -53,9 +53,15 @@ interface Props {
|
||||
mode: string;
|
||||
imageUrl?: string;
|
||||
onOpenImage?: () => void;
|
||||
// Optional controlled active tab (so the app can switch it via keyboard).
|
||||
tab?: TabName;
|
||||
onTab?: (t: TabName) => void;
|
||||
// When the WinKeyer is active, F1-F12 fire macros, so the tab shortcut is
|
||||
// shown as Ctrl+F1…F5 instead of F1…F5.
|
||||
keyerActive?: boolean;
|
||||
}
|
||||
|
||||
type TabName = 'stats' | 'info' | 'awards' | 'my' | 'extended';
|
||||
export type TabName = 'stats' | 'info' | 'awards' | 'my' | 'extended';
|
||||
|
||||
const PROP_MODES = ['NONE','AS','AUE','AUR','BS','ECH','EME','ES','F2','F2M','FAI','GWAVE','INTERNET','ION','IRL','LOS','MS','RPT','RS','SAT','TEP','TR'];
|
||||
|
||||
@@ -75,8 +81,9 @@ function Field({ label, span = 1, children }: { label: string; span?: 1 | 2 | 3
|
||||
);
|
||||
}
|
||||
|
||||
export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid, details, onChange, wb, wbBusy, band, mode }: Props) {
|
||||
const [open, setOpen] = useState<TabName>('stats');
|
||||
export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid, details, onChange, wb, wbBusy, band, mode, tab, onTab, keyerActive }: Props) {
|
||||
const [internalOpen, setInternalOpen] = useState<TabName>('stats');
|
||||
const open = tab ?? internalOpen; // controlled when `tab` is provided
|
||||
|
||||
// Bearing/distance from operator's home grid to the remote station.
|
||||
// Recomputed only when either grid actually changes.
|
||||
@@ -87,7 +94,8 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
|
||||
const fmtDeg = (n: number) => `${Math.round(n)}°`;
|
||||
const fmtKm = (n: number) => `${Math.round(n).toLocaleString()} km`;
|
||||
|
||||
function toggle(t: TabName) { setOpen(t); }
|
||||
function toggle(t: TabName) { onTab ? onTab(t) : setInternalOpen(t); }
|
||||
const fk = keyerActive ? 'Ctrl+F' : 'F';
|
||||
|
||||
const satelliteMode = !!details.sat_name || !!details.sat_mode || details.prop_mode === 'SAT';
|
||||
function setSatellite(on: boolean) {
|
||||
@@ -102,15 +110,15 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
|
||||
}
|
||||
|
||||
const tabs: { key: TabName; label: string }[] = [
|
||||
{ key: 'stats', label: 'Stats (F1)' },
|
||||
{ key: 'info', label: 'Info (F2)' },
|
||||
{ key: 'awards', label: 'Awards (F3)' },
|
||||
{ key: 'my', label: 'My (F4)' },
|
||||
{ key: 'extended', label: 'Extended (F5)' },
|
||||
{ key: 'stats', label: `Stats (${fk}1)` },
|
||||
{ key: 'info', label: `Info (${fk}2)` },
|
||||
{ key: 'awards', label: `Awards (${fk}3)` },
|
||||
{ key: 'my', label: `My (${fk}4)` },
|
||||
{ key: 'extended', label: `Extended (${fk}5)` },
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="border border-border rounded-lg bg-card flex flex-col flex-1 min-h-0 overflow-hidden">
|
||||
<section className="bg-card shadow-sm border border-border rounded-lg flex flex-col flex-1 min-h-0 overflow-hidden">
|
||||
<nav className="flex items-center gap-1 px-3 bg-muted/40 border-b border-border shrink-0">
|
||||
{tabs.map((t) => (
|
||||
<button
|
||||
|
||||
Reference in New Issue
Block a user