style(cluster): one header row in the docked pane

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.
This commit is contained in:
2026-08-28 13:15:41 +02:00
parent f7b9aa2181
commit 30f74583ff
3 changed files with 24 additions and 9 deletions
+9 -2
View File
@@ -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<string, string> = { 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<any>(null);
const [pickerOpen, setPickerOpen] = useState(false);
@@ -689,7 +694,9 @@ export function ClusterGrid({ rows, spotStatus, onSpotClick, onSpotSelect }: Pro
return (
<>
<div className="flex items-center justify-end gap-2 px-2.5 py-1 border-b border-border/60 bg-muted/20">
<div className="flex items-center gap-2 px-2.5 py-1 border-b border-border/60 bg-muted/20">
{headerLeft}
<div className="flex-1" />
<Button variant="ghost" size="sm" className="h-7 text-[11px]" onClick={() => gridRef.current?.api?.setFilterModel(null)}
title={t('clg2.clearFiltersTitle')}>
<FilterX className="size-3.5" /> {t('clg2.clearFilters')}