Skip to content

Commit

Permalink
feat: 后台增加黑暗模式
Browse files Browse the repository at this point in the history
  • Loading branch information
Mereithhh committed Aug 9, 2022
1 parent 506a25b commit c92996a
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 10 deletions.
35 changes: 25 additions & 10 deletions packages/admin/src/app.jsx
Expand Up @@ -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 */
Expand Down Expand Up @@ -37,26 +39,33 @@ 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

export const layout = ({ initialState, setInitialState }) => {
return {
rightContentRender: () => {
return (
<LogoutButton
key="logoutRightContent"
trigger={
<a>
<LogoutOutlined />
<span style={{ marginLeft: 6 }}>登出</span>
</a>
}
/>
<div style={{ display: 'flex', alignItems: 'center' }}>
<ThemeButton />
<LogoutButton
key="logoutRightContent"
trigger={
<a>
<LogoutOutlined />
<span style={{ marginLeft: 6 }}>登出</span>
</a>
}
/>
</div>
);
},
// disableContentMargin: true,
Expand Down Expand Up @@ -101,8 +110,14 @@ export const layout = ({ initialState, setInitialState }) => {
<SettingDrawer
disableUrlParams
enableDarkTheme
colorList={false}
settings={initialState?.settings}
themeOnly={true}
onSettingChange={(settings) => {
if (settings.navTheme != initialState?.settings?.navTheme) {
// 切换了主题
beforeSwitchTheme(settings.navTheme);
}
setInitialState((preInitialState) => ({ ...preInitialState, settings }));
}}
/>
Expand Down
25 changes: 25 additions & 0 deletions 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);
}

}
102 changes: 102 additions & 0 deletions 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<any>({ 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 (
<div className={style['theme-button']} onClick={handleSwitch}>
<div
style={{
display: theme == 'light' ? 'flex' : 'none',
height: 20,
}}
className={sysTheme == 'light' ? style['theme-icon'] : style['theme-icon-dark']}
>
<svg
className="fill-gray-600"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1024 1024"
fill="currentColor"
aria-label="light icon"
width={20}
height={20}
>
<path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path>
</svg>
</div>
<div
className={sysTheme == 'light' ? style['theme-icon'] : style['theme-icon-dark']}
style={{
display: theme == 'dark' ? 'flex' : 'none',
height: 20,
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 1024 1024"
fill="currentColor"
aria-label="dark icon"
width={20}
height={20}
>
<path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path>
</svg>
</div>
<div
className={sysTheme == 'light' ? style['theme-icon'] : style['theme-icon-dark']}
style={{
display: theme.includes('auto') ? 'flex' : 'none',
height: 20,
}}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width={20}
height={20}
viewBox="0 0 1024 1024"
aria-label="auto icon"
>
<path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path>
</svg>
</div>
</div>
);
}
44 changes: 44 additions & 0 deletions 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);
};

0 comments on commit c92996a

Please sign in to comment.