Files
TUIkit/docs/app/components/ThemeSwitcher.tsx
T
phranck bdb6d0c3f9 Chore: Fourth-pass optimization — bug fix, auto test counts, ESLint clean, constant extraction
- Fix: parseTerminalFormatting used undefined 'key' instead of 'partKey' (TS error)
- Fix: ESLint setState-in-effect errors (4→0) via cleanup patterns and hydration-sync
- Feat: Auto test/suite counts from Swift project at build-time (prebuild script + env vars)
- Refactor: ArchHighlight sub-component eliminates 4× duplicated pattern in page.tsx
- Refactor: BTN_PRIMARY/BTN_SECONDARY constants replace duplicated button classes
- Refactor: CRT geometry object centralizes repeated calc() layer positions
- Refactor: 13 magic numbers → named constants in TerminalScreen (timings, delays)
- Refactor: Icon component extended with custom SVG support (copy icon)
- Refactor: cloudGradient() helper replaces 6× duplicated radial-gradient strings
- Refactor: HIGHLIGHT constants object for syntax highlighter colors
- Refactor: text-glow CSS utility replaces duplicated textShadow inline styles
2026-02-02 15:38:33 +01:00

61 lines
2.0 KiB
TypeScript

"use client";
import { useTheme, themes, type Theme } from "./ThemeProvider";
/**
* Fixed foreground color per theme — used for the color dots so each dot
* always shows its own theme color regardless of the currently active theme.
* Values mirror the --foreground CSS variables in globals.css.
*/
const themeColors: Record<Theme, string> = {
green: "#33ff33",
amber: "#ffaa00",
red: "#ff4444",
violet: "#bb77ff",
blue: "#00aaff",
white: "#e8e8e8",
};
/** Theme labels for accessibility. */
const themeLabels: Record<Theme, string> = {
green: "Green",
amber: "Amber",
red: "Red",
violet: "Violet",
blue: "Blue",
white: "White",
};
/** Compact theme switcher with colored dots and active indicator. */
export default function ThemeSwitcher() {
const { theme, setTheme } = useTheme();
return (
<div className="flex items-center gap-1.5">
{themes.map((themeOption) => {
const isActive = theme === themeOption;
return (
<button
key={themeOption}
onClick={() => setTheme(themeOption)}
aria-label={`${themeLabels[themeOption]} theme`}
aria-pressed={isActive}
className="group relative flex h-7 w-7 cursor-pointer items-center justify-center rounded-full transition-transform hover:scale-110 focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2 focus-visible:ring-offset-background"
>
<span
className={`block h-3 w-3 rounded-full ${isActive ? "animate-[theme-pulse_3s_ease-in-out_infinite]" : "transition-all"}`}
style={{
backgroundColor: themeColors[themeOption],
boxShadow: isActive
? `0 0 8px ${themeColors[themeOption]}, 0 0 20px ${themeColors[themeOption]}90, 0 0 36px ${themeColors[themeOption]}40`
: "none",
opacity: isActive ? 1 : 0.35,
}}
/>
</button>
);
})}
</div>
);
}