样式修改
This commit is contained in:
1 parent
284445e0c9
commit
ab6b6876aa
4 files changed
+84
-47
No files matched your search
@@ -1,4 +1,10 @@
|
||||
import React, { createContext, useContext, useState, useEffect, ReactNode } from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useState,
|
||||
type ReactNode,
|
||||
} from 'react';
|
||||
import { useTheme as useNextTheme } from 'next-themes';
|
||||
|
||||
// 主题类型
|
||||
@@ -76,12 +82,24 @@ const themes: Record<ThemeType, ThemeConfig> = {
|
||||
},
|
||||
};
|
||||
|
||||
const STORAGE_KEY = 'strategy-theme';
|
||||
|
||||
function readPersistedTheme(): ThemeType {
|
||||
if (typeof window === 'undefined') {
|
||||
return 'dark';
|
||||
}
|
||||
const saved = localStorage.getItem(STORAGE_KEY);
|
||||
return saved === 'light' ? 'light' : 'dark';
|
||||
}
|
||||
|
||||
// 主题上下文
|
||||
interface ThemeContextType {
|
||||
theme: ThemeType;
|
||||
themeConfig: ThemeConfig;
|
||||
toggleTheme: () => void;
|
||||
setTheme: (theme: ThemeType) => void;
|
||||
/** next-themes 完成挂载前为 false,避免 hydration 与 DOM 不同步 */
|
||||
mounted: boolean;
|
||||
}
|
||||
|
||||
const ThemeContext = createContext<ThemeContextType | undefined>(undefined);
|
||||
@@ -92,35 +110,52 @@ interface ThemeProviderProps {
|
||||
}
|
||||
|
||||
export const ThemeProvider: React.FC<ThemeProviderProps> = ({ children }) => {
|
||||
const { setTheme: setNextTheme } = useNextTheme();
|
||||
const [theme, setThemeState] = useState<ThemeType>(() => {
|
||||
// 从 localStorage 读取保存的主题
|
||||
const saved = localStorage.getItem('strategy-theme');
|
||||
return (saved as ThemeType) || 'dark';
|
||||
});
|
||||
const { resolvedTheme, setTheme: setNextTheme } = useNextTheme();
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
// 切换主题
|
||||
const toggleTheme = () => {
|
||||
setThemeState((prev) => (prev === 'dark' ? 'light' : 'dark'));
|
||||
};
|
||||
|
||||
// 设置特定主题
|
||||
const setTheme = (newTheme: ThemeType) => {
|
||||
setThemeState(newTheme);
|
||||
};
|
||||
|
||||
// 保存到 localStorage,并同步 html class 与 next-themes
|
||||
useEffect(() => {
|
||||
localStorage.setItem('strategy-theme', theme);
|
||||
document.documentElement.classList.remove('dark', 'light');
|
||||
document.documentElement.classList.add(theme);
|
||||
setNextTheme(theme);
|
||||
}, [theme, setNextTheme]);
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
// 迁移 / 规范化 localStorage,避免与 next-themes 冲突导致闪回浅色
|
||||
useEffect(() => {
|
||||
if (!mounted) return;
|
||||
const current = localStorage.getItem(STORAGE_KEY);
|
||||
const legacy = localStorage.getItem('theme');
|
||||
|
||||
if (current !== 'light' && current !== 'dark') {
|
||||
const fallback =
|
||||
legacy === 'light' || legacy === 'dark' ? legacy : 'dark';
|
||||
setNextTheme(fallback);
|
||||
} else if (!current && legacy && (legacy === 'light' || legacy === 'dark')) {
|
||||
setNextTheme(legacy);
|
||||
}
|
||||
|
||||
if (legacy) {
|
||||
localStorage.removeItem('theme');
|
||||
}
|
||||
}, [mounted, setNextTheme]);
|
||||
|
||||
const theme: ThemeType = mounted
|
||||
? resolvedTheme === 'light'
|
||||
? 'light'
|
||||
: 'dark'
|
||||
: readPersistedTheme();
|
||||
|
||||
const toggleTheme = () => {
|
||||
setNextTheme(theme === 'dark' ? 'light' : 'dark');
|
||||
};
|
||||
|
||||
const setTheme = (newTheme: ThemeType) => {
|
||||
setNextTheme(newTheme);
|
||||
};
|
||||
|
||||
const themeConfig = themes[theme];
|
||||
|
||||
return (
|
||||
<ThemeContext.Provider value={{ theme, themeConfig, toggleTheme, setTheme }}>
|
||||
<ThemeContext.Provider
|
||||
value={{ theme, themeConfig, toggleTheme, setTheme, mounted }}
|
||||
>
|
||||
{children}
|
||||
</ThemeContext.Provider>
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user