This commit is contained in:
pincman 2024-05-15 09:42:19 +08:00
parent a9638cfa38
commit ebd3a66499
12 changed files with 175 additions and 88 deletions

View File

@ -2,24 +2,24 @@ import { StyleProvider } from '@ant-design/cssinjs';
import { ConfigProvider, App as AntdApp } from 'antd'; import { ConfigProvider, App as AntdApp } from 'antd';
// import 'dayjs/locale/zh-cn'; // import 'dayjs/locale/zh-cn';
import { FC, useMemo } from 'react'; import { FC } from 'react';
import $styles from './app.module.css'; import $styles from './app.module.css';
import { localeData } from './components/demo/constants';
import { Locale } from './components/demo/context'; import { Locale } from './components/demo/context';
import { useLocale } from './components/demo/hooks'; import { useLocaleData } from './components/i18n/hooks';
import Setting from './components/setting';
import Theme from './components/theme'; import Theme from './components/theme';
import ThemeDemo from './components/theme/demo';
import { useAntdAlgorithm } from './components/theme/hooks'; import { useAntdAlgorithm } from './components/theme/hooks';
const Wrapper: FC = () => { const Wrapper: FC = () => {
const locale = useLocale(); const locale = useLocaleData();
const antdLocaleData = useMemo(() => { // const locale = useLocale();
if (!Object.keys(localeData).find((v) => v === locale.name)) { // const antdLocaleData = useMemo(() => {
return localeData[0]; // if (!Object.keys(localeData).find((v) => v === locale.name)) {
} // return localeData[0];
return localeData[locale.name]; // }
}, [locale.name]); // return localeData[locale.name];
// }, [locale.name]);
// const themeState = useTheme(); // const themeState = useTheme();
// const algorithm = useMemo(() => { // const algorithm = useMemo(() => {
// const result = [themeState.compact ? theme.compactAlgorithm : theme.defaultAlgorithm]; // const result = [themeState.compact ? theme.compactAlgorithm : theme.defaultAlgorithm];
@ -29,7 +29,7 @@ const Wrapper: FC = () => {
const algorithm = useAntdAlgorithm(); const algorithm = useAntdAlgorithm();
return ( return (
<ConfigProvider <ConfigProvider
locale={antdLocaleData} locale={locale.antd}
theme={{ theme={{
algorithm, algorithm,
token: {}, token: {},
@ -46,7 +46,7 @@ const Wrapper: FC = () => {
<ContextDemo /> <ContextDemo />
<ReducerDemo /> <ReducerDemo />
<CustomDemo /> */} <CustomDemo /> */}
<ThemeDemo /> <Setting />
</div> </div>
</AntdApp> </AntdApp>
</StyleProvider> </StyleProvider>

View File

@ -0,0 +1,3 @@
import { LangType } from './types';
export const langs: `${LangType}`[] = ['en_US', 'zh_CN'];

View File

@ -0,0 +1,15 @@
import enUS from 'antd/es/locale/en_US';
import zhCN from 'antd/es/locale/zh_CN';
import { LangType, LocaleItem } from './types';
export const localeData: Record<`${LangType}`, LocaleItem> = {
en_US: {
label: '🇺🇸 english(US)',
antd: enUS,
},
zh_CN: {
label: '🇨🇳 简体中文',
antd: zhCN,
},
};

View File

@ -0,0 +1,11 @@
import { useMemo } from 'react';
import { localeData } from './data';
import { useLocaleStore } from './store';
export const useLocale = () => useLocaleStore((state) => state.lang);
export const useLocaleChange = () => useLocaleStore((state) => state.changeLang);
export const useLocaleData = () => {
const lang = useLocale();
return useMemo(() => localeData[lang], [lang]);
};

View File

@ -0,0 +1,12 @@
import { isNil } from 'lodash';
import { FC, ReactNode } from 'react';
import { useLocaleChange } from './hooks';
import { LangType } from './types';
const Locale: FC<{ children?: ReactNode } & { lang: `${LangType}` }> = ({ children, lang }) => {
const changeLocale = useLocaleChange();
if (!isNil(changeLocale)) changeLocale(lang);
return <>{children}</>;
};
export default Locale;

View File

@ -0,0 +1,23 @@
import { isNil } from 'lodash';
import { createPersistStore } from '../store';
import { langs } from './constants';
import { LangType } from './types';
export const useLocaleStore = createPersistStore<{
lang: `${LangType}`;
changeLang: (name: `${LangType}`) => void;
}>(
(set) => ({
lang: langs[0],
changeLang: (name: `${LangType}`) =>
set((state) => {
const item = langs.find((n) => n === name);
if (!isNil(item)) state.lang = item;
}),
}),
{
name: 'locale',
},
);

View File

@ -0,0 +1,10 @@
import { Locale } from 'antd/es/locale';
export enum LangType {
EN_US = 'en_US',
ZH_CN = 'zh_CN',
}
export interface LocaleItem {
label: string;
antd: Locale;
}

View File

@ -0,0 +1,64 @@
import { Calendar, Select, Switch } from 'antd';
import { FC } from 'react';
import { langs } from '../i18n/constants';
import { localeData } from '../i18n/data';
import { useLocale, useLocaleChange } from '../i18n/hooks';
import { useTheme, useThemeActions } from '../theme/hooks';
import $styles from './style.module.css';
const ThemeSetting: 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}
/>
</>
);
};
export const LocaleSetting: FC = () => {
const locale = useLocale();
const changeLocale = useLocaleChange();
return (
<Select defaultValue={locale} style={{ width: 120 }} onChange={changeLocale}>
{langs.map((name) => (
<Select.Option key={name} value={name}>
{localeData[name].label}
</Select.Option>
))}
</Select>
);
};
const Setting: FC = () => (
<div className={$styles.container}>
<h2 className="tw-text-center">Setting Demo</h2>
<div className="tw-flex tw-items-center tw-flex-col">
<div className="tw-flex-auto tw-mb-5">
<ThemeSetting />
</div>
<div className="tw-flex-auto tw-mb-5">
<LocaleSetting />
</div>
<div className="tw-max-w-md">
<Calendar fullscreen={false} />
</div>
</div>
</div>
);
export default Setting;

View File

@ -1,48 +0,0 @@
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;

View File

@ -1,5 +1,5 @@
import { theme } from 'antd'; import { theme } from 'antd';
import { omit } from 'lodash'; import { debounce, omit } from 'lodash';
import { useCallback, useMemo } from 'react'; import { useCallback, useMemo } from 'react';
import { useShallow } from 'zustand/react/shallow'; import { useShallow } from 'zustand/react/shallow';
@ -30,17 +30,21 @@ export const useThemeActions = () => {
const dispatch = useThemeStore((state) => state.dispatch); const dispatch = useThemeStore((state) => state.dispatch);
return { return {
changeMode: useCallback( changeMode: useCallback(
(v: `${ThemeMode}`) => dispatch({ type: 'change_mode', value: v }), debounce(
(v: `${ThemeMode}`) => () => dispatch({ type: 'change_mode', value: v }),
100,
{},
),
[],
),
toggleMode: useCallback(
debounce(() => dispatch({ type: 'toggle_mode' }), 100, {}),
[], [],
), ),
toggleMode: useCallback(() => dispatch({ type: 'toggle_mode' }), []),
changeCompact: useCallback( changeCompact: useCallback(
(v: boolean) => dispatch({ type: 'change_compact', value: v }), (v: boolean) => dispatch({ type: 'change_compact', value: v }),
[], [],
), ),
toggleCompact: useCallback( toggleCompact: useCallback(() => dispatch({ type: 'toggle_compact' }), []),
useCallback(() => dispatch({ type: 'toggle_compact' }), []),
[],
),
}; };
}; };

View File

@ -1,40 +1,31 @@
import { debounce, isNil } from 'lodash'; import { isNil } from 'lodash';
import { FC, ReactNode } from 'react'; import { FC, ReactNode } from 'react';
import { useLifecycles } from 'react-use'; import { useLifecycles } from 'react-use';
import { useThemeActions } from './hooks';
import { useThemeStore } from './store'; import { useThemeStore } from './store';
import { ThemeMode } from './types';
const Theme: FC<{ children?: ReactNode }> = ({ children }) => { const Theme: FC<{ children?: ReactNode; mode?: `${ThemeMode}`; compact?: boolean }> = ({
children,
mode,
compact,
}) => {
const { changeMode, changeCompact } = useThemeActions();
let unSub: () => void; let unSub: () => void;
useLifecycles( useLifecycles(
() => { () => {
useThemeStore.subscribe( useThemeStore.subscribe(
(state) => state.mode, (state) => state.mode,
(mode) => { (m) => {
debounce(() => {
console.log(mode);
});
const body = document.getElementsByTagName('body'); const body = document.getElementsByTagName('body');
if (body.length) { if (body.length) {
body[0].classList.remove('light'); body[0].classList.remove('light');
body[0].classList.remove('dark'); body[0].classList.remove('dark');
body[0].classList.add(mode === 'dark' ? 'dark' : 'light'); body[0].classList.add(m === '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, fireImmediately: true,
}, },
@ -44,6 +35,8 @@ const Theme: FC<{ children?: ReactNode }> = ({ children }) => {
if (!isNil(unSub)) unSub(); if (!isNil(unSub)) unSub();
}, },
); );
if (!isNil(mode)) changeMode(mode);
if (!isNil(compact)) changeCompact(compact);
return <>{children}</>; return <>{children}</>;
}; };