ui: Station Control masonry layout — pack cards into balanced columns

flex-wrap with fixed-width cards started each new row below the TALLEST card of
the previous row, leaving big gaps under short panels (e.g. the amplifier alone
on a second line). Switch the dashboard to balanced CSS columns (column-width
430px, break-inside-avoid): cards flow top-to-bottom and pack tightly by height.
"Auto" fits as many columns as the window allows; 1-4 cap the column count via
the container max-width. Grip-drag reorder unchanged. Changelog 0.21.1.
This commit is contained in:
2026-07-25 01:49:18 +02:00
parent 3f15608c59
commit 88202efddb
2 changed files with 12 additions and 9 deletions
+4 -2
View File
@@ -4,11 +4,13 @@
"date": "2026-07-24", "date": "2026-07-24",
"en": [ "en": [
"Fixed the colour theme sometimes reverting to the default when reopening OpsLog — it's now restored reliably.", "Fixed the colour theme sometimes reverting to the default when reopening OpsLog — it's now restored reliably.",
"ADIF export field picker: the per-group All / None buttons work again." "ADIF export field picker: the per-group All / None buttons work again.",
"Station Control: cards now pack tightly into balanced columns instead of leaving big gaps under shorter panels — a cleaner, more even dashboard."
], ],
"fr": [ "fr": [
"Correction du thème qui revenait parfois au défaut à la réouverture d'OpsLog — il est maintenant restauré de façon fiable.", "Correction du thème qui revenait parfois au défaut à la réouverture d'OpsLog — il est maintenant restauré de façon fiable.",
"Sélecteur de champs à l'export ADIF : les boutons Tout / Aucun par groupe refonctionnent." "Sélecteur de champs à l'export ADIF : les boutons Tout / Aucun par groupe refonctionnent.",
"Station Control : les cartes se rangent en colonnes équilibrées et se tassent au lieu de laisser de gros trous sous les panneaux plus courts — tableau de bord plus propre et régulier."
] ]
}, },
{ {
@@ -442,14 +442,15 @@ export function StationControlPanel({ centerLat, centerLon, bearing }: RotatorPr
</div> </div>
)} )}
{/* Dashboard of FIXED-WIDTH cards that wrap. "Auto" fills the window; a fixed {/* Masonry dashboard: fixed-width cards flow into balanced CSS columns so
column count caps the container width so cards wrap onto more lines. Each they pack tightly by height (no ragged gaps under short cards). "Auto"
card has a grip handle (left rail) as the drag initiator (the card body is fits as many ~430px columns as the window allows; a fixed count caps the
full of buttons, so dragging the whole card was unreliable). */} container width to that many columns. Each card has a grip handle (left
<div className="flex flex-wrap gap-4 items-start" rail) as the drag initiator (the body is full of buttons). */}
style={cols !== 'auto' ? { maxWidth: `${Number(cols) * 446}px` } : undefined}> <div style={{ columnWidth: '430px', columnGap: '1rem', columnFill: 'balance',
...(cols !== 'auto' ? { maxWidth: `${Number(cols) * 446}px` } : {}) }}>
{ordered.map((w) => ( {ordered.map((w) => (
<div key={w.id} className="flex items-stretch w-[430px]" <div key={w.id} className="flex items-stretch break-inside-avoid mb-4"
onDragOver={(e) => { if (dragId.current) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; } }} onDragOver={(e) => { if (dragId.current) { e.preventDefault(); e.dataTransfer.dropEffect = 'move'; } }}
onDrop={(e) => { if (dragId.current) { e.preventDefault(); onDrop(w.id); } }}> onDrop={(e) => { if (dragId.current) { e.preventDefault(); onDrop(w.id); } }}>
<div draggable <div draggable