From f8add4ca49635090f9bdae0f7468de95ae1a6127 Mon Sep 17 00:00:00 2001 From: CaIon Date: Tue, 26 May 2026 18:35:51 +0800 Subject: [PATCH] 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. --- web/default/src/components/config-drawer.tsx | 3 +- .../components/columns/column-helpers.tsx | 1 + .../columns/common-logs-columns.tsx | 3 +- web/default/src/i18n/locales/en.json | 2 + web/default/src/i18n/locales/fr.json | 2 + web/default/src/i18n/locales/ja.json | 2 + web/default/src/i18n/locales/ru.json | 2 + web/default/src/i18n/locales/vi.json | 2 + web/default/src/i18n/locales/zh.json | 2 + web/default/src/lib/theme-customization.ts | 8 +- web/default/src/styles/theme-presets.css | 135 +++++++++++++++++- 11 files changed, 153 insertions(+), 9 deletions(-) diff --git a/web/default/src/components/config-drawer.tsx b/web/default/src/components/config-drawer.tsx index b1c806bf..10273678 100644 --- a/web/default/src/components/config-drawer.tsx +++ b/web/default/src/components/config-drawer.tsx @@ -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 (
@@ -501,7 +502,7 @@ function ScaleConfig() { 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) => ( diff --git a/web/default/src/features/usage-logs/components/columns/column-helpers.tsx b/web/default/src/features/usage-logs/components/columns/column-helpers.tsx index df3b140e..22cd2139 100644 --- a/web/default/src/features/usage-logs/components/columns/column-helpers.tsx +++ b/web/default/src/features/usage-logs/components/columns/column-helpers.tsx @@ -183,6 +183,7 @@ export function createChannelColumn(config: { autoColor={String(channelId)} copyText={String(channelId)} size='sm' + showDot={false} className='font-mono' /> ) diff --git a/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx b/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx index 1d15c9c7..0a0732a9 100644 --- a/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx +++ b/web/default/src/features/usage-logs/components/columns/common-logs-columns.tsx @@ -332,6 +332,7 @@ export function useCommonLogsColumns(isAdmin: boolean): ColumnDef[] { 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[] { ? 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 = { success: diff --git a/web/default/src/i18n/locales/en.json b/web/default/src/i18n/locales/en.json index 04486dfc..1db3f68f 100644 --- a/web/default/src/i18n/locales/en.json +++ b/web/default/src/i18n/locales/en.json @@ -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", diff --git a/web/default/src/i18n/locales/fr.json b/web/default/src/i18n/locales/fr.json index 2bada212..18c8b0b8 100644 --- a/web/default/src/i18n/locales/fr.json +++ b/web/default/src/i18n/locales/fr.json @@ -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", diff --git a/web/default/src/i18n/locales/ja.json b/web/default/src/i18n/locales/ja.json index 2c5f35ec..a8eb2383 100644 --- a/web/default/src/i18n/locales/ja.json +++ b/web/default/src/i18n/locales/ja.json @@ -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モデル", diff --git a/web/default/src/i18n/locales/ru.json b/web/default/src/i18n/locales/ru.json index 6e3bb805..57e7d529 100644 --- a/web/default/src/i18n/locales/ru.json +++ b/web/default/src/i18n/locales/ru.json @@ -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", diff --git a/web/default/src/i18n/locales/vi.json b/web/default/src/i18n/locales/vi.json index 23441a9c..f829ebd5 100644 --- a/web/default/src/i18n/locales/vi.json +++ b/web/default/src/i18n/locales/vi.json @@ -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ợ", diff --git a/web/default/src/i18n/locales/zh.json b/web/default/src/i18n/locales/zh.json index c567f97f..b930666a 100644 --- a/web/default/src/i18n/locales/zh.json +++ b/web/default/src/i18n/locales/zh.json @@ -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 模型", diff --git a/web/default/src/lib/theme-customization.ts b/web/default/src/lib/theme-customization.ts index c107ed1f..b6680338 100644 --- a/web/default/src/lib/theme-customization.ts +++ b/web/default/src/lib/theme-customization.ts @@ -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 = new Set([ 'default', 'sm', 'lg', + 'xl', ]) export const CONTENT_LAYOUT_VALUES: ReadonlySet = new Set([ diff --git a/web/default/src/styles/theme-presets.css b/web/default/src/styles/theme-presets.css index 11be0720..dc237392 100644 --- a/web/default/src/styles/theme-presets.css +++ b/web/default/src/styles/theme-presets.css @@ -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.