- Reduce themes from 6 to 4: system, light, dark, paper
- Remove midnight (too similar to dark) and whitewall (too similar to light)
- Drop all unused tokens: chart-*, sidebar-primary, sidebar-border,
sidebar-ring, shadow-2xs, tracking-normal, spacing
- Remove redundant @theme inline blocks from dynamic theme files
(Tailwind only processes them at compile time, not at runtime)
- Move shared tokens (fonts, radius) to default.css only
- Polish dark mode color palette
- Consistent cool-slate hue (h265) across all surfaces
- Proper surface layering: sidebar(0.07) → bg(0.09) → card(0.13) →
popover(0.17) → secondary(0.19) → muted(0.21) → accent(0.22)
- Foreground softened to 0.82 (from 0.9) — comfortable off-white
- Accent more chromatic than muted (0.012 vs 0.008) — hover feels interactive
- Popover elevated above card (0.17 vs 0.13) — floating elements visible
- Destructive more vivid (0.62/c0.20) — clearly red on dark surfaces
- Input border (0.25) more distinct than layout border (0.21)
- Sidebar foreground (0.68) dimmer than content foreground (0.82)
- Fix inline code background invisible in dark mode (#5674)
- Muted was same lightness as card — increased to 0.21 for clear contrast
51 lines
1.6 KiB
TypeScript
51 lines
1.6 KiB
TypeScript
import { Monitor, Moon, Palette, Sun } from "lucide-react";
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
|
|
import { loadTheme, THEME_OPTIONS } from "@/utils/theme";
|
|
|
|
interface ThemeSelectProps {
|
|
value?: string;
|
|
onValueChange?: (theme: string) => void;
|
|
className?: string;
|
|
}
|
|
|
|
const THEME_ICONS: Record<string, JSX.Element> = {
|
|
system: <Monitor className="w-4 h-4" />,
|
|
default: <Sun className="w-4 h-4" />,
|
|
"default-dark": <Moon className="w-4 h-4" />,
|
|
paper: <Palette className="w-4 h-4" />,
|
|
};
|
|
|
|
const ThemeSelect = ({ value, onValueChange, className }: ThemeSelectProps = {}) => {
|
|
const currentTheme = value || "system";
|
|
|
|
const handleThemeChange = (newTheme: string) => {
|
|
// Apply theme globally immediately
|
|
loadTheme(newTheme);
|
|
// Also notify parent component if callback is provided
|
|
if (onValueChange) {
|
|
onValueChange(newTheme);
|
|
}
|
|
};
|
|
|
|
return (
|
|
<Select value={currentTheme} onValueChange={handleThemeChange}>
|
|
<SelectTrigger className={className}>
|
|
<div className="flex items-center gap-2">
|
|
<SelectValue placeholder="Select theme" />
|
|
</div>
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{THEME_OPTIONS.map((option) => (
|
|
<SelectItem key={option.value} value={option.value}>
|
|
<div className="flex items-center gap-2">
|
|
{THEME_ICONS[option.value]}
|
|
<span>{option.label}</span>
|
|
</div>
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
);
|
|
};
|
|
|
|
export default ThemeSelect;
|