feat(KB-024): add comprehensive theme system to dashboard

- Add ThemePreference type and useTheme hook for theme state management
- Create CSS theme architecture with 8 built-in color themes
- Build ThemeSelector component with live preview and keyboard navigation
- Add theme toggle to Header with quick-switch capability
- Integrate Appearance section into SettingsModal
- Wire theme system into App component with system preference detection
- Add comprehensive tests for useTheme, ThemeSelector, and Header
- Include theming documentation in dashboard README
- Add changeset for patch release
This commit is contained in:
gsxdsm
2026-03-29 20:22:00 -07:00
parent 6c59560a0a
commit 6bfdb6bcde
16 changed files with 1602 additions and 10 deletions

View File

@@ -3252,4 +3252,553 @@ body {
font-style: italic;
}
/* ============================================================
THEME SYSTEM
============================================================ */
/* Smooth transitions for theme changes */
html,
html *,
html *::before,
html *::after {
transition: background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}
/* Disable transitions on specific elements that shouldn't animate */
html .card.dragging,
html .card.dragging *,
html .list-row.dragging,
html .list-row.dragging *,
html .column.drag-over,
html .column.drag-over * {
transition: none !important;
}
/* ============================================================
LIGHT THEME (data-theme="light")
============================================================ */
[data-theme="light"] {
/* Backgrounds */
--bg: #ffffff;
--surface: #f6f8fa;
--card: #ffffff;
--card-hover: #f3f4f6;
--border: #d0d7de;
/* Text */
--text: #1f2328;
--text-muted: #656d76;
--text-dim: #8c959f;
/* Status colors (adjusted for light backgrounds) */
--triage: #9a6700;
--todo: #0969da;
--in-progress: #8250df;
--in-review: #1a7f37;
--done: #6e7781;
/* Feedback colors */
--color-success: #1a7f37;
--color-error: #cf222e;
--color-muted: #6e7781;
/* Shadow for light mode */
--shadow: 0 4px 24px rgba(31, 35, 40, 0.15);
}
/* Light theme specific overrides */
[data-theme="light"] .modal-overlay {
background: rgba(31, 35, 40, 0.5);
}
[data-theme="light"] .modal-header {
background: rgba(246, 248, 250, 0.8);
}
[data-theme="light"] .modal-actions {
background: rgba(246, 248, 250, 0.6);
}
[data-theme="light"] .settings-sidebar {
background: rgba(246, 248, 250, 0.6);
}
[data-theme="light"] .toast-success {
background: #1a7f37;
}
[data-theme="light"] .toast-error {
background: #cf222e;
}
[data-theme="light"] .toast-info {
background: #0969da;
}
[data-theme="light"] .btn-primary {
background: #1a7f37;
border-color: #1f883d;
}
[data-theme="light"] .btn-primary:hover {
background: #1f883d;
box-shadow: 0 0 8px rgba(26, 127, 55, 0.3);
}
[data-theme="light"] .btn-danger {
background: #cf222e;
border-color: #a40e26;
}
[data-theme="light"] .btn-danger:hover {
background: #a40e26;
box-shadow: 0 0 8px rgba(207, 34, 46, 0.3);
}
[data-theme="light"] .btn-warning {
background: #9a6700;
border-color: #7d5400;
}
[data-theme="light"] .btn-warning:hover {
background: #7d5400;
box-shadow: 0 0 8px rgba(154, 103, 0, 0.3);
}
[data-theme="light"] .card.agent-active {
box-shadow:
0 0 8px rgba(130, 80, 223, 0.3),
0 0 20px rgba(130, 80, 223, 0.1);
}
@keyframes agent-glow-light {
0%,
100% {
box-shadow:
0 0 8px rgba(130, 80, 223, 0.3),
0 0 20px rgba(130, 80, 223, 0.1);
}
50% {
box-shadow:
0 0 12px rgba(130, 80, 223, 0.5),
0 0 28px rgba(130, 80, 223, 0.2);
}
}
[data-theme="light"] .card.agent-active {
animation: agent-glow-light 2.5s ease-in-out infinite;
}
/* ============================================================
COLOR THEMES (data-color-theme="...")
============================================================ */
/* OCEAN - Deep blues and cyans */
[data-color-theme="ocean"] {
--todo: #00b8d4;
--in-progress: #00e5ff;
--in-review: #00c853;
--triage: #ffab00;
--done: #607d8b;
--color-success: #00c853;
--color-error: #ff5252;
}
[data-color-theme="ocean"][data-theme="light"] {
--todo: #0097a7;
--in-progress: #00bcd4;
--in-review: #4caf50;
--triage: #f57c00;
--done: #546e7a;
--color-success: #4caf50;
--color-error: #f44336;
}
/* FOREST - Deep greens and emeralds */
[data-color-theme="forest"] {
--todo: #34d399;
--in-progress: #10b981;
--in-review: #22c55e;
--triage: #fbbf24;
--done: #6b7280;
--color-success: #22c55e;
--color-error: #ef4444;
}
[data-color-theme="forest"][data-theme="light"] {
--todo: #059669;
--in-progress: #047857;
--in-review: #16a34a;
--triage: #d97706;
--done: #4b5563;
--color-success: #16a34a;
--color-error: #dc2626;
}
/* SUNSET - Warm oranges and reds */
[data-color-theme="sunset"] {
--todo: #ffab00;
--in-progress: #ff6d00;
--in-review: #ff9100;
--triage: #ff3d00;
--done: #8d6e63;
--color-success: #ff9100;
--color-error: #ff1744;
}
[data-color-theme="sunset"][data-theme="light"] {
--todo: #e65100;
--in-progress: #ef6c00;
--in-review: #f57c00;
--triage: #d84315;
--done: #5d4037;
--color-success: #f57c00;
--color-error: #c62828;
}
/* BERRY - Purple/pink tones */
[data-color-theme="berry"] {
--todo: #e040fb;
--in-progress: #ea80fc;
--in-review: #b388ff;
--triage: #ff4081;
--done: #9575cd;
--color-success: #b388ff;
--color-error: #ff5252;
}
[data-color-theme="berry"][data-theme="light"] {
--todo: #7b1fa2;
--in-progress: #8e24aa;
--in-review: #9c27b0;
--triage: #c2185b;
--done: #673ab7;
--color-success: #9c27b0;
--color-error: #d32f2f;
}
/* MONOCHROME - Pure grays */
[data-color-theme="monochrome"] {
--todo: #9e9e9e;
--in-progress: #bdbdbd;
--in-review: #e0e0e0;
--triage: #757575;
--done: #616161;
--color-success: #e0e0e0;
--color-error: #ff5252;
}
[data-color-theme="monochrome"][data-theme="light"] {
--todo: #616161;
--in-progress: #757575;
--in-review: #9e9e9e;
--triage: #424242;
--done: #424242;
--color-success: #616161;
--color-error: #d32f2f;
}
/* HIGH CONTRAST - Extreme contrast for accessibility */
[data-color-theme="high-contrast"] {
--bg: #000000;
--surface: #0a0a0a;
--card: #141414;
--card-hover: #1f1f1f;
--border: #ffffff;
--text: #ffffff;
--text-muted: #cccccc;
--text-dim: #999999;
--todo: #00ffff;
--in-progress: #ff00ff;
--in-review: #00ff00;
--triage: #ffff00;
--done: #ffffff;
--color-success: #00ff00;
--color-error: #ff0000;
}
[data-color-theme="high-contrast"][data-theme="light"] {
--bg: #ffffff;
--surface: #ffffff;
--card: #ffffff;
--card-hover: #f0f0f0;
--border: #000000;
--text: #000000;
--text-muted: #333333;
--text-dim: #666666;
--todo: #0066ff;
--in-progress: #cc00cc;
--in-review: #009900;
--triage: #cc6600;
--done: #000000;
--color-success: #009900;
--color-error: #cc0000;
}
/* SOLARIZED - Classic solarized palette */
[data-color-theme="solarized"] {
--bg: #002b36;
--surface: #073642;
--card: #083c4a;
--card-hover: #094c5e;
--border: #586e75;
--text: #839496;
--text-muted: #657b83;
--text-dim: #586e75;
--todo: #268bd2;
--in-progress: #2aa198;
--in-review: #859900;
--triage: #b58900;
--done: #93a1a1;
--color-success: #859900;
--color-error: #dc322f;
}
[data-color-theme="solarized"][data-theme="light"] {
--bg: #fdf6e3;
--surface: #eee8d5;
--card: #f5efdc;
--card-hover: #e8e2d0;
--border: #93a1a1;
--text: #586e75;
--text-muted: #657b83;
--text-dim: #839496;
--todo: #268bd2;
--in-progress: #2aa198;
--in-review: #859900;
--triage: #b58900;
--done: #93a1a1;
--color-success: #859900;
--color-error: #dc322f;
}
/* ============================================================
THEME SELECTOR COMPONENT STYLES
============================================================ */
.theme-selector {
padding: 0 20px 20px;
}
.theme-mode-toggle {
display: flex;
align-items: center;
gap: 8px;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 4px;
margin-bottom: 20px;
}
.theme-mode-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 8px 16px;
background: none;
border: none;
border-radius: 4px;
color: var(--text-muted);
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all var(--transition-fast);
flex: 1;
}
.theme-mode-btn:hover {
color: var(--text);
background: var(--card-hover);
}
.theme-mode-btn.active {
background: var(--todo);
color: var(--bg);
}
.theme-mode-btn.active:hover {
background: var(--todo);
color: var(--bg);
}
.theme-section-title {
font-size: 12px;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 12px;
}
.theme-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
@media (max-width: 768px) {
.theme-grid {
grid-template-columns: repeat(2, 1fr);
}
}
.theme-option {
display: flex;
flex-direction: column;
align-items: center;
gap: 8px;
padding: 12px;
background: var(--card);
border: 2px solid var(--border);
border-radius: var(--radius);
cursor: pointer;
transition: all var(--transition-fast);
}
.theme-option:hover {
border-color: var(--todo);
background: var(--card-hover);
}
.theme-option.active {
border-color: var(--todo);
background: rgba(88, 166, 255, 0.1);
}
.theme-option-swatch {
width: 48px;
height: 48px;
border-radius: var(--radius);
border: 2px solid var(--border);
position: relative;
overflow: hidden;
}
.theme-option-swatch::after {
content: "";
position: absolute;
inset: 0;
background: linear-gradient(135deg, var(--bg) 50%, var(--surface) 50%);
}
.theme-option-label {
font-size: 12px;
font-weight: 500;
color: var(--text);
text-align: center;
}
/* Theme preview swatch colors */
.theme-swatch-default {
--bg: #0d1117;
--surface: #161b22;
}
.theme-swatch-ocean {
--bg: #0a1929;
--surface: #132f4c;
}
.theme-swatch-forest {
--bg: #0d2818;
--surface: #1a472a;
}
.theme-swatch-sunset {
--bg: #2d1f1f;
--surface: #4a2c2c;
}
.theme-swatch-berry {
--bg: #1a0b2e;
--surface: #2d1b4e;
}
.theme-swatch-monochrome {
--bg: #0d0d0d;
--surface: #1a1a1a;
}
.theme-swatch-high-contrast {
--bg: #000000;
--surface: #0a0a0a;
}
.theme-swatch-solarized {
--bg: #002b36;
--surface: #073642;
}
/* Reset to defaults button */
.theme-reset-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
margin-top: 20px;
padding: 10px 16px;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
color: var(--text-muted);
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all var(--transition-fast);
width: 100%;
}
.theme-reset-btn:hover {
background: var(--card-hover);
color: var(--text);
border-color: var(--text-muted);
}
/* Theme current preview in settings */
.theme-current-preview {
display: flex;
align-items: center;
gap: 12px;
padding: 12px 16px;
background: var(--card);
border: 1px solid var(--border);
border-radius: var(--radius);
margin-bottom: 20px;
}
.theme-preview-icon {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
background: var(--surface);
border-radius: var(--radius);
color: var(--todo);
}
.theme-preview-info {
flex: 1;
}
.theme-preview-label {
font-size: 12px;
color: var(--text-muted);
margin-bottom: 2px;
}
.theme-preview-value {
font-size: 14px;
font-weight: 600;
color: var(--text);
text-transform: capitalize;
}