feat(dark-mode): 实现深色模式支持

- 定义87个CSS变量的深色值([data-theme=dark]选择器)
- 升级ThemeProvider支持light/dark/system三种模式
- 新增ThemeToggle组件(桌面端Header+移动端菜单)
- 添加防FOUC内联脚本(渲染前应用主题)
- Logo根据主题自动切换(logo.svg/logo-white.svg)
- 更新测试用例覆盖主题切换逻辑
This commit is contained in:
张翔
2026-05-10 10:00:14 +08:00
parent 37296b5717
commit 27d486d820
6 changed files with 312 additions and 9 deletions
+9 -1
View File
@@ -7,6 +7,8 @@ import { usePathname } from 'next/navigation';
import { Menu, X } from 'lucide-react';
import { AnimatePresence, motion } from 'framer-motion';
import { Button } from '@/components/ui/button';
import { ThemeToggle } from '@/components/ui/theme-toggle';
import { useTheme } from '@/contexts/theme-context';
import { COMPANY_INFO, NAVIGATION_V2, MEGA_DROPDOWN_DATA, type NavigationItemV2 } from '@/lib/constants';
import { MegaDropdown } from '@/components/layout/mega-dropdown';
import { useFocusTrap } from '@/hooks/use-focus-trap';
@@ -17,6 +19,7 @@ function HeaderContent() {
const [openDropdown, setOpenDropdown] = useState<string | null>(null);
const pathname = usePathname();
const focusTrapRef = useFocusTrap<HTMLDivElement>(isOpen);
const { resolvedTheme } = useTheme();
useEffect(() => {
const handleScroll = () => {
@@ -90,7 +93,7 @@ function HeaderContent() {
aria-label="返回首页"
>
<Image
src="/logo.svg"
src={resolvedTheme === 'dark' ? '/logo-white.svg' : '/logo.svg'}
alt={COMPANY_INFO.name}
width={120}
height={30}
@@ -146,6 +149,7 @@ function HeaderContent() {
</nav>
<div className="hidden md:flex items-center gap-3">
<ThemeToggle />
<Button
size="sm"
asChild
@@ -222,6 +226,10 @@ function HeaderContent() {
</motion.div>
))}
<div className="mt-6 px-4 pt-6 border-t border-[var(--color-border-primary)]">
<div className="flex items-center justify-between mb-4">
<span className="text-sm text-[var(--color-text-muted)]"></span>
<ThemeToggle />
</div>
<Button
className="w-full"
asChild