From 30f74583fff30253277b6b4242893dc634b5b4bf Mon Sep 17 00:00:00 2001 From: rouggy Date: Fri, 28 Aug 2026 13:15:41 +0200 Subject: [PATCH] style(cluster): one header row in the docked pane MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pane drew its own title bar above the grid's toolbar, so the cluster spent two lines on headers where Recent QSOs beside it spent one — in a pane often only a few spots tall. The grid's toolbar now takes what the caller wants on its left, and the pane passes its title, live count and Filters button there. Reported by VK4DX. --- changelog.json | 6 ++++-- frontend/src/App.tsx | 16 +++++++++++----- frontend/src/components/ClusterGrid.tsx | 11 +++++++++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/changelog.json b/changelog.json index b955642..00e626f 100644 --- a/changelog.json +++ b/changelog.json @@ -8,7 +8,8 @@ "TCI (SunSDR): clicking a cluster spot no longer needs a second click to get the mode right — the sideband was chosen from the frequency the radio had last reported instead of the one just asked for. The log also names the ExpertSDR version now, and says so when it is older than the 1.5 that panorama spots need.", "Two screens: OpsLog no longer walks off the desktop. On a monitor placed left of the primary one, the saved position was being added to that monitor’s own origin at every launch, so the window moved one screen further out each time until it was invisible.", "CW over TCI: a SunSDR can now be keyed through its own macro keyer — pick TCI as the keyer engine (Settings → CW Keyer) and macros, auto-call and the speed control all work over the link already open, with no WinKeyer and no second serial port. NOT TESTED on the air yet.", - "LoTW upload: a refusal now shows TQSL’s own explanation — which contacts were already uploaded, which fell outside the certificate’s dates — instead of the bare “no QSOs processed”, and names the two settings that cause it." + "LoTW upload: a refusal now shows TQSL’s own explanation — which contacts were already uploaded, which fell outside the certificate’s dates — instead of the bare “no QSOs processed”, and names the two settings that cause it.", + "Main tab: the docked cluster now has ONE header row — its title, live count and Filters button sit with Clear filters and Columns, as Recent QSOs beside it already did. The pane is titled DX Cluster." ], "fr": [ "Téléchargement LoTW : les détails QSL (date du QSL, locator, état, comté) deviennent optionnels et désactivés par défaut — LoTW met environ dix fois plus longtemps à construire ce rapport, vingt minutes contre deux sur le même compte, et marquer une confirmation n'en a pas besoin. Toujours demandés automatiquement quand on ajoute les QSO absents du log.", @@ -16,7 +17,8 @@ "TCI (SunSDR) : cliquer un spot du cluster ne demande plus un second clic pour obtenir le bon mode — la bande latérale était choisie d'après la fréquence encore annoncée par la radio au lieu de celle qu'on venait de demander. Le journal indique aussi la version d'ExpertSDR, et signale si elle est antérieure à la 1.5 qu'exigent les spots sur le panorama.", "Deux écrans : OpsLog ne s'échappe plus du bureau. Sur un écran placé à gauche de l'écran principal, la position enregistrée était ajoutée à l'origine de cet écran à chaque lancement, si bien que la fenêtre s'éloignait d'un écran à chaque fois jusqu'à devenir invisible.", "CW en TCI : un SunSDR peut désormais être manipulé par son propre keyer à macros — choisissez TCI comme moteur (Réglages → Manipulateur CW) et les macros, l'appel automatique et le réglage de vitesse passent par la liaison déjà ouverte, sans WinKeyer ni second port série. PAS ENCORE TESTÉ sur l'air.", - "Envoi LoTW : un refus affiche désormais l'explication de TQSL — quels contacts étaient déjà envoyés, lesquels tombaient hors des dates du certificat — au lieu du seul « no QSOs processed », et nomme les deux réglages qui en sont la cause." + "Envoi LoTW : un refus affiche désormais l'explication de TQSL — quels contacts étaient déjà envoyés, lesquels tombaient hors des dates du certificat — au lieu du seul « no QSOs processed », et nomme les deux réglages qui en sont la cause.", + "Onglet Main : le cluster ancré n'a plus qu'UNE ligne d'en-tête — son titre, le compteur live et le bouton Filtres rejoignent Effacer les filtres et Colonnes, comme le faisait déjà la liste des QSO récents à côté. Le panneau s'intitule DX Cluster." ] }, { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 383e0cf..4d556ba 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -6236,13 +6236,19 @@ export default function App() { case 'cluster': return (
-
- Cluster - {clusterFiltersToggleBtn} -
- + {/* Title, count and Filters ride INSIDE the grid's toolbar: two + header rows cost a pane that is often only a few spots tall + one of the few lines it has. */} + + DX Cluster + {spots.length} live + {clusterFiltersToggleBtn} + + )} />
{clusterShowFilters && renderClusterFilters()}
diff --git a/frontend/src/components/ClusterGrid.tsx b/frontend/src/components/ClusterGrid.tsx index 7a63456..f237a01 100644 --- a/frontend/src/components/ClusterGrid.tsx +++ b/frontend/src/components/ClusterGrid.tsx @@ -84,6 +84,11 @@ type Props = { // stray click while looking took the operator off the station they were // working. Looking and going are now two different gestures. onSpotSelect?: (s: ClusterSpot) => void; + // Anything the caller wants on the LEFT of the toolbar — the pane's title, its + // live count, its Filters button. Docked in a pane, the title used to sit on a + // row of its own above this one, so the cluster ate two lines of a short pane + // where Recent QSOs beside it ate one. Reported by VK4DX. + headerLeft?: React.ReactNode; }; const COL_STATE_KEY = 'hamlog.clusterColState.v1'; @@ -523,7 +528,7 @@ const GROUP_ORDER = ['Spot', 'Geo']; const CLG_GRP_KEYS: Record = { Spot: 'clg2.grpSpot', Geo: 'clg2.grpGeo' }; const groupLabel = (t: TFn, g: string): string => t(CLG_GRP_KEYS[g] ?? g); -export function ClusterGrid({ rows, spotStatus, onSpotClick, onSpotSelect }: Props) { +export function ClusterGrid({ rows, spotStatus, onSpotClick, onSpotSelect, headerLeft }: Props) { const { t } = useI18n(); const gridRef = useRef(null); const [pickerOpen, setPickerOpen] = useState(false); @@ -689,7 +694,9 @@ export function ClusterGrid({ rows, spotStatus, onSpotClick, onSpotSelect }: Pro return ( <> -
+
+ {headerLeft} +