update
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-use": "^17.5.0",
|
||||
"zustand": "^4.5.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { ConfigProvider, App as AntdApp } from 'antd';
|
||||
import { FC, useMemo } from 'react';
|
||||
|
||||
import $styles from './app.module.css';
|
||||
import { localeData } from './components/demo/constants';
|
||||
import ContextDemo from './components/demo/context';
|
||||
import CustomDemo from './components/demo/custom';
|
||||
import { useLocale } from './components/demo/hooks';
|
||||
import { useAntdAlgorithm } from './components/theme/hooks';
|
||||
|
||||
export const Wrapper: FC = () => {
|
||||
const locale = useLocale();
|
||||
const antdLocaleData = useMemo(() => {
|
||||
if (!Object.keys(localeData).find((v) => v === locale.name)) {
|
||||
return localeData[0];
|
||||
}
|
||||
return localeData[locale.name];
|
||||
}, [locale.name]);
|
||||
// const themeState = useTheme();
|
||||
// const algorithm = useMemo(() => {
|
||||
// const result = [themeState.compact ? theme.compactAlgorithm : theme.defaultAlgorithm];
|
||||
// if (themeState.mode === 'dark') result.push(theme.darkAlgorithm);
|
||||
// return result;
|
||||
// }, [themeState]);
|
||||
const algorithm = useAntdAlgorithm();
|
||||
return (
|
||||
<ConfigProvider
|
||||
locale={antdLocaleData}
|
||||
theme={{
|
||||
algorithm,
|
||||
token: {},
|
||||
}}
|
||||
>
|
||||
<StyleProvider hashPriority="high">
|
||||
<AntdApp>
|
||||
<div className={$styles.app}>
|
||||
{/* <StateDemo />
|
||||
<EffectDemo />
|
||||
<RefDemo />
|
||||
<MemoDemo />
|
||||
<CallbackDemo /> */}
|
||||
<ContextDemo />
|
||||
{/* <ReducerDemo /> */}
|
||||
<CustomDemo />
|
||||
</div>
|
||||
</AntdApp>
|
||||
</StyleProvider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
+16
-13
@@ -1,15 +1,16 @@
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { ConfigProvider, theme, App as AntdApp } from 'antd';
|
||||
import { ConfigProvider, App as AntdApp } from 'antd';
|
||||
// import 'dayjs/locale/zh-cn';
|
||||
|
||||
import { FC, useMemo } from 'react';
|
||||
|
||||
import $styles from './app.module.css';
|
||||
import { localeData } from './components/demo/constants';
|
||||
import ContextDemo, { Locale } from './components/demo/context';
|
||||
import CustomDemo from './components/demo/custom';
|
||||
import { useLocale, useTheme } from './components/demo/hooks';
|
||||
import ReducerDemo, { Theme } from './components/demo/reducer';
|
||||
import { Locale } from './components/demo/context';
|
||||
import { useLocale } from './components/demo/hooks';
|
||||
import Theme from './components/theme';
|
||||
import ThemeDemo from './components/theme/demo';
|
||||
import { useAntdAlgorithm } from './components/theme/hooks';
|
||||
|
||||
const Wrapper: FC = () => {
|
||||
const locale = useLocale();
|
||||
@@ -19,12 +20,13 @@ const Wrapper: FC = () => {
|
||||
}
|
||||
return localeData[locale.name];
|
||||
}, [locale.name]);
|
||||
const themeState = useTheme();
|
||||
const algorithm = useMemo(() => {
|
||||
const result = [themeState.compact ? theme.compactAlgorithm : theme.defaultAlgorithm];
|
||||
if (themeState.mode === 'dark') result.push(theme.darkAlgorithm);
|
||||
return result;
|
||||
}, [themeState]);
|
||||
// const themeState = useTheme();
|
||||
// const algorithm = useMemo(() => {
|
||||
// const result = [themeState.compact ? theme.compactAlgorithm : theme.defaultAlgorithm];
|
||||
// if (themeState.mode === 'dark') result.push(theme.darkAlgorithm);
|
||||
// return result;
|
||||
// }, [themeState]);
|
||||
const algorithm = useAntdAlgorithm();
|
||||
return (
|
||||
<ConfigProvider
|
||||
locale={antdLocaleData}
|
||||
@@ -40,10 +42,11 @@ const Wrapper: FC = () => {
|
||||
<EffectDemo />
|
||||
<RefDemo />
|
||||
<MemoDemo />
|
||||
<CallbackDemo /> */}
|
||||
<CallbackDemo />
|
||||
<ContextDemo />
|
||||
<ReducerDemo />
|
||||
<CustomDemo />
|
||||
<CustomDemo /> */}
|
||||
<ThemeDemo />
|
||||
</div>
|
||||
</AntdApp>
|
||||
</StyleProvider>
|
||||
|
||||
@@ -21,12 +21,16 @@ export type ThemeState = {
|
||||
|
||||
export enum ThemeActionType {
|
||||
CHANGE_MODE = 'change_mode',
|
||||
TOOGLE_MODE = 'toggle_mode',
|
||||
CHANGE_COMPACT = 'change_compact',
|
||||
TOOGLE_COMPACT = 'toggle_compact',
|
||||
}
|
||||
|
||||
export type ThemeAction =
|
||||
| { type: `${ThemeActionType.CHANGE_MODE}`; value: `${ThemeMode}` }
|
||||
| { type: `${ThemeActionType.CHANGE_COMPACT}`; value: boolean };
|
||||
| { type: `${ThemeActionType.TOOGLE_MODE}` }
|
||||
| { type: `${ThemeActionType.CHANGE_COMPACT}`; value: boolean }
|
||||
| { type: `${ThemeActionType.TOOGLE_COMPACT}` };
|
||||
|
||||
export type ThemeContextType = {
|
||||
state: ThemeState;
|
||||
|
||||
@@ -1,2 +1,167 @@
|
||||
export * from './utils';
|
||||
export * from './types';
|
||||
import { capitalize } from 'lodash';
|
||||
import { create, StateCreator, Mutate, StoreApi, UseBoundStore } from 'zustand';
|
||||
import {
|
||||
subscribeWithSelector,
|
||||
devtools,
|
||||
persist,
|
||||
PersistOptions,
|
||||
DevtoolsOptions,
|
||||
redux,
|
||||
} from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
export type ZustandHookSelectors<StateType> = {
|
||||
[Key in keyof StateType as `use${Capitalize<string & Key>}`]: () => StateType[Key];
|
||||
};
|
||||
export interface ZustandGetterSelectors<StateType> {
|
||||
getters: {
|
||||
[key in keyof StateType]: () => StateType[key];
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的普通状态商店
|
||||
* @param creator
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createStore = <T extends object>(
|
||||
creator: StateCreator<
|
||||
T,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => {
|
||||
return create<T>()(subscribeWithSelector(immer(devtools(creator, devtoolsOptions))));
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的普通状态商店
|
||||
* 同时支持自动存储到客户端,默认存储到localstorage
|
||||
* @param creator
|
||||
* @param persistOptions
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createPersistStore = <T extends object, P = T>(
|
||||
creator: StateCreator<
|
||||
T,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
['zustand/persist', P],
|
||||
]
|
||||
>,
|
||||
persistOptions: PersistOptions<T, P>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => {
|
||||
return create<T>()(
|
||||
subscribeWithSelector(
|
||||
immer(devtools(persist(creator as unknown as any, persistOptions), devtoolsOptions)),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的reducer状态商店
|
||||
* 同时支持自动存储到客户端,默认存储到localstorage
|
||||
* @param reducer
|
||||
* @param initialState
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createReduxStore = <
|
||||
T extends object,
|
||||
A extends {
|
||||
type: string;
|
||||
},
|
||||
>(
|
||||
reducer: (state: T, action: A) => T,
|
||||
initialState: T,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => create(subscribeWithSelector(immer(devtools(redux(reducer, initialState), devtoolsOptions))));
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的reducer状态商店
|
||||
* @param reducer
|
||||
* @param initialState
|
||||
* @param persistOptions
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createPersistReduxStore = <
|
||||
T extends object,
|
||||
A extends {
|
||||
type: string;
|
||||
},
|
||||
P = T,
|
||||
>(
|
||||
reducer: (state: T, action: A) => T,
|
||||
initialState: T,
|
||||
persistOptions: PersistOptions<T, P>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) =>
|
||||
create(
|
||||
subscribeWithSelector(
|
||||
immer(
|
||||
devtools(
|
||||
persist(redux(reducer, initialState), persistOptions as any),
|
||||
devtoolsOptions,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* 直接通过getters获取状态值,比如store.getters.xxx()
|
||||
* @param store
|
||||
*/
|
||||
export function createStoreGetters<T extends object>(
|
||||
store: UseBoundStore<
|
||||
Mutate<
|
||||
StoreApi<T>,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>
|
||||
>,
|
||||
) {
|
||||
const storeIn = store as any;
|
||||
|
||||
storeIn.getters = {};
|
||||
Object.keys(storeIn.getState()).forEach((key) => {
|
||||
const selector = (state: T) => state[key as keyof T];
|
||||
storeIn.getters[key] = () => storeIn(selector);
|
||||
});
|
||||
|
||||
return storeIn as typeof store & ZustandGetterSelectors<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接通过类似hooks的方法获取状态值,比如store.useXxx()
|
||||
* @param store
|
||||
*/
|
||||
export function createStoreHooks<T extends Record<string, any>>(
|
||||
store: UseBoundStore<
|
||||
Mutate<
|
||||
StoreApi<T>,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>
|
||||
>,
|
||||
) {
|
||||
const storeIn = store as any;
|
||||
|
||||
Object.keys(storeIn.getState()).forEach((key) => {
|
||||
const selector = (state: T) => state[key as keyof T];
|
||||
storeIn[`use${capitalize(key)}`] = () => storeIn(selector);
|
||||
});
|
||||
|
||||
return storeIn as typeof store & ZustandHookSelectors<T>;
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
export type ZustandHookSelectors<StateType> = {
|
||||
[Key in keyof StateType as `use${Capitalize<string & Key>}`]: () => StateType[Key];
|
||||
};
|
||||
export interface ZustandGetterSelectors<StateType> {
|
||||
getters: {
|
||||
[key in keyof StateType]: () => StateType[key];
|
||||
};
|
||||
}
|
||||
@@ -1,160 +0,0 @@
|
||||
import { capitalize } from 'lodash';
|
||||
import { create, Mutate, StateCreator, StoreApi, UseBoundStore } from 'zustand';
|
||||
import {
|
||||
subscribeWithSelector,
|
||||
devtools,
|
||||
persist,
|
||||
PersistOptions,
|
||||
DevtoolsOptions,
|
||||
redux,
|
||||
} from 'zustand/middleware';
|
||||
import { immer } from 'zustand/middleware/immer';
|
||||
|
||||
import { ZustandGetterSelectors, ZustandHookSelectors } from './types';
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的普通状态商店
|
||||
* @param creator
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createStore = <T extends object>(
|
||||
creator: StateCreator<
|
||||
T,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => {
|
||||
return create<T>()(subscribeWithSelector(immer(devtools(creator, devtoolsOptions))));
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的普通状态商店
|
||||
* 同时支持自动存储到客户端,默认存储到localstorage
|
||||
* @param creator
|
||||
* @param persistOptions
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createPersistStore = <T extends object, P = T>(
|
||||
creator: StateCreator<
|
||||
T,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
['zustand/persist', P],
|
||||
]
|
||||
>,
|
||||
persistOptions: PersistOptions<T, P>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => {
|
||||
return create<T>()(
|
||||
subscribeWithSelector(
|
||||
immer(devtools(persist(creator as unknown as any, persistOptions), devtoolsOptions)),
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的reducer状态商店
|
||||
* 同时支持自动存储到客户端,默认存储到localstorage
|
||||
* @param reducer
|
||||
* @param initialState
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createReduxStore = <
|
||||
T extends object,
|
||||
A extends {
|
||||
type: string;
|
||||
},
|
||||
>(
|
||||
reducer: (state: T, action: A) => T,
|
||||
initialState: T,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) => create(subscribeWithSelector(immer(devtools(redux(reducer, initialState), devtoolsOptions))));
|
||||
|
||||
/**
|
||||
* 创建包含订阅,immer以及devtoools功能的reducer状态商店
|
||||
* @param reducer
|
||||
* @param initialState
|
||||
* @param persistOptions
|
||||
* @param devtoolsOptions
|
||||
*/
|
||||
export const createPersistReduxStore = <
|
||||
T extends object,
|
||||
A extends {
|
||||
type: string;
|
||||
},
|
||||
P = T,
|
||||
>(
|
||||
reducer: (state: T, action: A) => T,
|
||||
initialState: T,
|
||||
persistOptions: PersistOptions<T, P>,
|
||||
devtoolsOptions?: DevtoolsOptions,
|
||||
) =>
|
||||
create(
|
||||
subscribeWithSelector(
|
||||
immer(
|
||||
devtools(
|
||||
persist(redux(reducer, initialState), persistOptions as any),
|
||||
devtoolsOptions,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* 直接通过getters获取状态值,比如store.getters.xxx()
|
||||
* @param store
|
||||
*/
|
||||
export function createStoreGetters<T extends object>(
|
||||
store: UseBoundStore<
|
||||
Mutate<
|
||||
StoreApi<T>,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>
|
||||
>,
|
||||
) {
|
||||
const storeIn = store as any;
|
||||
|
||||
storeIn.getters = {};
|
||||
Object.keys(storeIn.getState()).forEach((key) => {
|
||||
const selector = (state: T) => state[key as keyof T];
|
||||
storeIn.getters[key] = () => storeIn(selector);
|
||||
});
|
||||
|
||||
return storeIn as typeof store & ZustandGetterSelectors<T>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 直接通过类似hooks的方法获取状态值,比如store.useXxx()
|
||||
* @param store
|
||||
*/
|
||||
export function createStoreHooks<T extends Record<string, any>>(
|
||||
store: UseBoundStore<
|
||||
Mutate<
|
||||
StoreApi<T>,
|
||||
[
|
||||
['zustand/subscribeWithSelector', never],
|
||||
['zustand/immer', never],
|
||||
['zustand/devtools', never],
|
||||
]
|
||||
>
|
||||
>,
|
||||
) {
|
||||
const storeIn = store as any;
|
||||
|
||||
Object.keys(storeIn.getState()).forEach((key) => {
|
||||
const selector = (state: T) => state[key as keyof T];
|
||||
storeIn[`use${capitalize(key)}`] = () => storeIn(selector);
|
||||
});
|
||||
|
||||
return storeIn as typeof store & ZustandHookSelectors<T>;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import { ThemeState } from './types';
|
||||
|
||||
export const defaultThemeConfig: ThemeState = {
|
||||
mode: 'light',
|
||||
compact: false,
|
||||
};
|
||||
@@ -0,0 +1,48 @@
|
||||
import { Calendar, Switch } from 'antd';
|
||||
import { FC } from 'react';
|
||||
|
||||
import { useTheme, useThemeActions } from './hooks';
|
||||
import $styles from './style.module.css';
|
||||
|
||||
const Setting: FC = () => {
|
||||
const { mode, compact } = useTheme();
|
||||
const { toggleMode, toggleCompact } = useThemeActions();
|
||||
return (
|
||||
<>
|
||||
<Switch
|
||||
checkedChildren="🌛"
|
||||
unCheckedChildren="☀️"
|
||||
onChange={toggleMode}
|
||||
checked={mode === 'dark'}
|
||||
defaultChecked={mode === 'dark'}
|
||||
/>
|
||||
<Switch
|
||||
checkedChildren="紧凑"
|
||||
unCheckedChildren="正常"
|
||||
onChange={toggleCompact}
|
||||
checked={compact}
|
||||
defaultChecked={compact}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ThemeDemo: FC = () => {
|
||||
const { mode, compact } = useTheme();
|
||||
return (
|
||||
<div className={$styles.container}>
|
||||
<h2 className="tw-text-center">Theme Setting Demo</h2>
|
||||
<div className="tw-flex tw-items-center tw-flex-col">
|
||||
<p>主题模式: 「{mode === 'dark' ? '暗黑' : '明亮'}」</p>
|
||||
<p>是否紧凑: 「{compact ? '是' : '否'}」</p>
|
||||
<div className="tw-flex-auto tw-mb-5">
|
||||
<Setting />
|
||||
</div>
|
||||
<div className="tw-max-w-md">
|
||||
<Calendar fullscreen={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ThemeDemo;
|
||||
@@ -0,0 +1,46 @@
|
||||
import { theme } from 'antd';
|
||||
import { omit } from 'lodash';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useShallow } from 'zustand/react/shallow';
|
||||
|
||||
import { useThemeStore } from './store';
|
||||
import { ThemeMode } from './types';
|
||||
|
||||
/**
|
||||
* 获取主题状态
|
||||
*/
|
||||
export const useTheme = () => useThemeStore(useShallow((state) => omit(state, ['dispatch'])));
|
||||
|
||||
/**
|
||||
* 获取Antd主题算法
|
||||
*/
|
||||
export const useAntdAlgorithm = () => {
|
||||
const { mode, compact } = useTheme();
|
||||
return useMemo(() => {
|
||||
const result = [compact ? theme.compactAlgorithm : theme.defaultAlgorithm];
|
||||
if (mode === 'dark') result.push(theme.darkAlgorithm);
|
||||
return result;
|
||||
}, [mode, compact]);
|
||||
};
|
||||
|
||||
/**
|
||||
* 主题操作函数
|
||||
*/
|
||||
export const useThemeActions = () => {
|
||||
const dispatch = useThemeStore((state) => state.dispatch);
|
||||
return {
|
||||
changeMode: useCallback(
|
||||
(v: `${ThemeMode}`) => dispatch({ type: 'change_mode', value: v }),
|
||||
[],
|
||||
),
|
||||
toggleMode: useCallback(() => dispatch({ type: 'toggle_mode' }), []),
|
||||
changeCompact: useCallback(
|
||||
(v: boolean) => dispatch({ type: 'change_compact', value: v }),
|
||||
[],
|
||||
),
|
||||
toggleCompact: useCallback(
|
||||
useCallback(() => dispatch({ type: 'toggle_compact' }), []),
|
||||
[],
|
||||
),
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,50 @@
|
||||
import { debounce, isNil } from 'lodash';
|
||||
import { FC, ReactNode } from 'react';
|
||||
|
||||
import { useLifecycles } from 'react-use';
|
||||
|
||||
import { useThemeStore } from './store';
|
||||
|
||||
const Theme: FC<{ children?: ReactNode }> = ({ children }) => {
|
||||
let unSub: () => void;
|
||||
|
||||
useLifecycles(
|
||||
() => {
|
||||
useThemeStore.subscribe(
|
||||
(state) => state.mode,
|
||||
(mode) => {
|
||||
debounce(() => {
|
||||
console.log(mode);
|
||||
});
|
||||
const body = document.getElementsByTagName('body');
|
||||
if (body.length) {
|
||||
body[0].classList.remove('light');
|
||||
body[0].classList.remove('dark');
|
||||
body[0].classList.add(mode === 'dark' ? 'dark' : 'light');
|
||||
}
|
||||
},
|
||||
// debounce(
|
||||
// () => {
|
||||
// const body = document.getElementsByTagName('body');
|
||||
// if (body.length) {
|
||||
// body[0].classList.remove('light');
|
||||
// body[0].classList.remove('dark');
|
||||
// body[0].classList.add(mode === 'dark' ? 'dark' : 'light');
|
||||
// }
|
||||
// },
|
||||
// 10,
|
||||
// {},
|
||||
// ),
|
||||
{
|
||||
fireImmediately: true,
|
||||
},
|
||||
);
|
||||
},
|
||||
() => {
|
||||
if (!isNil(unSub)) unSub();
|
||||
},
|
||||
);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
export default Theme;
|
||||
@@ -0,0 +1,32 @@
|
||||
import { produce } from 'immer';
|
||||
import { Reducer } from 'react';
|
||||
|
||||
import { ThemeAction } from '../demo/types';
|
||||
import { createPersistReduxStore } from '../store';
|
||||
|
||||
import { defaultThemeConfig } from './constants';
|
||||
import { ThemeState } from './types';
|
||||
|
||||
const ThemeReducer: Reducer<ThemeState, ThemeAction> = produce((draft, action) => {
|
||||
switch (action.type) {
|
||||
case 'change_mode':
|
||||
draft.mode = action.value;
|
||||
break;
|
||||
case 'toggle_mode':
|
||||
draft.mode = draft.mode === 'dark' ? 'light' : 'dark';
|
||||
break;
|
||||
case 'change_compact':
|
||||
draft.compact = action.value;
|
||||
break;
|
||||
case 'toggle_compact':
|
||||
draft.compact = !draft.compact;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
export const useThemeStore = createPersistReduxStore(ThemeReducer, defaultThemeConfig, {
|
||||
name: 'theme',
|
||||
partialize: (state) => ({ mode: state.mode, compact: state.compact }),
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
.container {
|
||||
@apply tw-bg-neutral-100/40 tw-shadow-black/20 tw-backdrop-blur-sm tw-shadow-md tw-rounded-md tw-p-5 tw-m-5 tw-min-w-[20rem];
|
||||
}
|
||||
|
||||
body(:global(.dark)) {
|
||||
.container {
|
||||
@apply tw-bg-neutral-800/40 tw-shadow-slate-100/30;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
export enum ThemeMode {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark',
|
||||
}
|
||||
|
||||
export type ThemeState = {
|
||||
mode: `${ThemeMode}`;
|
||||
compact: boolean;
|
||||
};
|
||||
Reference in New Issue
Block a user