🎨 fix(web): align UI and charts with theme tokens and presets

Improve theme switching fidelity (including system preference), extend design tokens so color presets tint real surfaces—not only primary/chrome—and refactor shared badges, tables, and dashboard visuals to semantic colors. Wire VChart series colors to `--chart-*` with safe fallbacks.

**Changes**

- **Theme runtime** (`theme-provider.tsx`): Validate stored theme cookie; keep `resolvedTheme` in sync with DOM + `(prefers-color-scheme)`; `resetTheme` respects `defaultTheme`; memoized context value.
- **Tokens** (`theme.css`): Add `--success|warning|info|neutral` (+ foregrounds) and map them under `@theme inline` for Tailwind utilities.
- **Presets** (`theme-presets.css`): For non-`default` presets, derive `card`, `popover`, `muted`, `accent`, `border`, `input`, and sidebar tokens from `--primary`/`--background`; map semantic status colors to preset chart variables.
- **Components**: `status-badge`, `colors` (avatars, announcements), `copy-button`, `group-badge`, `data-table` row styles, `sidebar` outline shadow (fix `var(--sidebar-border)` usage), ai-elements tool/web-preview status colors.
- **Dashboard**: Latency/API helpers and overview fragments use semantic tokens; `charts.ts` reads `--chart-1`…`--chart-5` from computed styles with fallbacks; `processChartData` / `processUserChartData` accept optional `themeKey` for preset churn; chart components pass `customization.preset` and bump `VChart` keys.

**Verification**

- `bun run typecheck`
This commit is contained in:
t0ng7u
2026-05-07 11:20:43 +08:00
parent 415d21d071
commit a7475a1e67
19 changed files with 315 additions and 172 deletions
@@ -210,13 +210,11 @@ function StartStepItem(props: {
<span
className={cn(
'bg-background relative z-10 flex size-8 shrink-0 items-center justify-center rounded-full border shadow-xs',
props.step.completed && 'border-emerald-500/30 bg-emerald-500/10'
props.step.completed && 'border-success/30 bg-success/10'
)}
>
<StatusIcon
className={
props.step.completed ? 'size-4 text-emerald-600' : 'size-4'
}
className={props.step.completed ? 'text-success size-4' : 'size-4'}
aria-hidden='true'
/>
</span>
@@ -316,9 +314,9 @@ function RequestPreview(props: {
<div className='bg-foreground/[0.035] my-3 rounded-xl p-3 font-mono text-xs'>
<div className='mb-2 flex items-center gap-1.5'>
<span className='size-2 rounded-full bg-red-400' />
<span className='size-2 rounded-full bg-amber-400' />
<span className='size-2 rounded-full bg-emerald-400' />
<span className='bg-destructive size-2 rounded-full' />
<span className='bg-warning size-2 rounded-full' />
<span className='bg-success size-2 rounded-full' />
</div>
<div className='flex flex-col gap-1 overflow-hidden'>
{previewLines.map((line, index) => (
@@ -650,10 +648,7 @@ export function OverviewDashboard() {
<div className='relative flex flex-wrap items-center justify-between gap-3'>
<div className='flex min-w-0 items-center gap-3'>
<span className='bg-background/70 flex size-9 shrink-0 items-center justify-center rounded-xl border shadow-xs'>
<Check
className='size-4 text-emerald-600'
aria-hidden='true'
/>
<Check className='text-success size-4' aria-hidden='true' />
</span>
<div className='min-w-0'>
<div className='flex items-center gap-2'>