feat: status bar added

This commit is contained in:
2026-05-30 01:35:50 +02:00
parent 8f1ad126ac
commit 806b39970b
24 changed files with 1933 additions and 451 deletions
+24 -16
View File
@@ -1,5 +1,5 @@
import { useMemo, useState } from 'react';
import { ChevronUp, Construction } from 'lucide-react';
import { Construction } from 'lucide-react';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Checkbox } from '@/components/ui/checkbox';
@@ -8,6 +8,7 @@ import {
} from '@/components/ui/select';
import { cn } from '@/lib/utils';
import { pathBetween } from '@/lib/maidenhead';
import { BandSlotGrid } from '@/components/BandSlotGrid';
export interface DetailsState {
state: string;
@@ -45,9 +46,16 @@ interface Props {
remoteGrid: string; // entry-strip Grid value — destination
details: DetailsState;
onChange: (patch: Partial<DetailsState>) => void;
// Stats (F1) tab content: the worked-before matrix + optional QRZ image.
wb?: any;
wbBusy?: boolean;
band: string;
mode: string;
imageUrl?: string;
onOpenImage?: () => void;
}
type TabName = 'info' | 'awards' | 'my' | 'extended';
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'];
@@ -67,8 +75,8 @@ function Field({ label, span = 1, children }: { label: string; span?: 1 | 2 | 3
);
}
export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid, details, onChange }: Props) {
const [open, setOpen] = useState<TabName | null>(null);
export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid, details, onChange, wb, wbBusy, band, mode }: Props) {
const [open, setOpen] = useState<TabName>('stats');
// Bearing/distance from operator's home grid to the remote station.
// Recomputed only when either grid actually changes.
@@ -79,7 +87,7 @@ 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((prev) => (prev === t ? null : t)); }
function toggle(t: TabName) { setOpen(t); }
const satelliteMode = !!details.sat_name || !!details.sat_mode || details.prop_mode === 'SAT';
function setSatellite(on: boolean) {
@@ -94,6 +102,7 @@ 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)' },
@@ -101,8 +110,8 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
];
return (
<section className="border-b border-border bg-card shrink-0">
<nav className="flex items-center gap-1 px-3 bg-muted/40 border-b border-border">
<section className="border border-border rounded-lg bg-card 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
key={t.key}
@@ -117,17 +126,15 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
{t.label}
</button>
))}
{open && (
<button
onClick={() => setOpen(null)}
className="ml-auto text-muted-foreground hover:text-foreground p-1.5"
title="Close"
>
<ChevronUp className="size-3.5" />
</button>
)}
</nav>
<div className="overflow-y-auto min-h-0">
{open === 'stats' && (
<div className="px-3 py-2.5">
<BandSlotGrid wb={wb} busy={!!wbBusy} currentBand={band} currentMode={mode} />
</div>
)}
{open === 'info' && (
<div className="grid grid-cols-6 gap-2 px-3 py-2.5">
<Field label="State / pref">
@@ -251,6 +258,7 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
</Field>
</div>
)}
</div>
</section>
);
}