diff --git a/web/src/components/ThemeSwitcher.tsx b/web/src/components/ThemeSwitcher.tsx index 4d50e611ef..462ccaacfc 100644 --- a/web/src/components/ThemeSwitcher.tsx +++ b/web/src/components/ThemeSwitcher.tsx @@ -4,6 +4,7 @@ import { Button } from "@nous-research/ui/ui/components/button"; import { ListItem } from "@nous-research/ui/ui/components/list-item"; import { Typography } from "@/components/NouiTypography"; import { BUILTIN_THEMES, useTheme } from "@/themes"; +import type { DashboardTheme } from "@/themes"; import { useI18n } from "@/i18n"; import { cn } from "@/lib/utils"; @@ -11,8 +12,8 @@ import { cn } from "@/lib/utils"; * Compact theme picker mounted next to the language switcher in the header. * Each dropdown row shows a 3-stop swatch (background / midground / warm * glow) so users can preview the palette before committing. User-defined - * themes from `~/.hermes/dashboard-themes/*.yaml` that aren't in - * `BUILTIN_THEMES` render without swatches and apply the default palette. + * themes from `~/.hermes/dashboard-themes/*.yaml` use their API-provided + * definitions so they show real palette swatches just like built-ins. * * When placed at the bottom of a container (e.g. the sidebar rail), pass * `dropUp` so the menu opens above the trigger instead of clipping below @@ -95,7 +96,7 @@ export function ThemeSwitcher({ dropUp = false }: ThemeSwitcherProps) { {availableThemes.map((th) => { const isActive = th.name === themeName; - const preset = BUILTIN_THEMES[th.name]; + const paletteTheme = BUILTIN_THEMES[th.name] ?? th.definition; return ( - {preset ? ( - + {paletteTheme ? ( + ) : ( )} @@ -144,10 +145,8 @@ export function ThemeSwitcher({ dropUp = false }: ThemeSwitcherProps) { ); } -function ThemeSwatch({ theme }: { theme: string }) { - const preset = BUILTIN_THEMES[theme]; - if (!preset) return ; - const { background, midground, warmGlow } = preset.palette; +function ThemeSwatch({ theme }: { theme: DashboardTheme }) { + const { background, midground, warmGlow } = theme.palette; return (
- >(() => + const [availableThemes, setAvailableThemes] = useState(() => Object.values(BUILTIN_THEMES).map((t) => ({ name: t.name, label: t.label, @@ -360,6 +358,7 @@ export function ThemeProvider({ children }: { children: ReactNode }) { name: t.name, label: t.label, description: t.description, + definition: t.definition, })), ); // Index any definitions the server shipped (user themes). @@ -430,8 +429,15 @@ const ThemeContext = createContext({ }); interface ThemeContextValue { - availableThemes: Array<{ description: string; label: string; name: string }>; + availableThemes: ThemeSummary[]; setTheme: (name: string) => void; theme: DashboardTheme; themeName: string; } + +interface ThemeSummary { + description: string; + label: string; + name: string; + definition?: DashboardTheme; +}