codeburn/app/renderer/components/SegTabs.tsx
iamtoruk 015a1a069a polish(app): shared empty states, type ladder, AA contrast, honest affordances, a11y semantics
D1 one shared EmptyNote (7 copies removed); CliErrorPanel on canonical
   tokens; dead code deleted (CapsuleChart, stale SERIES_HEX palette,
   Stat tone API, unused rail/doc-chrome CSS)
D2 type ladder tokens (--fs-*/--fw-*); panel titles unified 13/600/ink;
   high-visibility sizes/weights snapped to rungs
D3 contrast: --mut2 5.00:1 light / 5.74:1 dark (was 2.37/3.11); new
   --accent-text 5.07:1 + persistent underline on text links; last
   prose em-dash removed
D4 'See all' and 'Most expensive sessions' navigate to Sessions; 'add
   alias' jumps to Settings/Aliases; chevrons only on clickable rows;
   inline confirm replaces window.confirm; default-period setting
   honored at boot; Sankey caption no longer promises a click; Optimize
   'improving' trend badges; cursor + Space-key fixes
D5 aria-current on nav, SegTabs as real tablist, aria-pressed toggles,
   ProviderPop rebuilt on Dropdown (one tab stop, arrow keys, focus ring)

191/191, typecheck + build green. Contrast ratios independently
recomputed. Net -93 lines.
2026-07-16 02:27:41 -07:00

37 lines
894 B
TypeScript

export type SegOption = { value: string; label: string }
/** The `.seg` segmented control used for period and lens switching. */
export function SegTabs({
options,
value,
onChange,
style,
}: {
options: SegOption[]
value: string
onChange: (value: string) => void
style?: React.CSSProperties
}) {
return (
<div className="seg" role="tablist" style={style}>
{options.map(opt => (
<span
key={opt.value}
className={opt.value === value ? 'on' : undefined}
role="tab"
aria-selected={opt.value === value}
tabIndex={0}
onClick={() => onChange(opt.value)}
onKeyDown={e => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
onChange(opt.value)
}
}}
>
{opt.label}
</span>
))}
</div>
)
}