fix(watchlist widget): one line per spot

Callsign, band, mode, badge, age in reading order, and the widget widened
to 290 px so the badge and the age never squeeze the callsign. Two lines
made the panel twice as tall for the same three facts; the entry that
matched — which only differs when it is a prefix — moved into the row's
tooltip.
This commit is contained in:
2026-09-06 00:10:21 +02:00
parent 03e71bfdf2
commit 4321eae647
3 changed files with 29 additions and 34 deletions
+2 -2
View File
@@ -6,7 +6,7 @@
"[NEW] Rotor widget redrawn: a night world map behind a square azimuth scale, an orange pointer following the mouse so a click lands where it is aimed, a yellow marker on the azimuth ordered until the antenna gets there, and quick turns in columns of six. The Ultrabeam boom and its second lobe are still drawn, and Station Control keeps the plain dial — dial only, since anything under it is pushed off the bottom of the row. Design contributed by EC1KD — thank you.", "[NEW] Rotor widget redrawn: a night world map behind a square azimuth scale, an orange pointer following the mouse so a click lands where it is aimed, a yellow marker on the azimuth ordered until the antenna gets there, and quick turns in columns of six. The Ultrabeam boom and its second lobe are still drawn, and Station Control keeps the plain dial — dial only, since anything under it is pushed off the bottom of the row. Design contributed by EC1KD — thank you.",
"[NEW] Settings → Rotator now chooses the dial: the new world-map compass or the classic one. Both are kept — one reads across the shack, the other is the compact dial that was there before — and the choice applies to the docked widget and to Station Control at once.", "[NEW] Settings → Rotator now chooses the dial: the new world-map compass or the classic one. Both are kept — one reads across the shack, the other is the compact dial that was there before — and the choice applies to the docked widget and to Station Control at once.",
"Rotor widget: the Stop button no longer flickers on a rotor standing still. Movement was inferred from a one-degree change, which is less than the jitter a controller reports at rest.", "Rotor widget: the Stop button no longer flickers on a rotor standing still. Movement was inferred from a one-degree change, which is less than the jitter a controller reports at rest.",
"[NEW] A docked watch-list panel, showing only what is ON THE AIR and still needed — one row per band and mode, freshest first, click to tune, with the clusters own NEW DXCC / NEW BAND / NEW SLOT badge on each row. The Watchlist tab is a tab, and an operator working FT8 lives on the decodes one: a station you asked to be told about was appearing on a screen you were not looking at. Turn it on with the bell in the toolbar.", "[NEW] A docked watch-list panel, showing only what is ON THE AIR and still needed — one line per band and mode — callsign, band, mode, what it is worth, how long ago — freshest first, click to tune, with the clusters own NEW DXCC / NEW BAND / NEW SLOT badge on each row. The Watchlist tab is a tab, and an operator working FT8 lives on the decodes one: a station you asked to be told about was appearing on a screen you were not looking at. Turn it on with the bell in the toolbar.",
"[NEW] FT decodes: a distance column, next to the square it is computed from and in your own unit (km or miles). Rounded to whole units — a four-character grid is a square tens of kilometres wide and nothing finer is honest.", "[NEW] FT decodes: a distance column, next to the square it is computed from and in your own unit (km or miles). Rounded to whole units — a four-character grid is a square tens of kilometres wide and nothing finer is honest.",
"[NEW] The PSK Reporter panel switches to the station auto-call is WAITING for (the hourglass), while nothing is being called. Its analysis takes a history query and a period or two of live reports to fill, so starting it when the DX finally comes free is starting it too late — the wait is exactly what it should be spent on.", "[NEW] The PSK Reporter panel switches to the station auto-call is WAITING for (the hourglass), while nothing is being called. Its analysis takes a history query and a period or two of live reports to fill, so starting it when the DX finally comes free is starting it too late — the wait is exactly what it should be spent on.",
"[NEW] Chase new: a band selection of its own, under the option (160 m to 70 cm). The stations band list still applies underneath — this one says what is worth WATCHING tonight.", "[NEW] Chase new: a band selection of its own, under the option (160 m to 70 cm). The stations band list still applies underneath — this one says what is worth WATCHING tonight.",
@@ -28,7 +28,7 @@
"[NEW] Widget rotor redessiné : carte du monde nocturne derrière une échelle dazimut carrée, aiguille orange qui suit la souris pour quun clic parte où on vise, repère jaune sur lazimut demandé jusqu’à larrivée de lantenne, et directions rapides en colonnes de six. Le boom Ultrabeam et son deuxième lobe sont toujours tracés, et Station Control garde le cadran seul — rien en dessous, ce qui y était se retrouvait coupé en bas de la rangée. Design proposé par EC1KD — merci à lui.", "[NEW] Widget rotor redessiné : carte du monde nocturne derrière une échelle dazimut carrée, aiguille orange qui suit la souris pour quun clic parte où on vise, repère jaune sur lazimut demandé jusqu’à larrivée de lantenne, et directions rapides en colonnes de six. Le boom Ultrabeam et son deuxième lobe sont toujours tracés, et Station Control garde le cadran seul — rien en dessous, ce qui y était se retrouvait coupé en bas de la rangée. Design proposé par EC1KD — merci à lui.",
"[NEW] Réglages → Rotator permet de choisir le cadran : la nouvelle boussole carte du monde ou le cadran classique. Les deux sont conservés — lun se lit de loin, lautre est le cadran compact davant — et le choix sapplique aussitôt au widget docké comme à Station Control.", "[NEW] Réglages → Rotator permet de choisir le cadran : la nouvelle boussole carte du monde ou le cadran classique. Les deux sont conservés — lun se lit de loin, lautre est le cadran compact davant — et le choix sapplique aussitôt au widget docké comme à Station Control.",
"Widget rotor : le bouton Stop ne clignote plus sur un rotor à larrêt. Le mouvement était déduit dun changement dun degré, soit moins que le tremblement de lecture dun contrôleur au repos.", "Widget rotor : le bouton Stop ne clignote plus sur un rotor à larrêt. Le mouvement était déduit dun changement dun degré, soit moins que le tremblement de lecture dun contrôleur au repos.",
"[NEW] Un panneau watchlist docké, qui ne montre que ce qui est EN LAIR et manque encore — une ligne par bande et mode, le plus frais en haut, clic pour sy caler, avec le badge NEW DXCC / NEW BAND / NEW SLOT du cluster sur chaque ligne. Longlet Watchlist est un onglet, et en FT8 on vit sur celui des décodes : une station quon avait demandé à surveiller apparaissait sur un écran quon ne regardait pas. À activer avec la cloche dans la barre doutils.", "[NEW] Un panneau watchlist docké, qui ne montre que ce qui est EN LAIR et manque encore — une ligne par bande et mode — indicatif, bande, mode, ce que ça vaut, il y a combien de temps — le plus frais en haut, clic pour sy caler, avec le badge NEW DXCC / NEW BAND / NEW SLOT du cluster sur chaque ligne. Longlet Watchlist est un onglet, et en FT8 on vit sur celui des décodes : une station quon avait demandé à surveiller apparaissait sur un écran quon ne regardait pas. À activer avec la cloche dans la barre doutils.",
"[NEW] FT decodes : une colonne distance, à côté du locator dont elle est calculée et dans votre unité (km ou miles). Arrondie à lunité — un locator à quatre caractères est un carré de plusieurs dizaines de kilomètres, rien de plus fin ne serait honnête.", "[NEW] FT decodes : une colonne distance, à côté du locator dont elle est calculée et dans votre unité (km ou miles). Arrondie à lunité — un locator à quatre caractères est un carré de plusieurs dizaines de kilomètres, rien de plus fin ne serait honnête.",
"[NEW] Le panneau PSK Reporter bascule sur la station que lauto-call ATTEND (le sablier), tant que rien nest appelé. Son analyse met une requête dhistorique et une période ou deux à se remplir : la lancer quand le DX se libère enfin, cest la lancer trop tard — lattente sert précisément à ça.", "[NEW] Le panneau PSK Reporter bascule sur la station que lauto-call ATTEND (le sablier), tant que rien nest appelé. Son analyse met une requête dhistorique et une période ou deux à se remplir : la lancer quand le DX se libère enfin, cest la lancer trop tard — lattente sert précisément à ça.",
"[NEW] Chase new : sélection de bandes propre au panneau, sous loption (160 m à 70 cm). La liste de bandes de la station sapplique toujours en dessous — celle-ci dit ce quon veut SURVEILLER ce soir.", "[NEW] Chase new : sélection de bandes propre au panneau, sous loption (160 m à 70 cm). La liste de bandes de la station sapplique toujours en dessous — celle-ci dit ce quon veut SURVEILLER ce soir.",
+1 -1
View File
@@ -7655,7 +7655,7 @@ export default function App() {
width. The classic dial sizes itself from the inside and expects a fixed width. The classic dial sizes itself from the inside and expects a fixed
column; the current one asks for the width it needs. */} column; the current one asks for the width it needs. */}
{showWatchWidget && ( {showWatchWidget && (
<div className="w-[260px] shrink-0 min-h-0" style={{ order: wOrder('watchlist') }}> <div className="w-[290px] shrink-0 min-h-0" style={{ order: wOrder('watchlist') }}>
{/* Same handler as a cluster row, for the same reason as Chase {/* Same handler as a cluster row, for the same reason as Chase
new: a row here IS a spot, and half the reflex the call new: a row here IS a spot, and half the reflex the call
without the frequency, or the frequency without the mode is without the frequency, or the frequency without the mode is
+26 -31
View File
@@ -110,39 +110,34 @@ export function WatchlistWidget({ spots, spotStatus, onPick, onClose }: Props) {
key={`${e.callsign}-${s.dx_call}-${s.band}-${mode}-${i}`} key={`${e.callsign}-${s.dx_call}-${s.band}-${mode}-${i}`}
type="button" type="button"
onClick={() => onPick?.(s)} onClick={() => onPick?.(s)}
title={t('wlw.pick', { call: s.dx_call })} title={e.callsign === s.dx_call
className="w-full text-left px-2 py-1 border-b border-border/20 hover:bg-muted/50 transition-colors" ? t('wlw.pick', { call: s.dx_call })
: `${t('wlw.pick', { call: s.dx_call })} — ${e.callsign}`}
className="w-full text-left px-2 py-1 border-b border-border/20 hover:bg-muted/50 transition-colors flex items-center gap-1.5"
> >
<div className="flex items-center gap-1.5"> {/* One line, in reading order: who, where, what it is worth, how
<span className="font-mono text-[13px] font-bold text-warning truncate">{s.dx_call}</span> long ago. The callsign is the only part allowed to give way —
{/* The entry it matched, when it is a prefix: "DP1*" told the everything else is short and fixed, and a row that wraps is a
operator to watch a fleet, and which member turned up is not row an operator has to parse instead of scan. */}
obvious from the callsign alone. */} <span className="font-mono text-[13px] font-bold text-warning truncate">{s.dx_call}</span>
{e.callsign !== s.dx_call && ( {s.band && (
<span className="text-[9px] text-muted-foreground shrink-0">{e.callsign}</span> <span className="rounded px-1 py-px text-[10px] font-bold uppercase bg-info-muted text-info-muted-foreground shrink-0">
)} {s.band}
<div className="flex-1" />
<span className="font-mono text-[10px] text-muted-foreground/70 tabular-nums shrink-0">
{age(s)}
</span> </span>
</div> )}
<div className="flex items-center gap-1.5 mt-0.5"> {mode && <span className="font-mono text-[10px] text-muted-foreground shrink-0">{mode}</span>}
{s.band && ( <div className="flex-1" />
<span className="rounded px-1 py-px text-[10px] font-bold uppercase bg-info-muted text-info-muted-foreground shrink-0"> {/* Why it is worth interrupting a QSO for — or not. */}
{s.band} {badge && (
</span> <span className="rounded px-1 py-px text-[10px] font-bold uppercase tracking-wide border shrink-0"
)} style={{ color: badge.colour, borderColor: `color-mix(in srgb, ${badge.colour} 45%, transparent)`,
{mode && <span className="font-mono text-[10px] text-muted-foreground shrink-0">{mode}</span>} background: `color-mix(in srgb, ${badge.colour} 12%, transparent)` }}>
<div className="flex-1" /> {t(badge.key)}
{/* Why it is worth interrupting a QSO for — or not. */} </span>
{badge && ( )}
<span className="rounded px-1 py-px text-[10px] font-bold uppercase tracking-wide border shrink-0" <span className="font-mono text-[10px] text-muted-foreground/70 tabular-nums shrink-0 w-7 text-right">
style={{ color: badge.colour, borderColor: `color-mix(in srgb, ${badge.colour} 45%, transparent)`, {age(s)}
background: `color-mix(in srgb, ${badge.colour} 12%, transparent)` }}> </span>
{t(badge.key)}
</span>
)}
</div>
</button> </button>
); );
})} })}