feat(theme): add simple-large preset, xl scale and clean up channel badge dots

Implement the Simple Large-font theme preset and xl font scale options to enhance interface accessibility. Remove status indicator dots from channel badges in logs to keep the table layout visual and clean.
This commit is contained in:
CaIon
2026-05-26 18:35:51 +08:00
parent 65f8afe922
commit f8add4ca49
11 changed files with 153 additions and 9 deletions
+2 -1
View File
@@ -490,6 +490,7 @@ function ScaleConfig() {
{ value: 'sm', label: t('Compact'), rows: 4, rowGap: '3px' },
{ value: 'default', label: t('Default'), rows: 3, rowGap: '6px' },
{ value: 'lg', label: t('Comfortable'), rows: 2, rowGap: '10px' },
{ value: 'xl', label: t('Super Large'), rows: 1, rowGap: '14px' },
]
return (
<div>
@@ -501,7 +502,7 @@ function ScaleConfig() {
<Radio
value={customization.scale}
onValueChange={(v) => setScale(v as ThemeScale)}
className='grid w-full grid-cols-3 gap-4'
className='grid w-full grid-cols-4 gap-3'
aria-label={t('Select interface density')}
>
{scaleOptions.map((option) => (
@@ -183,6 +183,7 @@ export function createChannelColumn<T>(config: {
autoColor={String(channelId)}
copyText={String(channelId)}
size='sm'
showDot={false}
className='font-mono'
/>
)
@@ -332,6 +332,7 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef<UsageLog>[] {
autoColor={String(log.channel)}
copyText={String(log.channel)}
size='sm'
showDot={false}
className='font-mono'
/>
{affinity && (
@@ -554,7 +555,7 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef<UsageLog>[] {
? log.completion_tokens / useTime
: null
const timeVariant = getResponseTimeColor(useTime, log.completion_tokens)
const frtVariant = frt ? getFirstResponseTimeColor(frt / 1000) : null
const frtVariant = frt ? getFirstResponseTimeColor(frt / 1000) : 'neutral'
const timingBgMap: Record<string, string> = {
success:
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "Lavender Dream",
"preset.ocean-breeze": "Ocean Breeze",
"preset.rose-garden": "Rose Garden",
"preset.simple-large": "Simple Large-font",
"preset.sunset-glow": "Sunset Glow",
"preset.underground": "Underground",
"Press Enter or comma to add tags": "Press Enter or comma to add tags",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "Sunset Glow",
"Super Admin": "Super Admin",
"Super Large": "Super Large",
"Support for high concurrency with automatic load balancing": "Support for high concurrency with automatic load balancing",
"Supported Applications": "Supported Applications",
"Supported Imagine Models": "Supported Imagine Models",
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "Rêve de lavande",
"preset.ocean-breeze": "Brise océane",
"preset.rose-garden": "Roseraie",
"preset.simple-large": "Simple & Grands Caractères",
"preset.sunset-glow": "Lueur du couchant",
"preset.underground": "Souterrain",
"Press Enter or comma to add tags": "Appuyez sur Entrée ou sur la virgule pour ajouter des tags",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "Lueur du couchant",
"Super Admin": "Super Administrateur",
"Super Large": "Très grand",
"Support for high concurrency with automatic load balancing": "Prise en charge de la haute concurrence avec équilibrage de charge automatique",
"Supported Applications": "Applications prises en charge",
"Supported Imagine Models": "Modèles Imagine pris en charge",
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "ラベンダードリーム",
"preset.ocean-breeze": "オーシャンブリーズ",
"preset.rose-garden": "ローズガーデン",
"preset.simple-large": "特大フォント・シンプル",
"preset.sunset-glow": "サンセットグロウ",
"preset.underground": "アンダーグラウンド",
"Press Enter or comma to add tags": "Enterキーまたはコンマを押してタグを追加",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "サンセットグロウ",
"Super Admin": "スーパー管理者",
"Super Large": "極大",
"Support for high concurrency with automatic load balancing": "自動ロードバランシングによる高並行性のサポート",
"Supported Applications": "サポートされているアプリケーション",
"Supported Imagine Models": "対応Imagineモデル",
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "Лавандовый сон",
"preset.ocean-breeze": "Морской бриз",
"preset.rose-garden": "Розовый сад",
"preset.simple-large": "Простая крупная",
"preset.sunset-glow": "Закатное сияние",
"preset.underground": "Подполье",
"Press Enter or comma to add tags": "Нажмите Enter или запятую, чтобы добавить теги",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "Закатное сияние",
"Super Admin": "Суперадмин",
"Super Large": "Очень крупная",
"Support for high concurrency with automatic load balancing": "Поддержка высокой конкурентности с автоматической балансировкой нагрузки",
"Supported Applications": "Поддерживаемые приложения",
"Supported Imagine Models": "Поддерживаемые модели Imagine",
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "Giấc mơ oải hương",
"preset.ocean-breeze": "Gió biển",
"preset.rose-garden": "Vườn hồng",
"preset.simple-large": "Chữ lớn & Đơn giản",
"preset.sunset-glow": "Hoàng hôn",
"preset.underground": "Bóng đêm",
"Press Enter or comma to add tags": "Nhấn Enter hoặc dấu phẩy để thêm thẻ",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "Hoàng hôn",
"Super Admin": "Siêu Quản trị viên",
"Super Large": "Rất lớn",
"Support for high concurrency with automatic load balancing": "Hỗ trợ đồng thời cao với cân bằng tải tự động",
"Supported Applications": "Ứng dụng được hỗ trợ",
"Supported Imagine Models": "Mô hình Imagine được hỗ trợ",
+2
View File
@@ -3019,6 +3019,7 @@
"preset.lavender-dream": "薰衣草梦",
"preset.ocean-breeze": "海风",
"preset.rose-garden": "玫瑰花园",
"preset.simple-large": "超大字体简易",
"preset.sunset-glow": "日落霞光",
"preset.underground": "暗夜",
"Press Enter or comma to add tags": "按 Enter 或逗号添加标签",
@@ -3784,6 +3785,7 @@
"SunoAPI": "SunoAPI",
"Sunset Glow": "日落霞光",
"Super Admin": "超级管理员",
"Super Large": "超大",
"Support for high concurrency with automatic load balancing": "支持高并发和自动负载均衡",
"Supported Applications": "常用应用支持",
"Supported Imagine Models": "支持的 Imagine 模型",
+7 -1
View File
@@ -37,6 +37,11 @@ export const THEME_PRESETS = [
name: 'Anthropic',
swatches: ['oklch(0.984 0.005 95)', 'oklch(0.685 0.142 38)'],
},
{
value: 'simple-large',
name: 'Simple Large-font',
swatches: ['oklch(0.15 0 0)', 'oklch(0.99 0 0)'],
},
{
value: 'underground',
name: 'Underground',
@@ -76,7 +81,7 @@ export const THEME_PRESETS = [
export type ThemePreset = (typeof THEME_PRESETS)[number]['value']
export type ThemeRadius = 'default' | 'none' | 'sm' | 'md' | 'lg' | 'xl'
export type ThemeScale = 'default' | 'sm' | 'lg'
export type ThemeScale = 'default' | 'sm' | 'lg' | 'xl'
export type ContentLayout = 'full' | 'centered'
/**
@@ -141,6 +146,7 @@ export const THEME_SCALE_VALUES: ReadonlySet<ThemeScale> = new Set([
'default',
'sm',
'lg',
'xl',
])
export const CONTENT_LAYOUT_VALUES: ReadonlySet<ContentLayout> = new Set([
+129 -6
View File
@@ -291,23 +291,136 @@ For commercial licensing, please contact support@quantumnous.com
--sidebar-ring: oklch(0.6359 0.1699 307.95);
}
/* ── Simple Large-font ────────────────────────────────────────────────── */
[data-theme-preset='simple-large'] {
--background: oklch(0.99 0 0);
--foreground: oklch(0.15 0 0);
--card: oklch(1 0 0);
--card-foreground: oklch(0.15 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.15 0 0);
--primary: oklch(0.22 0 0);
--primary-foreground: oklch(1 0 0);
--secondary: oklch(0.93 0 0);
--secondary-foreground: oklch(0.15 0 0);
--muted: oklch(0.95 0 0);
--muted-foreground: oklch(0.36 0 0);
--accent: oklch(0.91 0 0);
--accent-foreground: oklch(0.15 0 0);
--destructive: oklch(0.55 0.2 28);
--destructive-foreground: oklch(1 0 0);
--success: oklch(0.45 0.12 145);
--success-foreground: oklch(1 0 0);
--warning: oklch(0.72 0.14 75);
--warning-foreground: oklch(0.15 0 0);
--info: oklch(0.48 0.13 250);
--info-foreground: oklch(1 0 0);
--neutral: oklch(0.36 0 0);
--neutral-foreground: oklch(1 0 0);
--border: oklch(0.82 0 0);
--input: oklch(0.82 0 0);
--ring: oklch(0.22 0 0);
--chart-1: oklch(0.22 0 0);
--chart-2: oklch(0.45 0.12 145);
--chart-3: oklch(0.48 0.13 250);
--chart-4: oklch(0.72 0.14 75);
--chart-5: oklch(0.55 0.2 28);
--sidebar: oklch(0.96 0 0);
--sidebar-foreground: oklch(0.15 0 0);
--sidebar-primary: oklch(0.22 0 0);
--sidebar-primary-foreground: oklch(1 0 0);
--sidebar-accent: oklch(0.9 0 0);
--sidebar-accent-foreground: oklch(0.15 0 0);
--sidebar-border: oklch(0.82 0 0);
--sidebar-ring: oklch(0.22 0 0);
--skeleton-base: oklch(0.9 0 0);
--skeleton-highlight: oklch(0.97 0 0);
--radius: 0.5rem;
--text-xs: 0.9rem;
--text-sm: 1rem;
--text-base: 1.125rem;
--text-lg: 1.25rem;
--text-xl: 1.45rem;
--text-2xl: 1.75rem;
--text-3xl: 2.15rem;
--spacing: 0.3rem;
}
.dark [data-theme-preset='simple-large'] {
--background: oklch(0.12 0 0);
--foreground: oklch(0.98 0 0);
--card: oklch(0.18 0 0);
--card-foreground: oklch(0.98 0 0);
--popover: oklch(0.2 0 0);
--popover-foreground: oklch(0.98 0 0);
--primary: oklch(0.94 0 0);
--primary-foreground: oklch(0.12 0 0);
--secondary: oklch(0.24 0 0);
--secondary-foreground: oklch(0.98 0 0);
--muted: oklch(0.24 0 0);
--muted-foreground: oklch(0.82 0 0);
--accent: oklch(0.3 0 0);
--accent-foreground: oklch(0.98 0 0);
--destructive: oklch(0.68 0.19 25);
--destructive-foreground: oklch(0.98 0 0);
--success: oklch(0.72 0.13 145);
--success-foreground: oklch(0.12 0 0);
--warning: oklch(0.82 0.13 75);
--warning-foreground: oklch(0.12 0 0);
--info: oklch(0.72 0.12 250);
--info-foreground: oklch(0.12 0 0);
--neutral: oklch(0.82 0 0);
--neutral-foreground: oklch(0.12 0 0);
--border: oklch(1 0 0 / 18%);
--input: oklch(1 0 0 / 24%);
--ring: oklch(0.94 0 0);
--chart-1: oklch(0.94 0 0);
--chart-2: oklch(0.72 0.13 145);
--chart-3: oklch(0.72 0.12 250);
--chart-4: oklch(0.82 0.13 75);
--chart-5: oklch(0.68 0.19 25);
--sidebar: oklch(0.16 0 0);
--sidebar-foreground: oklch(0.98 0 0);
--sidebar-primary: oklch(0.94 0 0);
--sidebar-primary-foreground: oklch(0.12 0 0);
--sidebar-accent: oklch(0.28 0 0);
--sidebar-accent-foreground: oklch(0.98 0 0);
--sidebar-border: oklch(1 0 0 / 18%);
--sidebar-ring: oklch(0.94 0 0);
--skeleton-base: oklch(0.24 0 0);
--skeleton-highlight: oklch(0.34 0 0);
}
/* ── 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
* 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
* resolves to (0,3,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). */
* cards/borders rather than tinting them with the clay accent).
* - `simple-large`: keeps intentionally neutral, high-contrast surfaces. */
[data-theme-preset]:not([data-theme-preset='default']):not(
[data-theme-preset='anthropic']
) {
):not([data-theme-preset='simple-large']) {
--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));
@@ -332,7 +445,7 @@ For commercial licensing, please contact support@quantumnous.com
.dark
[data-theme-preset]:not([data-theme-preset='default']):not(
[data-theme-preset='anthropic']
) {
):not([data-theme-preset='simple-large']) {
--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));
@@ -362,7 +475,7 @@ For commercial licensing, please contact support@quantumnous.com
*
* 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
* the bridge selector (specificity 0,3,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.
*
@@ -574,7 +687,7 @@ For commercial licensing, please contact support@quantumnous.com
}
/* ── Density scale ────────────────────────────────────────────────────── */
/* `sm` = compact UI; `lg` = comfortable. Default (no attribute) keeps Tailwind defaults. */
/* `sm` = compact UI; `lg` = comfortable; `xl` = extra readable. Default keeps Tailwind defaults. */
[data-theme-scale='sm'] {
--text-xs: 0.7rem;
--text-sm: 0.78rem;
@@ -595,6 +708,16 @@ For commercial licensing, please contact support@quantumnous.com
--text-3xl: 2rem;
--spacing: 0.28rem;
}
[data-theme-scale='xl'] {
--text-xs: 0.9rem;
--text-sm: 1rem;
--text-base: 1.125rem;
--text-lg: 1.25rem;
--text-xl: 1.45rem;
--text-2xl: 1.75rem;
--text-3xl: 2.15rem;
--spacing: 0.3rem;
}
/* ── Content layout ───────────────────────────────────────────────────── */
/* `centered` clamps inset content to a comfortable reading width on large screens.