This commit is contained in:
2026-06-07 02:51:00 +02:00
parent 16c04fc12b
commit 8040a37315
11 changed files with 1150 additions and 224 deletions
+52 -15
View File
@@ -67,7 +67,39 @@ interface Props {
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'];
// ADIF PROP_MODE: stored value is the code, shown with the full name (Log4OM-style).
const PROP_MODES: { value: string; label: string }[] = [
{ value: 'NONE', label: '—' },
{ value: 'AS', label: 'Aircraft Scatter' },
{ value: 'AUR', label: 'Aurora' },
{ value: 'AUE', label: 'Aurora-E' },
{ value: 'BS', label: 'Back Scatter' },
{ value: 'ECH', label: 'EchoLink' },
{ value: 'EME', label: 'Earth-Moon-Earth' },
{ value: 'ES', label: 'Sporadic E' },
{ value: 'FAI', label: 'Field Aligned Irregularities' },
{ value: 'F2', label: 'F2 Reflection' },
{ value: 'GWAVE', label: 'Ground Wave' },
{ value: 'INTERNET', label: 'Internet-assisted' },
{ value: 'ION', label: 'Ionoscatter' },
{ value: 'IRL', label: 'IRLP' },
{ value: 'LOS', label: 'Line of Sight' },
{ value: 'MS', label: 'Meteor Scatter' },
{ value: 'RPT', label: 'Terrestrial / atmospheric repeater' },
{ value: 'RS', label: 'Rain Scatter' },
{ value: 'SAT', label: 'Satellite' },
{ value: 'TEP', label: 'Trans-Equatorial' },
{ value: 'TR', label: 'Tropospheric Ducting' },
];
// ADIF ANT_PATH enum (Grayline, Other, Short Path, Long Path).
const ANT_PATHS: { value: string; label: string }[] = [
{ value: 'NONE', label: '—' },
{ value: 'S', label: 'Short Path' },
{ value: 'L', label: 'Long Path' },
{ value: 'G', label: 'Grayline' },
{ value: 'O', label: 'Other' },
];
function numOrUndef(v: string): number | undefined {
if (v === '') return undefined;
@@ -76,9 +108,9 @@ function numOrUndef(v: string): number | undefined {
}
// Compact field helper to keep the JSX dense.
function Field({ label, span = 1, children }: { label: string; span?: 1 | 2 | 3 | 6; children: React.ReactNode }) {
function Field({ label, span = 1, children }: { label: string; span?: 1 | 2 | 3 | 4 | 6; children: React.ReactNode }) {
return (
<div className={cn('flex flex-col min-w-0', span === 2 && 'col-span-2', span === 3 && 'col-span-3', span === 6 && 'col-span-6')}>
<div className={cn('flex flex-col min-w-0', span === 2 && 'col-span-2', span === 3 && 'col-span-3', span === 4 && 'col-span-4', span === 6 && 'col-span-6')}>
<Label className="mb-1">{label}</Label>
{children}
</div>
@@ -217,26 +249,31 @@ export function DetailsPanel({ callsign: _cs, prefix, operatorGrid, remoteGrid,
<Field label="Elevation (°)">
<Input type="number" value={details.ant_el ?? ''} onChange={(e) => onChange({ ant_el: numOrUndef(e.target.value) })} />
</Field>
<Field label="Ant. path">
<Input value={details.ant_path} placeholder="S / L / G" onChange={(e) => onChange({ ant_path: e.target.value })} />
</Field>
<Field label="Propagation">
<Select value={details.prop_mode || 'NONE'} onValueChange={(v) => onChange({ prop_mode: v === 'NONE' ? '' : v })}>
<SelectTrigger><SelectValue /></SelectTrigger>
<SelectContent>
{PROP_MODES.map((p) => <SelectItem key={p} value={p}>{p === 'NONE' ? '—' : p}</SelectItem>)}
</SelectContent>
</Select>
</Field>
<Field label="TX power (W)">
<Input type="number" value={details.tx_pwr ?? ''} onChange={(e) => onChange({ tx_pwr: numOrUndef(e.target.value) })} />
</Field>
<div className="flex items-end pb-1.5">
<div className="col-span-3 flex items-end pb-1.5">
<label className="flex items-center gap-2 text-sm cursor-pointer">
<Checkbox checked={satelliteMode} onCheckedChange={(c) => setSatellite(!!c)} />
Satellite mode
</label>
</div>
<Field label="Ant. path" span={2}>
<Select value={details.ant_path || 'NONE'} onValueChange={(v) => onChange({ ant_path: v === 'NONE' ? '' : v })}>
<SelectTrigger><SelectValue /></SelectTrigger>
<SelectContent>
{ANT_PATHS.map((p) => <SelectItem key={p.value} value={p.value}>{p.label}</SelectItem>)}
</SelectContent>
</Select>
</Field>
<Field label="Propagation" span={4}>
<Select value={details.prop_mode || 'NONE'} onValueChange={(v) => onChange({ prop_mode: v === 'NONE' ? '' : v })}>
<SelectTrigger><SelectValue /></SelectTrigger>
<SelectContent>
{PROP_MODES.map((p) => <SelectItem key={p.value} value={p.value}>{p.label}</SelectItem>)}
</SelectContent>
</Select>
</Field>
<Field label="Rig" span={3}>
<Input value={details.my_rig} placeholder="Flex 8600" onChange={(e) => onChange({ my_rig: e.target.value })} />
</Field>