2026-05-09 11:35:07 +08:00
|
|
|
/*
|
|
|
|
|
Copyright (C) 2023-2026 QuantumNous
|
|
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU Affero General Public License as
|
|
|
|
|
published by the Free Software Foundation, either version 3 of the
|
|
|
|
|
License, or (at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU Affero General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
|
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
|
|
For commercial licensing, please contact support@quantumnous.com
|
|
|
|
|
*/
|
feat(web/default): unified UI overhaul — Base UI migration, theme presets, rankings dashboard, and table toolbar refactor (#4633)
* 🎨 feat(web/default): add shadcn-style theme presets, radius prefs, and fix selection badges
Integrate the qn-platform–style OKLCH color system into the default frontend while keeping the existing blue-tinted dark tokens for the default theme. Add [data-theme-preset] palettes for seven named presets plus the default zinc-like scale, define [data-theme-radius] overrides so user radius beats preset --radius, and align the Tailwind @custom-variant dark helper with .dark usage.
Introduce ThemeCustomizationProvider to own preset and radius state, persist choices in cookies (theme-preset, theme-radius), and sync data-theme-preset / data-theme-radius on <html>. Wrap the tree in main.tsx.
Extend ConfigDrawer with theme preset swatches (scoped data-theme-preset) and radius previews wired to context; refactor swatch/card markup so selected CircleCheck badges sit outside clipped rows (remove outer overflow-hidden that hid the centered checkmark).
Add i18n keys for preset names, radius, and accessibility labels across en, zh, fr, ja, ru, vi.
* 🎨 fix(web): align segmented controls with theme radius tokens
- Replace hard-coded inner pill radii (rounded-[5px]) on dashboard chart
toolbars with radius-md so the active state follows --radius when users
change Radius in Theme Settings.
- Use nested radii consistent with TabsList/TabsTrigger: outer
rounded-lg (var(--radius)) and inner rounded-md (calc(var(--radius) - 2px))
so the track and active thumb stay concentric at small scales (e.g.
0.3rem) instead of a squared “focus” block inside a rounded shell.
- Apply the same pattern to pricing SegmentedControl and the segmented
groups in consumption-distribution-chart, model-charts, and user-charts.
Verified: bun run typecheck (web/default)
* ✨ feat(pricing): enrich model details with uptime sparkline and API documentation
Add a compact 30-day uptime sparkline (OpenRouter-style bars + aggregate %) with
per-day tooltips, surface it in a status row under quick stats and in the
per-group performance table, and extend mock data so uptime series are stable
and optionally scoped by group.
Introduce an API tab with Shiki-highlighted code samples (cURL, Python,
TypeScript, JavaScript), endpoint-type switching, authentication guidance, a
supported-parameters table, and mock per-group RPM/TPM/RPD limits. Infer
vendor, tokenizer, license, and data-retention hints for a provider & data
privacy card on the Overview tab (capabilities/modalities stay with model
identity; rate limits stay with the API tab).
Update i18n for all new user-facing strings across en, zh, fr, ja, ru, and vi.
* 🏆 feat(rankings): add comprehensive rankings dashboard
Add a mock-data powered rankings experience with period tabs, model, app, and vendor leaderboards, market share and history charts, movers, new releases, and per-category sections while backend analytics are pending.
Link ranked models to pricing details and ranked vendors to filtered pricing results, and include localized copy for all supported frontend locales.
* fix(theme): correct theme preset selection state
- update Base UI Radio selectors to use data-checked/data-unchecked states.
- fix unchecked theme options still showing selected indicators.
- isolate the default theme preview tokens to prevent preset changes from leaking into it.
* fix(setup): correct usage mode radio state
- use Base UI data-checked/data-unchecked states for RadioGroup styling.
- hide radio indicators when options are unchecked to avoid setup page display issues.
- drive usage mode card and icon selection styles from Base UI state.
* fix(auth): submit sign-in and sign-up forms
* 🎨 refactor: Align default theme with shadcn Base Nova and prune legacy customization
Migrate shadcn UI to Base UI primitives via CLI (`base-nova` / `components.json`)
and reinstall full component registry with `--overwrite`, including Hugeicons-backed
widgets and newly added registry components.
- Remove custom multi-preset/theme-radius system (`ThemeCustomizationProvider`, cookies,
preset UI from config drawer); rely on official semantic CSS tokens + light/dark only.
- Replace `theme.css` with shadcn’s documented neutral `:root`/`.dark` palette and
`@theme inline` mappings (plus skeleton token vars for existing shimmer usage).
- Update global styles for Base UI: collapsible animation uses `--collapsible-panel-height`;
clarify scroll-lock override comment.
Application compatibility:
- Keep minimal shims where app code diverged from official APIs (popover collision props,
combobox legacy `options` callers, Spinner prop typing).
- Switch interactive styling from Radix-era `data-state` / `--radix-*` selectors to Base UI
semantics (`data-open`, `data-popup-open`, `data-panel-open`, `--anchor-width`, etc.)
Tooling / docs / build:
- Rename Rsbuild vendor chunk grouping to `@base-ui` + transitive `@radix-ui`.
- Refresh AGENTS.md / CLAUDE.md / classic→default sync skill for Base UI stack.
- Bump `package.json` / lockfile for shadcn-postinstall deps (Hugeicons, chart stack, themes, etc.)
Verified: `bun run typecheck` passes.
Note: `bun run lint` still reports pre-existing hooks rule violations elsewhere;
not addressed in this change.
* 🎨 chore(web/default): unify table toolbar, relocate usage stats, refine filters
- Refactor DataTableToolbar to a single wrapping flex row with a
right-aligned action cluster (Reset / Search / View / Expand) for a
cleaner Ant Design Pro–style filter bar; remove the dedicated stats row
and the toolbar `stats` prop.
- Move Common Logs summary badges (Usage / RPM / TPM) and the sensitive-
data visibility toggle into the page header via CommonLogsHeaderActions
and SectionPageLayout.Actions so the toolbar stays focused on filters.
- Slim CommonLogsFilterBar props (no stats / preActions eye control).
- Improve CompactDateTimeRangePicker: show minute-precision labels on the
trigger (seconds omitted; aligns with datetime-local inputs); widen the
trigger on sm+ breakpoints so the full range is visible without truncation;
apply the same width in task logs filters.
- Simplify DataTableViewOptions: text-only “View” trigger, no sliders icon.
- Earlier layout tweak: extra top padding on SectionPageLayout scroll
content so control focus rings are not clipped by overflow.
* feat(web/default): Base UI migration and component foundation
Migrate from Radix UI to Base UI, rewrite core UI primitives,
update dependencies (recharts, date-fns, next-themes), add
shadcn agent skill documentation, and refresh AI element components.
This is the foundational work from the v2/localmain lineage that
was not covered by the individual feature commits above.
---------
Co-authored-by: t0ng7u <dev@aiass.cc>
Co-authored-by: QuentinHsu <xuquentinyang@gmail.com>
2026-05-06 12:39:36 +08:00
|
|
|
/*
|
|
|
|
|
* Theme presets — color palettes, border radius, and density scaling.
|
|
|
|
|
*
|
|
|
|
|
* Usage: applied via data attributes on <body>:
|
|
|
|
|
* <body data-theme-preset="rose-garden" data-theme-radius="lg" data-theme-scale="sm" />
|
|
|
|
|
*
|
|
|
|
|
* - `data-theme-preset` overrides the color palette defined in ./theme.css and
|
|
|
|
|
* ships a curated default `--radius` value to match the preset's mood
|
|
|
|
|
* (e.g. rose-garden uses 1rem, ocean-breeze uses 0.3rem).
|
|
|
|
|
* - Each preset declares both light and dark color values; dark values use
|
|
|
|
|
* the `.dark` ancestor selector so they apply when html has the `.dark` class.
|
|
|
|
|
* - `data-theme-radius` and `data-theme-scale` adjust visual density
|
|
|
|
|
* independently. The radius block is intentionally placed AFTER the preset
|
|
|
|
|
* blocks so an explicit user choice overrides the preset's default radius.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* ── Underground ──────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='underground'] {
|
|
|
|
|
--primary: oklch(0.5315 0.0694 156.19);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.5748 0.0862 336.52);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.5315 0.0694 156.19);
|
|
|
|
|
--chart-1: oklch(0.5315 0.0694 156.19);
|
|
|
|
|
--chart-2: oklch(0.5748 0.0862 336.52);
|
|
|
|
|
--chart-3: oklch(0.8603 0.0731 158.6);
|
|
|
|
|
--chart-4: oklch(0.8292 0.0422 332);
|
|
|
|
|
--chart-5: oklch(0.9564 0.0234 159.23);
|
|
|
|
|
--sidebar-primary: oklch(0.5315 0.0694 156.19);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.9687 0.0051 247.88);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0.279 0.0299 260.05);
|
|
|
|
|
--sidebar-ring: oklch(0.5315 0.0694 156.19);
|
|
|
|
|
--radius: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='underground'] {
|
|
|
|
|
--primary: oklch(0.6147 0.0867 154.73);
|
|
|
|
|
--primary-foreground: oklch(0.129 0.0306 264.71);
|
|
|
|
|
--secondary: oklch(0.6624 0.0855 334.26);
|
|
|
|
|
--secondary-foreground: oklch(0.129 0.0306 264.71);
|
|
|
|
|
--ring: oklch(0.6147 0.0867 154.73);
|
|
|
|
|
--chart-1: oklch(0.6147 0.0867 154.73);
|
|
|
|
|
--chart-2: oklch(0.6624 0.0855 334.26);
|
|
|
|
|
--chart-3: oklch(0.7122 0.0991 154.66);
|
|
|
|
|
--chart-4: oklch(0.7308 0.07 333.6);
|
|
|
|
|
--chart-5: oklch(0.781 0.0975 156.24);
|
|
|
|
|
--sidebar-primary: oklch(0.6147 0.0867 154.73);
|
|
|
|
|
--sidebar-primary-foreground: oklch(0.129 0.0306 264.71);
|
|
|
|
|
--sidebar-accent: oklch(0.279 0.0299 260.05);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0.929 0.0095 255.53);
|
|
|
|
|
--sidebar-ring: oklch(0.6147 0.0867 154.73);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Rose Garden ──────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='rose-garden'] {
|
|
|
|
|
--primary: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.8131 0.1129 5.67);
|
|
|
|
|
--secondary-foreground: oklch(0.2686 0.0032 34.85);
|
|
|
|
|
--ring: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--chart-1: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--chart-2: oklch(0.8938 0.0563 3.77);
|
|
|
|
|
--chart-3: oklch(0.7135 0.1879 7.69);
|
|
|
|
|
--chart-4: oklch(0.8131 0.1129 5.67);
|
|
|
|
|
--chart-5: oklch(0.9429 0.0283 5.52);
|
|
|
|
|
--sidebar-primary: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5827 0.2418 12.23);
|
|
|
|
|
--radius: 1rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='rose-garden'] {
|
|
|
|
|
--primary: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.8131 0.1129 5.67);
|
|
|
|
|
--secondary-foreground: oklch(0.9227 0.0029 34.49);
|
|
|
|
|
--ring: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
--chart-1: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
--chart-2: oklch(0.8938 0.0563 3.77);
|
|
|
|
|
--chart-3: oklch(0.7135 0.1879 7.69);
|
|
|
|
|
--chart-4: oklch(0.8131 0.1129 5.67);
|
|
|
|
|
--chart-5: oklch(0.9429 0.0283 5.52);
|
|
|
|
|
--sidebar-primary: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.6476 0.2348 10.36);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Lake View ────────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='lake-view'] {
|
|
|
|
|
--primary: oklch(0.765 0.177 163.22);
|
|
|
|
|
--primary-foreground: oklch(0 0 0);
|
|
|
|
|
--secondary: oklch(0.551 0.0899 200.52);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.765 0.177 163.22);
|
|
|
|
|
--chart-1: oklch(0.765 0.177 163.22);
|
|
|
|
|
--chart-2: oklch(0.551 0.0899 200.52);
|
|
|
|
|
--chart-3: oklch(0.845 0.143 164.98);
|
|
|
|
|
--chart-4: oklch(0.8576 0.1202 192.38);
|
|
|
|
|
--chart-5: oklch(0.95 0.052 163.05);
|
|
|
|
|
--sidebar-primary: oklch(0.765 0.177 163.22);
|
|
|
|
|
--sidebar-primary-foreground: oklch(0 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.765 0.177 163.22);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0.2742 0.0208 165.96);
|
|
|
|
|
--sidebar-ring: oklch(0.765 0.177 163.22);
|
|
|
|
|
--radius: 0.75rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='lake-view'] {
|
|
|
|
|
--primary: oklch(0.765 0.177 163.22);
|
|
|
|
|
--primary-foreground: oklch(0 0 0);
|
|
|
|
|
--secondary: oklch(0.551 0.0899 200.52);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.765 0.177 163.22);
|
|
|
|
|
--chart-1: oklch(0.765 0.177 163.22);
|
|
|
|
|
--chart-2: oklch(0.551 0.0899 200.52);
|
|
|
|
|
--chart-3: oklch(0.845 0.143 164.98);
|
|
|
|
|
--chart-4: oklch(0.8576 0.1202 192.38);
|
|
|
|
|
--chart-5: oklch(0.95 0.052 163.05);
|
|
|
|
|
--sidebar-primary: oklch(0.765 0.177 163.22);
|
|
|
|
|
--sidebar-primary-foreground: oklch(0 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.765 0.177 163.22);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.765 0.177 163.22);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Sunset Glow ──────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='sunset-glow'] {
|
|
|
|
|
--primary: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.7938 0.1248 42.42);
|
|
|
|
|
--secondary-foreground: oklch(0 0 0);
|
|
|
|
|
--ring: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--chart-1: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--chart-2: oklch(0.7938 0.1248 42.42);
|
|
|
|
|
--chart-3: oklch(0.809 0.0875 17.95);
|
|
|
|
|
--chart-4: oklch(0.8964 0.0724 43.73);
|
|
|
|
|
--chart-5: oklch(0.9381 0.0241 16.66);
|
|
|
|
|
--sidebar-primary: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5591 0.1882 25.33);
|
|
|
|
|
--radius: 1rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='sunset-glow'] {
|
|
|
|
|
--primary: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.7938 0.1248 42.42);
|
|
|
|
|
--secondary-foreground: oklch(0 0 0);
|
|
|
|
|
--ring: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
--chart-1: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
--chart-2: oklch(0.7938 0.1248 42.42);
|
|
|
|
|
--chart-3: oklch(0.809 0.0875 17.95);
|
|
|
|
|
--chart-4: oklch(0.8964 0.0724 43.73);
|
|
|
|
|
--chart-5: oklch(0.9381 0.0241 16.66);
|
|
|
|
|
--sidebar-primary: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.6387 0.1822 23.51);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Forest Whisper ───────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='forest-whisper'] {
|
|
|
|
|
--primary: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.5236 0.0505 250.18);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--chart-1: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--chart-2: oklch(0.5236 0.0505 250.18);
|
|
|
|
|
--chart-3: oklch(0.7741 0.1676 178.16);
|
|
|
|
|
--chart-4: oklch(0.7294 0.0416 244.67);
|
|
|
|
|
--chart-5: oklch(0.9511 0.0547 177.24);
|
|
|
|
|
--sidebar-primary: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5276 0.1072 182.22);
|
|
|
|
|
--radius: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='forest-whisper'] {
|
|
|
|
|
--primary: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.6578 0.0485 247.35);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
--chart-1: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
--chart-2: oklch(0.6578 0.0485 247.35);
|
|
|
|
|
--chart-3: oklch(0.7741 0.1676 178.16);
|
|
|
|
|
--chart-4: oklch(0.7294 0.0416 244.67);
|
|
|
|
|
--chart-5: oklch(0.9511 0.0547 177.24);
|
|
|
|
|
--sidebar-primary: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5991 0.1318 180.39);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Ocean Breeze ─────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='ocean-breeze'] {
|
|
|
|
|
--primary: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.5854 0.2041 277.12);
|
|
|
|
|
--secondary-foreground: oklch(1 0 0);
|
|
|
|
|
--ring: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--chart-1: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--chart-2: oklch(0.5854 0.2041 277.12);
|
|
|
|
|
--chart-3: oklch(0.809 0.0922 251.81);
|
|
|
|
|
--chart-4: oklch(0.785 0.1007 274.72);
|
|
|
|
|
--chart-5: oklch(0.932 0.0281 255.58);
|
|
|
|
|
--sidebar-primary: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5461 0.2152 262.88);
|
|
|
|
|
--radius: 0.3rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='ocean-breeze'] {
|
|
|
|
|
--primary: oklch(0.623 0.188 259.81);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.5854 0.2041 277.12);
|
|
|
|
|
--secondary-foreground: oklch(0 0 0);
|
|
|
|
|
--ring: oklch(0.623 0.188 259.81);
|
|
|
|
|
--chart-1: oklch(0.623 0.188 259.81);
|
|
|
|
|
--chart-2: oklch(0.5854 0.2041 277.12);
|
|
|
|
|
--chart-3: oklch(0.809 0.0922 251.81);
|
|
|
|
|
--chart-4: oklch(0.785 0.1007 274.72);
|
|
|
|
|
--chart-5: oklch(0.932 0.0281 255.58);
|
|
|
|
|
--sidebar-primary: oklch(0.623 0.188 259.81);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.623 0.188 259.81);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.623 0.188 259.81);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Lavender Dream ───────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-preset='lavender-dream'] {
|
|
|
|
|
--primary: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.811 0.0589 201.14);
|
|
|
|
|
--secondary-foreground: oklch(0 0 0);
|
|
|
|
|
--ring: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--chart-1: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--chart-2: oklch(0.811 0.0589 201.14);
|
|
|
|
|
--chart-3: oklch(0.8281 0.078 309.73);
|
|
|
|
|
--chart-4: oklch(0.8611 0.0504 198.03);
|
|
|
|
|
--chart-5: oklch(0.947 0.0212 309.77);
|
|
|
|
|
--sidebar-primary: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.5709 0.1808 306.89);
|
|
|
|
|
--radius: 1rem;
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='lavender-dream'] {
|
|
|
|
|
--primary: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
--primary-foreground: oklch(1 0 0);
|
|
|
|
|
--secondary: oklch(0.811 0.0589 201.14);
|
|
|
|
|
--secondary-foreground: oklch(0 0 0);
|
|
|
|
|
--ring: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
--chart-1: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
--chart-2: oklch(0.811 0.0589 201.14);
|
|
|
|
|
--chart-3: oklch(0.8281 0.078 309.73);
|
|
|
|
|
--chart-4: oklch(0.8611 0.0504 198.03);
|
|
|
|
|
--chart-5: oklch(0.947 0.0212 309.77);
|
|
|
|
|
--sidebar-primary: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
--sidebar-primary-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-accent: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
--sidebar-accent-foreground: oklch(1 0 0);
|
|
|
|
|
--sidebar-ring: oklch(0.6359 0.1699 307.95);
|
|
|
|
|
}
|
|
|
|
|
|
🎨 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`
2026-05-07 11:20:43 +08:00
|
|
|
/* ── Semantic surface bridge ──────────────────────────────────────────── */
|
|
|
|
|
/* Color presets should tint the surfaces most components actually use, not
|
|
|
|
|
* only primary buttons. These derived tokens keep the app theme-aware without
|
🎨 feat(web/default): add Anthropic theme preset and configurable serif typography
Introduce a switchable Anthropic-inspired color preset and a new Font customization axis so users can adopt the editorial serif look across the entire UI, including sidebar navigation, tabs, form controls, buttons, and table headers.
Theme preset
Add anthropic to the theme preset registry with warm cream canvas, slate foreground, and clay/coral accent tokens for light and dark modes
Define explicit surface colors for the Anthropic preset instead of relying on the semantic surface bridge
Exclude anthropic from the primary-color surface bridge so bespoke warm neutrals are not overridden by accent-tinted mixes
Typography system
Add @fontsource-variable/lora and a global --font-serif token with CJK serif fallbacks (Noto Serif SC, Source Han Serif, Songti SC, etc.)
Introduce a --font-body token and drive <body> font-family from it
Add a Font axis (default | sans | serif) parallel to radius/scale
Resolve font: 'default' against preset defaults (anthropic → serif)
Persist font preference via cookie and apply data-theme-font on <body>
Apply serif OpenType features (kern, liga, calt, tnum) and heading display tuning when serif is active
Remove per-component sans opt-outs so serif inherits through sidebar, tabs, inputs, buttons, badges, and table headers via natural CSS cascade
Keep monospace contexts unchanged via Tailwind preflight and .font-mono
UI and i18n
Add Font selector to the theme config drawer (Auto / Sans / Serif)
Add "Font" and "Select body font" translations for en, zh, fr, ja, ru, vi
Misc
Tighten group and status badge sizing for better balance with serif text
2026-05-26 04:31:13 +08:00
|
|
|
* duplicating per-component dark-mode overrides.
|
|
|
|
|
*
|
|
|
|
|
* NOTE: `:not()` contributes its argument's specificity, so this selector
|
|
|
|
|
* resolves to (0,2,0). Presets that define bespoke surfaces below need to
|
|
|
|
|
* either match that specificity or opt out here — the latter is cleaner.
|
|
|
|
|
*
|
|
|
|
|
* Opt-outs:
|
|
|
|
|
* - `default`: keeps neutral surfaces from :root.
|
|
|
|
|
* - `anthropic`: warm cream surfaces are a brand choice, NOT a primary-mix
|
|
|
|
|
* derivation (the Anthropic system deliberately uses warm neutrals for
|
|
|
|
|
* cards/borders rather than tinting them with the clay accent). */
|
|
|
|
|
[data-theme-preset]:not([data-theme-preset='default']):not(
|
|
|
|
|
[data-theme-preset='anthropic']
|
|
|
|
|
) {
|
🎨 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`
2026-05-07 11:20:43 +08:00
|
|
|
--card: color-mix(in oklch, var(--primary) 3%, var(--background));
|
|
|
|
|
--popover: color-mix(in oklch, var(--primary) 5%, var(--background));
|
|
|
|
|
--muted: color-mix(in oklch, var(--primary) 7%, var(--background));
|
|
|
|
|
--muted-foreground: color-mix(
|
|
|
|
|
in oklch,
|
|
|
|
|
var(--foreground) 68%,
|
|
|
|
|
var(--primary)
|
|
|
|
|
);
|
|
|
|
|
--accent: color-mix(in oklch, var(--primary) 14%, var(--background));
|
|
|
|
|
--accent-foreground: var(--foreground);
|
|
|
|
|
--border: color-mix(in oklch, var(--primary) 20%, var(--background));
|
|
|
|
|
--input: color-mix(in oklch, var(--primary) 22%, var(--background));
|
|
|
|
|
--sidebar: color-mix(in oklch, var(--primary) 4%, var(--background));
|
|
|
|
|
--sidebar-accent: color-mix(in oklch, var(--primary) 14%, var(--background));
|
|
|
|
|
--sidebar-accent-foreground: var(--foreground);
|
|
|
|
|
--sidebar-border: color-mix(in oklch, var(--primary) 18%, var(--background));
|
|
|
|
|
--success: var(--chart-2);
|
|
|
|
|
--warning: var(--chart-4);
|
|
|
|
|
--info: var(--chart-1);
|
|
|
|
|
--neutral: var(--muted-foreground);
|
|
|
|
|
}
|
🎨 feat(web/default): add Anthropic theme preset and configurable serif typography
Introduce a switchable Anthropic-inspired color preset and a new Font customization axis so users can adopt the editorial serif look across the entire UI, including sidebar navigation, tabs, form controls, buttons, and table headers.
Theme preset
Add anthropic to the theme preset registry with warm cream canvas, slate foreground, and clay/coral accent tokens for light and dark modes
Define explicit surface colors for the Anthropic preset instead of relying on the semantic surface bridge
Exclude anthropic from the primary-color surface bridge so bespoke warm neutrals are not overridden by accent-tinted mixes
Typography system
Add @fontsource-variable/lora and a global --font-serif token with CJK serif fallbacks (Noto Serif SC, Source Han Serif, Songti SC, etc.)
Introduce a --font-body token and drive <body> font-family from it
Add a Font axis (default | sans | serif) parallel to radius/scale
Resolve font: 'default' against preset defaults (anthropic → serif)
Persist font preference via cookie and apply data-theme-font on <body>
Apply serif OpenType features (kern, liga, calt, tnum) and heading display tuning when serif is active
Remove per-component sans opt-outs so serif inherits through sidebar, tabs, inputs, buttons, badges, and table headers via natural CSS cascade
Keep monospace contexts unchanged via Tailwind preflight and .font-mono
UI and i18n
Add Font selector to the theme config drawer (Auto / Sans / Serif)
Add "Font" and "Select body font" translations for en, zh, fr, ja, ru, vi
Misc
Tighten group and status badge sizing for better balance with serif text
2026-05-26 04:31:13 +08:00
|
|
|
.dark
|
|
|
|
|
[data-theme-preset]:not([data-theme-preset='default']):not(
|
|
|
|
|
[data-theme-preset='anthropic']
|
|
|
|
|
) {
|
🎨 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`
2026-05-07 11:20:43 +08:00
|
|
|
--card: color-mix(in oklch, var(--primary) 8%, var(--background));
|
|
|
|
|
--popover: color-mix(in oklch, var(--primary) 12%, var(--background));
|
|
|
|
|
--muted: color-mix(in oklch, var(--primary) 12%, var(--background));
|
|
|
|
|
--muted-foreground: color-mix(
|
|
|
|
|
in oklch,
|
|
|
|
|
var(--foreground) 74%,
|
|
|
|
|
var(--primary)
|
|
|
|
|
);
|
|
|
|
|
--accent: color-mix(in oklch, var(--primary) 18%, var(--background));
|
|
|
|
|
--border: color-mix(in oklch, var(--primary) 24%, var(--background));
|
|
|
|
|
--input: color-mix(in oklch, var(--primary) 28%, var(--background));
|
|
|
|
|
--sidebar: color-mix(in oklch, var(--primary) 5%, var(--background));
|
|
|
|
|
--sidebar-accent: color-mix(in oklch, var(--primary) 18%, var(--background));
|
|
|
|
|
--sidebar-border: color-mix(in oklch, var(--primary) 22%, var(--background));
|
|
|
|
|
}
|
|
|
|
|
|
🎨 feat(web/default): add Anthropic theme preset and configurable serif typography
Introduce a switchable Anthropic-inspired color preset and a new Font customization axis so users can adopt the editorial serif look across the entire UI, including sidebar navigation, tabs, form controls, buttons, and table headers.
Theme preset
Add anthropic to the theme preset registry with warm cream canvas, slate foreground, and clay/coral accent tokens for light and dark modes
Define explicit surface colors for the Anthropic preset instead of relying on the semantic surface bridge
Exclude anthropic from the primary-color surface bridge so bespoke warm neutrals are not overridden by accent-tinted mixes
Typography system
Add @fontsource-variable/lora and a global --font-serif token with CJK serif fallbacks (Noto Serif SC, Source Han Serif, Songti SC, etc.)
Introduce a --font-body token and drive <body> font-family from it
Add a Font axis (default | sans | serif) parallel to radius/scale
Resolve font: 'default' against preset defaults (anthropic → serif)
Persist font preference via cookie and apply data-theme-font on <body>
Apply serif OpenType features (kern, liga, calt, tnum) and heading display tuning when serif is active
Remove per-component sans opt-outs so serif inherits through sidebar, tabs, inputs, buttons, badges, and table headers via natural CSS cascade
Keep monospace contexts unchanged via Tailwind preflight and .font-mono
UI and i18n
Add Font selector to the theme config drawer (Auto / Sans / Serif)
Add "Font" and "Select body font" translations for en, zh, fr, ja, ru, vi
Misc
Tighten group and status badge sizing for better balance with serif text
2026-05-26 04:31:13 +08:00
|
|
|
/* ── Anthropic ────────────────────────────────────────────────────────── */
|
|
|
|
|
/*
|
|
|
|
|
* Inspired by Anthropic's official brand language: warm cream canvas
|
|
|
|
|
* (#faf9f5) on warm slate ink (#141413), with clay/coral (#d97757) as the
|
|
|
|
|
* single primary accent. The dormant accent palette (olive, sky, fig,
|
|
|
|
|
* cactus) is wired into chart and semantic tokens.
|
|
|
|
|
*
|
|
|
|
|
* Defining counter-positioning: a tinted (non-white) canvas with warm
|
|
|
|
|
* neutral cards and borders — NOT primary-tinted surfaces. This is the
|
|
|
|
|
* brand's deliberate counter-positioning against every cool-gray AI tool.
|
|
|
|
|
*
|
|
|
|
|
* Anthropic is opted out of the semantic surface bridge above so these
|
|
|
|
|
* bespoke warm-neutral surface tokens win the cascade. Without the opt-out,
|
|
|
|
|
* the bridge selector (specificity 0,2,0 because of `:not()`) would override
|
|
|
|
|
* this block (specificity 0,1,0) and tint every surface with the clay
|
|
|
|
|
* accent — producing the peach/pink look that doesn't match Anthropic.
|
|
|
|
|
*
|
|
|
|
|
* OKLCH hue 95 = warm yellow-cream (matches #faf9f5 family);
|
|
|
|
|
* OKLCH hue 60 = warm slate (matches #141413 family);
|
|
|
|
|
* OKLCH hue 38 = clay/coral (matches #d97757).
|
|
|
|
|
*/
|
|
|
|
|
[data-theme-preset='anthropic'] {
|
|
|
|
|
/* Canvas + ink — the defining pair. */
|
|
|
|
|
--background: oklch(0.984 0.004 95); /* ≈ #faf9f5 cream */
|
|
|
|
|
--foreground: oklch(0.205 0.005 60); /* ≈ #141413 ink */
|
|
|
|
|
|
|
|
|
|
/* Warm-neutral surfaces (NOT primary-tinted). Stepped opacity matches
|
|
|
|
|
* the Anthropic surface ladder: canvas → secondary → card → strong. */
|
|
|
|
|
--card: oklch(0.945 0.008 92); /* ≈ #efe9de */
|
|
|
|
|
--card-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
--popover: oklch(0.97 0.006 92); /* slight cream lift */
|
|
|
|
|
--popover-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
|
|
|
|
|
/* Clay/coral — Anthropic's signature accent, used scarcely on CTAs. */
|
|
|
|
|
--primary: oklch(0.685 0.142 38); /* ≈ #d97757 */
|
|
|
|
|
--primary-foreground: oklch(0.99 0.005 95);
|
|
|
|
|
|
|
|
|
|
--secondary: oklch(0.925 0.008 92);
|
|
|
|
|
--secondary-foreground: oklch(0.255 0.005 60);
|
|
|
|
|
|
|
|
|
|
--muted: oklch(0.94 0.007 92);
|
|
|
|
|
--muted-foreground: oklch(0.51 0.006 75); /* ≈ #5e5d59 warm gray */
|
|
|
|
|
--accent: oklch(0.92 0.009 92);
|
|
|
|
|
--accent-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
|
|
|
|
|
--destructive: oklch(0.55 0.18 27);
|
|
|
|
|
--destructive-foreground: oklch(0.985 0 0);
|
|
|
|
|
--success: oklch(0.59 0.082 130); /* olive #788c5d */
|
|
|
|
|
--success-foreground: oklch(0.985 0 0);
|
|
|
|
|
--warning: oklch(0.78 0.13 70); /* kraft amber */
|
|
|
|
|
--warning-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
--info: oklch(0.67 0.075 248); /* sky #6a9bcc */
|
|
|
|
|
--info-foreground: oklch(0.985 0 0);
|
|
|
|
|
--neutral: oklch(0.51 0.006 75);
|
|
|
|
|
--neutral-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
|
|
|
|
|
/* Hairline borders — warm gray, not coral. */
|
|
|
|
|
--border: oklch(0.895 0.008 92); /* ≈ #e8e6dc */
|
|
|
|
|
--input: oklch(0.895 0.008 92);
|
|
|
|
|
--ring: oklch(0.685 0.142 38);
|
|
|
|
|
|
|
|
|
|
/* Chart palette uses Anthropic's dormant accent swatches. */
|
|
|
|
|
--chart-1: oklch(0.685 0.142 38); /* clay */
|
|
|
|
|
--chart-2: oklch(0.59 0.082 130); /* olive */
|
|
|
|
|
--chart-3: oklch(0.67 0.075 248); /* sky */
|
|
|
|
|
--chart-4: oklch(0.7 0.115 0); /* fig */
|
|
|
|
|
--chart-5: oklch(0.83 0.027 175); /* cactus */
|
|
|
|
|
|
|
|
|
|
--sidebar: oklch(0.955 0.008 92);
|
|
|
|
|
--sidebar-foreground: oklch(0.255 0.005 60);
|
|
|
|
|
--sidebar-primary: oklch(0.685 0.142 38);
|
|
|
|
|
--sidebar-primary-foreground: oklch(0.99 0.005 95);
|
|
|
|
|
--sidebar-accent: oklch(0.915 0.009 92);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0.205 0.005 60);
|
|
|
|
|
--sidebar-border: oklch(0.895 0.008 92);
|
|
|
|
|
--sidebar-ring: oklch(0.685 0.142 38);
|
|
|
|
|
|
|
|
|
|
--skeleton-base: oklch(0.93 0.008 92);
|
|
|
|
|
--skeleton-highlight: oklch(0.96 0.006 92);
|
|
|
|
|
|
|
|
|
|
--radius: 0.625rem;
|
|
|
|
|
|
|
|
|
|
/* Default typography for the Anthropic preset is the editorial serif.
|
|
|
|
|
* Users can override this with the Font axis (`data-theme-font='sans'`).
|
|
|
|
|
* The `--font-serif` token itself is declared once in theme.css. */
|
|
|
|
|
--font-body: var(--font-serif);
|
|
|
|
|
}
|
|
|
|
|
.dark [data-theme-preset='anthropic'] {
|
|
|
|
|
/* Warm near-black product surfaces, not pure black — keeps the editorial
|
|
|
|
|
* personality even when inverted. Coral lifts slightly for legibility. */
|
|
|
|
|
--background: oklch(0.205 0.004 60); /* ≈ #181715 */
|
|
|
|
|
--foreground: oklch(0.965 0.005 92); /* ≈ #faf9f5 */
|
|
|
|
|
--card: oklch(0.245 0.004 60);
|
|
|
|
|
--card-foreground: oklch(0.965 0.005 92);
|
|
|
|
|
--popover: oklch(0.265 0.004 60);
|
|
|
|
|
--popover-foreground: oklch(0.965 0.005 92);
|
|
|
|
|
|
|
|
|
|
--primary: oklch(0.72 0.135 40);
|
|
|
|
|
--primary-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
--secondary: oklch(0.295 0.004 60);
|
|
|
|
|
--secondary-foreground: oklch(0.945 0.005 92);
|
|
|
|
|
|
|
|
|
|
--muted: oklch(0.275 0.004 60);
|
|
|
|
|
--muted-foreground: oklch(0.76 0.006 75);
|
|
|
|
|
--accent: oklch(0.32 0.006 60);
|
|
|
|
|
--accent-foreground: oklch(0.985 0.005 92);
|
|
|
|
|
|
|
|
|
|
--destructive: oklch(0.7 0.19 22);
|
|
|
|
|
--destructive-foreground: oklch(0.985 0 0);
|
|
|
|
|
--success: oklch(0.7 0.105 135);
|
|
|
|
|
--success-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
--warning: oklch(0.78 0.13 70);
|
|
|
|
|
--warning-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
--info: oklch(0.72 0.085 248);
|
|
|
|
|
--info-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
--neutral: oklch(0.76 0.006 75);
|
|
|
|
|
--neutral-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
|
|
|
|
|
--border: oklch(1 0 0 / 10%);
|
|
|
|
|
--input: oklch(1 0 0 / 16%);
|
|
|
|
|
--ring: oklch(0.72 0.135 40);
|
|
|
|
|
|
|
|
|
|
--chart-1: oklch(0.72 0.135 40);
|
|
|
|
|
--chart-2: oklch(0.7 0.105 135);
|
|
|
|
|
--chart-3: oklch(0.72 0.085 248);
|
|
|
|
|
--chart-4: oklch(0.78 0.13 0);
|
|
|
|
|
--chart-5: oklch(0.83 0.027 175);
|
|
|
|
|
|
|
|
|
|
--sidebar: oklch(0.175 0.004 60);
|
|
|
|
|
--sidebar-foreground: oklch(0.95 0.005 92);
|
|
|
|
|
--sidebar-primary: oklch(0.72 0.135 40);
|
|
|
|
|
--sidebar-primary-foreground: oklch(0.18 0.005 60);
|
|
|
|
|
--sidebar-accent: oklch(0.31 0.006 60);
|
|
|
|
|
--sidebar-accent-foreground: oklch(0.985 0.005 92);
|
|
|
|
|
--sidebar-border: oklch(1 0 0 / 10%);
|
|
|
|
|
--sidebar-ring: oklch(0.72 0.135 40);
|
|
|
|
|
|
|
|
|
|
--skeleton-base: oklch(0.295 0.004 60);
|
|
|
|
|
--skeleton-highlight: oklch(0.4 0.004 60);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Font axis ────────────────────────────────────────────────────────────
|
|
|
|
|
* Mirrors how `data-theme-radius` overrides a preset's default radius:
|
|
|
|
|
* presets may set `--font-body` (Anthropic → serif), and the user's
|
|
|
|
|
* explicit Font choice wins because these blocks sit AFTER preset blocks.
|
|
|
|
|
*
|
|
|
|
|
* The provider resolves `font: 'default'` → `'sans' | 'serif'` against the
|
|
|
|
|
* active preset before writing the attribute, so the DOM always carries a
|
|
|
|
|
* concrete value and CSS only needs the simple `[data-theme-font='serif']`
|
|
|
|
|
* selector below (no `:not()`, no per-preset branches). */
|
|
|
|
|
[data-theme-font='sans'] {
|
|
|
|
|
--font-body: var(--font-sans);
|
|
|
|
|
}
|
|
|
|
|
[data-theme-font='serif'] {
|
|
|
|
|
--font-body: var(--font-serif);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Serif typography refinements ────────────────────────────────────────
|
|
|
|
|
* When the body runs in serif, three things happen:
|
|
|
|
|
* 1. Editorial OpenType features (kern/liga + tabular numerals so numeric
|
|
|
|
|
* columns stay grid-aligned even with proportional serif glyphs).
|
|
|
|
|
* 2. Every UI surface inherits the editorial voice — buttons, inputs,
|
|
|
|
|
* tabs, sidebar, table headers, badges, pagination, popovers — all
|
|
|
|
|
* through Tailwind preflight's `button, input, ... { font: inherit }`
|
|
|
|
|
* rule plus natural HTML inheritance. We intentionally do NOT carry
|
|
|
|
|
* a per-slot opt-out list: it adds maintenance cost and only blunts
|
|
|
|
|
* the Anthropic editorial intent. Monospace contexts are excluded
|
|
|
|
|
* automatically because:
|
|
|
|
|
* - `<code>`, `<kbd>`, `<pre>`, `<samp>` are typed monospace by
|
|
|
|
|
* Tailwind preflight (specificity wins over body inheritance).
|
|
|
|
|
* - `.font-mono` and `.tabular-nums` utilities declare their own
|
|
|
|
|
* font-family / font-variant-numeric on the element itself.
|
|
|
|
|
* 3. Headings adopt the Anthropic display setting (medium weight, slight
|
|
|
|
|
* negative tracking).
|
|
|
|
|
*
|
|
|
|
|
* All keyed off `[data-theme-font='serif']` so they apply to any preset
|
|
|
|
|
* paired with the serif font — not just Anthropic. */
|
|
|
|
|
[data-theme-font='serif'] {
|
|
|
|
|
font-feature-settings:
|
|
|
|
|
'kern' 1,
|
|
|
|
|
'liga' 1,
|
|
|
|
|
'calt' 1,
|
|
|
|
|
'tnum' 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Heading tuning — applies to <h*> tags and the shadcn title slots so
|
|
|
|
|
* card/sheet/dialog titles read with the same authoritative voice as
|
|
|
|
|
* page headers. */
|
|
|
|
|
[data-theme-font='serif'] :is(h1, h2, h3, h4, h5, h6),
|
|
|
|
|
[data-theme-font='serif'] [data-slot='sheet-title'],
|
|
|
|
|
[data-theme-font='serif'] [data-slot='dialog-title'],
|
|
|
|
|
[data-theme-font='serif'] [data-slot='alert-dialog-title'],
|
|
|
|
|
[data-theme-font='serif'] [data-slot='drawer-title'],
|
|
|
|
|
[data-theme-font='serif'] [data-slot='card-title'] {
|
|
|
|
|
font-weight: 500;
|
|
|
|
|
letter-spacing: -0.012em;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Larger displays earn tighter tracking, matching Copernicus/Tiempos
|
|
|
|
|
* editorial display setting (~ -0.02em at 30px+). */
|
|
|
|
|
[data-theme-font='serif'] h1,
|
|
|
|
|
[data-theme-font='serif'] .text-3xl,
|
|
|
|
|
[data-theme-font='serif'] .text-4xl,
|
|
|
|
|
[data-theme-font='serif'] .text-5xl {
|
|
|
|
|
letter-spacing: -0.02em;
|
|
|
|
|
}
|
|
|
|
|
|
feat(web/default): unified UI overhaul — Base UI migration, theme presets, rankings dashboard, and table toolbar refactor (#4633)
* 🎨 feat(web/default): add shadcn-style theme presets, radius prefs, and fix selection badges
Integrate the qn-platform–style OKLCH color system into the default frontend while keeping the existing blue-tinted dark tokens for the default theme. Add [data-theme-preset] palettes for seven named presets plus the default zinc-like scale, define [data-theme-radius] overrides so user radius beats preset --radius, and align the Tailwind @custom-variant dark helper with .dark usage.
Introduce ThemeCustomizationProvider to own preset and radius state, persist choices in cookies (theme-preset, theme-radius), and sync data-theme-preset / data-theme-radius on <html>. Wrap the tree in main.tsx.
Extend ConfigDrawer with theme preset swatches (scoped data-theme-preset) and radius previews wired to context; refactor swatch/card markup so selected CircleCheck badges sit outside clipped rows (remove outer overflow-hidden that hid the centered checkmark).
Add i18n keys for preset names, radius, and accessibility labels across en, zh, fr, ja, ru, vi.
* 🎨 fix(web): align segmented controls with theme radius tokens
- Replace hard-coded inner pill radii (rounded-[5px]) on dashboard chart
toolbars with radius-md so the active state follows --radius when users
change Radius in Theme Settings.
- Use nested radii consistent with TabsList/TabsTrigger: outer
rounded-lg (var(--radius)) and inner rounded-md (calc(var(--radius) - 2px))
so the track and active thumb stay concentric at small scales (e.g.
0.3rem) instead of a squared “focus” block inside a rounded shell.
- Apply the same pattern to pricing SegmentedControl and the segmented
groups in consumption-distribution-chart, model-charts, and user-charts.
Verified: bun run typecheck (web/default)
* ✨ feat(pricing): enrich model details with uptime sparkline and API documentation
Add a compact 30-day uptime sparkline (OpenRouter-style bars + aggregate %) with
per-day tooltips, surface it in a status row under quick stats and in the
per-group performance table, and extend mock data so uptime series are stable
and optionally scoped by group.
Introduce an API tab with Shiki-highlighted code samples (cURL, Python,
TypeScript, JavaScript), endpoint-type switching, authentication guidance, a
supported-parameters table, and mock per-group RPM/TPM/RPD limits. Infer
vendor, tokenizer, license, and data-retention hints for a provider & data
privacy card on the Overview tab (capabilities/modalities stay with model
identity; rate limits stay with the API tab).
Update i18n for all new user-facing strings across en, zh, fr, ja, ru, and vi.
* 🏆 feat(rankings): add comprehensive rankings dashboard
Add a mock-data powered rankings experience with period tabs, model, app, and vendor leaderboards, market share and history charts, movers, new releases, and per-category sections while backend analytics are pending.
Link ranked models to pricing details and ranked vendors to filtered pricing results, and include localized copy for all supported frontend locales.
* fix(theme): correct theme preset selection state
- update Base UI Radio selectors to use data-checked/data-unchecked states.
- fix unchecked theme options still showing selected indicators.
- isolate the default theme preview tokens to prevent preset changes from leaking into it.
* fix(setup): correct usage mode radio state
- use Base UI data-checked/data-unchecked states for RadioGroup styling.
- hide radio indicators when options are unchecked to avoid setup page display issues.
- drive usage mode card and icon selection styles from Base UI state.
* fix(auth): submit sign-in and sign-up forms
* 🎨 refactor: Align default theme with shadcn Base Nova and prune legacy customization
Migrate shadcn UI to Base UI primitives via CLI (`base-nova` / `components.json`)
and reinstall full component registry with `--overwrite`, including Hugeicons-backed
widgets and newly added registry components.
- Remove custom multi-preset/theme-radius system (`ThemeCustomizationProvider`, cookies,
preset UI from config drawer); rely on official semantic CSS tokens + light/dark only.
- Replace `theme.css` with shadcn’s documented neutral `:root`/`.dark` palette and
`@theme inline` mappings (plus skeleton token vars for existing shimmer usage).
- Update global styles for Base UI: collapsible animation uses `--collapsible-panel-height`;
clarify scroll-lock override comment.
Application compatibility:
- Keep minimal shims where app code diverged from official APIs (popover collision props,
combobox legacy `options` callers, Spinner prop typing).
- Switch interactive styling from Radix-era `data-state` / `--radix-*` selectors to Base UI
semantics (`data-open`, `data-popup-open`, `data-panel-open`, `--anchor-width`, etc.)
Tooling / docs / build:
- Rename Rsbuild vendor chunk grouping to `@base-ui` + transitive `@radix-ui`.
- Refresh AGENTS.md / CLAUDE.md / classic→default sync skill for Base UI stack.
- Bump `package.json` / lockfile for shadcn-postinstall deps (Hugeicons, chart stack, themes, etc.)
Verified: `bun run typecheck` passes.
Note: `bun run lint` still reports pre-existing hooks rule violations elsewhere;
not addressed in this change.
* 🎨 chore(web/default): unify table toolbar, relocate usage stats, refine filters
- Refactor DataTableToolbar to a single wrapping flex row with a
right-aligned action cluster (Reset / Search / View / Expand) for a
cleaner Ant Design Pro–style filter bar; remove the dedicated stats row
and the toolbar `stats` prop.
- Move Common Logs summary badges (Usage / RPM / TPM) and the sensitive-
data visibility toggle into the page header via CommonLogsHeaderActions
and SectionPageLayout.Actions so the toolbar stays focused on filters.
- Slim CommonLogsFilterBar props (no stats / preActions eye control).
- Improve CompactDateTimeRangePicker: show minute-precision labels on the
trigger (seconds omitted; aligns with datetime-local inputs); widen the
trigger on sm+ breakpoints so the full range is visible without truncation;
apply the same width in task logs filters.
- Simplify DataTableViewOptions: text-only “View” trigger, no sliders icon.
- Earlier layout tweak: extra top padding on SectionPageLayout scroll
content so control focus rings are not clipped by overflow.
* feat(web/default): Base UI migration and component foundation
Migrate from Radix UI to Base UI, rewrite core UI primitives,
update dependencies (recharts, date-fns, next-themes), add
shadcn agent skill documentation, and refresh AI element components.
This is the foundational work from the v2/localmain lineage that
was not covered by the individual feature commits above.
---------
Co-authored-by: t0ng7u <dev@aiass.cc>
Co-authored-by: QuentinHsu <xuquentinyang@gmail.com>
2026-05-06 12:39:36 +08:00
|
|
|
/* ── Border radius ────────────────────────────────────────────────────── */
|
|
|
|
|
[data-theme-radius='none'] {
|
|
|
|
|
--radius: 0rem;
|
|
|
|
|
}
|
|
|
|
|
[data-theme-radius='sm'] {
|
|
|
|
|
--radius: 0.3rem;
|
|
|
|
|
}
|
|
|
|
|
[data-theme-radius='md'] {
|
|
|
|
|
--radius: 0.5rem;
|
|
|
|
|
}
|
|
|
|
|
[data-theme-radius='lg'] {
|
|
|
|
|
--radius: 0.75rem;
|
|
|
|
|
}
|
|
|
|
|
[data-theme-radius='xl'] {
|
|
|
|
|
--radius: 1rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Density scale ────────────────────────────────────────────────────── */
|
|
|
|
|
/* `sm` = compact UI; `lg` = comfortable. Default (no attribute) keeps Tailwind defaults. */
|
|
|
|
|
[data-theme-scale='sm'] {
|
|
|
|
|
--text-xs: 0.7rem;
|
|
|
|
|
--text-sm: 0.78rem;
|
|
|
|
|
--text-base: 0.88rem;
|
|
|
|
|
--text-lg: 1rem;
|
|
|
|
|
--text-xl: 1.13rem;
|
|
|
|
|
--text-2xl: 1.38rem;
|
|
|
|
|
--text-3xl: 1.7rem;
|
|
|
|
|
--spacing: 0.225rem;
|
|
|
|
|
}
|
|
|
|
|
[data-theme-scale='lg'] {
|
|
|
|
|
--text-xs: 0.84rem;
|
|
|
|
|
--text-sm: 0.95rem;
|
|
|
|
|
--text-base: 1.075rem;
|
|
|
|
|
--text-lg: 1.2rem;
|
|
|
|
|
--text-xl: 1.35rem;
|
|
|
|
|
--text-2xl: 1.65rem;
|
|
|
|
|
--text-3xl: 2rem;
|
|
|
|
|
--spacing: 0.28rem;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ── Content layout ───────────────────────────────────────────────────── */
|
|
|
|
|
/* `centered` clamps inset content to a comfortable reading width on large screens.
|
|
|
|
|
* Targets every direct child of <SidebarInset> so router outlet wrappers and
|
|
|
|
|
* page content alike are centered. Only kicks in once the viewport exceeds the
|
|
|
|
|
* clamp value. */
|
|
|
|
|
@media (min-width: 1280px) {
|
|
|
|
|
[data-theme-content-layout='centered'] [data-slot='sidebar-inset'] > * {
|
|
|
|
|
max-width: var(--max-content-width, 1280px);
|
|
|
|
|
margin-inline: auto;
|
|
|
|
|
width: 100%;
|
|
|
|
|
}
|
|
|
|
|
}
|