Files
agent-fox/packages/web/src/components/ThemeToggle.tsx
YANG JIANKUAN 9b41878ae7 refactor: 优化 i18n 类型安全与渲染性能
- 导出 TranslationKey 类型,翻译 key 拼写错误编译期即报错
- zh.ts 使用 TranslationKey 约束,确保中英文 key 同步
- useMemo 包装 context value,避免不必要的全局重渲染
- ConfirmDialog confirmText 默认值改用 t() 而非硬编码英文
- SchemaProperties 递归组件改为 prop 传递 t,减少 useContext 调用

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 13:26:57 +08:00

47 lines
1.6 KiB
TypeScript

import { useTheme } from '../lib/theme';
import { useI18n, type TranslationKey } from '../lib/i18n';
const icons = {
light: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<circle cx="12" cy="12" r="5" /><path d="M12 1v2m0 18v2M4.22 4.22l1.42 1.42m12.72 12.72l1.42 1.42M1 12h2m18 0h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42" />
</svg>
),
dark: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
</svg>
),
system: (
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
<rect x="2" y="3" width="20" height="14" rx="2" /><path d="M8 21h8m-4-4v4" />
</svg>
),
};
const order: Array<'light' | 'dark' | 'system'> = ['light', 'dark', 'system'];
export default function ThemeToggle() {
const { theme, setTheme } = useTheme();
const { t } = useI18n();
return (
<div className="flex items-center gap-1 p-1 rounded-lg bg-bg-tertiary">
{order.map((key) => (
<button
key={key}
onClick={() => setTheme(key)}
title={t(`theme.${key}` as TranslationKey)}
className={`flex items-center justify-center w-8 h-7 rounded-md transition-all duration-150 ${
theme === key
? 'bg-bg-elevated text-text-primary shadow-sm'
: 'text-text-muted hover:text-text-secondary'
}`}
>
{icons[key]}
</button>
))}
</div>
);
}