fix(ui): use theme semantic colors for toasts and filter status message
- Changed filter toast from ToastSuccess (hardcoded green) to ToastInfo (uses accent color) - Updated filter toast message from "Filters active" to "Ad blocker ready" for clarity - Refactored theme system to define semantic colors (success, warning, destructive) as CSS variables - Replaced all hardcoded status colors with theme variables across webui components - Ensures toast and status indicators follow user's theme preferences consistently
- commit
- cd2db314138341b70fbfbf890bba882284f9c122
- author
- bnema · · 2025-12-21 21:56 UTC
- parent
- 9b5fe54
- signature
- unsigned
14 files · +152 -58
M internal/ui/app.go +1 -1
| @@ -862,7 +862,7 @@ func (a *App) showFilterStatus(ctx context.Context, status filtering.FilterStatu | |||
| 862 | 862 | log.Debug().Msg("applied filters to all existing webviews") | |
| 863 | 863 | } | |
| 864 | 864 | if a.appToaster != nil { | |
| 865 | - | a.appToaster.Show(ctx, fmt.Sprintf("Filters active (%s)", status.Version), component.ToastSuccess) | |
| 865 | + | a.appToaster.Show(ctx, fmt.Sprintf("Ad blocker ready (%s)", status.Version), component.ToastInfo) | |
| 866 | 866 | } | |
| 867 | 867 | case filtering.StateError: | |
| 868 | 868 | if a.appToaster != nil { | |
| @@ -862,7 +862,7 @@ func (a *App) showFilterStatus(ctx context.Context, status filtering.FilterStatu | |||||
| 862 | log.Debug().Msg("applied filters to all existing webviews") | 862 | log.Debug().Msg("applied filters to all existing webviews") | ||
| 863 | } | 863 | } | ||
| 864 | if a.appToaster != nil { | 864 | if a.appToaster != nil { | ||
| 865 | - | a.appToaster.Show(ctx, fmt.Sprintf("Filters active (%s)", status.Version), component.ToastSuccess) | 865 | + | a.appToaster.Show(ctx, fmt.Sprintf("Ad blocker ready (%s)", status.Version), component.ToastInfo) |
| 866 | } | 866 | } | ||
| 867 | case filtering.StateError: | 867 | case filtering.StateError: | ||
| 868 | if a.appToaster != nil { | 868 | if a.appToaster != nil { | ||
M internal/ui/theme/css.go +7 -7
| @@ -518,22 +518,22 @@ func generateToasterCSS(p Palette) string { | |||
| 518 | 518 | color: var(--bg); | |
| 519 | 519 | } | |
| 520 | 520 | ||
| 521 | - | /* Toast level: success (green) */ | |
| 521 | + | /* Toast level: success */ | |
| 522 | 522 | .toast-success { | |
| 523 | - | background-color: alpha(#4ade80, 0.9); | |
| 523 | + | background-color: alpha(var(--success), 0.9); | |
| 524 | 524 | color: var(--bg); | |
| 525 | 525 | } | |
| 526 | 526 | ||
| 527 | - | /* Toast level: warning (yellow/amber) */ | |
| 527 | + | /* Toast level: warning */ | |
| 528 | 528 | .toast-warning { | |
| 529 | - | background-color: alpha(#fbbf24, 0.9); | |
| 529 | + | background-color: alpha(var(--warning), 0.9); | |
| 530 | 530 | color: var(--bg); | |
| 531 | 531 | } | |
| 532 | 532 | ||
| 533 | - | /* Toast level: error (red) */ | |
| 533 | + | /* Toast level: error */ | |
| 534 | 534 | .toast-error { | |
| 535 | - | background-color: alpha(#ef4444, 0.9); | |
| 536 | - | color: white; | |
| 535 | + | background-color: alpha(var(--destructive), 0.9); | |
| 536 | + | color: var(--bg); | |
| 537 | 537 | } | |
| 538 | 538 | ` | |
| 539 | 539 | } | |
| @@ -518,22 +518,22 @@ func generateToasterCSS(p Palette) string { | |||||
| 518 | color: var(--bg); | 518 | color: var(--bg); | ||
| 519 | } | 519 | } | ||
| 520 | 520 | ||||
| 521 | - | /* Toast level: success (green) */ | 521 | + | /* Toast level: success */ |
| 522 | .toast-success { | 522 | .toast-success { | ||
| 523 | - | background-color: alpha(#4ade80, 0.9); | 523 | + | background-color: alpha(var(--success), 0.9); |
| 524 | color: var(--bg); | 524 | color: var(--bg); | ||
| 525 | } | 525 | } | ||
| 526 | 526 | ||||
| 527 | - | /* Toast level: warning (yellow/amber) */ | 527 | + | /* Toast level: warning */ |
| 528 | .toast-warning { | 528 | .toast-warning { | ||
| 529 | - | background-color: alpha(#fbbf24, 0.9); | 529 | + | background-color: alpha(var(--warning), 0.9); |
| 530 | color: var(--bg); | 530 | color: var(--bg); | ||
| 531 | } | 531 | } | ||
| 532 | 532 | ||||
| 533 | - | /* Toast level: error (red) */ | 533 | + | /* Toast level: error */ |
| 534 | .toast-error { | 534 | .toast-error { | ||
| 535 | - | background-color: alpha(#ef4444, 0.9); | 535 | + | background-color: alpha(var(--destructive), 0.9); |
| 536 | - | color: white; | 536 | + | color: var(--bg); |
| 537 | } | 537 | } | ||
| 538 | ` | 538 | ` | ||
| 539 | } | 539 | } | ||
M internal/ui/theme/palette.go +26 -0
| @@ -18,6 +18,10 @@ type Palette struct { | |||
| 18 | 18 | Muted string // Secondary/disabled text | |
| 19 | 19 | Accent string // Primary accent color (actions, highlights) | |
| 20 | 20 | Border string // Border and divider lines | |
| 21 | + | // Semantic status colors (not user-editable, derived defaults) | |
| 22 | + | Success string // Success/positive feedback | |
| 23 | + | Warning string // Warning/caution feedback | |
| 24 | + | Destructive string // Error/destructive actions | |
| 21 | 25 | } | |
| 22 | 26 | ||
| 23 | 27 | // DefaultDarkPalette returns the default dark theme palette. | |
| @@ -30,6 +34,9 @@ func DefaultDarkPalette() Palette { | |||
| 30 | 34 | Muted: "#909090", | |
| 31 | 35 | Accent: "#4ade80", | |
| 32 | 36 | Border: "#333333", | |
| 37 | + | Success: "#4ade80", | |
| 38 | + | Warning: "#fbbf24", | |
| 39 | + | Destructive: "#ef4444", | |
| 33 | 40 | } | |
| 34 | 41 | } | |
| 35 | 42 | ||
| @@ -43,6 +50,9 @@ func DefaultLightPalette() Palette { | |||
| 43 | 50 | Muted: "#666666", | |
| 44 | 51 | Accent: "#22c55e", | |
| 45 | 52 | Border: "#dddddd", | |
| 53 | + | Success: "#22c55e", | |
| 54 | + | Warning: "#f59e0b", | |
| 55 | + | Destructive: "#dc2626", | |
| 46 | 56 | } | |
| 47 | 57 | } | |
| 48 | 58 | ||
| @@ -67,6 +77,10 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||
| 67 | 77 | Muted: coalesce(cfg.Muted, defaults.Muted), | |
| 68 | 78 | Accent: coalesce(cfg.Accent, defaults.Accent), | |
| 69 | 79 | Border: coalesce(cfg.Border, defaults.Border), | |
| 80 | + | // Semantic colors always use defaults (not user-editable) | |
| 81 | + | Success: defaults.Success, | |
| 82 | + | Warning: defaults.Warning, | |
| 83 | + | Destructive: defaults.Destructive, | |
| 70 | 84 | } | |
| 71 | 85 | } | |
| 72 | 86 | ||
| @@ -124,6 +138,9 @@ func (p Palette) ToCSSVars() string { | |||
| 124 | 138 | sb.WriteString(" --muted: " + p.Muted + ";\n") | |
| 125 | 139 | sb.WriteString(" --accent: " + p.Accent + ";\n") | |
| 126 | 140 | sb.WriteString(" --border: " + p.Border + ";\n") | |
| 141 | + | sb.WriteString(" --success: " + p.Success + ";\n") | |
| 142 | + | sb.WriteString(" --warning: " + p.Warning + ";\n") | |
| 143 | + | sb.WriteString(" --destructive: " + p.Destructive + ";\n") | |
| 127 | 144 | return sb.String() | |
| 128 | 145 | } | |
| 129 | 146 | ||
| @@ -141,6 +158,15 @@ func (p Palette) ToWebCSSVars() string { | |||
| 141 | 158 | sb.WriteString(" --muted: " + p.SurfaceVariant + " !important;\n") | |
| 142 | 159 | sb.WriteString(" --muted-foreground: " + p.Muted + " !important;\n") | |
| 143 | 160 | sb.WriteString(" --border: " + p.Border + " !important;\n") | |
| 161 | + | // Ring follows primary (accent) | |
| 162 | + | sb.WriteString(" --ring: " + p.Accent + " !important;\n") | |
| 163 | + | // Semantic colors from palette defaults | |
| 164 | + | sb.WriteString(" --success: " + p.Success + " !important;\n") | |
| 165 | + | sb.WriteString(" --success-foreground: " + p.Background + " !important;\n") | |
| 166 | + | sb.WriteString(" --warning: " + p.Warning + " !important;\n") | |
| 167 | + | sb.WriteString(" --warning-foreground: " + p.Text + " !important;\n") | |
| 168 | + | sb.WriteString(" --destructive: " + p.Destructive + " !important;\n") | |
| 169 | + | sb.WriteString(" --destructive-foreground: " + p.Background + " !important;\n") | |
| 144 | 170 | // Keep GTK names for compatibility | |
| 145 | 171 | sb.WriteString(" --bg: " + p.Background + " !important;\n") | |
| 146 | 172 | sb.WriteString(" --surface: " + p.Surface + " !important;\n") | |
| @@ -18,6 +18,10 @@ type Palette struct { | |||||
| 18 | Muted string // Secondary/disabled text | 18 | Muted string // Secondary/disabled text | ||
| 19 | Accent string // Primary accent color (actions, highlights) | 19 | Accent string // Primary accent color (actions, highlights) | ||
| 20 | Border string // Border and divider lines | 20 | Border string // Border and divider lines | ||
| 21 | + | // Semantic status colors (not user-editable, derived defaults) | |||
| 22 | + | Success string // Success/positive feedback | |||
| 23 | + | Warning string // Warning/caution feedback | |||
| 24 | + | Destructive string // Error/destructive actions | |||
| 21 | } | 25 | } | ||
| 22 | 26 | ||||
| 23 | // DefaultDarkPalette returns the default dark theme palette. | 27 | // DefaultDarkPalette returns the default dark theme palette. | ||
| @@ -30,6 +34,9 @@ func DefaultDarkPalette() Palette { | |||||
| 30 | Muted: "#909090", | 34 | Muted: "#909090", | ||
| 31 | Accent: "#4ade80", | 35 | Accent: "#4ade80", | ||
| 32 | Border: "#333333", | 36 | Border: "#333333", | ||
| 37 | + | Success: "#4ade80", | |||
| 38 | + | Warning: "#fbbf24", | |||
| 39 | + | Destructive: "#ef4444", | |||
| 33 | } | 40 | } | ||
| 34 | } | 41 | } | ||
| 35 | 42 | ||||
| @@ -43,6 +50,9 @@ func DefaultLightPalette() Palette { | |||||
| 43 | Muted: "#666666", | 50 | Muted: "#666666", | ||
| 44 | Accent: "#22c55e", | 51 | Accent: "#22c55e", | ||
| 45 | Border: "#dddddd", | 52 | Border: "#dddddd", | ||
| 53 | + | Success: "#22c55e", | |||
| 54 | + | Warning: "#f59e0b", | |||
| 55 | + | Destructive: "#dc2626", | |||
| 46 | } | 56 | } | ||
| 47 | } | 57 | } | ||
| 48 | 58 | ||||
| @@ -67,6 +77,10 @@ func PaletteFromConfig(cfg *config.ColorPalette, isDark bool) Palette { | |||||
| 67 | Muted: coalesce(cfg.Muted, defaults.Muted), | 77 | Muted: coalesce(cfg.Muted, defaults.Muted), | ||
| 68 | Accent: coalesce(cfg.Accent, defaults.Accent), | 78 | Accent: coalesce(cfg.Accent, defaults.Accent), | ||
| 69 | Border: coalesce(cfg.Border, defaults.Border), | 79 | Border: coalesce(cfg.Border, defaults.Border), | ||
| 80 | + | // Semantic colors always use defaults (not user-editable) | |||
| 81 | + | Success: defaults.Success, | |||
| 82 | + | Warning: defaults.Warning, | |||
| 83 | + | Destructive: defaults.Destructive, | |||
| 70 | } | 84 | } | ||
| 71 | } | 85 | } | ||
| 72 | 86 | ||||
| @@ -124,6 +138,9 @@ func (p Palette) ToCSSVars() string { | |||||
| 124 | sb.WriteString(" --muted: " + p.Muted + ";\n") | 138 | sb.WriteString(" --muted: " + p.Muted + ";\n") | ||
| 125 | sb.WriteString(" --accent: " + p.Accent + ";\n") | 139 | sb.WriteString(" --accent: " + p.Accent + ";\n") | ||
| 126 | sb.WriteString(" --border: " + p.Border + ";\n") | 140 | sb.WriteString(" --border: " + p.Border + ";\n") | ||
| 141 | + | sb.WriteString(" --success: " + p.Success + ";\n") | |||
| 142 | + | sb.WriteString(" --warning: " + p.Warning + ";\n") | |||
| 143 | + | sb.WriteString(" --destructive: " + p.Destructive + ";\n") | |||
| 127 | return sb.String() | 144 | return sb.String() | ||
| 128 | } | 145 | } | ||
| 129 | 146 | ||||
| @@ -141,6 +158,15 @@ func (p Palette) ToWebCSSVars() string { | |||||
| 141 | sb.WriteString(" --muted: " + p.SurfaceVariant + " !important;\n") | 158 | sb.WriteString(" --muted: " + p.SurfaceVariant + " !important;\n") | ||
| 142 | sb.WriteString(" --muted-foreground: " + p.Muted + " !important;\n") | 159 | sb.WriteString(" --muted-foreground: " + p.Muted + " !important;\n") | ||
| 143 | sb.WriteString(" --border: " + p.Border + " !important;\n") | 160 | sb.WriteString(" --border: " + p.Border + " !important;\n") | ||
| 161 | + | // Ring follows primary (accent) | |||
| 162 | + | sb.WriteString(" --ring: " + p.Accent + " !important;\n") | |||
| 163 | + | // Semantic colors from palette defaults | |||
| 164 | + | sb.WriteString(" --success: " + p.Success + " !important;\n") | |||
| 165 | + | sb.WriteString(" --success-foreground: " + p.Background + " !important;\n") | |||
| 166 | + | sb.WriteString(" --warning: " + p.Warning + " !important;\n") | |||
| 167 | + | sb.WriteString(" --warning-foreground: " + p.Text + " !important;\n") | |||
| 168 | + | sb.WriteString(" --destructive: " + p.Destructive + " !important;\n") | |||
| 169 | + | sb.WriteString(" --destructive-foreground: " + p.Background + " !important;\n") | |||
| 144 | // Keep GTK names for compatibility | 170 | // Keep GTK names for compatibility | ||
| 145 | sb.WriteString(" --bg: " + p.Background + " !important;\n") | 171 | sb.WriteString(" --bg: " + p.Background + " !important;\n") | ||
| 146 | sb.WriteString(" --surface: " + p.Surface + " !important;\n") | 172 | sb.WriteString(" --surface: " + p.Surface + " !important;\n") | ||
M webui/src/pages/homepage/favorites/FavoriteEditor.svelte +7 -7
| @@ -455,18 +455,18 @@ | |||
| 455 | 455 | } | |
| 456 | 456 | ||
| 457 | 457 | .btn-danger-outline:hover { | |
| 458 | - | color: #ef4444; | |
| 459 | - | border-color: #ef4444; | |
| 458 | + | color: var(--destructive); | |
| 459 | + | border-color: var(--destructive); | |
| 460 | 460 | } | |
| 461 | 461 | ||
| 462 | 462 | .btn-danger { | |
| 463 | - | background: #b91c1c; | |
| 464 | - | color: #fef2f2; | |
| 465 | - | border-color: #991b1b; | |
| 463 | + | background: var(--destructive); | |
| 464 | + | color: var(--destructive-foreground); | |
| 465 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); | |
| 466 | 466 | } | |
| 467 | 467 | ||
| 468 | 468 | .btn-danger:hover { | |
| 469 | - | background: #dc2626; | |
| 469 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); | |
| 470 | 470 | } | |
| 471 | 471 | ||
| 472 | 472 | .btn-cancel { | |
| @@ -489,7 +489,7 @@ | |||
| 489 | 489 | .confirm-text { | |
| 490 | 490 | flex: 1; | |
| 491 | 491 | font-size: 0.72rem; | |
| 492 | - | color: #ef4444; | |
| 492 | + | color: var(--destructive); | |
| 493 | 493 | font-weight: 500; | |
| 494 | 494 | } | |
| 495 | 495 | </style> | |
| @@ -455,18 +455,18 @@ | |||||
| 455 | } | 455 | } | ||
| 456 | 456 | ||||
| 457 | .btn-danger-outline:hover { | 457 | .btn-danger-outline:hover { | ||
| 458 | - | color: #ef4444; | 458 | + | color: var(--destructive); |
| 459 | - | border-color: #ef4444; | 459 | + | border-color: var(--destructive); |
| 460 | } | 460 | } | ||
| 461 | 461 | ||||
| 462 | .btn-danger { | 462 | .btn-danger { | ||
| 463 | - | background: #b91c1c; | 463 | + | background: var(--destructive); |
| 464 | - | color: #fef2f2; | 464 | + | color: var(--destructive-foreground); |
| 465 | - | border-color: #991b1b; | 465 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); |
| 466 | } | 466 | } | ||
| 467 | 467 | ||||
| 468 | .btn-danger:hover { | 468 | .btn-danger:hover { | ||
| 469 | - | background: #dc2626; | 469 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); |
| 470 | } | 470 | } | ||
| 471 | 471 | ||||
| 472 | .btn-cancel { | 472 | .btn-cancel { | ||
| @@ -489,7 +489,7 @@ | |||||
| 489 | .confirm-text { | 489 | .confirm-text { | ||
| 490 | flex: 1; | 490 | flex: 1; | ||
| 491 | font-size: 0.72rem; | 491 | font-size: 0.72rem; | ||
| 492 | - | color: #ef4444; | 492 | + | color: var(--destructive); |
| 493 | font-weight: 500; | 493 | font-weight: 500; | ||
| 494 | } | 494 | } | ||
| 495 | </style> | 495 | </style> | ||
M webui/src/pages/homepage/favorites/FolderList.svelte +2 -2
| @@ -204,8 +204,8 @@ | |||
| 204 | 204 | } | |
| 205 | 205 | ||
| 206 | 206 | .add-folder-btn.cancel:hover { | |
| 207 | - | color: #ef4444; | |
| 208 | - | border-color: #ef4444; | |
| 207 | + | color: var(--destructive); | |
| 208 | + | border-color: var(--destructive); | |
| 209 | 209 | } | |
| 210 | 210 | ||
| 211 | 211 | .create-input-row { | |
| @@ -204,8 +204,8 @@ | |||||
| 204 | } | 204 | } | ||
| 205 | 205 | ||||
| 206 | .add-folder-btn.cancel:hover { | 206 | .add-folder-btn.cancel:hover { | ||
| 207 | - | color: #ef4444; | 207 | + | color: var(--destructive); |
| 208 | - | border-color: #ef4444; | 208 | + | border-color: var(--destructive); |
| 209 | } | 209 | } | ||
| 210 | 210 | ||||
| 211 | .create-input-row { | 211 | .create-input-row { | ||
M webui/src/pages/homepage/favorites/TagCloud.svelte +2 -2
| @@ -214,8 +214,8 @@ | |||
| 214 | 214 | } | |
| 215 | 215 | ||
| 216 | 216 | .add-tag-btn.cancel:hover { | |
| 217 | - | color: #ef4444; | |
| 218 | - | border-color: #ef4444; | |
| 217 | + | color: var(--destructive); | |
| 218 | + | border-color: var(--destructive); | |
| 219 | 219 | } | |
| 220 | 220 | ||
| 221 | 221 | .create-input-row { | |
| @@ -214,8 +214,8 @@ | |||||
| 214 | } | 214 | } | ||
| 215 | 215 | ||||
| 216 | .add-tag-btn.cancel:hover { | 216 | .add-tag-btn.cancel:hover { | ||
| 217 | - | color: #ef4444; | 217 | + | color: var(--destructive); |
| 218 | - | border-color: #ef4444; | 218 | + | border-color: var(--destructive); |
| 219 | } | 219 | } | ||
| 220 | 220 | ||||
| 221 | .create-input-row { | 221 | .create-input-row { | ||
M webui/src/pages/homepage/history/HistoryCleanup.svelte +8 -8
| @@ -191,7 +191,7 @@ | |||
| 191 | 191 | .modal-icon::before { | |
| 192 | 192 | content: ''; | |
| 193 | 193 | font-size: 0.9rem; | |
| 194 | - | color: #fbbf24; | |
| 194 | + | color: var(--warning); | |
| 195 | 195 | } | |
| 196 | 196 | ||
| 197 | 197 | .modal-title { | |
| @@ -258,7 +258,7 @@ | |||
| 258 | 258 | } | |
| 259 | 259 | ||
| 260 | 260 | .cleanup-option.destructive .option-label { | |
| 261 | - | color: #ef4444; | |
| 261 | + | color: var(--destructive); | |
| 262 | 262 | } | |
| 263 | 263 | ||
| 264 | 264 | .option-main { | |
| @@ -303,7 +303,7 @@ | |||
| 303 | 303 | .confirm-icon::before { | |
| 304 | 304 | content: ''; | |
| 305 | 305 | font-size: 2rem; | |
| 306 | - | color: #ef4444; | |
| 306 | + | color: var(--destructive); | |
| 307 | 307 | } | |
| 308 | 308 | ||
| 309 | 309 | .confirm-message { | |
| @@ -314,7 +314,7 @@ | |||
| 314 | 314 | } | |
| 315 | 315 | ||
| 316 | 316 | .confirm-message strong { | |
| 317 | - | color: #ef4444; | |
| 317 | + | color: var(--destructive); | |
| 318 | 318 | } | |
| 319 | 319 | ||
| 320 | 320 | .confirm-actions { | |
| @@ -359,13 +359,13 @@ | |||
| 359 | 359 | } | |
| 360 | 360 | ||
| 361 | 361 | .confirm-btn.destructive { | |
| 362 | - | background: #b91c1c; | |
| 363 | - | color: #fef2f2; | |
| 364 | - | border-color: #991b1b; | |
| 362 | + | background: var(--destructive); | |
| 363 | + | color: var(--destructive-foreground); | |
| 364 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); | |
| 365 | 365 | } | |
| 366 | 366 | ||
| 367 | 367 | .confirm-btn.destructive:hover { | |
| 368 | - | background: #dc2626; | |
| 368 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); | |
| 369 | 369 | } | |
| 370 | 370 | ||
| 371 | 371 | .modal-footer { | |
| @@ -191,7 +191,7 @@ | |||||
| 191 | .modal-icon::before { | 191 | .modal-icon::before { | ||
| 192 | content: ''; | 192 | content: ''; | ||
| 193 | font-size: 0.9rem; | 193 | font-size: 0.9rem; | ||
| 194 | - | color: #fbbf24; | 194 | + | color: var(--warning); |
| 195 | } | 195 | } | ||
| 196 | 196 | ||||
| 197 | .modal-title { | 197 | .modal-title { | ||
| @@ -258,7 +258,7 @@ | |||||
| 258 | } | 258 | } | ||
| 259 | 259 | ||||
| 260 | .cleanup-option.destructive .option-label { | 260 | .cleanup-option.destructive .option-label { | ||
| 261 | - | color: #ef4444; | 261 | + | color: var(--destructive); |
| 262 | } | 262 | } | ||
| 263 | 263 | ||||
| 264 | .option-main { | 264 | .option-main { | ||
| @@ -303,7 +303,7 @@ | |||||
| 303 | .confirm-icon::before { | 303 | .confirm-icon::before { | ||
| 304 | content: ''; | 304 | content: ''; | ||
| 305 | font-size: 2rem; | 305 | font-size: 2rem; | ||
| 306 | - | color: #ef4444; | 306 | + | color: var(--destructive); |
| 307 | } | 307 | } | ||
| 308 | 308 | ||||
| 309 | .confirm-message { | 309 | .confirm-message { | ||
| @@ -314,7 +314,7 @@ | |||||
| 314 | } | 314 | } | ||
| 315 | 315 | ||||
| 316 | .confirm-message strong { | 316 | .confirm-message strong { | ||
| 317 | - | color: #ef4444; | 317 | + | color: var(--destructive); |
| 318 | } | 318 | } | ||
| 319 | 319 | ||||
| 320 | .confirm-actions { | 320 | .confirm-actions { | ||
| @@ -359,13 +359,13 @@ | |||||
| 359 | } | 359 | } | ||
| 360 | 360 | ||||
| 361 | .confirm-btn.destructive { | 361 | .confirm-btn.destructive { | ||
| 362 | - | background: #b91c1c; | 362 | + | background: var(--destructive); |
| 363 | - | color: #fef2f2; | 363 | + | color: var(--destructive-foreground); |
| 364 | - | border-color: #991b1b; | 364 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); |
| 365 | } | 365 | } | ||
| 366 | 366 | ||||
| 367 | .confirm-btn.destructive:hover { | 367 | .confirm-btn.destructive:hover { | ||
| 368 | - | background: #dc2626; | 368 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); |
| 369 | } | 369 | } | ||
| 370 | 370 | ||||
| 371 | .modal-footer { | 371 | .modal-footer { | ||
M webui/src/pages/homepage/history/HistoryFilters.svelte +2 -2
| @@ -144,8 +144,8 @@ | |||
| 144 | 144 | } | |
| 145 | 145 | ||
| 146 | 146 | .cleanup-btn:hover { | |
| 147 | - | color: #ef4444; | |
| 148 | - | border-color: #ef4444; | |
| 147 | + | color: var(--destructive); | |
| 148 | + | border-color: var(--destructive); | |
| 149 | 149 | } | |
| 150 | 150 | ||
| 151 | 151 | .cleanup-icon::before { | |
| @@ -144,8 +144,8 @@ | |||||
| 144 | } | 144 | } | ||
| 145 | 145 | ||||
| 146 | .cleanup-btn:hover { | 146 | .cleanup-btn:hover { | ||
| 147 | - | color: #ef4444; | 147 | + | color: var(--destructive); |
| 148 | - | border-color: #ef4444; | 148 | + | border-color: var(--destructive); |
| 149 | } | 149 | } | ||
| 150 | 150 | ||||
| 151 | .cleanup-icon::before { | 151 | .cleanup-icon::before { | ||
M webui/src/pages/homepage/history/HistoryItem.svelte +2 -2
| @@ -270,7 +270,7 @@ | |||
| 270 | 270 | } | |
| 271 | 271 | ||
| 272 | 272 | .delete-btn:hover { | |
| 273 | - | color: #ef4444; | |
| 274 | - | border-color: #ef4444; | |
| 273 | + | color: var(--destructive); | |
| 274 | + | border-color: var(--destructive); | |
| 275 | 275 | } | |
| 276 | 276 | </style> | |
| @@ -270,7 +270,7 @@ | |||||
| 270 | } | 270 | } | ||
| 271 | 271 | ||||
| 272 | .delete-btn:hover { | 272 | .delete-btn:hover { | ||
| 273 | - | color: #ef4444; | 273 | + | color: var(--destructive); |
| 274 | - | border-color: #ef4444; | 274 | + | border-color: var(--destructive); |
| 275 | } | 275 | } | ||
| 276 | </style> | 276 | </style> | ||
M webui/src/pages/homepage/shell/HomepageShell.svelte +5 -5
| @@ -533,7 +533,7 @@ | |||
| 533 | 533 | ||
| 534 | 534 | .modal-icon { | |
| 535 | 535 | font-size: 1rem; | |
| 536 | - | color: #fbbf24; | |
| 536 | + | color: var(--warning); | |
| 537 | 537 | } | |
| 538 | 538 | ||
| 539 | 539 | .modal-title { | |
| @@ -599,13 +599,13 @@ | |||
| 599 | 599 | } | |
| 600 | 600 | ||
| 601 | 601 | .modal-btn-confirm { | |
| 602 | - | color: #fef2f2; | |
| 603 | - | background: #b91c1c; | |
| 604 | - | border-color: #991b1b; | |
| 602 | + | color: var(--destructive-foreground); | |
| 603 | + | background: var(--destructive); | |
| 604 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); | |
| 605 | 605 | } | |
| 606 | 606 | ||
| 607 | 607 | .modal-btn-confirm:hover { | |
| 608 | - | background: #dc2626; | |
| 608 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); | |
| 609 | 609 | } | |
| 610 | 610 | ||
| 611 | 611 | /* Responsive */ | |
| @@ -533,7 +533,7 @@ | |||||
| 533 | 533 | ||||
| 534 | .modal-icon { | 534 | .modal-icon { | ||
| 535 | font-size: 1rem; | 535 | font-size: 1rem; | ||
| 536 | - | color: #fbbf24; | 536 | + | color: var(--warning); |
| 537 | } | 537 | } | ||
| 538 | 538 | ||||
| 539 | .modal-title { | 539 | .modal-title { | ||
| @@ -599,13 +599,13 @@ | |||||
| 599 | } | 599 | } | ||
| 600 | 600 | ||||
| 601 | .modal-btn-confirm { | 601 | .modal-btn-confirm { | ||
| 602 | - | color: #fef2f2; | 602 | + | color: var(--destructive-foreground); |
| 603 | - | background: #b91c1c; | 603 | + | background: var(--destructive); |
| 604 | - | border-color: #991b1b; | 604 | + | border-color: color-mix(in srgb, var(--destructive) 80%, black 20%); |
| 605 | } | 605 | } | ||
| 606 | 606 | ||||
| 607 | .modal-btn-confirm:hover { | 607 | .modal-btn-confirm:hover { | ||
| 608 | - | background: #dc2626; | 608 | + | background: color-mix(in srgb, var(--destructive) 85%, white 15%); |
| 609 | } | 609 | } | ||
| 610 | 610 | ||||
| 611 | /* Responsive */ | 611 | /* Responsive */ | ||
M webui/src/pages/homepage/shell/StatusBar.svelte +13 -13
| @@ -235,15 +235,15 @@ | |||
| 235 | 235 | } | |
| 236 | 236 | ||
| 237 | 237 | .mode-chip[data-color="warning"] { | |
| 238 | - | background: color-mix(in srgb, #fbbf24 15%, transparent); | |
| 239 | - | border-color: color-mix(in srgb, #fbbf24 40%, var(--border) 60%); | |
| 240 | - | color: #fbbf24; | |
| 238 | + | background: color-mix(in srgb, var(--warning) 15%, transparent); | |
| 239 | + | border-color: color-mix(in srgb, var(--warning) 40%, var(--border) 60%); | |
| 240 | + | color: var(--warning); | |
| 241 | 241 | } | |
| 242 | 242 | ||
| 243 | 243 | .mode-chip[data-color="info"] { | |
| 244 | - | background: color-mix(in srgb, #60a5fa 15%, transparent); | |
| 245 | - | border-color: color-mix(in srgb, #60a5fa 40%, var(--border) 60%); | |
| 246 | - | color: #60a5fa; | |
| 244 | + | background: color-mix(in srgb, var(--info) 15%, transparent); | |
| 245 | + | border-color: color-mix(in srgb, var(--info) 40%, var(--border) 60%); | |
| 246 | + | color: var(--info); | |
| 247 | 247 | } | |
| 248 | 248 | ||
| 249 | 249 | /* Pending prefix indicator */ | |
| @@ -252,17 +252,17 @@ | |||
| 252 | 252 | } | |
| 253 | 253 | ||
| 254 | 254 | .prefix-chip[data-color="warning"] { | |
| 255 | - | background: color-mix(in srgb, #fbbf24 15%, transparent); | |
| 256 | - | border-color: color-mix(in srgb, #fbbf24 50%, var(--border) 50%); | |
| 257 | - | color: #fbbf24; | |
| 255 | + | background: color-mix(in srgb, var(--warning) 15%, transparent); | |
| 256 | + | border-color: color-mix(in srgb, var(--warning) 50%, var(--border) 50%); | |
| 257 | + | color: var(--warning); | |
| 258 | 258 | } | |
| 259 | 259 | ||
| 260 | 260 | .prefix-key { | |
| 261 | 261 | font-size: 0.7rem; | |
| 262 | 262 | font-weight: 700; | |
| 263 | 263 | padding: 0.1rem 0.25rem; | |
| 264 | - | background: color-mix(in srgb, #fbbf24 25%, transparent); | |
| 265 | - | border: 1px solid color-mix(in srgb, #fbbf24 40%, var(--border) 60%); | |
| 264 | + | background: color-mix(in srgb, var(--warning) 25%, transparent); | |
| 265 | + | border: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border) 60%); | |
| 266 | 266 | font-family: ui-monospace, 'Fira Code', 'Cascadia Code', Menlo, Monaco, Consolas, monospace; | |
| 267 | 267 | } | |
| 268 | 268 | ||
| @@ -273,8 +273,8 @@ | |||
| 273 | 273 | } | |
| 274 | 274 | ||
| 275 | 275 | @keyframes pulse-border { | |
| 276 | - | 0%, 100% { border-color: color-mix(in srgb, #fbbf24 50%, var(--border) 50%); } | |
| 277 | - | 50% { border-color: #fbbf24; } | |
| 276 | + | 0%, 100% { border-color: color-mix(in srgb, var(--warning) 50%, var(--border) 50%); } | |
| 277 | + | 50% { border-color: var(--warning); } | |
| 278 | 278 | } | |
| 279 | 279 | ||
| 280 | 280 | @keyframes blink { | |
| @@ -235,15 +235,15 @@ | |||||
| 235 | } | 235 | } | ||
| 236 | 236 | ||||
| 237 | .mode-chip[data-color="warning"] { | 237 | .mode-chip[data-color="warning"] { | ||
| 238 | - | background: color-mix(in srgb, #fbbf24 15%, transparent); | 238 | + | background: color-mix(in srgb, var(--warning) 15%, transparent); |
| 239 | - | border-color: color-mix(in srgb, #fbbf24 40%, var(--border) 60%); | 239 | + | border-color: color-mix(in srgb, var(--warning) 40%, var(--border) 60%); |
| 240 | - | color: #fbbf24; | 240 | + | color: var(--warning); |
| 241 | } | 241 | } | ||
| 242 | 242 | ||||
| 243 | .mode-chip[data-color="info"] { | 243 | .mode-chip[data-color="info"] { | ||
| 244 | - | background: color-mix(in srgb, #60a5fa 15%, transparent); | 244 | + | background: color-mix(in srgb, var(--info) 15%, transparent); |
| 245 | - | border-color: color-mix(in srgb, #60a5fa 40%, var(--border) 60%); | 245 | + | border-color: color-mix(in srgb, var(--info) 40%, var(--border) 60%); |
| 246 | - | color: #60a5fa; | 246 | + | color: var(--info); |
| 247 | } | 247 | } | ||
| 248 | 248 | ||||
| 249 | /* Pending prefix indicator */ | 249 | /* Pending prefix indicator */ | ||
| @@ -252,17 +252,17 @@ | |||||
| 252 | } | 252 | } | ||
| 253 | 253 | ||||
| 254 | .prefix-chip[data-color="warning"] { | 254 | .prefix-chip[data-color="warning"] { | ||
| 255 | - | background: color-mix(in srgb, #fbbf24 15%, transparent); | 255 | + | background: color-mix(in srgb, var(--warning) 15%, transparent); |
| 256 | - | border-color: color-mix(in srgb, #fbbf24 50%, var(--border) 50%); | 256 | + | border-color: color-mix(in srgb, var(--warning) 50%, var(--border) 50%); |
| 257 | - | color: #fbbf24; | 257 | + | color: var(--warning); |
| 258 | } | 258 | } | ||
| 259 | 259 | ||||
| 260 | .prefix-key { | 260 | .prefix-key { | ||
| 261 | font-size: 0.7rem; | 261 | font-size: 0.7rem; | ||
| 262 | font-weight: 700; | 262 | font-weight: 700; | ||
| 263 | padding: 0.1rem 0.25rem; | 263 | padding: 0.1rem 0.25rem; | ||
| 264 | - | background: color-mix(in srgb, #fbbf24 25%, transparent); | 264 | + | background: color-mix(in srgb, var(--warning) 25%, transparent); |
| 265 | - | border: 1px solid color-mix(in srgb, #fbbf24 40%, var(--border) 60%); | 265 | + | border: 1px solid color-mix(in srgb, var(--warning) 40%, var(--border) 60%); |
| 266 | font-family: ui-monospace, 'Fira Code', 'Cascadia Code', Menlo, Monaco, Consolas, monospace; | 266 | font-family: ui-monospace, 'Fira Code', 'Cascadia Code', Menlo, Monaco, Consolas, monospace; | ||
| 267 | } | 267 | } | ||
| 268 | 268 | ||||
| @@ -273,8 +273,8 @@ | |||||
| 273 | } | 273 | } | ||
| 274 | 274 | ||||
| 275 | @keyframes pulse-border { | 275 | @keyframes pulse-border { | ||
| 276 | - | 0%, 100% { border-color: color-mix(in srgb, #fbbf24 50%, var(--border) 50%); } | 276 | + | 0%, 100% { border-color: color-mix(in srgb, var(--warning) 50%, var(--border) 50%); } |
| 277 | - | 50% { border-color: #fbbf24; } | 277 | + | 50% { border-color: var(--warning); } |
| 278 | } | 278 | } | ||
| 279 | 279 | ||||
| 280 | @keyframes blink { | 280 | @keyframes blink { | ||
M webui/src/styles/app.css +24 -2
| @@ -54,7 +54,15 @@ | |||
| 54 | 54 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | |
| 55 | 55 | --border: oklch(0.88 0.008 260); | |
| 56 | 56 | --input: oklch(0.88 0.008 260); | |
| 57 | - | --ring: oklch(0.55 0.20 145); | |
| 57 | + | --ring: var(--primary); | |
| 58 | + | ||
| 59 | + | /* Semantic colors - for status indicators */ | |
| 60 | + | --success: oklch(0.65 0.20 145); | |
| 61 | + | --success-foreground: oklch(0.985 0 0); | |
| 62 | + | --warning: oklch(0.75 0.18 85); | |
| 63 | + | --warning-foreground: oklch(0.145 0.02 260); | |
| 64 | + | --info: oklch(0.65 0.15 230); | |
| 65 | + | --info-foreground: oklch(0.985 0 0); | |
| 58 | 66 | ||
| 59 | 67 | /* Chart colors */ | |
| 60 | 68 | --chart-1: oklch(0.58 0.18 145); | |
| @@ -113,7 +121,15 @@ | |||
| 113 | 121 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | |
| 114 | 122 | --border: oklch(0.35 0.01 260); | |
| 115 | 123 | --input: oklch(0.35 0.01 260); | |
| 116 | - | --ring: oklch(0.75 0.19 145); | |
| 124 | + | --ring: var(--primary); | |
| 125 | + | ||
| 126 | + | /* Semantic colors - brighter for dark bg */ | |
| 127 | + | --success: oklch(0.72 0.18 145); | |
| 128 | + | --success-foreground: oklch(0.12 0.02 145); | |
| 129 | + | --warning: oklch(0.80 0.16 85); | |
| 130 | + | --warning-foreground: oklch(0.12 0.02 85); | |
| 131 | + | --info: oklch(0.70 0.14 230); | |
| 132 | + | --info-foreground: oklch(0.12 0.02 230); | |
| 117 | 133 | ||
| 118 | 134 | /* Chart colors - brighter for dark bg */ | |
| 119 | 135 | --chart-1: oklch(0.72 0.18 145); | |
| @@ -159,6 +175,12 @@ | |||
| 159 | 175 | --color-accent-foreground: var(--accent-foreground); | |
| 160 | 176 | --color-destructive: var(--destructive); | |
| 161 | 177 | --color-destructive-foreground: var(--destructive-foreground); | |
| 178 | + | --color-success: var(--success); | |
| 179 | + | --color-success-foreground: var(--success-foreground); | |
| 180 | + | --color-warning: var(--warning); | |
| 181 | + | --color-warning-foreground: var(--warning-foreground); | |
| 182 | + | --color-info: var(--info); | |
| 183 | + | --color-info-foreground: var(--info-foreground); | |
| 162 | 184 | --color-border: var(--border); | |
| 163 | 185 | --color-input: var(--input); | |
| 164 | 186 | --color-ring: var(--ring); | |
| @@ -54,7 +54,15 @@ | |||||
| 54 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | 54 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | ||
| 55 | --border: oklch(0.88 0.008 260); | 55 | --border: oklch(0.88 0.008 260); | ||
| 56 | --input: oklch(0.88 0.008 260); | 56 | --input: oklch(0.88 0.008 260); | ||
| 57 | - | --ring: oklch(0.55 0.20 145); | 57 | + | --ring: var(--primary); |
| 58 | + | ||||
| 59 | + | /* Semantic colors - for status indicators */ | |||
| 60 | + | --success: oklch(0.65 0.20 145); | |||
| 61 | + | --success-foreground: oklch(0.985 0 0); | |||
| 62 | + | --warning: oklch(0.75 0.18 85); | |||
| 63 | + | --warning-foreground: oklch(0.145 0.02 260); | |||
| 64 | + | --info: oklch(0.65 0.15 230); | |||
| 65 | + | --info-foreground: oklch(0.985 0 0); | |||
| 58 | 66 | ||||
| 59 | /* Chart colors */ | 67 | /* Chart colors */ | ||
| 60 | --chart-1: oklch(0.58 0.18 145); | 68 | --chart-1: oklch(0.58 0.18 145); | ||
| @@ -113,7 +121,15 @@ | |||||
| 113 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | 121 | /* Borders & Inputs - solid colors for WebKitGTK compatibility */ | ||
| 114 | --border: oklch(0.35 0.01 260); | 122 | --border: oklch(0.35 0.01 260); | ||
| 115 | --input: oklch(0.35 0.01 260); | 123 | --input: oklch(0.35 0.01 260); | ||
| 116 | - | --ring: oklch(0.75 0.19 145); | 124 | + | --ring: var(--primary); |
| 125 | + | ||||
| 126 | + | /* Semantic colors - brighter for dark bg */ | |||
| 127 | + | --success: oklch(0.72 0.18 145); | |||
| 128 | + | --success-foreground: oklch(0.12 0.02 145); | |||
| 129 | + | --warning: oklch(0.80 0.16 85); | |||
| 130 | + | --warning-foreground: oklch(0.12 0.02 85); | |||
| 131 | + | --info: oklch(0.70 0.14 230); | |||
| 132 | + | --info-foreground: oklch(0.12 0.02 230); | |||
| 117 | 133 | ||||
| 118 | /* Chart colors - brighter for dark bg */ | 134 | /* Chart colors - brighter for dark bg */ | ||
| 119 | --chart-1: oklch(0.72 0.18 145); | 135 | --chart-1: oklch(0.72 0.18 145); | ||
| @@ -159,6 +175,12 @@ | |||||
| 159 | --color-accent-foreground: var(--accent-foreground); | 175 | --color-accent-foreground: var(--accent-foreground); | ||
| 160 | --color-destructive: var(--destructive); | 176 | --color-destructive: var(--destructive); | ||
| 161 | --color-destructive-foreground: var(--destructive-foreground); | 177 | --color-destructive-foreground: var(--destructive-foreground); | ||
| 178 | + | --color-success: var(--success); | |||
| 179 | + | --color-success-foreground: var(--success-foreground); | |||
| 180 | + | --color-warning: var(--warning); | |||
| 181 | + | --color-warning-foreground: var(--warning-foreground); | |||
| 182 | + | --color-info: var(--info); | |||
| 183 | + | --color-info-foreground: var(--info-foreground); | |||
| 162 | --color-border: var(--border); | 184 | --color-border: var(--border); | ||
| 163 | --color-input: var(--input); | 185 | --color-input: var(--input); | ||
| 164 | --color-ring: var(--ring); | 186 | --color-ring: var(--ring); | ||
M webui/src/styles/design-tokens.css +24 -2
| @@ -58,7 +58,15 @@ | |||
| 58 | 58 | /* Borders & Inputs */ | |
| 59 | 59 | --border: oklch(0.88 0.008 260); | |
| 60 | 60 | --input: oklch(0.88 0.008 260); | |
| 61 | - | --ring: oklch(0.55 0.20 145); | |
| 61 | + | --ring: var(--primary); | |
| 62 | + | ||
| 63 | + | /* Semantic colors - for status indicators */ | |
| 64 | + | --success: oklch(0.65 0.20 145); | |
| 65 | + | --success-foreground: oklch(0.985 0 0); | |
| 66 | + | --warning: oklch(0.75 0.18 85); | |
| 67 | + | --warning-foreground: oklch(0.145 0.02 260); | |
| 68 | + | --info: oklch(0.65 0.15 230); | |
| 69 | + | --info-foreground: oklch(0.985 0 0); | |
| 62 | 70 | ||
| 63 | 71 | /* Chart colors for analytics */ | |
| 64 | 72 | --chart-1: oklch(0.58 0.18 145); /* Green */ | |
| @@ -118,7 +126,15 @@ | |||
| 118 | 126 | /* Borders & Inputs - more visible */ | |
| 119 | 127 | --border: oklch(0.35 0.01 260); | |
| 120 | 128 | --input: oklch(0.35 0.01 260); | |
| 121 | - | --ring: oklch(0.75 0.19 145); | |
| 129 | + | --ring: var(--primary); | |
| 130 | + | ||
| 131 | + | /* Semantic colors - brighter for dark bg */ | |
| 132 | + | --success: oklch(0.72 0.18 145); | |
| 133 | + | --success-foreground: oklch(0.12 0.02 145); | |
| 134 | + | --warning: oklch(0.80 0.16 85); | |
| 135 | + | --warning-foreground: oklch(0.12 0.02 85); | |
| 136 | + | --info: oklch(0.70 0.14 230); | |
| 137 | + | --info-foreground: oklch(0.12 0.02 230); | |
| 122 | 138 | ||
| 123 | 139 | /* Chart colors for analytics - brighter for dark bg */ | |
| 124 | 140 | --chart-1: oklch(0.72 0.18 145); /* Green */ | |
| @@ -159,6 +175,12 @@ | |||
| 159 | 175 | --color-accent-foreground: var(--accent-foreground); | |
| 160 | 176 | --color-destructive: var(--destructive); | |
| 161 | 177 | --color-destructive-foreground: var(--destructive-foreground); | |
| 178 | + | --color-success: var(--success); | |
| 179 | + | --color-success-foreground: var(--success-foreground); | |
| 180 | + | --color-warning: var(--warning); | |
| 181 | + | --color-warning-foreground: var(--warning-foreground); | |
| 182 | + | --color-info: var(--info); | |
| 183 | + | --color-info-foreground: var(--info-foreground); | |
| 162 | 184 | --color-border: var(--border); | |
| 163 | 185 | --color-input: var(--input); | |
| 164 | 186 | --color-ring: var(--ring); | |
| @@ -58,7 +58,15 @@ | |||||
| 58 | /* Borders & Inputs */ | 58 | /* Borders & Inputs */ | ||
| 59 | --border: oklch(0.88 0.008 260); | 59 | --border: oklch(0.88 0.008 260); | ||
| 60 | --input: oklch(0.88 0.008 260); | 60 | --input: oklch(0.88 0.008 260); | ||
| 61 | - | --ring: oklch(0.55 0.20 145); | 61 | + | --ring: var(--primary); |
| 62 | + | ||||
| 63 | + | /* Semantic colors - for status indicators */ | |||
| 64 | + | --success: oklch(0.65 0.20 145); | |||
| 65 | + | --success-foreground: oklch(0.985 0 0); | |||
| 66 | + | --warning: oklch(0.75 0.18 85); | |||
| 67 | + | --warning-foreground: oklch(0.145 0.02 260); | |||
| 68 | + | --info: oklch(0.65 0.15 230); | |||
| 69 | + | --info-foreground: oklch(0.985 0 0); | |||
| 62 | 70 | ||||
| 63 | /* Chart colors for analytics */ | 71 | /* Chart colors for analytics */ | ||
| 64 | --chart-1: oklch(0.58 0.18 145); /* Green */ | 72 | --chart-1: oklch(0.58 0.18 145); /* Green */ | ||
| @@ -118,7 +126,15 @@ | |||||
| 118 | /* Borders & Inputs - more visible */ | 126 | /* Borders & Inputs - more visible */ | ||
| 119 | --border: oklch(0.35 0.01 260); | 127 | --border: oklch(0.35 0.01 260); | ||
| 120 | --input: oklch(0.35 0.01 260); | 128 | --input: oklch(0.35 0.01 260); | ||
| 121 | - | --ring: oklch(0.75 0.19 145); | 129 | + | --ring: var(--primary); |
| 130 | + | ||||
| 131 | + | /* Semantic colors - brighter for dark bg */ | |||
| 132 | + | --success: oklch(0.72 0.18 145); | |||
| 133 | + | --success-foreground: oklch(0.12 0.02 145); | |||
| 134 | + | --warning: oklch(0.80 0.16 85); | |||
| 135 | + | --warning-foreground: oklch(0.12 0.02 85); | |||
| 136 | + | --info: oklch(0.70 0.14 230); | |||
| 137 | + | --info-foreground: oklch(0.12 0.02 230); | |||
| 122 | 138 | ||||
| 123 | /* Chart colors for analytics - brighter for dark bg */ | 139 | /* Chart colors for analytics - brighter for dark bg */ | ||
| 124 | --chart-1: oklch(0.72 0.18 145); /* Green */ | 140 | --chart-1: oklch(0.72 0.18 145); /* Green */ | ||
| @@ -159,6 +175,12 @@ | |||||
| 159 | --color-accent-foreground: var(--accent-foreground); | 175 | --color-accent-foreground: var(--accent-foreground); | ||
| 160 | --color-destructive: var(--destructive); | 176 | --color-destructive: var(--destructive); | ||
| 161 | --color-destructive-foreground: var(--destructive-foreground); | 177 | --color-destructive-foreground: var(--destructive-foreground); | ||
| 178 | + | --color-success: var(--success); | |||
| 179 | + | --color-success-foreground: var(--success-foreground); | |||
| 180 | + | --color-warning: var(--warning); | |||
| 181 | + | --color-warning-foreground: var(--warning-foreground); | |||
| 182 | + | --color-info: var(--info); | |||
| 183 | + | --color-info-foreground: var(--info-foreground); | |||
| 162 | --color-border: var(--border); | 184 | --color-border: var(--border); | ||
| 163 | --color-input: var(--input); | 185 | --color-input: var(--input); | ||
| 164 | --color-ring: var(--ring); | 186 | --color-ring: var(--ring); | ||
M webui/src/styles/tailwind.css +29 -5
| @@ -24,6 +24,14 @@ | |||
| 24 | 24 | --dynamic-secondary: var(--secondary); | |
| 25 | 25 | --dynamic-destructive: var(--destructive); | |
| 26 | 26 | --dynamic-ring: var(--ring); | |
| 27 | + | ||
| 28 | + | /* Semantic status colors - backend can override */ | |
| 29 | + | --dynamic-success: var(--color-browser-success, var(--success)); | |
| 30 | + | --dynamic-success-foreground: var(--success-foreground); | |
| 31 | + | --dynamic-warning: var(--color-browser-warning, var(--warning)); | |
| 32 | + | --dynamic-warning-foreground: var(--warning-foreground); | |
| 33 | + | --dynamic-info: var(--color-browser-info, var(--info)); | |
| 34 | + | --dynamic-info-foreground: var(--info-foreground); | |
| 27 | 35 | } | |
| 28 | 36 | ||
| 29 | 37 | /* Dark mode border override */ | |
| @@ -53,12 +61,28 @@ | |||
| 53 | 61 | border: 1px solid var(--dynamic-border); | |
| 54 | 62 | } | |
| 55 | 63 | ||
| 56 | - | .toast-success, | |
| 57 | - | .toast-error, | |
| 64 | + | .toast-success { | |
| 65 | + | background-color: var(--dynamic-success); | |
| 66 | + | color: var(--dynamic-success-foreground); | |
| 67 | + | border: 1px solid color-mix(in srgb, var(--dynamic-success) 50%, var(--dynamic-border) 50%); | |
| 68 | + | } | |
| 69 | + | ||
| 70 | + | .toast-error { | |
| 71 | + | background-color: var(--dynamic-destructive); | |
| 72 | + | color: var(--destructive-foreground); | |
| 73 | + | border: 1px solid color-mix(in srgb, var(--dynamic-destructive) 50%, var(--dynamic-border) 50%); | |
| 74 | + | } | |
| 75 | + | ||
| 58 | 76 | .toast-info { | |
| 59 | - | background-color: var(--toast-bg, var(--dynamic-surface)); | |
| 60 | - | color: var(--toast-text, var(--dynamic-text)); | |
| 61 | - | border: 1px solid var(--toast-border, var(--dynamic-border)); | |
| 77 | + | background-color: var(--dynamic-info); | |
| 78 | + | color: var(--dynamic-info-foreground); | |
| 79 | + | border: 1px solid color-mix(in srgb, var(--dynamic-info) 50%, var(--dynamic-border) 50%); | |
| 80 | + | } | |
| 81 | + | ||
| 82 | + | .toast-warning { | |
| 83 | + | background-color: var(--dynamic-warning); | |
| 84 | + | color: var(--dynamic-warning-foreground); | |
| 85 | + | border: 1px solid color-mix(in srgb, var(--dynamic-warning) 50%, var(--dynamic-border) 50%); | |
| 62 | 86 | } | |
| 63 | 87 | ||
| 64 | 88 | /* Omnibox/Find bar styles */ | |
| @@ -24,6 +24,14 @@ | |||||
| 24 | --dynamic-secondary: var(--secondary); | 24 | --dynamic-secondary: var(--secondary); | ||
| 25 | --dynamic-destructive: var(--destructive); | 25 | --dynamic-destructive: var(--destructive); | ||
| 26 | --dynamic-ring: var(--ring); | 26 | --dynamic-ring: var(--ring); | ||
| 27 | + | ||||
| 28 | + | /* Semantic status colors - backend can override */ | |||
| 29 | + | --dynamic-success: var(--color-browser-success, var(--success)); | |||
| 30 | + | --dynamic-success-foreground: var(--success-foreground); | |||
| 31 | + | --dynamic-warning: var(--color-browser-warning, var(--warning)); | |||
| 32 | + | --dynamic-warning-foreground: var(--warning-foreground); | |||
| 33 | + | --dynamic-info: var(--color-browser-info, var(--info)); | |||
| 34 | + | --dynamic-info-foreground: var(--info-foreground); | |||
| 27 | } | 35 | } | ||
| 28 | 36 | ||||
| 29 | /* Dark mode border override */ | 37 | /* Dark mode border override */ | ||
| @@ -53,12 +61,28 @@ | |||||
| 53 | border: 1px solid var(--dynamic-border); | 61 | border: 1px solid var(--dynamic-border); | ||
| 54 | } | 62 | } | ||
| 55 | 63 | ||||
| 56 | - | .toast-success, | 64 | + | .toast-success { |
| 57 | - | .toast-error, | 65 | + | background-color: var(--dynamic-success); |
| 66 | + | color: var(--dynamic-success-foreground); | |||
| 67 | + | border: 1px solid color-mix(in srgb, var(--dynamic-success) 50%, var(--dynamic-border) 50%); | |||
| 68 | + | } | |||
| 69 | + | ||||
| 70 | + | .toast-error { | |||
| 71 | + | background-color: var(--dynamic-destructive); | |||
| 72 | + | color: var(--destructive-foreground); | |||
| 73 | + | border: 1px solid color-mix(in srgb, var(--dynamic-destructive) 50%, var(--dynamic-border) 50%); | |||
| 74 | + | } | |||
| 75 | + | ||||
| 58 | .toast-info { | 76 | .toast-info { | ||
| 59 | - | background-color: var(--toast-bg, var(--dynamic-surface)); | 77 | + | background-color: var(--dynamic-info); |
| 60 | - | color: var(--toast-text, var(--dynamic-text)); | 78 | + | color: var(--dynamic-info-foreground); |
| 61 | - | border: 1px solid var(--toast-border, var(--dynamic-border)); | 79 | + | border: 1px solid color-mix(in srgb, var(--dynamic-info) 50%, var(--dynamic-border) 50%); |
| 80 | + | } | |||
| 81 | + | ||||
| 82 | + | .toast-warning { | |||
| 83 | + | background-color: var(--dynamic-warning); | |||
| 84 | + | color: var(--dynamic-warning-foreground); | |||
| 85 | + | border: 1px solid color-mix(in srgb, var(--dynamic-warning) 50%, var(--dynamic-border) 50%); | |||
| 62 | } | 86 | } | ||
| 63 | 87 | ||||
| 64 | /* Omnibox/Find bar styles */ | 88 | /* Omnibox/Find bar styles */ | ||