diff --git a/frontend/src/components/ClusterGrid.tsx b/frontend/src/components/ClusterGrid.tsx index aa03a8a..e77d222 100644 --- a/frontend/src/components/ClusterGrid.tsx +++ b/frontend/src/components/ClusterGrid.tsx @@ -103,13 +103,23 @@ function statusFor(p: any): SpotStatusEntry | undefined { // Status column, using the same colours as the per-cell fills (NEW DXCC = // call cell, NEW BAND = band cell, NEW SLOT = mode cell). Returns null when // there's nothing notable to show. -function statusBadge(t: TFn, s: SpotStatusEntry | undefined): { text: string; fg: string; bg: string } | null { +type Badge = { text: string; fg: string; bg: string; bd: string }; + +// tok builds a badge from a semantic status token (success/warning/caution/ +// danger/info/neutral) so the colours adapt to every theme via CSS variables, +// instead of the hard-coded light-theme pastels that looked wrong in dark mode. +function tok(name: string, text: string): Badge { + if (name === 'neutral') return { text, fg: 'var(--muted-foreground)', bg: 'var(--muted)', bd: 'var(--border)' }; + return { text, fg: `var(--${name}-muted-foreground)`, bg: `var(--${name}-muted)`, bd: `var(--${name}-border)` }; +} + +function statusBadge(t: TFn, s: SpotStatusEntry | undefined): Badge | null { switch (s?.status) { - case 'new': return { text: t('clg2.newDxcc'), fg: '#be123c', bg: '#ffe4e6' }; - case 'new-band': return { text: t('clg2.newBand'), fg: '#92400e', bg: '#fde68a' }; - case 'new-mode': return { text: t('clg2.newMode'), fg: '#854d0e', bg: '#fef08a' }; - case 'new-slot': return { text: t('clg2.newSlot'), fg: '#854d0e', bg: '#fef08a' }; - default: return s?.worked_call ? { text: t('clg2.wkdCall'), fg: '#0369a1', bg: '#e0f2fe' } : null; + case 'new': return tok('danger', t('clg2.newDxcc')); + case 'new-band': return tok('warning', t('clg2.newBand')); + case 'new-mode': return tok('caution', t('clg2.newMode')); + case 'new-slot': return tok('caution', t('clg2.newSlot')); + default: return s?.worked_call ? tok('neutral', t('clg2.wkdCall')) : null; } } @@ -132,8 +142,8 @@ const makeColCatalog = (t: TFn): ColEntry[] => [ // the rest of the row across every theme instead of always shouting orange. cellStyle: (p: any): any => { const s = statusFor(p); - if (s?.status === 'new') return { backgroundColor: '#ffe4e6', color: '#be123c', fontWeight: 700 }; - if (s?.worked_call) return { color: '#0369a1', fontWeight: 700 }; + if (s?.status === 'new') return { backgroundColor: 'var(--danger-muted)', color: 'var(--danger-muted-foreground)', fontWeight: 700 }; + if (s?.worked_call) return { color: 'var(--info)', fontWeight: 700 }; return { fontWeight: 700 }; }, tooltipValueGetter: (p: any) => { @@ -162,18 +172,20 @@ const makeColCatalog = (t: TFn): ColEntry[] => [ }, cellRenderer: (p: any) => { const s = statusFor(p); - const badges: { text: string; fg: string; bg: string }[] = []; + const badges: Badge[] = []; const b = statusBadge(t, s); if (b) badges.push(b); - if (s?.new_county) badges.push({ text: t('clg2.newCounty'), fg: '#6b21a8', bg: '#f3e8ff' }); - if (s?.new_pota) badges.push({ text: t('clg2.newPota'), fg: '#166534', bg: '#dcfce7' }); - if (badges.length === 0) return ; + if (s?.new_county) badges.push(tok('info', t('clg2.newCounty'))); + if (s?.new_pota) badges.push(tok('success', t('clg2.newPota'))); + if (badges.length === 0) return ; return ( {badges.map((bd, i) => ( {bd.text} ))}