feat: add colored active state to status filter pills
All checks were successful
Build & Publish / publish (push) Successful in 43s

FilterPill gains activeColor prop — when active, border/text/background
tint match the status color instead of generic amber. Inactive dots
are muted at 40% opacity for clear active/inactive contrast.

Applied to TopBar status pills and EventFeed severity pills.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-19 10:58:28 +01:00
parent fdf45d0d94
commit 8418b89a77
4 changed files with 37 additions and 9 deletions

View File

@@ -53,6 +53,13 @@ const DEFAULT_ICONS: Record<SeverityFilter, string> = {
running: '\u2699', // ⚙
}
const SEVERITY_COLORS: Record<SeverityFilter, string> = {
error: 'var(--error)',
warning: 'var(--warning)',
success: 'var(--success)',
running: 'var(--running)',
}
const SEVERITY_LABELS: Record<SeverityFilter, string> = {
error: 'Error',
warning: 'Warning',
@@ -140,6 +147,9 @@ export function EventFeed({ events, maxItems = 200, className }: EventFeedProps)
key={sev}
label={SEVERITY_LABELS[sev]}
count={count}
dot
dotColor={SEVERITY_COLORS[sev]}
activeColor={SEVERITY_COLORS[sev]}
active={activeFilters.has(sev)}
onClick={() => toggleFilter(sev)}
/>

View File

@@ -18,11 +18,11 @@ interface TopBarProps {
className?: string
}
const STATUS_PILLS: { status: ExchangeStatus; label: string }[] = [
{ status: 'completed', label: 'OK' },
{ status: 'warning', label: 'Warn' },
{ status: 'failed', label: 'Error' },
{ status: 'running', label: 'Running' },
const STATUS_PILLS: { status: ExchangeStatus; label: string; color: string }[] = [
{ status: 'completed', label: 'OK', color: 'var(--success)' },
{ status: 'warning', label: 'Warn', color: 'var(--warning)' },
{ status: 'failed', label: 'Error', color: 'var(--error)' },
{ status: 'running', label: 'Running', color: 'var(--running)' },
]
export function TopBar({
@@ -58,10 +58,13 @@ export function TopBar({
{/* Status pills */}
<div className={styles.filters}>
{STATUS_PILLS.map(({ status, label }) => (
{STATUS_PILLS.map(({ status, label, color }) => (
<FilterPill
key={status}
label={label}
dot
dotColor={color}
activeColor={color}
active={globalFilters.statusFilters.has(status)}
onClick={() => globalFilters.toggleStatus(status)}
/>

View File

@@ -35,6 +35,14 @@
flex-shrink: 0;
}
.dotMuted {
opacity: 0.4;
}
.activeColored {
font-weight: 600;
}
.label {
line-height: 1;
}

View File

@@ -7,6 +7,7 @@ interface FilterPillProps {
active?: boolean
dot?: boolean
dotColor?: string
activeColor?: string
onClick?: () => void
className?: string
}
@@ -18,21 +19,27 @@ export const FilterPill = forwardRef<HTMLButtonElement, FilterPillProps>(
active = false,
dot = false,
dotColor,
activeColor,
onClick,
className,
}, ref) => {
const classes = [
styles.pill,
active ? styles.active : '',
active && activeColor ? styles.activeColored : '',
className ?? '',
].filter(Boolean).join(' ')
const activeStyle = active && activeColor
? { borderColor: activeColor, backgroundColor: `color-mix(in srgb, ${activeColor} 12%, transparent)`, color: activeColor } as React.CSSProperties
: undefined
return (
<button ref={ref} className={classes} onClick={onClick} type="button" data-active={active || undefined}>
<button ref={ref} className={classes} style={activeStyle} onClick={onClick} type="button" data-active={active || undefined}>
{dot && (
<span
className={styles.dot}
style={dotColor ? { background: dotColor } : undefined}
className={`${styles.dot} ${!active ? styles.dotMuted : ''}`}
style={dotColor ? { background: active ? dotColor : undefined } : undefined}
/>
)}
<span className={styles.label}>{label}</span>