mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-24 05:41:40 +00:00
feat: dashboard theme system with live switching
Add a theme engine for the web dashboard that mirrors the CLI skin engine philosophy — pure data, no code changes needed for new themes. Frontend: - ThemeProvider context that loads active theme from backend on mount and applies CSS variable overrides to document.documentElement - ThemeSwitcher dropdown component in the header (next to language switcher) with instant preview on click - 6 built-in themes: Hermes Teal (default), Midnight, Ember, Mono, Cyberpunk, Rosé — each defines all 21 color tokens + overlay settings - Theme types, presets, and context in web/src/themes/ Backend: - GET /api/dashboard/themes — returns available themes + active name - PUT /api/dashboard/theme — persists selection to config.yaml - User custom themes discoverable from ~/.hermes/dashboard-themes/*.yaml - Theme list endpoint added to public API paths (no auth needed) Config: - dashboard.theme key in DEFAULT_CONFIG (default: 'default') - Schema override for select dropdown in config page - Category merged into 'display' tab in config UI i18n: theme switcher strings added for en + zh.
This commit is contained in:
parent
9a9b8cd1e4
commit
3f6c4346ac
13 changed files with 681 additions and 1 deletions
229
web/src/themes/presets.ts
Normal file
229
web/src/themes/presets.ts
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
import type { DashboardTheme } from "./types";
|
||||
|
||||
/**
|
||||
* Built-in dashboard themes.
|
||||
*
|
||||
* The "default" theme matches the current index.css @theme values exactly,
|
||||
* so applying it is a no-op (CSS vars stay at their stylesheet defaults).
|
||||
* Other themes override only what they change.
|
||||
*/
|
||||
|
||||
export const defaultTheme: DashboardTheme = {
|
||||
name: "default",
|
||||
label: "Hermes Teal",
|
||||
description: "Classic dark teal — the canonical Hermes look",
|
||||
colors: {
|
||||
background: "#041C1C",
|
||||
foreground: "#ffe6cb",
|
||||
card: "#062424",
|
||||
"card-foreground": "#ffe6cb",
|
||||
primary: "#ffe6cb",
|
||||
"primary-foreground": "#041C1C",
|
||||
secondary: "#0a2e2e",
|
||||
"secondary-foreground": "#ffe6cb",
|
||||
muted: "#083030",
|
||||
"muted-foreground": "#8aaa9a",
|
||||
accent: "#0c3838",
|
||||
"accent-foreground": "#ffe6cb",
|
||||
destructive: "#fb2c36",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#4ade80",
|
||||
warning: "#ffbd38",
|
||||
border: "color-mix(in srgb, #ffe6cb 15%, transparent)",
|
||||
input: "color-mix(in srgb, #ffe6cb 15%, transparent)",
|
||||
ring: "#ffe6cb",
|
||||
popover: "#062424",
|
||||
"popover-foreground": "#ffe6cb",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.10,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.22,
|
||||
warmGlowColor: "rgba(255,189,56,0.35)",
|
||||
},
|
||||
};
|
||||
|
||||
export const midnightTheme: DashboardTheme = {
|
||||
name: "midnight",
|
||||
label: "Midnight",
|
||||
description: "Deep blue-violet with cool accents",
|
||||
colors: {
|
||||
background: "#0a0a1a",
|
||||
foreground: "#e0e0f0",
|
||||
card: "#10102a",
|
||||
"card-foreground": "#e0e0f0",
|
||||
primary: "#a78bfa",
|
||||
"primary-foreground": "#0a0a1a",
|
||||
secondary: "#151530",
|
||||
"secondary-foreground": "#e0e0f0",
|
||||
muted: "#1a1a3a",
|
||||
"muted-foreground": "#8888bb",
|
||||
accent: "#1e1e44",
|
||||
"accent-foreground": "#e0e0f0",
|
||||
destructive: "#f43f5e",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#34d399",
|
||||
warning: "#fbbf24",
|
||||
border: "color-mix(in srgb, #a78bfa 15%, transparent)",
|
||||
input: "color-mix(in srgb, #a78bfa 15%, transparent)",
|
||||
ring: "#a78bfa",
|
||||
popover: "#10102a",
|
||||
"popover-foreground": "#e0e0f0",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.08,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.15,
|
||||
warmGlowColor: "rgba(120,80,220,0.3)",
|
||||
},
|
||||
};
|
||||
|
||||
export const emberTheme: DashboardTheme = {
|
||||
name: "ember",
|
||||
label: "Ember",
|
||||
description: "Warm crimson and bronze — forge vibes",
|
||||
colors: {
|
||||
background: "#1a0a0a",
|
||||
foreground: "#fde8d0",
|
||||
card: "#241010",
|
||||
"card-foreground": "#fde8d0",
|
||||
primary: "#f97316",
|
||||
"primary-foreground": "#1a0a0a",
|
||||
secondary: "#2a1515",
|
||||
"secondary-foreground": "#fde8d0",
|
||||
muted: "#301818",
|
||||
"muted-foreground": "#b08878",
|
||||
accent: "#381e1e",
|
||||
"accent-foreground": "#fde8d0",
|
||||
destructive: "#ef4444",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#4ade80",
|
||||
warning: "#fbbf24",
|
||||
border: "color-mix(in srgb, #f97316 15%, transparent)",
|
||||
input: "color-mix(in srgb, #f97316 15%, transparent)",
|
||||
ring: "#f97316",
|
||||
popover: "#241010",
|
||||
"popover-foreground": "#fde8d0",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.10,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.25,
|
||||
warmGlowColor: "rgba(249,115,22,0.3)",
|
||||
},
|
||||
};
|
||||
|
||||
export const monoTheme: DashboardTheme = {
|
||||
name: "mono",
|
||||
label: "Mono",
|
||||
description: "Clean grayscale — minimal and focused",
|
||||
colors: {
|
||||
background: "#111111",
|
||||
foreground: "#e0e0e0",
|
||||
card: "#1a1a1a",
|
||||
"card-foreground": "#e0e0e0",
|
||||
primary: "#e0e0e0",
|
||||
"primary-foreground": "#111111",
|
||||
secondary: "#1e1e1e",
|
||||
"secondary-foreground": "#e0e0e0",
|
||||
muted: "#222222",
|
||||
"muted-foreground": "#888888",
|
||||
accent: "#2a2a2a",
|
||||
"accent-foreground": "#e0e0e0",
|
||||
destructive: "#ef4444",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#4ade80",
|
||||
warning: "#fbbf24",
|
||||
border: "color-mix(in srgb, #e0e0e0 12%, transparent)",
|
||||
input: "color-mix(in srgb, #e0e0e0 12%, transparent)",
|
||||
ring: "#e0e0e0",
|
||||
popover: "#1a1a1a",
|
||||
"popover-foreground": "#e0e0e0",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.06,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.0,
|
||||
warmGlowColor: "rgba(255,255,255,0)",
|
||||
},
|
||||
};
|
||||
|
||||
export const cyberpunkTheme: DashboardTheme = {
|
||||
name: "cyberpunk",
|
||||
label: "Cyberpunk",
|
||||
description: "Neon green on black — matrix terminal",
|
||||
colors: {
|
||||
background: "#050505",
|
||||
foreground: "#00ff88",
|
||||
card: "#0a0a0a",
|
||||
"card-foreground": "#00ff88",
|
||||
primary: "#00ff88",
|
||||
"primary-foreground": "#050505",
|
||||
secondary: "#0e0e0e",
|
||||
"secondary-foreground": "#00ff88",
|
||||
muted: "#121212",
|
||||
"muted-foreground": "#00aa55",
|
||||
accent: "#161616",
|
||||
"accent-foreground": "#00ff88",
|
||||
destructive: "#ff0055",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#00ff88",
|
||||
warning: "#ffff00",
|
||||
border: "color-mix(in srgb, #00ff88 12%, transparent)",
|
||||
input: "color-mix(in srgb, #00ff88 12%, transparent)",
|
||||
ring: "#00ff88",
|
||||
popover: "#0a0a0a",
|
||||
"popover-foreground": "#00ff88",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.12,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.10,
|
||||
warmGlowColor: "rgba(0,255,136,0.15)",
|
||||
},
|
||||
};
|
||||
|
||||
export const roseTheme: DashboardTheme = {
|
||||
name: "rose",
|
||||
label: "Rosé",
|
||||
description: "Soft pink and warm ivory — easy on the eyes",
|
||||
colors: {
|
||||
background: "#1a1015",
|
||||
foreground: "#f5e6e0",
|
||||
card: "#221820",
|
||||
"card-foreground": "#f5e6e0",
|
||||
primary: "#f9a8d4",
|
||||
"primary-foreground": "#1a1015",
|
||||
secondary: "#281e28",
|
||||
"secondary-foreground": "#f5e6e0",
|
||||
muted: "#2e2230",
|
||||
"muted-foreground": "#b08898",
|
||||
accent: "#352838",
|
||||
"accent-foreground": "#f5e6e0",
|
||||
destructive: "#fb2c36",
|
||||
"destructive-foreground": "#fff",
|
||||
success: "#4ade80",
|
||||
warning: "#fbbf24",
|
||||
border: "color-mix(in srgb, #f9a8d4 14%, transparent)",
|
||||
input: "color-mix(in srgb, #f9a8d4 14%, transparent)",
|
||||
ring: "#f9a8d4",
|
||||
popover: "#221820",
|
||||
"popover-foreground": "#f5e6e0",
|
||||
},
|
||||
overlay: {
|
||||
noiseOpacity: 0.08,
|
||||
noiseBlendMode: "color-dodge",
|
||||
warmGlowOpacity: 0.18,
|
||||
warmGlowColor: "rgba(249,168,212,0.2)",
|
||||
},
|
||||
};
|
||||
|
||||
/** All built-in themes, keyed by name. */
|
||||
export const BUILTIN_THEMES: Record<string, DashboardTheme> = {
|
||||
default: defaultTheme,
|
||||
midnight: midnightTheme,
|
||||
ember: emberTheme,
|
||||
mono: monoTheme,
|
||||
cyberpunk: cyberpunkTheme,
|
||||
rose: roseTheme,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue