-
Notifications
You must be signed in to change notification settings - Fork 0
2.2 color harmony
The dashboard implements a multi-theme dark-mode system inspired by the visual palettes of contemporary video games—each theme evokes a distinct atmospheric mood while preserving functional readability. Rather than simple light/dark toggles, the system uses CSS custom property overrides to establish semantic color mappings that propagate through Tailwind CSS v4's @theme directive. This architecture decouples color values from component logic, allowing instantaneous theme switching without JavaScript-driven style computation or class list mutation.
Nine themes are available, each named after a video game that informed its color palette:
| Theme ID | Display Name | Primary Accent | Atmosphere |
|---|---|---|---|
souls |
Dark Souls |
#cd853f (warm bronze) |
Gothic decay, ash, and bonfire light |
diablo |
Diablo |
#c0392b (deep crimson) |
Demonic hellfire and blood-red shadows |
gothic |
Gothic |
#4a6741 (moss green) |
Deep forest and obsidian stone |
cyberpunk |
Cyberpunk 2077 |
#1abc9c (neon cyan) |
Synthwave neon and tech-noir |
stellar |
Stellar Blade |
#e84393 (electric magenta) |
Sci-fi futurism and chrome |
ghostwire |
Ghostwire Tokyo |
#1dd1a1 (spirit teal) |
Supernatural ether and urban mysticism |
deathspace |
Dead Space |
#8e44ad (necrotic purple) |
Industrial decay and cosmic horror |
nioh |
Nioh |
#e74c3c (sanguine red) |
Feudal Japan and supernatural corruption |
pragmata |
Pragmata |
#4a6de5 (cobalt steel) |
Lunar station, cold and precise |
Each theme is a self-contained CSS file that overrides variables on :root[data-theme='{id}']:
/* themes/souls.css (excerpt) */
:root[data-theme='souls'] {
--color-accent-primary: #e6a23c;
--color-accent-secondary: #8b6914;
--color-glow: #b8860b;
--color-status-success: #7cb342;
--color-status-warning: #f0a030;
--color-status-error: #e74c3c;
--color-status-info: #5dade2;
--color-tab-rest: #cd853f;
--color-tab-mcp: #c19665;
--color-tab-debug: #d4a574;
--color-tab-preprocessing: #e6a23c;
--color-harmony-1: #f4d03f;
--color-harmony-2: #cd853f;
--color-harmony-3: #5d6d7e;
--color-harmony-4: #5d4e37;
--color-bg-primary: #0d0c0a;
--color-bg-secondary: #1a1814;
--color-bg-tertiary: #252018;
--color-fg-primary: #e8dcc8;
--color-fg-secondary: #c9b99a;
--color-fg-muted: #9a8b75;
--color-divider: #3d3228;
}The colors.css file defines a semantic color system accessible via Tailwind v4's @theme block:
@theme {
/* Fonts */
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
--font-sans: 'Inter', system-ui, sans-serif;
/* Semantic Tokens */
--color-status-success: #00cc7f;
--color-status-warning: #ff9933;
--color-status-error: #ff4466;
--color-status-info: #00cccc;
--color-method-get: #00cc7f;
--color-method-post: #00aadd;
--color-method-put: #ddaa00;
--color-method-delete: #dd4466;
--color-method-patch: #aa44dd;
--color-bg-primary: #0a0a0f;
--color-bg-secondary: #12121a;
--color-bg-tertiary: #1a1a2e;
--color-fg-primary: #e8e8e8;
--color-fg-secondary: #b8b8c8;
--color-fg-muted: #9090a0;
--color-accent-primary: #ff8c00;
--color-accent-secondary: #4a3728;
/* Harmony Colors */
--color-harmony-1: #ffd700;
--color-harmony-2: #9932cc;
--color-harmony-3: #ff8c00;
--color-harmony-4: #5f9ea0;
/* Backward Compatibility */
--color-primary: var(--color-bg-primary);
--color-secondary: var(--color-bg-secondary);
--color-brand: var(--color-accent-primary);
--color-gold: var(--color-harmony-1);
/* Tab Semantic Mapping */
--color-tab-primary: var(--color-harmony-1);
--color-tab-secondary: var(--color-harmony-2);
--color-tab-tertiary: var(--color-harmony-3);
/* Semantic Harmony Roles */
--color-accent-hover: var(--color-harmony-2);
--color-accent-active: var(--color-harmony-1);
--color-accent-border: var(--color-harmony-3);
--color-accent-muted: var(--color-harmony-4);
--color-accent-glow: var(--color-harmony-1);
}The ThemeStore applies themes by setting a data-theme attribute on document.documentElement:
// stores/theme.ts
export const useThemeStore = defineStore('theme', () => {
const currentTheme = ref<ThemeName>('souls');
function applyTheme(theme: ThemeName) {
document.documentElement.setAttribute('data-theme', theme);
}
watch(currentTheme, (newTheme) => {
localStorage.setItem('theme', newTheme);
applyTheme(newTheme);
});
function initTheme() {
const saved = localStorage.getItem('theme') as ThemeName | null;
if (saved && validThemes.includes(saved)) currentTheme.value = saved;
applyTheme(currentTheme.value);
}
return { currentTheme, themeColors, darkThemes, darkThemes2, applyTheme, initTheme };
});Theme state is persisted to localStorage and restored on application mount, ensuring consistency across sessions.
Themes are visually grouped in the AppThemeSwitcher component:
-
darkThemes:
souls,diablo,gothic,cyberpunk,stellar,pragmata -
darkThemes2:
ghostwire,deathspace,nioh
This grouping controls layout spacing in the theme switcher sidebar and allows future extension (e.g., light theme categories) without UI refactoring.
Each theme defines four harmony accent colors (--color-harmony-1 through --color-harmony-4) that serve semantic roles across the interface. These roles abstract away raw color values, enabling theme-agnostic component styling:
| Semantic Role | CSS Variable | Default Mapping | Usage |
|---|---|---|---|
| Primary Accent | --color-harmony-1 |
#ffd700 (gold) |
Active states, primary buttons, highlights |
| Secondary Accent | --color-harmony-2 |
#9932cc (purple) |
Hover states, secondary highlights |
| Border/Divider | --color-harmony-3 |
#ff8c00 (orange) |
Subtle separation elements |
| Muted/Disabled | --color-harmony-4 |
#5f9ea0 (teal) |
Disabled controls, secondary text |
The Cyberpunk theme demonstrates a cool-analogous harmony with complementary accents:
/* themes/cyberpunk.css */
:root[data-theme='cyberpunk'] {
--color-accent-primary: #1abc9c; /* primary: cyan */
--color-accent-secondary: #16a085;
--color-glow: #148f77;
--color-harmony-1: #e84393; /* complementary: magenta */
--color-harmony-2: #f1c40f; /* complementary: gold */
--color-harmony-3: #8e44ad; /* analogous: purple */
--color-harmony-4: #3498db; /* analogous: sky blue */
}Each theme assigns a distinct color to functional tabs, creating visual differentiation without relying solely on iconography:
| Tab | Default Color | Souls Theme | Cyberpunk Theme |
|---|---|---|---|
REST (tab-rest) |
#ff8c00 |
#cd853f (bronze) |
#1abc9c (cyan) |
MCP (tab-mcp) |
#ffd700 |
#c19665 (light bronze) |
#1dd1a1 (teal) |
Debug (tab-debug) |
#00cc7f |
#d4a574 (tan) |
#20e5b5 (aquamarine) |
Preprocessing (tab-preprocessing) |
#ff6347 |
#e6a23c (amber) |
#23f9ca (mint) |
The theme switcher is a fixed-position sidebar rendered on the right edge of the viewport. It uses dynamic gradient backgrounds and text-shadow effects to preview each theme:
<template>
<div class="fixed right-0 top-1/2 -translate-y-1/2 z-50 flex flex-col gap-0.5 pr-0 w-40 pointer-events-none font-mono">
<template v-for="name in darkThemes" :key="name">
<button
class="group relative h-10 w-full flex items-center justify-end pointer-events-auto"
@click="emit('change', name)"
>
<div
class="w-28 h-full flex items-center justify-end pr-2 transition-all duration-300"
:style="{
background: currentTheme === name
? `linear-gradient(to left, ${themeColors[name].primary}88, ${themeColors[name].primary}20 30%, transparent)`
: `linear-gradient(to left, ${themeColors[name].primary}15, transparent 60%)`
}"
>
<span
class="text-[10px] font-bold uppercase tracking-wider transition-all duration-300"
:class="currentTheme === name ? 'text-fg-primary' : 'text-fg-muted/20 group-hover:text-fg-muted/80'"
:style="currentTheme !== name ? { textShadow: `0 0 8px ${themeColors[name].primary}40` } : {}"
>
{{ themeColors[name].name }}
</span>
</div>
</button>
</template>
</div>
</template>The component uses CSS viewport-unit positioning (fixed right-0 top-1/2) to remain accessible without consuming main-content layout space.
Theme colors propagate to the Toastification system via CSS overrides:
:root[data-theme='souls'] {
--toastify-color-dark: #1a1814;
--toastify-color-success: #7cb342;
--toastify-color-warning: #f0a030;
--toastify-color-error: #e74c3c;
--toastify-color-info: #5dade2;
}This ensures toast notifications harmonize with the active theme rather than falling back to generic light/dark defaults.
Status colors are mapped per theme to maintain contrast and cultural consistency:
| Status | Souls Theme | Cyberpunk Theme | Pragmata Theme |
|---|---|---|---|
| Success |
#7cb342 (moss) |
#2ecc71 (neon green) |
#2a9d8f (seafoam) |
| Warning |
#f0a030 (ember) |
#f1c40f (electric yellow) |
#e9c46a (brass) |
| Error |
#e74c3c (blood) |
#e74c3c (alert red) |
#e07a5f (rust) |
| Info |
#5dade2 (frost) |
#3498db (ice blue) |
#a8dadc (moonlight) |
HTTP method badges are color-coded consistently across themes, ensuring API operation visibility:
| Method | Default Hex | Tailwind Class |
|---|---|---|
GET |
#00cc7f |
text-method-get |
POST |
#00aadd |
text-method-post |
PUT |
#ddaa00 |
text-method-put |
DELETE |
#dd4466 |
text-method-delete |
PATCH |
#aa44dd |
text-method-patch |
| System | #888899 |
text-method-system |
All foreground text colors (--color-fg-primary, --color-fg-secondary) are calibrated against their respective background colors to maintain a minimum WCAG 2.1 AA contrast ratio of 4.5:1 for normal text. The theme system is intentionally dark-mode only to reduce eye strain during prolonged debugging sessions and to preserve the atmospheric aesthetic.
- 2. Dashboard Overview — Dashboard functional panels
- 2.1 Frontend Architecture — Component hierarchy and composables
- 2.3 State Management & Real-time Events — ThemeStore integration with persistence