fix(theme): replace Gruvbox with Midnight, fix accent/info hue collisions and hardcoded colors

- Replace Gruvbox preset with Midnight (deep blue-purple, violet accent)
- Fix accent/info hue collisions in Nord, Monokai, Dracula, Solarized
- Fix Solarized error/warning collision (error-h 25->5) and WCAG contrast
- Make --color-skip-refresh-* follow --color-warning-h dynamically
- Replace hardcoded rgba(24,144,255) in onboarding.css with --color-accent
- Replace hardcoded #00B87A in import modals with --color-success
This commit is contained in:
Will Miao
2026-06-18 18:57:53 +08:00
parent c5c7373e10
commit 80ec9085dd
17 changed files with 137 additions and 94 deletions

View File

@@ -255,7 +255,7 @@
"presets": "Theme-Voreinstellungen",
"default": "Standard",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "Theme Presets",
"default": "Default",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "Preajustes de tema",
"default": "Predeterminado",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "Préréglages de thème",
"default": "Par défaut",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "ערכות נושא מוגדרות",
"default": "ברירת מחדל",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "テーマプリセット",
"default": "デフォルト",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "테마 프리셋",
"default": "기본",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "Предустановки тем",
"default": "По умолчанию",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "主题预设",
"default": "默认",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -255,7 +255,7 @@
"presets": "主題預設",
"default": "預設",
"nord": "Nord",
"gruvbox": "Gruvbox",
"midnight": "Midnight",
"monokai": "Monokai",
"dracula": "Dracula",
"solarized": "Solarized",

View File

@@ -389,7 +389,7 @@
}
.stat-item.success {
border-left: 3px solid #00B87A;
border-left: 3px solid var(--color-success);
}
.stat-item.failed {
@@ -455,7 +455,7 @@
.results-icon {
font-size: 3em;
color: #00B87A;
color: var(--color-success);
margin-bottom: var(--space-1);
}
@@ -493,7 +493,7 @@
}
.result-card.success {
border-left: 3px solid #00B87A;
border-left: 3px solid var(--color-success);
}
.result-card.failed {
@@ -582,8 +582,8 @@
}
.result-item-status.success {
background: oklch(from #00B87A l c h / 0.2);
color: #00B87A;
background: color-mix(in oklch, var(--color-success) 20%, transparent);
color: var(--color-success);
}
.result-item-status.failed {
@@ -661,11 +661,11 @@
/* Completed State */
.batch-progress-container.completed .progress-bar {
background: #00B87A;
background: var(--color-success);
}
.batch-progress-container.completed .status-icon {
color: #00B87A;
color: var(--color-success);
}
.batch-progress-container.completed .status-icon i {

View File

@@ -472,8 +472,8 @@
background: oklch(62% 0.18 213);
}
.preset-swatch-gruvbox {
background: oklch(58% 0.22 25);
.preset-swatch-midnight {
background: oklch(52% 0.15 300);
}
.preset-swatch-monokai {
@@ -508,8 +508,8 @@
background: oklch(68% 0.18 213);
}
[data-theme="dark"] .preset-swatch-gruvbox {
background: oklch(62% 0.22 25);
[data-theme="dark"] .preset-swatch-midnight {
background: oklch(68% 0.14 300);
}
[data-theme="dark"] .preset-swatch-monokai {

View File

@@ -211,7 +211,7 @@
.lora-item.is-early-access {
background: rgba(0, 184, 122, 0.05);
border-left: 4px solid #00B87A;
border-left: 4px solid var(--color-success);
}
.lora-item.missing-locally {
@@ -310,7 +310,7 @@
.missing-lora-item.is-early-access {
background: rgba(0, 184, 122, 0.05);
border-left: 3px solid #00B87A;
border-left: 3px solid var(--color-success);
padding-left: 10px;
}
@@ -630,7 +630,7 @@
gap: 12px;
padding: 12px 16px;
background: rgba(0, 184, 122, 0.1);
border: 1px solid #00B87A;
border: 1px solid var(--color-success);
border-radius: var(--border-radius-sm);
color: var(--text-color);
margin-bottom: var(--space-2);
@@ -646,7 +646,7 @@
/* Specific styling for the early access warning container in import modal */
.early-access-warning .warning-icon {
color: #00B87A;
color: var(--color-success);
font-size: 1.2em;
}

View File

@@ -27,8 +27,8 @@
transition: var(--transition-slow);
/* Add glow effect */
box-shadow:
0 0 0 2px rgba(24, 144, 255, 0.3),
0 0 20px rgba(24, 144, 255, 0.2),
0 0 0 2px color-mix(in oklch, var(--color-accent) 30%, transparent),
0 0 20px color-mix(in oklch, var(--color-accent) 20%, transparent),
inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
@@ -221,14 +221,14 @@
@keyframes onboarding-pulse {
0%, 100% {
box-shadow:
0 0 0 2px rgba(24, 144, 255, 0.4),
0 0 20px rgba(24, 144, 255, 0.3),
0 0 0 2px color-mix(in oklch, var(--color-accent) 40%, transparent),
0 0 20px color-mix(in oklch, var(--color-accent) 30%, transparent),
inset 0 0 0 1px rgba(255, 255, 255, 0.1);
}
50% {
box-shadow:
0 0 0 4px rgba(24, 144, 255, 0.6),
0 0 30px rgba(24, 144, 255, 0.4),
0 0 0 4px color-mix(in oklch, var(--color-accent) 60%, transparent),
0 0 30px color-mix(in oklch, var(--color-accent) 40%, transparent),
inset 0 0 0 1px rgba(255, 255, 255, 0.2);
}
}

View File

@@ -37,13 +37,13 @@
--color-error-border: color-mix(in oklch, var(--color-error) 50%, transparent);
--color-info: oklch(var(--color-info-l) var(--color-info-c) var(--color-info-h));
--color-info-bg: oklch(72% 0.2 220);
--color-info-text: oklch(28% 0.03 220);
--color-info-glow: oklch(72% 0.2 220 / 0.28);
--color-info-bg: oklch(var(--color-info-l) var(--color-info-c) var(--color-info-h));
--color-info-text: oklch(28% 0.03 var(--color-info-h));
--color-info-glow: oklch(var(--color-info-l) var(--color-info-c) var(--color-info-h) / 0.28);
--color-skip-refresh-bg: oklch(82% 0.12 45);
--color-skip-refresh-text: oklch(35% 0.02 45);
--color-skip-refresh-glow: oklch(82% 0.12 45 / 0.15);
--color-skip-refresh-bg: oklch(82% 0.12 var(--color-warning-h));
--color-skip-refresh-text: oklch(35% 0.02 var(--color-warning-h));
--color-skip-refresh-glow: oklch(82% 0.12 var(--color-warning-h) / 0.15);
}
:root {
@@ -106,9 +106,9 @@
--status-info-bg: oklch(50% 0.10 190 / 0.25);
--status-info-border: oklch(55% 0.12 195 / 0.3);
--color-info-bg: oklch(62% 0.18 220);
--color-info-text: oklch(98% 0.02 240);
--color-info-glow: oklch(62% 0.18 220 / 0.4);
--color-info-bg: oklch(62% 0.18 var(--color-info-h));
--color-info-text: oklch(98% 0.02 var(--color-info-h));
--color-info-glow: oklch(62% 0.18 var(--color-info-h) / 0.4);
--color-error-bg: color-mix(in oklch, var(--color-error) 15%, transparent);
--color-error-border: color-mix(in oklch, var(--color-error) 40%, transparent);
@@ -125,7 +125,11 @@
--color-warning-h: 35;
--color-warning-c: 0.18;
--color-success-h: 130;
--color-error-l: 62%;
--color-error-c: 0.22;
--color-error-h: 5;
--color-info-h: 195;
--color-info-c: 0.18;
--bg-base: oklch(96% 0.01 240);
--bg-elevated: oklch(98% 0.008 240 / 0.95);
@@ -155,7 +159,11 @@
--color-warning-h: 35;
--color-warning-c: 0.18;
--color-success-h: 130;
--color-error-l: 65%;
--color-error-c: 0.22;
--color-error-h: 5;
--color-info-h: 195;
--color-info-c: 0.18;
--bg-base: oklch(20% 0.03 260);
--bg-elevated: oklch(24% 0.03 260 / 0.98);
@@ -178,66 +186,74 @@
--favorite-glow: oklch(78% 0.15 85 / 0.5);
}
/* ── Preset: Gruvbox ───────────────────────────────────────── */
/* ── Preset: Midnight ───────────────────────────────────────── */
[data-theme-preset="gruvbox"] {
--color-accent-h: 25;
--color-accent-c: 0.22;
--color-accent-l: 58%;
--color-warning-h: 45;
--color-warning-c: 0.22;
--color-success-h: 120;
--color-error-h: 4;
[data-theme-preset="midnight"] {
--color-accent-h: 300;
--color-accent-c: 0.15;
--color-accent-l: 52%;
--color-warning-h: 50;
--color-warning-c: 0.18;
--color-success-h: 135;
--color-error-h: 5;
--color-error-l: 62%;
--color-error-c: 0.22;
--color-info-h: 195;
--color-info-c: 0.12;
--bg-base: oklch(95% 0.02 80);
--bg-elevated: oklch(97% 0.015 80 / 0.95);
--bg-hover: oklch(91% 0.03 80);
--bg-disabled: oklch(90% 0.02 80);
--bg-base: oklch(96% 0.01 255);
--bg-elevated: oklch(98% 0.008 255 / 0.95);
--bg-hover: oklch(93% 0.02 255);
--bg-disabled: oklch(92% 0.01 255);
--text-primary: oklch(28% 0.03 55);
--text-secondary: oklch(48% 0.03 55);
--text-inverse: oklch(95% 0.02 80);
--text-primary: oklch(22% 0.03 260);
--text-secondary: oklch(48% 0.03 260);
--text-inverse: oklch(97% 0.01 255);
--surface-base: oklch(96% 0.015 80);
--surface-elevated: oklch(97% 0.015 80 / 0.95);
--surface-hover: oklch(91% 0.03 80);
--surface-base: oklch(97% 0.01 255);
--surface-elevated: oklch(98% 0.008 255 / 0.95);
--surface-hover: oklch(93% 0.02 255);
--surface-subtle: oklch(0% 0 0 / 0.03);
--border-base: oklch(78% 0.04 75);
--border-subtle: oklch(78% 0.04 75 / 0.45);
--border-base: oklch(80% 0.03 255);
--border-subtle: oklch(80% 0.03 255 / 0.45);
--favorite-color: oklch(72% 0.16 75);
--favorite-glow: oklch(72% 0.16 75 / 0.5);
--favorite-color: oklch(72% 0.16 85);
--favorite-glow: oklch(72% 0.16 85 / 0.5);
}
[data-theme="dark"][data-theme-preset="gruvbox"] {
--color-accent-h: 25;
--color-accent-c: 0.22;
--color-accent-l: 62%;
--color-warning-h: 45;
--color-warning-c: 0.22;
--color-success-h: 120;
--color-error-h: 4;
[data-theme="dark"][data-theme-preset="midnight"] {
--color-accent-h: 300;
--color-accent-c: 0.14;
--color-accent-l: 68%;
--color-warning-h: 50;
--color-warning-c: 0.18;
--color-success-h: 135;
--color-error-h: 5;
--color-error-l: 65%;
--color-error-c: 0.22;
--color-info-h: 195;
--color-info-c: 0.12;
--bg-base: oklch(22% 0.02 55);
--bg-elevated: oklch(26% 0.025 55 / 0.98);
--bg-hover: oklch(32% 0.03 55);
--bg-disabled: oklch(30% 0.02 55);
--bg-base: oklch(18% 0.03 260);
--bg-elevated: oklch(22% 0.03 260 / 0.98);
--bg-hover: oklch(28% 0.03 260);
--bg-disabled: oklch(28% 0.02 260);
--text-primary: oklch(85% 0.03 75);
--text-secondary: oklch(68% 0.03 75);
--text-inverse: oklch(22% 0.02 55);
--text-primary: oklch(88% 0.02 255);
--text-secondary: oklch(68% 0.02 255);
--text-inverse: oklch(18% 0.03 260);
--surface-base: oklch(28% 0.025 55);
--surface-elevated: oklch(26% 0.025 55 / 0.98);
--surface-hover: oklch(32% 0.03 55);
--surface-base: oklch(24% 0.03 260);
--surface-elevated: oklch(22% 0.03 260 / 0.98);
--surface-hover: oklch(28% 0.03 260);
--surface-subtle: oklch(100% 0 0 / 0.03);
--border-base: oklch(38% 0.03 55);
--border-subtle: oklch(85% 0.03 75 / 0.15);
--border-base: oklch(36% 0.03 260);
--border-subtle: oklch(88% 0.02 255 / 0.15);
--favorite-color: oklch(78% 0.16 75);
--favorite-glow: oklch(78% 0.16 75 / 0.5);
--favorite-color: oklch(78% 0.16 85);
--favorite-glow: oklch(78% 0.16 85 / 0.5);
}
/* ── Preset: Monokai ───────────────────────────────────────── */
@@ -249,7 +265,10 @@
--color-warning-h: 50;
--color-warning-c: 0.22;
--color-success-h: 140;
--color-error-l: 60%;
--color-error-c: 0.22;
--color-error-h: 340;
--color-info-h: 250;
--bg-base: oklch(96% 0.01 80);
--bg-elevated: oklch(98% 0.005 80 / 0.95);
@@ -279,7 +298,10 @@
--color-warning-h: 50;
--color-warning-c: 0.22;
--color-success-h: 140;
--color-error-l: 65%;
--color-error-c: 0.22;
--color-error-h: 340;
--color-info-h: 250;
--bg-base: oklch(18% 0.02 100);
--bg-elevated: oklch(22% 0.02 100 / 0.98);
@@ -311,7 +333,10 @@
--color-warning-h: 45;
--color-warning-c: 0.22;
--color-success-h: 135;
--color-error-l: 62%;
--color-error-c: 0.22;
--color-error-h: 350;
--color-info-h: 195;
--bg-base: oklch(96% 0.01 290);
--bg-elevated: oklch(98% 0.008 290 / 0.95);
@@ -341,7 +366,10 @@
--color-warning-h: 45;
--color-warning-c: 0.22;
--color-success-h: 135;
--color-error-l: 65%;
--color-error-c: 0.22;
--color-error-h: 350;
--color-info-h: 195;
--bg-base: oklch(18% 0.04 290);
--bg-elevated: oklch(22% 0.04 290 / 0.98);
@@ -373,7 +401,12 @@
--color-warning-h: 45;
--color-warning-c: 0.20;
--color-success-h: 68;
--color-error-h: 25;
--color-error-l: 62%;
--color-error-c: 0.22;
--color-error-h: 5;
--color-info-h: 220;
--color-info-c: 0.16;
--color-info-l: 68%;
--bg-base: oklch(95% 0.03 85);
--bg-elevated: oklch(97% 0.025 85 / 0.95);
@@ -403,7 +436,12 @@
--color-warning-h: 45;
--color-warning-c: 0.20;
--color-success-h: 68;
--color-error-h: 25;
--color-error-l: 65%;
--color-error-c: 0.22;
--color-error-h: 5;
--color-info-h: 220;
--color-info-c: 0.16;
--color-info-l: 68%;
--bg-base: oklch(18% 0.05 200);
--bg-elevated: oklch(22% 0.05 200 / 0.98);
@@ -411,7 +449,7 @@
--bg-disabled: oklch(28% 0.04 200);
--text-primary: oklch(72% 0.03 85);
--text-secondary: oklch(58% 0.03 85);
--text-secondary: oklch(62% 0.03 85);
--text-inverse: oklch(18% 0.05 200);
--surface-base: oklch(24% 0.05 200);

View File

@@ -198,15 +198,20 @@ export function restoreFolderFilter() {
}
const CYCLE_ORDER = ['auto', 'light', 'dark'];
const PRESET_NAMES = ['default', 'nord', 'gruvbox', 'monokai', 'dracula', 'solarized'];
const PRESET_NAMES = ['default', 'nord', 'midnight', 'monokai', 'dracula', 'solarized'];
export { CYCLE_ORDER, PRESET_NAMES };
export function initTheme() {
const savedTheme = getStorageItem('theme') || 'auto';
const savedPreset = getStorageItem('theme_preset') || 'default';
// Migrate deprecated presets
let savedPreset = getStorageItem('theme_preset');
if (savedPreset === 'gruvbox') {
savedPreset = 'midnight';
setStorageItem('theme_preset', 'midnight');
}
applyTheme(savedTheme);
applyPreset(savedPreset);
applyPreset(savedPreset || 'default');
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const currentTheme = getStorageItem('theme') || 'auto';

View File

@@ -102,9 +102,9 @@
<span class="preset-swatch preset-swatch-nord"></span>
<span>{{ t('header.theme.nord') }}</span>
</button>
<button class="theme-preset-btn" data-preset="gruvbox" title="{{ t('header.theme.gruvbox') }}">
<span class="preset-swatch preset-swatch-gruvbox"></span>
<span>{{ t('header.theme.gruvbox') }}</span>
<button class="theme-preset-btn" data-preset="midnight" title="{{ t('header.theme.midnight') }}">
<span class="preset-swatch preset-swatch-midnight"></span>
<span>{{ t('header.theme.midnight') }}</span>
</button>
<button class="theme-preset-btn" data-preset="monokai" title="{{ t('header.theme.monokai') }}">
<span class="preset-swatch preset-swatch-monokai"></span>