mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-02 07:23:35 +00:00
feat(ui): add theme switching system with Twitter, Claude, and Neo Brutalism themes
Add a comprehensive theme system allowing users to switch between three distinct visual themes, each supporting both light and dark modes: - Twitter (default): Clean blue design with soft shadows - Claude: Warm beige/cream tones with orange primary accents - Neo Brutalism: Bold colors, hard shadows, 0px border radius New files: - ui/src/hooks/useTheme.ts: Theme state management hook with localStorage persistence for both theme selection and dark mode preference - ui/src/components/ThemeSelector.tsx: Header dropdown with hover preview and color swatches for quick theme switching Modified files: - ui/src/styles/globals.css: Added CSS custom properties for Claude and Neo Brutalism themes with light/dark variants, shadow variables integrated into @theme inline block - ui/src/App.tsx: Integrated useTheme hook and ThemeSelector component - ui/src/components/SettingsModal.tsx: Added theme selection UI with preview swatches and dark mode toggle - ui/index.html: Added DM Sans and Space Mono fonts for Neo Brutalism Features: - Independent theme and dark mode controls - Smooth CSS transitions when switching themes - Theme-specific shadow styles (soft vs hard) - Theme-specific fonts and border radius - Persisted preferences in localStorage Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,8 @@
|
||||
@custom-variant dark (&:where(.dark, .dark *));
|
||||
|
||||
/* ============================================================================
|
||||
ShadCN Theme - Clean Twitter-Style Design
|
||||
Theme: Twitter (Default)
|
||||
Clean, modern blue design
|
||||
============================================================================ */
|
||||
|
||||
:root {
|
||||
@@ -43,6 +44,12 @@
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
|
||||
/* Shadow variables */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
||||
|
||||
/* Log level colors (kept for Terminal/Debug components) */
|
||||
--color-log-error: #ef4444;
|
||||
--color-log-warning: #f59e0b;
|
||||
@@ -99,6 +106,12 @@
|
||||
--sidebar-border: oklch(1 0 0 / 10%);
|
||||
--sidebar-ring: oklch(0.556 0 0);
|
||||
|
||||
/* Shadow variables - dark mode */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.3);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.4), 0 1px 2px -1px rgb(0 0 0 / 0.3);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.4), 0 2px 4px -2px rgb(0 0 0 / 0.3);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.4), 0 4px 6px -4px rgb(0 0 0 / 0.3);
|
||||
|
||||
/* Log level colors for dark mode */
|
||||
--color-log-error: #f87171;
|
||||
--color-log-warning: #fbbf24;
|
||||
@@ -112,7 +125,242 @@
|
||||
--color-status-done: oklch(0.25 0.05 245);
|
||||
}
|
||||
|
||||
/* ShadCN Tailwind v4 Theme Integration */
|
||||
/* ============================================================================
|
||||
Theme: Claude
|
||||
Warm beige/cream tones with orange primary
|
||||
============================================================================ */
|
||||
|
||||
.theme-claude {
|
||||
--radius: 0.5rem;
|
||||
--background: oklch(0.9818 0.0054 95.0986);
|
||||
--foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--card: oklch(0.9650 0.0080 90);
|
||||
--card-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--popover: oklch(0.9818 0.0054 95.0986);
|
||||
--popover-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--primary: oklch(0.6171 0.1375 39.0427);
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.9400 0.0120 85);
|
||||
--secondary-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--muted: oklch(0.9300 0.0100 90);
|
||||
--muted-foreground: oklch(0.5500 0.0200 95);
|
||||
--accent: oklch(0.9200 0.0150 80);
|
||||
--accent-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--destructive: oklch(0.6188 0.2376 25.7658);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
--border: oklch(0.8900 0.0180 85);
|
||||
--input: oklch(0.9500 0.0080 90);
|
||||
--ring: oklch(0.6171 0.1375 39.0427);
|
||||
--chart-1: oklch(0.6171 0.1375 39.0427);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar: oklch(0.9700 0.0070 92);
|
||||
--sidebar-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--sidebar-primary: oklch(0.6171 0.1375 39.0427);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.9200 0.0150 80);
|
||||
--sidebar-accent-foreground: oklch(0.3438 0.0269 95.7226);
|
||||
--sidebar-border: oklch(0.8900 0.0180 85);
|
||||
--sidebar-ring: oklch(0.6171 0.1375 39.0427);
|
||||
|
||||
/* Shadow variables - softer for Claude theme */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(139 115 85 / 0.05);
|
||||
--shadow: 0 1px 3px 0 rgb(139 115 85 / 0.08), 0 1px 2px -1px rgb(139 115 85 / 0.06);
|
||||
--shadow-md: 0 4px 6px -1px rgb(139 115 85 / 0.08), 0 2px 4px -2px rgb(139 115 85 / 0.06);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(139 115 85 / 0.08), 0 4px 6px -4px rgb(139 115 85 / 0.06);
|
||||
|
||||
/* Log level colors */
|
||||
--color-log-error: #dc6b52;
|
||||
--color-log-warning: #d9a74a;
|
||||
--color-log-info: #6b9dc4;
|
||||
--color-log-debug: #8b8578;
|
||||
--color-log-success: #6b9e6b;
|
||||
|
||||
/* Status colors for Kanban */
|
||||
--color-status-pending: oklch(0.9200 0.0300 80);
|
||||
--color-status-progress: oklch(0.8800 0.0500 60);
|
||||
--color-status-done: oklch(0.8800 0.0500 140);
|
||||
|
||||
/* Font stacks - system fonts for Claude theme */
|
||||
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--font-mono: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas, monospace;
|
||||
}
|
||||
|
||||
.theme-claude.dark {
|
||||
--background: oklch(0.2679 0.0036 106.6427);
|
||||
--foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--card: oklch(0.3200 0.0050 100);
|
||||
--card-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--popover: oklch(0.3200 0.0050 100);
|
||||
--popover-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--primary: oklch(0.6800 0.1500 39);
|
||||
--primary-foreground: oklch(0.15 0 0);
|
||||
--secondary: oklch(0.3500 0.0080 100);
|
||||
--secondary-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--muted: oklch(0.3800 0.0060 100);
|
||||
--muted-foreground: oklch(0.6500 0.0120 93);
|
||||
--accent: oklch(0.4000 0.0100 90);
|
||||
--accent-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--destructive: oklch(0.704 0.191 22.216);
|
||||
--destructive-foreground: oklch(0.985 0 0);
|
||||
--border: oklch(0.4200 0.0080 95);
|
||||
--input: oklch(0.3500 0.0050 100);
|
||||
--ring: oklch(0.6800 0.1500 39);
|
||||
--chart-1: oklch(0.6800 0.1500 39);
|
||||
--chart-2: oklch(0.696 0.17 162.48);
|
||||
--chart-3: oklch(0.769 0.188 70.08);
|
||||
--chart-4: oklch(0.627 0.265 303.9);
|
||||
--chart-5: oklch(0.645 0.246 16.439);
|
||||
--sidebar: oklch(0.2900 0.0040 105);
|
||||
--sidebar-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--sidebar-primary: oklch(0.6800 0.1500 39);
|
||||
--sidebar-primary-foreground: oklch(0.15 0 0);
|
||||
--sidebar-accent: oklch(0.3800 0.0080 95);
|
||||
--sidebar-accent-foreground: oklch(0.8074 0.0142 93.0137);
|
||||
--sidebar-border: oklch(0.4000 0.0060 100);
|
||||
--sidebar-ring: oklch(0.6800 0.1500 39);
|
||||
|
||||
/* Shadow variables - dark mode */
|
||||
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.25);
|
||||
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.35), 0 1px 2px -1px rgb(0 0 0 / 0.25);
|
||||
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.35), 0 2px 4px -2px rgb(0 0 0 / 0.25);
|
||||
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.35), 0 4px 6px -4px rgb(0 0 0 / 0.25);
|
||||
|
||||
/* Log level colors for dark mode */
|
||||
--color-log-error: #e8877a;
|
||||
--color-log-warning: #e5be6d;
|
||||
--color-log-info: #8bb5d6;
|
||||
--color-log-debug: #a8a49a;
|
||||
--color-log-success: #8bb58b;
|
||||
|
||||
/* Status colors for Kanban - dark mode */
|
||||
--color-status-pending: oklch(0.3500 0.0300 80);
|
||||
--color-status-progress: oklch(0.4000 0.0500 60);
|
||||
--color-status-done: oklch(0.4000 0.0500 140);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
Theme: Neo Brutalism
|
||||
Bold colors, hard shadows, no border radius
|
||||
============================================================================ */
|
||||
|
||||
.theme-neo-brutalism {
|
||||
--radius: 0px;
|
||||
--background: oklch(1.0000 0 0);
|
||||
--foreground: oklch(0 0 0);
|
||||
--card: oklch(0.9800 0.0150 95);
|
||||
--card-foreground: oklch(0 0 0);
|
||||
--popover: oklch(1.0000 0 0);
|
||||
--popover-foreground: oklch(0 0 0);
|
||||
--primary: oklch(0.6489 0.2370 26.9728);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.9500 0.1500 100);
|
||||
--secondary-foreground: oklch(0 0 0);
|
||||
--muted: oklch(0.9400 0.0100 90);
|
||||
--muted-foreground: oklch(0.4000 0 0);
|
||||
--accent: oklch(0.8800 0.1800 85);
|
||||
--accent-foreground: oklch(0 0 0);
|
||||
--destructive: oklch(0.6500 0.2500 25);
|
||||
--destructive-foreground: oklch(0 0 0);
|
||||
--border: oklch(0 0 0);
|
||||
--input: oklch(1.0000 0 0);
|
||||
--ring: oklch(0.6489 0.2370 26.9728);
|
||||
--chart-1: oklch(0.6489 0.2370 26.9728);
|
||||
--chart-2: oklch(0.8000 0.2000 130);
|
||||
--chart-3: oklch(0.7000 0.2200 280);
|
||||
--chart-4: oklch(0.8800 0.1800 85);
|
||||
--chart-5: oklch(0.6500 0.2500 330);
|
||||
--sidebar: oklch(0.9500 0.1500 100);
|
||||
--sidebar-foreground: oklch(0 0 0);
|
||||
--sidebar-primary: oklch(0.6489 0.2370 26.9728);
|
||||
--sidebar-primary-foreground: oklch(0 0 0);
|
||||
--sidebar-accent: oklch(0.8800 0.1800 85);
|
||||
--sidebar-accent-foreground: oklch(0 0 0);
|
||||
--sidebar-border: oklch(0 0 0);
|
||||
--sidebar-ring: oklch(0.6489 0.2370 26.9728);
|
||||
|
||||
/* Shadow variables - hard shadows */
|
||||
--shadow-sm: 2px 2px 0px rgb(0 0 0);
|
||||
--shadow: 3px 3px 0px rgb(0 0 0);
|
||||
--shadow-md: 4px 4px 0px rgb(0 0 0);
|
||||
--shadow-lg: 6px 6px 0px rgb(0 0 0);
|
||||
|
||||
/* Log level colors */
|
||||
--color-log-error: #ff0000;
|
||||
--color-log-warning: #ffaa00;
|
||||
--color-log-info: #0066ff;
|
||||
--color-log-debug: #666666;
|
||||
--color-log-success: #00cc00;
|
||||
|
||||
/* Status colors for Kanban */
|
||||
--color-status-pending: oklch(0.9500 0.1500 100);
|
||||
--color-status-progress: oklch(0.8200 0.1800 200);
|
||||
--color-status-done: oklch(0.8000 0.2000 130);
|
||||
|
||||
/* Font stacks - DM Sans for Neo Brutalism */
|
||||
--font-sans: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
--font-mono: 'Space Mono', 'JetBrains Mono', monospace;
|
||||
}
|
||||
|
||||
.theme-neo-brutalism.dark {
|
||||
--background: oklch(0.1200 0 0);
|
||||
--foreground: oklch(1.0000 0 0);
|
||||
--card: oklch(0.1800 0.0080 280);
|
||||
--card-foreground: oklch(1.0000 0 0);
|
||||
--popover: oklch(0.1500 0 0);
|
||||
--popover-foreground: oklch(1.0000 0 0);
|
||||
--primary: oklch(0.7200 0.2500 27);
|
||||
--primary-foreground: oklch(0 0 0);
|
||||
--secondary: oklch(0.4500 0.1200 100);
|
||||
--secondary-foreground: oklch(1.0000 0 0);
|
||||
--muted: oklch(0.2500 0.0050 0);
|
||||
--muted-foreground: oklch(0.6500 0 0);
|
||||
--accent: oklch(0.5500 0.1500 85);
|
||||
--accent-foreground: oklch(0 0 0);
|
||||
--destructive: oklch(0.6500 0.2500 25);
|
||||
--destructive-foreground: oklch(0 0 0);
|
||||
--border: oklch(0.7000 0 0);
|
||||
--input: oklch(0.2000 0 0);
|
||||
--ring: oklch(0.7200 0.2500 27);
|
||||
--chart-1: oklch(0.7200 0.2500 27);
|
||||
--chart-2: oklch(0.7500 0.1800 130);
|
||||
--chart-3: oklch(0.6500 0.2000 280);
|
||||
--chart-4: oklch(0.7000 0.1500 85);
|
||||
--chart-5: oklch(0.6000 0.2200 330);
|
||||
--sidebar: oklch(0.1500 0.0050 280);
|
||||
--sidebar-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-primary: oklch(0.7200 0.2500 27);
|
||||
--sidebar-primary-foreground: oklch(0 0 0);
|
||||
--sidebar-accent: oklch(0.4500 0.1200 85);
|
||||
--sidebar-accent-foreground: oklch(1.0000 0 0);
|
||||
--sidebar-border: oklch(0.5000 0 0);
|
||||
--sidebar-ring: oklch(0.7200 0.2500 27);
|
||||
|
||||
/* Shadow variables - hard shadows for dark mode */
|
||||
--shadow-sm: 2px 2px 0px rgb(255 255 255 / 0.3);
|
||||
--shadow: 3px 3px 0px rgb(255 255 255 / 0.3);
|
||||
--shadow-md: 4px 4px 0px rgb(255 255 255 / 0.3);
|
||||
--shadow-lg: 6px 6px 0px rgb(255 255 255 / 0.3);
|
||||
|
||||
/* Log level colors for dark mode */
|
||||
--color-log-error: #ff4444;
|
||||
--color-log-warning: #ffcc00;
|
||||
--color-log-info: #4499ff;
|
||||
--color-log-debug: #999999;
|
||||
--color-log-success: #44dd44;
|
||||
|
||||
/* Status colors for Kanban - dark mode */
|
||||
--color-status-pending: oklch(0.4500 0.1200 100);
|
||||
--color-status-progress: oklch(0.4500 0.1500 200);
|
||||
--color-status-done: oklch(0.4500 0.1500 130);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
ShadCN Tailwind v4 Theme Integration
|
||||
============================================================================ */
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
@@ -155,6 +403,10 @@
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--font-sans: var(--font-sans);
|
||||
--font-mono: var(--font-mono);
|
||||
--shadow-sm: var(--shadow-sm);
|
||||
--shadow: var(--shadow);
|
||||
--shadow-md: var(--shadow-md);
|
||||
--shadow-lg: var(--shadow-lg);
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -182,6 +434,11 @@
|
||||
color: inherit;
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* Smooth theme transitions */
|
||||
:root {
|
||||
transition: background-color 0.2s ease, color 0.2s ease;
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
@@ -496,6 +753,19 @@
|
||||
.font-mono {
|
||||
font-family: var(--font-mono);
|
||||
}
|
||||
|
||||
/* Neo Brutalism specific utilities */
|
||||
.shadow-neo {
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.shadow-neo-sm {
|
||||
box-shadow: var(--shadow-sm);
|
||||
}
|
||||
|
||||
.shadow-neo-lg {
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
}
|
||||
|
||||
/* ============================================================================
|
||||
|
||||
Reference in New Issue
Block a user