chore: release v0.26.3
This commit is contained in:
@@ -25,6 +25,16 @@ interface Spot {
|
||||
band?: string;
|
||||
comment?: string;
|
||||
spotter?: string;
|
||||
// The park reference the POTA poller tagged this spot with. The map never
|
||||
// reads it — the click handler upstream turns it into the QSO's POTA award
|
||||
// reference — but it is declared so it cannot be lost by accident.
|
||||
//
|
||||
// It travelled only because the spot objects are passed through by reference
|
||||
// and the type was erased. The first refactor to copy a spot field by field
|
||||
// would have dropped the park silently, and the only symptom would be an
|
||||
// activation logged without its reference. Same mistake as the status entry
|
||||
// below, whose extra markers were arriving and undeclared.
|
||||
pota_ref?: string;
|
||||
}
|
||||
|
||||
// The FULL status entry, not the two fields the map used to declare. The extra
|
||||
@@ -83,11 +93,12 @@ interface Props {
|
||||
// globally from the band-map tab toolbar.
|
||||
hideDigital?: boolean;
|
||||
fitToBand?: boolean;
|
||||
// onToggleFit turns the zoom readout into the fit-to-band switch. Only the
|
||||
// docked map passes it: the Band Map tab has the same control in its own
|
||||
// toolbar, above maps that all obey it at once, and a second switch inside
|
||||
// each card would be four ways to change one setting.
|
||||
// onToggleFit and onToggleHideDigital add the two switches to this map's own
|
||||
// header. Only the docked map passes them: the Band Map tab has both in its
|
||||
// toolbar, above maps that all obey them at once, and a switch inside each
|
||||
// card as well would be four ways to change one setting.
|
||||
onToggleFit?: () => void;
|
||||
onToggleHideDigital?: () => void;
|
||||
// Mark stations that upload to LoTW (Settings → Appearance).
|
||||
showLotw?: boolean;
|
||||
// keyNav enables Ctrl+↑ / Ctrl+↓ to hop to the next spot above / below the rig
|
||||
@@ -164,6 +175,7 @@ function LegendDot({ cls, colour, label }: { cls?: string; colour?: string; labe
|
||||
function statusLabel(s: string, t: (k: string) => string): string {
|
||||
switch (s) {
|
||||
case 'new': return t('bmp.statusNew');
|
||||
case 'new-band-mode': return t('bmp.statusNewBandMode');
|
||||
case 'new-band': return t('bmp.statusNewBand');
|
||||
case 'new-mode': return t('bmp.statusNewMode');
|
||||
case 'new-slot': return t('bmp.statusNewSlot');
|
||||
@@ -191,7 +203,11 @@ function statusStyle(s: string): { pill: string; bar: string; line: string; dot:
|
||||
// line = SVG leader stroke (visible on hover)
|
||||
// dot = small marker on the freq scale
|
||||
switch (s) {
|
||||
case 'new': return {
|
||||
// NEW and NEW BAND+MODE share the strongest colour: both mean "there is
|
||||
// something here you have never had", and a sixth shade in a palette read at
|
||||
// a glance is a shade nobody can name.
|
||||
case 'new':
|
||||
case 'new-band-mode': return {
|
||||
pill: 'bg-danger-muted text-danger-muted-foreground border-danger-border hover:bg-danger-muted',
|
||||
bar: 'bg-danger',
|
||||
line: 'stroke-danger',
|
||||
@@ -268,7 +284,7 @@ const BOT_PAD = 14; // the top-most freq label isn't clipped at y=0
|
||||
// last; ties broken by closeness to the rig freq).
|
||||
const MAX_VISIBLE_SPOTS = 30;
|
||||
|
||||
export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, onSpotClick, onClose, side = 'right', onToggleSide, hideDigital = false, fitToBand = false, onToggleFit, keyNav = false, showLotw = false }: Props) {
|
||||
export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz, onSpotClick, onClose, side = 'right', onToggleSide, hideDigital = false, fitToBand = false, onToggleFit, onToggleHideDigital, keyNav = false, showLotw = false }: Props) {
|
||||
const { t } = useI18n();
|
||||
|
||||
// The two display options are applied ONCE here, on the whole map, so the
|
||||
@@ -366,6 +382,7 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz,
|
||||
const k = spotStatusKey(s.dx_call, s.band ?? '', s.comment ?? '', s.freq_hz);
|
||||
switch (spotStatus[k]?.status ?? '') {
|
||||
case 'new': return 0;
|
||||
case 'new-band-mode': return 0;
|
||||
case 'new-band': return 1;
|
||||
case 'new-slot': return 2;
|
||||
case 'new-call': return 2;
|
||||
@@ -564,16 +581,18 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz,
|
||||
title={t('bmp.zoomOut')}>
|
||||
<Minus className="size-3" />
|
||||
</button>
|
||||
{/* The readout IS the switch when the parent offers one — the header is
|
||||
already tight with four maps side by side, and a separate chip would
|
||||
cost width to say what this text says anyway. */}
|
||||
{onToggleFit ? (
|
||||
<button type="button" onClick={onToggleFit} title={t('bmp.fitTitle')}
|
||||
className={cn('shrink-0 font-mono text-[10px] normal-case tracking-normal whitespace-nowrap px-1 rounded border transition-colors',
|
||||
fitToBand ? 'border-primary bg-primary text-primary-foreground' : 'border-border hover:bg-muted')}>
|
||||
{fitToBand ? t('bmp.fit') : `${pxPerKHz}px/kHz`}
|
||||
</button>
|
||||
) : (
|
||||
{/* A readout, not a switch.
|
||||
|
||||
It WAS the switch for a day: clicking the px/kHz value toggled
|
||||
fit-to-band, and in fit it read "FIT". Nobody found it — a control
|
||||
whose label is a measurement does not look like a control, and once
|
||||
switched off there was no longer anything on screen saying the option
|
||||
existed. The switches below say what they are. */}
|
||||
{/* In fit mode the readout has nothing left to say — the lit FIT button
|
||||
says it, and printing the word twice side by side is just noise. The
|
||||
Band Map tab's cards have no button, so there the readout keeps
|
||||
reporting both states. */}
|
||||
{(!fitToBand || !onToggleFit) && (
|
||||
<span className="shrink-0 font-mono text-[10px] normal-case tracking-normal whitespace-nowrap px-0.5">{fitToBand ? t('bmp.fit') : `${pxPerKHz}px/kHz`}</span>
|
||||
)}
|
||||
<button type="button" onClick={() => changeZoom(1)} disabled={fitToBand || zoomIdx === PX_PER_KHZ.length - 1}
|
||||
@@ -581,6 +600,20 @@ export function BandMap({ band, spots, spotStatus: spotStatusRaw, currentFreqHz,
|
||||
title={t('bmp.zoomIn')}>
|
||||
<Plus className="size-3" />
|
||||
</button>
|
||||
{onToggleFit && (
|
||||
<button type="button" onClick={onToggleFit} title={t('bmp.fitTitle')}
|
||||
className={cn('shrink-0 text-[10px] font-semibold normal-case tracking-normal px-1 rounded border transition-colors',
|
||||
fitToBand ? 'border-primary bg-primary text-primary-foreground' : 'border-border text-muted-foreground hover:bg-muted')}>
|
||||
{t('bmp.fit')}
|
||||
</button>
|
||||
)}
|
||||
{onToggleHideDigital && (
|
||||
<button type="button" onClick={onToggleHideDigital} title={t('bmp.hideFtTitle')}
|
||||
className={cn('shrink-0 text-[10px] font-semibold normal-case tracking-normal px-1 rounded border transition-colors',
|
||||
hideDigital ? 'border-primary bg-primary text-primary-foreground' : 'border-border text-muted-foreground hover:bg-muted')}>
|
||||
{t('bmp.ftx')}
|
||||
</button>
|
||||
)}
|
||||
<button type="button" onClick={recenterOnRig}
|
||||
className="size-5 inline-flex items-center justify-center rounded hover:bg-muted"
|
||||
title={t('bmp.scrollToRig')}>
|
||||
|
||||
Reference in New Issue
Block a user