diff --git a/packages/admin/src/app.jsx b/packages/admin/src/app.jsx index f2f797318..44cc373a5 100644 --- a/packages/admin/src/app.jsx +++ b/packages/admin/src/app.jsx @@ -4,7 +4,9 @@ import { PageLoading, SettingDrawer } from '@ant-design/pro-layout'; import { history } from 'umi'; import defaultSettings from '../config/defaultSettings'; import LogoutButton from './components/LogoutButton'; +import ThemeButton from './components/ThemeButton'; import { fetchAllMeta } from './services/van-blog/api'; +import { beforeSwitchTheme, getInitTheme, mapTheme } from './services/van-blog/theme'; const isDev = process.env.UMI_ENV === 'dev'; const loginPath = '/user/login'; /** 获取用户信息比较慢的时候会展示一个 loading */ @@ -37,10 +39,14 @@ export async function getInitialState() { option.skipErrorHandler = true; } const initData = await fetchInitData(option); + // 暗色模式 + const theme = getInitTheme(); + const sysTheme = mapTheme(theme); return { fetchInitData, ...initData, - settings: defaultSettings, + settings: { ...defaultSettings, navTheme: sysTheme }, + theme, }; } // ProLayout 支持的api https://procomponents.ant.design/components/layout @@ -48,15 +54,18 @@ export const layout = ({ initialState, setInitialState }) => { return { rightContentRender: () => { return ( - - - 登出 - - } - /> +
+ + + + 登出 + + } + /> +
); }, // disableContentMargin: true, @@ -101,8 +110,14 @@ export const layout = ({ initialState, setInitialState }) => { { + if (settings.navTheme != initialState?.settings?.navTheme) { + // 切换了主题 + beforeSwitchTheme(settings.navTheme); + } setInitialState((preInitialState) => ({ ...preInitialState, settings })); }} /> diff --git a/packages/admin/src/components/ThemeButton/index.less b/packages/admin/src/components/ThemeButton/index.less new file mode 100644 index 000000000..9b659fb38 --- /dev/null +++ b/packages/admin/src/components/ThemeButton/index.less @@ -0,0 +1,25 @@ +.theme-button { + display: flex; + align-items: center; + cursor: pointer; + height: 100%; + margin-right: 8px; +} +.theme-icon { + fill: #4b5563; + height: 100%; + align-items: center; + :hover { + fill: #7a7e84; + } +} + +.theme-icon-dark { + fill: rgb(158, 158, 158); + height: 100%; + align-items: center; + :hover { + fill: rgb(112, 112, 112); + } + +} diff --git a/packages/admin/src/components/ThemeButton/index.tsx b/packages/admin/src/components/ThemeButton/index.tsx new file mode 100644 index 000000000..a642097e8 --- /dev/null +++ b/packages/admin/src/components/ThemeButton/index.tsx @@ -0,0 +1,102 @@ +import { useMemo, useRef } from 'react'; +import { useModel } from 'umi'; +import { beforeSwitchTheme } from '../../services/van-blog/theme'; +import style from './index.less'; +export default function (props: {}) { + const { current: currentTimer } = useRef({ timer: null }); + const { initialState, setInitialState } = useModel('@@initialState'); + const setTheme = (newTheme: 'auto' | 'light' | 'dark') => { + clearTimer(); + if (newTheme == 'auto') { + setTimer(); + } + const newSettings = { ...initialState?.settings, navTheme: beforeSwitchTheme(newTheme) }; + setInitialState({ ...initialState, theme: newTheme, settings: newSettings }); + }; + const theme = useMemo(() => { + return initialState?.theme || 'auto'; + }, [initialState]); + const sysTheme = useMemo(() => { + return initialState?.settings?.navTheme || 'light'; + }, [initialState]); + const clearTimer = () => { + clearInterval(currentTimer.timer); + currentTimer.timer = null; + }; + const setTimer = () => { + clearTimer(); + currentTimer.timer = setInterval(() => { + console.log('auto theme timer running'); + setTheme('auto'); + }, 10000); + }; + + const handleSwitch = () => { + clearTimer(); + if (theme == 'light') { + setTheme('dark'); + } else if (theme == 'dark') { + setTheme('auto'); + } else { + setTheme('light'); + } + }; + return ( +
+
+ + + +
+
+ + + +
+
+ + + +
+
+ ); +} diff --git a/packages/admin/src/services/van-blog/theme.js b/packages/admin/src/services/van-blog/theme.js new file mode 100644 index 000000000..18d6d012c --- /dev/null +++ b/packages/admin/src/services/van-blog/theme.js @@ -0,0 +1,44 @@ +export const getInitTheme = () => { + let theme = 'light'; + if (!('theme' in localStorage) || localStorage.theme == 'auto') { + return 'auto'; + } else { + if (localStorage.theme === 'dark') { + theme = 'dark'; + } else { + theme = 'light'; + } + } + return theme; +}; +export const decodeAutoTheme = () => { + const d = new Date().getHours(); + const night = d > 18 || d < 8; + if (night || window.matchMedia('(prefers-color-scheme: dark)').matches) { + return 'realDark'; + } else { + return 'light'; + } +}; +export const mapTheme = (theme) => { + // 把自己定义的主题变成系统的 + if (theme == 'auto') { + return decodeAutoTheme(); + } else { + if (theme == 'light') { + return 'light'; + } else { + return 'realDark'; + } + } +}; +export const beforeSwitchTheme = (to) => { + if (to == 'light') { + localStorage.theme = 'light'; + } else if (to == 'auto') { + localStorage.theme = 'auto'; + } else { + localStorage.theme = 'dark'; + } + return mapTheme(to); +};