91 lines
2.9 KiB
TypeScript
91 lines
2.9 KiB
TypeScript
import type { FC, PropsWithChildren } from 'react';
|
|
|
|
import { Switch } from 'antd';
|
|
import { createContext, useContext, useEffect, useReducer } from 'react';
|
|
|
|
import type { ThemeAction, ThemeContextType, ThemeState } from './types';
|
|
|
|
import { ThemeMode } from './types';
|
|
|
|
const initialState: ThemeState = {
|
|
mode: ThemeMode.LIGHT,
|
|
compact: false,
|
|
};
|
|
const ThemeContext = createContext<ThemeContextType>({
|
|
state: initialState,
|
|
dispatch: () => null,
|
|
});
|
|
const ThemeReducer = (state: ThemeState, action: ThemeAction) => {
|
|
switch (action.type) {
|
|
case 'change_mode':
|
|
return { ...state, mode: action.value };
|
|
case 'change_compact':
|
|
return { ...state, compact: action.value };
|
|
default:
|
|
throw new Error(`Unhandled action type`);
|
|
}
|
|
};
|
|
|
|
export const Theme: FC<PropsWithChildren> = ({ children }) => {
|
|
const [state, dispatch] = useReducer(ThemeReducer, initialState);
|
|
useEffect(() => {
|
|
const html = document.getElementsByTagName('html');
|
|
console.log(html[0], 'html');
|
|
|
|
if (html.length > 0) {
|
|
html[0].classList.remove('light', 'dark');
|
|
html[0].classList.add(state.mode);
|
|
}
|
|
}, [state.mode]);
|
|
return <ThemeContext value={{ state, dispatch }}>{children}</ThemeContext>;
|
|
};
|
|
export const ThemeConfig = () => {
|
|
const { state, dispatch } = useContext(ThemeContext);
|
|
const handleModeChange = () =>
|
|
dispatch({
|
|
type: 'change_mode',
|
|
value: state.mode === ThemeMode.LIGHT ? ThemeMode.DARK : ThemeMode.LIGHT,
|
|
});
|
|
const handleCompactChange = () =>
|
|
dispatch({
|
|
type: 'change_compact',
|
|
value: !state.compact,
|
|
});
|
|
return (
|
|
<>
|
|
<Switch
|
|
checkedChildren="🌛"
|
|
unCheckedChildren="🌞"
|
|
onChange={handleModeChange}
|
|
checked={state.mode === ThemeMode.DARK}
|
|
defaultChecked={state.mode === ThemeMode.DARK}
|
|
></Switch>
|
|
<Switch
|
|
checkedChildren="紧凑"
|
|
unCheckedChildren="正常"
|
|
onChange={handleCompactChange}
|
|
checked={state.compact}
|
|
defaultChecked={state.compact}
|
|
></Switch>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export const ReducerDemo = () => {
|
|
const {
|
|
state: { mode, compact },
|
|
} = useContext(ThemeContext);
|
|
return (
|
|
<div className="tw-container">
|
|
<h2 className="tw-text-center dark:tw-text-white ">useReducer Demo</h2>
|
|
<div className="tw-flex tw-flex-col tw-items-center">
|
|
<p>主题模式: 「{mode === 'dark' ? '暗黑' : '明亮'}」</p>
|
|
<p>是否紧凑: 「{compact ? '是' : '否'}」</p>
|
|
<div className="tw-mb-5 tw-flex-auto">
|
|
<ThemeConfig />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|