feat(rotator): short and long path headings under the compass

The same pair already sits in the status bar, where it is 10px and several
operators reported not being able to read it. Repeated under the compass at a
size that can be read across a shack.

Clickable, like the ones in the status bar: a heading you can see and not act
on would be a step backwards from what is already there. Disabled and dashed
when no station is entered, rather than showing a heading to nowhere.
This commit is contained in:
2026-08-13 11:34:00 +02:00
parent 03598cfaff
commit 700b688fc0
3 changed files with 37 additions and 15 deletions
+31 -11
View File
@@ -77,17 +77,37 @@ function RotatorWidget({ hd, refetch, centerLat, centerLon, bearing, t }: Rotato
title={hd.ok ? t('station.online') : t('station.rotatorNoRead')} />
</div>
<div className="p-3 flex gap-4 items-start">
<RotorCompass
bearing={bearing ?? null}
headings={hd.ok ? [hd.azimuth] : []}
centerLat={centerLat ?? null}
centerLon={centerLon ?? null}
rotorEnabled={hd.ok}
rotors={hd.rotors}
activeRotor={hd.active}
onSelectRotor={(i) => { SetActiveRotor(i).then(refetch).catch((e) => setErr(String(e?.message ?? e))); }}
onGoto={(az) => turn(az)}
/>
<div className="flex flex-col gap-2">
<RotorCompass
bearing={bearing ?? null}
headings={hd.ok ? [hd.azimuth] : []}
centerLat={centerLat ?? null}
centerLon={centerLon ?? null}
rotorEnabled={hd.ok}
rotors={hd.rotors}
activeRotor={hd.active}
onSelectRotor={(i) => { SetActiveRotor(i).then(refetch).catch((e) => setErr(String(e?.message ?? e))); }}
onGoto={(az) => turn(az)}
/>
{/* Short and long path to the station being worked, repeated here at a
readable size: the same pair sits in the status bar, where it is 10px
and several operators reported not being able to read it.
Clickable, like the ones up there — a heading you can see and not
act on would be a step backwards. */}
<div className="flex gap-1.5 font-mono">
{([['SP', bearing], ['LP', bearing == null ? null : (bearing + 180) % 360]] as const).map(([lbl, az]) => (
<button key={lbl} type="button" disabled={az == null}
onClick={() => az != null && turn(az)}
title={az == null ? '' : t('station.rotateTo', { az: Math.round(az) })}
className={cn('flex-1 rounded-md border py-1 text-xs font-semibold tabular-nums transition-colors',
az == null
? 'border-border text-muted-foreground/50 cursor-not-allowed'
: 'border-info-border text-info-muted-foreground hover:bg-info-muted')}>
{lbl} {az == null ? '—' : `${Math.round(az)}°`}
</button>
))}
</div>
</div>
<div className="flex-1 min-w-0 space-y-2">
<div className="font-mono">
<span className="text-2xl font-bold tabular-nums">{hd.ok ? `${hd.azimuth}°` : '—'}</span>