update
This commit is contained in:
parent
24f7f9524e
commit
18d79b79a7
@ -1,38 +1,60 @@
|
||||
import { StyleProvider } from '@ant-design/cssinjs';
|
||||
import { ConfigProvider, theme, App as AntdApp } from 'antd';
|
||||
// import 'dayjs/locale/zh-cn';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
|
||||
import { FC } from 'react';
|
||||
import { FC, useMemo } from 'react';
|
||||
|
||||
import $styles from './app.module.css';
|
||||
import { CallbackDemo } from './components/demo/callback';
|
||||
import EffectDemo from './components/demo/effect';
|
||||
import MemoDemo from './components/demo/memo';
|
||||
import RefDemo from './components/demo/ref';
|
||||
import StateDemo from './components/demo/state';
|
||||
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';
|
||||
|
||||
const App: FC = () => {
|
||||
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]);
|
||||
return (
|
||||
<ConfigProvider
|
||||
locale={zhCN}
|
||||
locale={antdLocaleData}
|
||||
theme={{
|
||||
algorithm: theme.defaultAlgorithm,
|
||||
algorithm,
|
||||
token: {},
|
||||
}}
|
||||
>
|
||||
<StyleProvider hashPriority="high">
|
||||
<AntdApp>
|
||||
<div className={$styles.app}>
|
||||
<StateDemo />
|
||||
{/* <StateDemo />
|
||||
<EffectDemo />
|
||||
<RefDemo />
|
||||
<MemoDemo />
|
||||
<CallbackDemo />
|
||||
<CallbackDemo /> */}
|
||||
<ContextDemo />
|
||||
<ReducerDemo />
|
||||
<CustomDemo />
|
||||
</div>
|
||||
</AntdApp>
|
||||
</StyleProvider>
|
||||
</ConfigProvider>
|
||||
);
|
||||
};
|
||||
const App: FC = () => (
|
||||
<Locale>
|
||||
<Theme>
|
||||
<Wrapper />
|
||||
</Theme>
|
||||
</Locale>
|
||||
);
|
||||
export default App;
|
||||
|
27
apps/admin/src/components/demo/constants.ts
Normal file
27
apps/admin/src/components/demo/constants.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Locale } from 'antd/es/locale';
|
||||
import enUS from 'antd/es/locale/en_US';
|
||||
import zhCN from 'antd/es/locale/zh_CN';
|
||||
|
||||
import { createContext } from 'react';
|
||||
|
||||
import { LocaleType, ThemeContextType, ThemeState } from './types';
|
||||
|
||||
export const localeData: Record<string, Locale> = {
|
||||
en_US: enUS,
|
||||
zh_CN: zhCN,
|
||||
};
|
||||
export const locales: LocaleType[] = [
|
||||
{
|
||||
name: 'en_US',
|
||||
label: '🇺🇸 english(US)',
|
||||
},
|
||||
{
|
||||
name: 'zh_CN',
|
||||
label: '🇨🇳 简体中文',
|
||||
},
|
||||
];
|
||||
export const defaultThemeConfig: ThemeState = {
|
||||
mode: 'light',
|
||||
compact: false,
|
||||
};
|
||||
export const ThemeContext = createContext<ThemeContextType | null>(null);
|
71
apps/admin/src/components/demo/context.tsx
Normal file
71
apps/admin/src/components/demo/context.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import { Pagination, Select } from 'antd';
|
||||
import { createContext, FC, ReactNode, useCallback, useMemo, useState } from 'react';
|
||||
|
||||
import { localeData, locales } from './constants';
|
||||
import { useLocale, useLocaleAction } from './hooks';
|
||||
import $styles from './style.module.css';
|
||||
import { LocaleState, LocaleType } from './types';
|
||||
|
||||
export const LocaleContext = createContext<LocaleState>({
|
||||
locale: locales[0],
|
||||
setLocale: (_locale: LocaleType) => {},
|
||||
});
|
||||
|
||||
const LocaleProvider: FC<LocaleState & { children?: ReactNode }> = ({
|
||||
locale,
|
||||
setLocale,
|
||||
children,
|
||||
}) => {
|
||||
const value = useMemo(() => ({ locale, setLocale }), [locale]);
|
||||
return <LocaleContext.Provider value={value}>{children}</LocaleContext.Provider>;
|
||||
};
|
||||
|
||||
export const Locale: FC<{ children?: ReactNode }> = ({ children }) => {
|
||||
const [locale, setLocale] = useState<LocaleType>(locales[0]);
|
||||
const changeLocale = useCallback((value: LocaleType) => {
|
||||
if (Object.keys(localeData).find((v) => v === value.name)) {
|
||||
setLocale(value);
|
||||
}
|
||||
}, []);
|
||||
return (
|
||||
<LocaleProvider locale={locale} setLocale={changeLocale}>
|
||||
{children}
|
||||
</LocaleProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const LocaleConfig: FC = () => {
|
||||
const locale = useLocale();
|
||||
const setLocale = useLocaleAction();
|
||||
const changeLocale = (value: string) => {
|
||||
const current = locales.find((item) => item.name === value);
|
||||
current && setLocale(current);
|
||||
};
|
||||
return (
|
||||
<Select defaultValue={locale.name} style={{ width: 120 }} onChange={changeLocale}>
|
||||
{locales.map(({ name, label }) => (
|
||||
<Select.Option key={name} value={name}>
|
||||
{label}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
);
|
||||
};
|
||||
|
||||
const ContextDemo: FC = () => {
|
||||
const locale = useLocale();
|
||||
return (
|
||||
<div className={$styles.container}>
|
||||
<h2 className="tw-text-center">useContext Demo</h2>
|
||||
<p className="tw-text-center tw-py-5">当前语言: {locale.label}</p>
|
||||
<div className="tw-w-full">
|
||||
<h3>Antd语言切换测试</h3>
|
||||
<div className="tw-w-full tw-my-4">
|
||||
<LocaleConfig />
|
||||
</div>
|
||||
</div>
|
||||
<Pagination defaultCurrent={0} total={500} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default ContextDemo;
|
25
apps/admin/src/components/demo/custom.tsx
Normal file
25
apps/admin/src/components/demo/custom.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Button } from 'antd';
|
||||
import clsx from 'clsx';
|
||||
import { FC, useState } from 'react';
|
||||
|
||||
import { useUpdateEffect } from './hooks';
|
||||
import $styles from './style.module.css';
|
||||
|
||||
const CustomDemo: FC = () => {
|
||||
const [count, setCount] = useState(0);
|
||||
useUpdateEffect(() => {
|
||||
console.log('changed');
|
||||
}, [count]);
|
||||
return (
|
||||
<div className={clsx($styles.container, 'tw-w-[20rem]')}>
|
||||
<h2 className="tw-text-center">Custom Demo</h2>
|
||||
<p className="tw-text-center tw-py-5">{count}</p>
|
||||
<div className="tw-flex tw-justify-around">
|
||||
<Button onClick={() => setCount(Math.ceil(Math.random() * 10))} type="dashed">
|
||||
变化
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default CustomDemo;
|
46
apps/admin/src/components/demo/hooks.tsx
Normal file
46
apps/admin/src/components/demo/hooks.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import { isEqual, isNil } from 'lodash';
|
||||
import {
|
||||
DependencyList,
|
||||
EffectCallback,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
} from 'react';
|
||||
|
||||
import { defaultThemeConfig, locales, ThemeContext } from './constants';
|
||||
import { LocaleContext } from './context';
|
||||
|
||||
export const useUpdateEffect = (effect: EffectCallback, deps?: DependencyList) => {
|
||||
const inited = useRef(deps);
|
||||
useEffect(() => {
|
||||
if (!isEqual(inited.current, deps)) {
|
||||
inited.current = deps;
|
||||
effect();
|
||||
}
|
||||
}, [deps]);
|
||||
};
|
||||
|
||||
export const useTheme = () => {
|
||||
const context = useContext(ThemeContext) ?? ({} as Record<string, any>);
|
||||
return useMemo(
|
||||
() => (isNil(context.state) ? defaultThemeConfig : context.state),
|
||||
[context.state],
|
||||
);
|
||||
};
|
||||
|
||||
export const useThemeAction = () => {
|
||||
const context = useContext(ThemeContext) ?? ({} as Record<string, any>);
|
||||
return useCallback(isNil(context.dispatch) ? null : context.dispatch, [context.dispatch]);
|
||||
};
|
||||
|
||||
export const useLocale = () => {
|
||||
const context = useContext(LocaleContext) ?? ({} as Record<string, any>);
|
||||
return useMemo(() => (isNil(context.locale) ? locales[0] : context.locale), [context.locale]);
|
||||
};
|
||||
|
||||
export const useLocaleAction = () => {
|
||||
const context = useContext(LocaleContext) ?? ({} as Record<string, any>);
|
||||
return useCallback(isNil(context.setLocale) ? null : context.setLocale, [context.setLocale]);
|
||||
};
|
90
apps/admin/src/components/demo/reducer.tsx
Normal file
90
apps/admin/src/components/demo/reducer.tsx
Normal file
@ -0,0 +1,90 @@
|
||||
import { Calendar, Switch } from 'antd';
|
||||
import { produce } from 'immer';
|
||||
import { isNil } from 'lodash';
|
||||
import { FC, ReactNode, Reducer, useContext, useEffect, useMemo, useReducer } from 'react';
|
||||
|
||||
import { defaultThemeConfig, ThemeContext } from './constants';
|
||||
import $styles from './style.module.css';
|
||||
import { ThemeAction, ThemeState } from './types';
|
||||
|
||||
const ThemeReducer: Reducer<ThemeState, ThemeAction> = produce((draft, action) => {
|
||||
switch (action.type) {
|
||||
case 'change_mode':
|
||||
draft.mode = action.value;
|
||||
break;
|
||||
case 'change_compact':
|
||||
draft.compact = action.value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
export const Theme: FC<{ data?: ThemeState; children?: ReactNode }> = ({ data = {}, children }) => {
|
||||
const [state, dispatch] = useReducer(ThemeReducer, data, (initData) => ({
|
||||
...defaultThemeConfig,
|
||||
...initData,
|
||||
}));
|
||||
useEffect(() => {
|
||||
const body = document.getElementsByTagName('body');
|
||||
if (body.length) {
|
||||
body[0].classList.remove('light');
|
||||
body[0].classList.remove('dark');
|
||||
body[0].classList.add(state.mode === 'dark' ? 'dark' : 'light');
|
||||
}
|
||||
}, [state.mode]);
|
||||
const value = useMemo(() => ({ state, dispatch }), [state]);
|
||||
return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
|
||||
};
|
||||
|
||||
export const ThemeConfig: FC = () => {
|
||||
const context = useContext(ThemeContext);
|
||||
if (isNil(context)) return null;
|
||||
const { state, dispatch } = context;
|
||||
const toggleMode = () =>
|
||||
dispatch({ type: 'change_mode', value: state.mode === 'light' ? 'dark' : 'light' });
|
||||
const toggleCompact = () => dispatch({ type: 'change_compact', value: !state.compact });
|
||||
return (
|
||||
<>
|
||||
<Switch
|
||||
checkedChildren="🌛"
|
||||
unCheckedChildren="☀️"
|
||||
onChange={toggleMode}
|
||||
checked={state.mode === 'dark'}
|
||||
defaultChecked={state.mode === 'dark'}
|
||||
/>
|
||||
<Switch
|
||||
checkedChildren="紧凑"
|
||||
unCheckedChildren="正常"
|
||||
onChange={toggleCompact}
|
||||
checked={state.compact}
|
||||
defaultChecked={state.compact}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const ReducerDemo: FC = () => {
|
||||
const context = useContext(ThemeContext);
|
||||
if (isNil(context)) return null;
|
||||
const {
|
||||
state: { mode, compact },
|
||||
} = context;
|
||||
return (
|
||||
<div className={$styles.container}>
|
||||
<h2 className="tw-text-center">useReducer 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">
|
||||
<ThemeConfig />
|
||||
</div>
|
||||
<div className="tw-max-w-md">
|
||||
<Calendar fullscreen={false} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReducerDemo;
|
34
apps/admin/src/components/demo/types.ts
Normal file
34
apps/admin/src/components/demo/types.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { Dispatch } from 'react';
|
||||
|
||||
export type LocaleType = {
|
||||
name: string;
|
||||
label: string;
|
||||
};
|
||||
export type LocaleState = {
|
||||
locale: LocaleType;
|
||||
setLocale: (locale: LocaleType) => void;
|
||||
};
|
||||
|
||||
export enum ThemeMode {
|
||||
LIGHT = 'light',
|
||||
DARK = 'dark',
|
||||
}
|
||||
|
||||
export type ThemeState = {
|
||||
mode: `${ThemeMode}`;
|
||||
compact: boolean;
|
||||
};
|
||||
|
||||
export enum ThemeActionType {
|
||||
CHANGE_MODE = 'change_mode',
|
||||
CHANGE_COMPACT = 'change_compact',
|
||||
}
|
||||
|
||||
export type ThemeAction =
|
||||
| { type: `${ThemeActionType.CHANGE_MODE}`; value: `${ThemeMode}` }
|
||||
| { type: `${ThemeActionType.CHANGE_COMPACT}`; value: boolean };
|
||||
|
||||
export type ThemeContextType = {
|
||||
state: ThemeState;
|
||||
dispatch: Dispatch<ThemeAction>;
|
||||
};
|
@ -8,3 +8,7 @@ body,
|
||||
body {
|
||||
@apply tw-bg-[url(@/assets/images/bg-light.png)];
|
||||
}
|
||||
|
||||
body.dark {
|
||||
@apply tw-bg-[url(@/assets/images/bg-dark.png)];
|
||||
}
|
||||
|
12076
pnpm-lock.yaml
12076
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user