feat(desktop): 亮/暗主题切换 —— 默认亮色,一处令牌驱动全 app 换肤
把高频硬编码色(ink 表面 / line 边框 / slate 文字)重定义为 CSS 变量(RGB 三元组, 保留 /透明度 修饰符),:root(亮) 与 .dark(暗) 两套值切换——改 tailwind.config + index.css 两处即让全 app 换肤,无需逐文件迁移。 - 亮色走 shadcn 中性灰(zinc:zinc-50 底/白卡/zinc-200 边/zinc-900 字); 暗色精炼为中性 zinc 暗(替代原偏蓝 ink),顺带提质感。 - lib/theme.ts:useTheme + applyInitialTheme(main 启动前设类,避免首屏闪烁)+ localStorage 持久化,默认亮色。 - TopBar 加 Sun/Moon 切换钮;滚动条/输入控件 color-scheme 随主题。 - 修亮色下会失效的 bg-white/5 → bg-ink-800(Tabs/Badge/ExecTrace 的中性微底); 模态遮罩 bg-black/55 两模式皆宜,保留。 验证:tsc + vitest 48 过 + 生产构建通过(var 色全解析)。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
// 主题(亮/暗)管理:持久化到 localStorage,切换在 <html> 上加/去 .dark 类。
|
||||
// 默认亮色(暗色为可选)。初始化在 applyInitialTheme(main 启动时调,先于渲染避免闪烁)。
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
|
||||
export type Theme = "light" | "dark";
|
||||
|
||||
const KEY = "sdx-theme";
|
||||
|
||||
export function getStoredTheme(): Theme {
|
||||
const t = localStorage.getItem(KEY);
|
||||
return t === "dark" ? "dark" : "light"; // 默认亮色
|
||||
}
|
||||
|
||||
function apply(theme: Theme): void {
|
||||
document.documentElement.classList.toggle("dark", theme === "dark");
|
||||
}
|
||||
|
||||
// applyInitialTheme 在渲染前调用,依据存储值设好 .dark 类(避免首屏闪烁)。
|
||||
export function applyInitialTheme(): void {
|
||||
apply(getStoredTheme());
|
||||
}
|
||||
|
||||
// useTheme 暴露当前主题与切换函数(写 localStorage + 切 .dark 类)。
|
||||
export function useTheme(): { theme: Theme; toggle: () => void; setTheme: (t: Theme) => void } {
|
||||
const [theme, setThemeState] = useState<Theme>(getStoredTheme);
|
||||
|
||||
useEffect(() => {
|
||||
apply(theme);
|
||||
localStorage.setItem(KEY, theme);
|
||||
}, [theme]);
|
||||
|
||||
const setTheme = useCallback((t: Theme) => setThemeState(t), []);
|
||||
const toggle = useCallback(() => setThemeState((t) => (t === "dark" ? "light" : "dark")), []);
|
||||
return { theme, toggle, setTheme };
|
||||
}
|
||||
Reference in New Issue
Block a user