This commit is contained in:
pincman 2024-05-13 09:35:26 +08:00
parent 24f7f9524e
commit 18d79b79a7
9 changed files with 6998 additions and 5421 deletions

View File

@ -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;

View 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);

View 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;

View 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;

View 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]);
};

View 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;

View 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>;
};

View File

@ -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)];
}

File diff suppressed because it is too large Load Diff