fix: address PR review feedback

- Use unique ID prefix for clipPath to avoid duplicate ID issues
- Add cleanup function to initializeTheme to prevent memory leak
- Change tooltip to show action description instead of current theme name
This commit is contained in:
XYenon
2025-12-24 00:18:44 +08:00
parent 5f7df33469
commit 961cc802b2
3 changed files with 22 additions and 14 deletions

View File

@@ -31,10 +31,11 @@ function App() {
const [authReady, setAuthReady] = useState(false);
useEffect(() => {
initializeTheme();
const cleanupTheme = initializeTheme();
void restoreSession().finally(() => {
setAuthReady(true);
});
return cleanupTheme;
}, [initializeTheme, restoreSession]);
useEffect(() => {

View File

@@ -119,12 +119,12 @@ const headerIcons = {
autoTheme: (
<svg {...headerIconProps}>
<defs>
<clipPath id="sunLeftHalf">
<clipPath id="mainLayoutAutoThemeSunLeftHalf">
<rect x="0" y="0" width="12" height="24" />
</clipPath>
</defs>
<circle cx="12" cy="12" r="4" />
<circle cx="12" cy="12" r="4" clipPath="url(#sunLeftHalf)" fill="currentColor" />
<circle cx="12" cy="12" r="4" clipPath="url(#mainLayoutAutoThemeSunLeftHalf)" fill="currentColor" />
<path d="M12 2v2" />
<path d="M12 20v2" />
<path d="M4.93 4.93l1.41 1.41" />
@@ -469,7 +469,7 @@ export function MainLayout() {
<Button variant="ghost" size="sm" onClick={toggleLanguage} title={t('language.switch')}>
{headerIcons.language}
</Button>
<Button variant="ghost" size="sm" onClick={cycleTheme} title={t(`theme.${theme}`)}>
<Button variant="ghost" size="sm" onClick={cycleTheme} title={t('theme.switch')}>
{theme === 'auto'
? headerIcons.autoTheme
: theme === 'dark'

View File

@@ -15,7 +15,7 @@ interface ThemeState {
resolvedTheme: ResolvedTheme;
setTheme: (theme: Theme) => void;
cycleTheme: () => void;
initializeTheme: () => void;
initializeTheme: () => () => void;
}
const getSystemTheme = (): ResolvedTheme => {
@@ -60,16 +60,23 @@ export const useThemeStore = create<ThemeState>()(
setTheme(theme);
// 监听系统主题变化(仅在 auto 模式下生效)
if (window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
const { theme: currentTheme } = get();
if (currentTheme === 'auto') {
const resolved = getSystemTheme();
applyTheme(resolved);
set({ resolvedTheme: resolved });
}
});
if (!window.matchMedia) {
return () => {};
}
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const listener = () => {
const { theme: currentTheme } = get();
if (currentTheme === 'auto') {
const resolved = getSystemTheme();
applyTheme(resolved);
set({ resolvedTheme: resolved });
}
};
mediaQuery.addEventListener('change', listener);
return () => mediaQuery.removeEventListener('change', listener);
},
}),
{