fix(compact): size the window to the strip instead of a tuned constant

compactH was 158px, "tuned so the compact entry strip fits in a single row".
A constant tuned against a layout stops being true the moment the layout
changes, and this one outlived a strip that had since shrunk — leaving about
70px of empty window under the fields.

The frontend now measures what it rendered and asks for that height, watched by
a ResizeObserver so a strip that wraps at a narrow width is followed too. The
topbar is added as its declared h-8 rather than measured, since it is fixed.

Bounded in the backend: a measurement of zero — a layout not yet painted —
must not collapse the window, and the call is ignored unless compact is on so
nothing can shrink the normal window. Rounded to whole pixels so a sub-pixel
reflow cannot start a resize loop.
This commit is contained in:
2026-08-13 11:54:09 +02:00
parent 8fccfa29b1
commit 93879a0ce1
5 changed files with 60 additions and 4 deletions
+24 -2
View File
@@ -16,7 +16,7 @@ import {
GetStartupStatus, CheckForUpdate, DownloadAndApplyUpdate, GetLiveStations, GetWhatsNew, GetChangelog,
SMTPConfigured, SendLogToDeveloper,
WorkedBefore,
SetCompactMode,
SetCompactMode, SetCompactHeight,
GetCATState, SetCATFrequency, SetCATMode, SwitchCATRig, FlexApplyBandAntenna, FlexApplyBandPower,
GetSecretStatus, UnlockSecrets,
RefreshCtyDat, DownloadAllReferenceLists,
@@ -529,6 +529,28 @@ export default function App() {
setCompact(next);
SetCompactMode(next);
}
// Fit the compact window to what was actually rendered.
//
// The height was a constant "tuned so the compact entry strip fits in a single
// row". A constant tuned against a layout stops being true the moment the
// layout changes, and this one outlived a strip that had since lost a row —
// leaving a band of empty window under the fields. Measure instead.
const compactRootRef = useRef<HTMLDivElement | null>(null);
useEffect(() => {
if (!compact) return;
const fit = () => {
const el = compactRootRef.current;
if (!el) return;
// Rounded, so a sub-pixel reflow cannot start a resize loop.
// + the compact topbar, which is a fixed h-8 (32px), + a couple of pixels
// for the border so the strip is never clipped by one row of anti-aliasing.
SetCompactHeight(Math.round(el.getBoundingClientRect().height) + 32 + 2);
};
const id = window.setTimeout(fit, 60); // let the strip paint first
const ro = new ResizeObserver(fit);
if (compactRootRef.current) ro.observe(compactRootRef.current);
return () => { window.clearTimeout(id); ro.disconnect(); };
}, [compact]);
// CAT — receives live rig state via Wails events.
const [catState, setCatState] = useState<CATState>({ enabled: false, connected: false } as any);
@@ -5892,7 +5914,7 @@ export default function App() {
Enter from any <input> inside the strip logs the QSO. Radix Selects
render as <button> elements and are ignored by this handler they
keep their own keyboard behaviour. */}
<div className={cn(!compact && 'flex gap-2.5 items-stretch px-2.5 pt-2.5 shrink-0')}>
<div ref={compactRootRef} className={cn(!compact && 'flex gap-2.5 items-stretch px-2.5 pt-2.5 shrink-0')}>
<section
className={cn('bg-card shadow-sm border-border',
compact