47 lines
2.0 KiB
TypeScript
47 lines
2.0 KiB
TypeScript
'use client';
|
||
|
||
import { useTheme } from './ThemeProvider';
|
||
import { useEffect, useState } from 'react';
|
||
|
||
export function ThemeToggle() {
|
||
const { theme, toggleTheme } = useTheme();
|
||
const [mounted, setMounted] = useState(false);
|
||
|
||
// Avoid hydration mismatch by only rendering icon after mount
|
||
useEffect(() => {
|
||
setMounted(true);
|
||
}, []);
|
||
|
||
if (!mounted) {
|
||
return <button className="theme-toggle" style={{ visibility: 'hidden' }}>☀️</button>;
|
||
}
|
||
|
||
return (
|
||
<button
|
||
onClick={toggleTheme}
|
||
className={`theme-toggle ${theme === 'light' ? 'is-light' : 'is-dark'}`}
|
||
title={theme === 'light' ? '切换到深色模式' : '切换到亮色模式'}
|
||
aria-label="Toggle theme"
|
||
>
|
||
<div className="theme-toggle-icon-wrapper">
|
||
{/* Sun Icon */}
|
||
<svg className="theme-toggle-sun" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||
<circle cx="12" cy="12" r="4"></circle>
|
||
<path d="M12 2v2"></path>
|
||
<path d="M12 20v2"></path>
|
||
<path d="M4.93 4.93l1.41 1.41"></path>
|
||
<path d="M17.66 17.66l1.41 1.41"></path>
|
||
<path d="M2 12h2"></path>
|
||
<path d="M20 12h2"></path>
|
||
<path d="M4.93 19.07l1.41-1.41"></path>
|
||
<path d="M17.66 6.34l1.41-1.41"></path>
|
||
</svg>
|
||
{/* Moon Icon */}
|
||
<svg className="theme-toggle-moon" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||
<path d="M12 3a6 6 0 0 0 9 9 9 9 0 1 1-9-9Z"></path>
|
||
</svg>
|
||
</div>
|
||
</button>
|
||
);
|
||
}
|