mirror of
https://github.com/QuantumNous/new-api.git
synced 2026-09-12 15:21:09 +00:00
refactor(web): make identity tints theme-aware and restore colorful default preset
Derive --color-identity-* tokens from theme palette variables (chart and status hues) instead of fixed oklch hues, so group names, channel ids and model badges re-tint automatically when a color preset overrides the palette. The monochrome simple-large preset collapses identity tints to the foreground via --identity-color-mix: 0%. Also port main's blue default palette (light/dark), preview the default preset as a rainbow swatch, and show the token group as a tinted GroupBadge on the usage-logs page.
This commit is contained in:
+3
-1
@@ -323,10 +323,12 @@ function PresetConfig() {
|
||||
aria-hidden='true'
|
||||
className='absolute inset-0 rounded-md'
|
||||
style={
|
||||
// The default preset is the full-color theme; two swatch
|
||||
// stops cannot convey that, so it previews as a rainbow.
|
||||
preset.value === 'default'
|
||||
? {
|
||||
background:
|
||||
'linear-gradient(135deg, var(--background) 0%, var(--muted) 50%, var(--foreground) 100%)',
|
||||
'linear-gradient(135deg, oklch(0.68 0.2 25) 0%, oklch(0.8 0.17 85) 25%, oklch(0.72 0.18 155) 50%, oklch(0.66 0.19 245) 75%, oklch(0.68 0.2 315) 100%)',
|
||||
}
|
||||
: {
|
||||
background: `linear-gradient(135deg, ${preset.swatches[0]} 0%, ${preset.swatches[1] ?? preset.swatches[0]} 100%)`,
|
||||
|
||||
+26
-14
@@ -21,6 +21,7 @@ import { GitBranch, Sparkles } from 'lucide-react'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
import { GroupBadge } from '@/components/group-badge'
|
||||
import { CopyableStatusBadge, StatusBadge } from '@/components/status-badge'
|
||||
import { Avatar, AvatarFallback } from '@/components/ui/avatar'
|
||||
import {
|
||||
@@ -567,31 +568,33 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef<UsageLog>[] {
|
||||
let group = log.group
|
||||
if (!group) group = other?.group || ''
|
||||
|
||||
const metaParts: string[] = []
|
||||
const groupRatioText = getGroupRatioText(
|
||||
other,
|
||||
group ? groupRatios[group] : undefined
|
||||
)
|
||||
if (group) {
|
||||
metaParts.push(sensitiveVisible ? group : '••••')
|
||||
}
|
||||
if (groupRatioText) metaParts.push(groupRatioText)
|
||||
const tokenBadgeClassName =
|
||||
'max-w-full min-w-0 overflow-hidden [&>[data-slot=status-badge-label]]:max-w-full [&>[data-slot=status-badge-label]]:min-w-0 [&>[data-slot=status-badge-label]]:overflow-hidden [&>[data-slot=status-badge-label]]:text-ellipsis'
|
||||
|
||||
return (
|
||||
<div className='flex w-max flex-col gap-0.5'>
|
||||
<div className='flex max-w-[200px] flex-col gap-0.5'>
|
||||
<TooltipProvider delay={300}>
|
||||
<Tooltip>
|
||||
<TooltipTrigger render={<div className='shrink-0' />}>
|
||||
<TooltipTrigger render={<div className='max-w-full' />}>
|
||||
{sensitiveVisible ? (
|
||||
<CopyableStatusBadge
|
||||
value={tokenName}
|
||||
variant='neutral'
|
||||
size='sm'
|
||||
className={tokenBadgeClassName}
|
||||
>
|
||||
{displayName}
|
||||
</CopyableStatusBadge>
|
||||
) : (
|
||||
<StatusBadge variant='neutral' size='sm'>
|
||||
<StatusBadge
|
||||
variant='neutral'
|
||||
size='sm'
|
||||
className={tokenBadgeClassName}
|
||||
>
|
||||
{displayName}
|
||||
</StatusBadge>
|
||||
)}
|
||||
@@ -603,12 +606,21 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef<UsageLog>[] {
|
||||
)}
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
{metaParts.length > 0 && (
|
||||
<span
|
||||
className='text-subtle-foreground max-w-[150px] truncate text-xs'
|
||||
title={sensitiveVisible ? metaParts.join(' · ') : undefined}
|
||||
>
|
||||
{metaParts.join(' · ')}
|
||||
{(group || groupRatioText) && (
|
||||
<span className='flex max-w-full min-w-0 items-baseline gap-1 text-xs leading-none'>
|
||||
{group && (
|
||||
<GroupBadge
|
||||
group={group}
|
||||
label={sensitiveVisible ? undefined : '••••'}
|
||||
size='sm'
|
||||
className='min-w-0 truncate'
|
||||
/>
|
||||
)}
|
||||
{groupRatioText && (
|
||||
<span className='text-subtle-foreground shrink-0 tabular-nums'>
|
||||
{groupRatioText}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -27,7 +27,7 @@ export const THEME_PRESETS = [
|
||||
{
|
||||
value: 'default',
|
||||
name: 'Default',
|
||||
swatches: ['oklch(0.13 0 0)', 'oklch(0.95 0 0)'],
|
||||
swatches: ['oklch(0.692 0.141 243.716)', 'oklch(0.7 0.12 280)'],
|
||||
},
|
||||
{
|
||||
// Inspired by Anthropic's official brand language: warm cream canvas
|
||||
|
||||
+6
@@ -342,6 +342,12 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
--skeleton-base: oklch(0.9 0 0);
|
||||
--skeleton-highlight: oklch(0.97 0 0);
|
||||
|
||||
/* Identity tints (group names, channel ids, model badges…) are decorative,
|
||||
* so this monochrome preset collapses them to the foreground by mixing 0%
|
||||
* of the palette hue. Status colors above stay colored on purpose: they
|
||||
* carry meaning (error/success), which accessibility asks us to keep. */
|
||||
--identity-color-mix: 0%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
--text-xs: 0.9rem;
|
||||
--text-sm: 1rem;
|
||||
|
||||
Vendored
+57
-88
@@ -105,94 +105,66 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
/* Metric identity accent; intentionally distinct from status semantics. */
|
||||
--color-metric-rpm: color-mix(
|
||||
in oklch,
|
||||
oklch(0.68 calc(0.2 * var(--identity-chroma-scale)) 350)
|
||||
var(--identity-color-mix),
|
||||
oklch(0.68 0.2 350) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
/* Stable entity hues used by deterministic string-to-color identity tints.
|
||||
* Mixing toward the achromatic foreground dilutes chroma along with
|
||||
* lightness, so each hue pre-scales its chroma by the per-mode
|
||||
* `--identity-chroma-scale` (see :root / .dark). */
|
||||
/* Stable entity tints used by deterministic string-to-color identity
|
||||
* coloring. Each tint derives from a theme palette token (chart and status
|
||||
* hues) instead of a fixed hue, so identity colors re-tint automatically
|
||||
* when a theme preset overrides the palette. Mixing toward the foreground
|
||||
* (via the per-mode `--identity-color-mix`) keeps compact text legible in
|
||||
* both light and dark modes. */
|
||||
--color-identity-amber: color-mix(
|
||||
in oklch,
|
||||
oklch(0.72 calc(0.17 * var(--identity-chroma-scale)) 75)
|
||||
var(--identity-color-mix),
|
||||
var(--warning) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-blue: color-mix(
|
||||
in oklch,
|
||||
oklch(0.62 calc(0.18 * var(--identity-chroma-scale)) 250)
|
||||
var(--identity-color-mix),
|
||||
var(--chart-1) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-cyan: color-mix(
|
||||
in oklch,
|
||||
oklch(0.7 calc(0.14 * var(--identity-chroma-scale)) 205)
|
||||
var(--identity-color-mix),
|
||||
var(--chart-2) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-green: color-mix(
|
||||
in oklch,
|
||||
oklch(0.64 calc(0.16 * var(--identity-chroma-scale)) 145)
|
||||
var(--identity-color-mix),
|
||||
var(--success) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-grey: var(--muted-foreground);
|
||||
--color-identity-indigo: color-mix(
|
||||
in oklch,
|
||||
oklch(0.6 calc(0.2 * var(--identity-chroma-scale)) 275)
|
||||
var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-indigo: var(--color-identity-blue);
|
||||
--color-identity-light-blue: color-mix(
|
||||
in oklch,
|
||||
oklch(0.74 calc(0.12 * var(--identity-chroma-scale)) 225)
|
||||
var(--identity-color-mix),
|
||||
var(--info) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-lime: color-mix(
|
||||
in oklch,
|
||||
oklch(0.75 calc(0.17 * var(--identity-chroma-scale)) 125)
|
||||
var(--identity-color-mix),
|
||||
var(--chart-3) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-orange: color-mix(
|
||||
--color-identity-orange: var(--color-identity-amber);
|
||||
--color-identity-pink: color-mix(
|
||||
in oklch,
|
||||
oklch(0.7 calc(0.19 * var(--identity-chroma-scale)) 50)
|
||||
var(--identity-color-mix),
|
||||
var(--chart-5) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-pink: var(--color-metric-rpm);
|
||||
--color-identity-purple: color-mix(
|
||||
in oklch,
|
||||
oklch(0.62 calc(0.2 * var(--identity-chroma-scale)) 305)
|
||||
var(--identity-color-mix),
|
||||
var(--chart-4) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-red: color-mix(
|
||||
in oklch,
|
||||
oklch(0.64 calc(0.21 * var(--identity-chroma-scale)) 25)
|
||||
var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-teal: color-mix(
|
||||
in oklch,
|
||||
oklch(0.66 calc(0.14 * var(--identity-chroma-scale)) 175)
|
||||
var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-violet: color-mix(
|
||||
in oklch,
|
||||
oklch(0.65 calc(0.2 * var(--identity-chroma-scale)) 325)
|
||||
var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-yellow: color-mix(
|
||||
in oklch,
|
||||
oklch(0.78 calc(0.16 * var(--identity-chroma-scale)) 95)
|
||||
var(--identity-color-mix),
|
||||
var(--destructive) var(--identity-color-mix),
|
||||
var(--foreground)
|
||||
);
|
||||
--color-identity-teal: var(--color-identity-cyan);
|
||||
--color-identity-violet: var(--color-identity-purple);
|
||||
--color-identity-yellow: var(--color-identity-amber);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
@@ -233,19 +205,19 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
* `[data-theme-font='...']` blocks in theme-presets.css. Default mirrors
|
||||
* `--font-sans` so behavior is identical when no font preference is set. */
|
||||
--font-body: var(--font-sans);
|
||||
/* Light mode uses a bright pure-white canvas (matching the original
|
||||
* palette) with soft light-grey borders and accents, so the UI reads
|
||||
* crisp instead of collapsing into muddy greys. */
|
||||
/* Light mode uses a bright pure-white canvas with the blue brand palette:
|
||||
* blue primary/ring/charts and primary-tinted accents, over soft
|
||||
* light-grey borders, so the default theme reads colorful but calm. */
|
||||
--background: oklch(1 0 0);
|
||||
--foreground: oklch(0.145 0 0);
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: oklch(0.13 0 0);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--primary: oklch(0.692 0.141 243.716);
|
||||
--primary-foreground: oklch(1 0 0);
|
||||
--secondary: oklch(0.95 0 0);
|
||||
--secondary-foreground: oklch(0.145 0 0);
|
||||
--secondary-foreground: oklch(0.42 0.16 250);
|
||||
--muted: oklch(0.97 0 0);
|
||||
--muted-foreground: oklch(0.49 0 0);
|
||||
/* Low-emphasis text tiers below `muted-foreground`, used for secondary
|
||||
@@ -263,7 +235,7 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
var(--muted-foreground) 40%,
|
||||
transparent
|
||||
);
|
||||
--accent: oklch(0.95 0 0);
|
||||
--accent: color-mix(in oklch, var(--primary) 12%, var(--background));
|
||||
--accent-foreground: oklch(0.145 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
@@ -277,20 +249,20 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
--neutral-foreground: oklch(0.145 0 0);
|
||||
--border: oklch(0.93 0 0);
|
||||
--input: oklch(0.93 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.975 0 0);
|
||||
--ring: oklch(0.708 0.16 249.003);
|
||||
--chart-1: oklch(0.72 0.18 250);
|
||||
--chart-2: oklch(0.65 0.15 200);
|
||||
--chart-3: oklch(0.7 0.12 280);
|
||||
--chart-4: oklch(0.68 0.19 325);
|
||||
--chart-5: oklch(0.68 0.16 155);
|
||||
--sidebar: color-mix(in oklch, var(--foreground) 0.5%, var(--background));
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.13 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.92 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.64 0.197 253.892);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: color-mix(in oklch, var(--primary) 12%, var(--background));
|
||||
--sidebar-accent-foreground: oklch(0.579 0.196 255.909);
|
||||
--sidebar-border: oklch(0.93 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--sidebar-ring: oklch(0.58 0.2 250);
|
||||
--skeleton-base: oklch(0.97 0 0);
|
||||
--skeleton-highlight: oklch(0.985 0 0);
|
||||
/* 100% keeps the original vivid semantic hues (matching the old palette
|
||||
@@ -298,7 +270,6 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
* of darkening them toward the near-black foreground. */
|
||||
--status-color-mix: 100%;
|
||||
--identity-color-mix: 100%;
|
||||
--identity-chroma-scale: 1;
|
||||
--identity-surface-mix: 13%;
|
||||
--identity-border-mix: 28%;
|
||||
--table-row: var(--card);
|
||||
@@ -333,13 +304,13 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
--card-foreground: oklch(0.965 0 0);
|
||||
--popover: oklch(0.305 0 0);
|
||||
--popover-foreground: oklch(0.965 0 0);
|
||||
--primary: oklch(0.965 0 0);
|
||||
--primary-foreground: oklch(0.155 0 0);
|
||||
--primary: oklch(0.54 0.142 248.516);
|
||||
--primary-foreground: oklch(1 0 0);
|
||||
--secondary: oklch(0.335 0 0);
|
||||
--secondary-foreground: oklch(0.965 0 0);
|
||||
--secondary-foreground: oklch(0.9 0.05 250);
|
||||
--muted: oklch(0.305 0 0);
|
||||
--muted-foreground: oklch(0.78 0 0);
|
||||
--accent: oklch(0.365 0 0);
|
||||
--accent: color-mix(in oklch, var(--primary) 20%, var(--background));
|
||||
--accent-foreground: oklch(0.985 0 0);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
@@ -347,32 +318,30 @@ For commercial licensing, please contact support@quantumnous.com
|
||||
--success-foreground: oklch(0.145 0 0);
|
||||
--warning: oklch(0.769 0.188 70.08);
|
||||
--warning-foreground: oklch(0.145 0 0);
|
||||
--info: oklch(0.68 0.17 237.323);
|
||||
--info: oklch(0.613 0.14 239.919);
|
||||
--info-foreground: oklch(0.145 0 0);
|
||||
--neutral: oklch(0.76 0 0);
|
||||
--neutral-foreground: oklch(0.155 0 0);
|
||||
--border: oklch(1 0 0 / 10%);
|
||||
--input: oklch(1 0 0 / 17%);
|
||||
--ring: oklch(0.68 0 0);
|
||||
--chart-1: oklch(0.488 0.243 264.376);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--ring: oklch(0.554 0.148 250.726);
|
||||
--chart-1: oklch(0.76 0.14 250);
|
||||
--chart-2: oklch(0.76 0.13 200);
|
||||
--chart-3: oklch(0.76 0.13 285);
|
||||
--chart-4: oklch(0.75 0.16 325);
|
||||
--chart-5: oklch(0.76 0.14 155);
|
||||
--sidebar: oklch(0.225 0 0);
|
||||
--sidebar-foreground: oklch(0.95 0 0);
|
||||
--sidebar-primary: oklch(0.965 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.155 0 0);
|
||||
--sidebar-accent: oklch(0.355 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||
--sidebar-primary: oklch(0.588 0.123 246.488);
|
||||
--sidebar-primary-foreground: oklch(1 0 0);
|
||||
--sidebar-accent: color-mix(in oklch, var(--primary) 20%, var(--background));
|
||||
--sidebar-accent-foreground: oklch(0.9 0.05 250);
|
||||
--sidebar-border: oklch(1 0 0 / 11%);
|
||||
--sidebar-ring: oklch(0.68 0 0);
|
||||
--sidebar-ring: oklch(0.7 0.17 250);
|
||||
--skeleton-base: oklch(0.335 0 0);
|
||||
--skeleton-highlight: oklch(0.44 0 0);
|
||||
--status-color-mix: 55%;
|
||||
--identity-color-mix: 55%;
|
||||
/* Dark mode keeps the soft macaron pastels unchanged. */
|
||||
--identity-chroma-scale: 1;
|
||||
--identity-surface-mix: 10%;
|
||||
--identity-border-mix: 20%;
|
||||
--table-row: var(--background);
|
||||
|
||||
Reference in New Issue
Block a user