mirror of https://github.com/longtai-cn/hippo4j
Add i18n header components (#1466)
parent
f1957dda88
commit
4abdf0a15b
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1,14 @@
|
||||
.header-wrapper {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
.logo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 200px;
|
||||
img {
|
||||
flex: 1;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,86 @@
|
||||
import React, { useContext } from 'react';
|
||||
import style from './index.module.less';
|
||||
import { UserOutlined } from '@ant-design/icons';
|
||||
import { Avatar, Button, Col, Dropdown, Row, Switch, Tag } from 'antd';
|
||||
import useThemeMode from '@/hooks/useThemeMode';
|
||||
import { MyContext } from '@/context';
|
||||
import IconFont from '@/components/icon';
|
||||
|
||||
const HeaderChild = () => {
|
||||
const { isDark, setIsDark } = useThemeMode();
|
||||
const { lang, setLang } = useContext<any>(MyContext);
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: '1',
|
||||
label: (
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://www.antgroup.com">
|
||||
1st menu
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: (
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://www.aliyun.com">
|
||||
2nd menu
|
||||
</a>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: (
|
||||
<a target="_blank" rel="noopener noreferrer" href="https://www.luohanacademy.com">
|
||||
登出
|
||||
</a>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={style['header-wrapper']}>
|
||||
<div className={style['logo']}>
|
||||
<img src="https://demo.knowstreaming.com/layout/assets/image/ks-logo.png" alt="" />
|
||||
</div>
|
||||
<div className={style['edit-container']}>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col></Col>
|
||||
<Col>
|
||||
<Dropdown menu={{ items }} placement="bottomRight" trigger={['click']}>
|
||||
<Avatar size={30} icon={<UserOutlined />} style={{ cursor: 'pointer' }} />
|
||||
</Dropdown>
|
||||
</Col>
|
||||
<Col>
|
||||
{/* <Tag
|
||||
onClick={() => {
|
||||
lang === 'zh' ? setLang('en') : setLang('zh');
|
||||
}}
|
||||
style={{ cursor: 'pointer' }}
|
||||
>
|
||||
{lang === 'zh' ? 'zh' : 'en'}
|
||||
</Tag> */}
|
||||
<Button
|
||||
type="link"
|
||||
onClick={() => {
|
||||
lang === 'zh' ? setLang('en') : setLang('zh');
|
||||
}}
|
||||
>
|
||||
<IconFont type="icon-qiehuanyuyan"></IconFont>
|
||||
</Button>
|
||||
</Col>
|
||||
<Col>
|
||||
<Switch
|
||||
checkedChildren={'🌞'}
|
||||
unCheckedChildren={'🌛'}
|
||||
defaultChecked={isDark}
|
||||
onChange={e => {
|
||||
setIsDark(e);
|
||||
}}
|
||||
></Switch>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default HeaderChild;
|
@ -0,0 +1,15 @@
|
||||
import { createFromIconfontCN } from '@ant-design/icons';
|
||||
|
||||
interface Props {
|
||||
type: string;
|
||||
}
|
||||
|
||||
const MyIcon = createFromIconfontCN({
|
||||
scriptUrl: '//at.alicdn.com/t/c/font_4254722_1xl4w1k5c53.js', // 在 iconfont.cn 上生成
|
||||
});
|
||||
|
||||
const IconFont = (props: Props) => {
|
||||
return <MyIcon {...props}></MyIcon>;
|
||||
};
|
||||
|
||||
export default IconFont;
|
@ -0,0 +1,28 @@
|
||||
// i18n.js
|
||||
|
||||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import zh from './locales/zh';
|
||||
import en from './locales/en';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
|
||||
i18n
|
||||
.use(LanguageDetector)
|
||||
.use(initReactI18next)
|
||||
.init({
|
||||
resources: {
|
||||
zh: {
|
||||
translation: zh,
|
||||
},
|
||||
en: {
|
||||
translation: en,
|
||||
},
|
||||
},
|
||||
debug: true,
|
||||
fallbackLng: 'zh', // 默认语言
|
||||
interpolation: {
|
||||
escapeValue: false, // 不转义HTML标签
|
||||
},
|
||||
});
|
||||
|
||||
export default i18n;
|
@ -0,0 +1,5 @@
|
||||
const enTranslationMap: { [key: string]: string } = {
|
||||
hello: 'hello',
|
||||
};
|
||||
|
||||
export default enTranslationMap;
|
@ -0,0 +1,5 @@
|
||||
const zhTranslationMap: { [key: string]: string } = {
|
||||
hello: '你好',
|
||||
};
|
||||
|
||||
export default zhTranslationMap;
|
@ -0,0 +1,45 @@
|
||||
import { theme } from 'antd';
|
||||
import { lightDefaultTheme } from '.';
|
||||
export const defaultAlgorithm = {
|
||||
token: {
|
||||
borderRadius: 6,
|
||||
colorPrimary: lightDefaultTheme.primary,
|
||||
fontSize: 14,
|
||||
// colorBgBase: lightDefaultTheme.backgroundColor.bg1,
|
||||
},
|
||||
components: {
|
||||
Layout: {
|
||||
bodyBg: lightDefaultTheme.backgroundColor.bg1,
|
||||
headerBg: lightDefaultTheme.backgroundColor.bgHeader,
|
||||
},
|
||||
// Button: {
|
||||
// fontSize: 14,
|
||||
// },
|
||||
// Table: {
|
||||
// padding: 10,
|
||||
// paddingXS: 5,
|
||||
// margin: 0,
|
||||
// fontSize: 14,
|
||||
// colorBorderSecondary: lightDefaultTheme.borderColor.bl1,
|
||||
// paddingContentVerticalLG: 4,
|
||||
// },
|
||||
// Modal: {
|
||||
// borderRadiusLG: 2,
|
||||
// borderRadiusSM: 2,
|
||||
// colorText: lightDefaultTheme.fontColor.fc3,
|
||||
// borderRadius: 2,
|
||||
// paddingContentHorizontalLG: 0,
|
||||
// paddingMD: 0,
|
||||
// },
|
||||
// Menu: {
|
||||
// itemBg: lightDefaultTheme.backgroundColor.bg1,
|
||||
// activeBarWidth: 0,
|
||||
// activeBarHeight: 0,
|
||||
// activeBarBorderWidth: 0,
|
||||
// subMenuItemBorderRadius: 8,
|
||||
// horizontalItemBorderRadius: 8,
|
||||
// itemBorderRadius: 8,
|
||||
// },
|
||||
},
|
||||
algorithm: theme.defaultAlgorithm,
|
||||
};
|
@ -1,18 +1,67 @@
|
||||
import React, { createContext, useState, ReactNode } from 'react';
|
||||
import React, { createContext, useState, ReactNode, useEffect } from 'react';
|
||||
import { ConfigProvider, theme } from 'antd';
|
||||
import { DefaultTheme, ThemeProvider } from 'styled-components';
|
||||
import enUS from 'antd/locale/en_US';
|
||||
import zhCN from 'antd/locale/zh_CN';
|
||||
import { darkDefaultTheme, lightDefaultTheme } from '@/config/theme';
|
||||
import { defaultAlgorithm } from '@/config/theme/default-algnorithm';
|
||||
import { darkAlgorithm } from '@/config/theme/dark-algorithm';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export enum THEME_NAME {
|
||||
DEFAULT = 'default',
|
||||
DARK = 'dark',
|
||||
}
|
||||
|
||||
export const StoreContext = createContext<{
|
||||
export enum LANG_NAME {
|
||||
ZH = 'zh',
|
||||
EN = 'en',
|
||||
}
|
||||
|
||||
export const MyContext = createContext<{
|
||||
themeName: string;
|
||||
lang: LANG_NAME;
|
||||
setThemeName: (name: THEME_NAME) => void;
|
||||
setLang: (lang: LANG_NAME) => void;
|
||||
} | null>(null);
|
||||
|
||||
export const Store: React.FC<{
|
||||
export const MyStore: React.FC<{
|
||||
children: ReactNode;
|
||||
}> = ({ children }) => {
|
||||
const [themeName, setThemeName] = useState<string>(THEME_NAME.DEFAULT);
|
||||
return <StoreContext.Provider value={{ themeName, setThemeName }}>{children}</StoreContext.Provider>;
|
||||
const [themeName, setThemeName] = useState<THEME_NAME>(THEME_NAME.DEFAULT);
|
||||
const [lang, setLang] = useState<LANG_NAME>(LANG_NAME.ZH);
|
||||
const [themes, setThemes] = useState(defaultAlgorithm);
|
||||
const [myThemes, setMyThemes] = useState<DefaultTheme>(lightDefaultTheme);
|
||||
const { i18n } = useTranslation();
|
||||
|
||||
const changeMode = (themeName: THEME_NAME) => {
|
||||
if (themeName === THEME_NAME.DARK) {
|
||||
darkAlgorithm.algorithm = theme.darkAlgorithm;
|
||||
// for ant change mode
|
||||
setThemes(darkAlgorithm);
|
||||
// for custome use mode
|
||||
setMyThemes(darkDefaultTheme);
|
||||
} else {
|
||||
defaultAlgorithm.algorithm = theme.defaultAlgorithm;
|
||||
setThemes(defaultAlgorithm);
|
||||
setMyThemes(lightDefaultTheme);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
changeMode(themeName);
|
||||
}, [themeName]);
|
||||
|
||||
useEffect(() => {
|
||||
// change lang
|
||||
i18n.changeLanguage(lang);
|
||||
}, [lang, i18n]);
|
||||
|
||||
return (
|
||||
<MyContext.Provider value={{ themeName, lang, setThemeName, setLang }}>
|
||||
<ConfigProvider locale={lang === LANG_NAME.ZH ? zhCN : enUS} theme={themes}>
|
||||
<ThemeProvider theme={myThemes}>{children}</ThemeProvider>
|
||||
</ConfigProvider>
|
||||
</MyContext.Provider>
|
||||
);
|
||||
};
|
||||
|
@ -1,17 +0,0 @@
|
||||
import React, { createContext, useState, ReactNode } from 'react';
|
||||
|
||||
export enum THEME_NAME {
|
||||
DEFAULT = 'default',
|
||||
DARK = 'dark',
|
||||
}
|
||||
|
||||
export const MyThemeContext = createContext<{ themeName: string; setThemeName: (name: THEME_NAME) => void } | null>(
|
||||
null
|
||||
);
|
||||
|
||||
export const ThemeStore: React.FC<{
|
||||
children: ReactNode;
|
||||
}> = ({ children }) => {
|
||||
const [themeName, setThemeName] = useState<string>(THEME_NAME.DEFAULT);
|
||||
return <MyThemeContext.Provider value={{ themeName, setThemeName }}>{children}</MyThemeContext.Provider>;
|
||||
};
|
@ -1,16 +1,16 @@
|
||||
import { useContext, useEffect } from 'react';
|
||||
import { useLocalStorageState } from 'ahooks';
|
||||
import { MyThemeContext, THEME_NAME } from '@/context/themeContext';
|
||||
import { MyContext, THEME_NAME } from '@/context';
|
||||
|
||||
const useThemeMode = () => {
|
||||
const useThemeMode = (): { isDark: boolean | undefined; setIsDark: (isDark: boolean) => void } => {
|
||||
const [isDark, setIsDark] = useLocalStorageState<boolean>('current-mode', { defaultValue: false });
|
||||
const { setThemeName } = useContext<any>(MyThemeContext);
|
||||
const { setThemeName } = useContext<any>(MyContext);
|
||||
|
||||
useEffect(() => {
|
||||
isDark ? setThemeName(THEME_NAME.DARK) : setThemeName(THEME_NAME.DEFAULT);
|
||||
}, [isDark, setThemeName]);
|
||||
|
||||
return [setIsDark];
|
||||
return { isDark, setIsDark };
|
||||
};
|
||||
|
||||
export default useThemeMode;
|
||||
|
@ -1,47 +0,0 @@
|
||||
import { theme } from 'antd';
|
||||
import { lightDefaultTheme } from '.';
|
||||
export const defaultAlgorithm = {
|
||||
token: {
|
||||
borderRadius: 2,
|
||||
colorPrimary: lightDefaultTheme.primary,
|
||||
fontSize: 14,
|
||||
// colorBgBase: lightDefaultTheme.backgroundColor.bg1,
|
||||
},
|
||||
components: {
|
||||
Layout: {
|
||||
bodyBg: lightDefaultTheme.backgroundColor.bg1,
|
||||
headerBg: lightDefaultTheme.backgroundColor.bgHeader,
|
||||
},
|
||||
Button: {
|
||||
fontSize: 14,
|
||||
},
|
||||
Table: {
|
||||
borderRadius: 0,
|
||||
borderRadiusLG: 0,
|
||||
padding: 10,
|
||||
paddingXS: 5,
|
||||
margin: 0,
|
||||
fontSize: 14,
|
||||
colorBorderSecondary: lightDefaultTheme.borderColor.bl1,
|
||||
paddingContentVerticalLG: 4,
|
||||
},
|
||||
Modal: {
|
||||
borderRadiusLG: 2,
|
||||
borderRadiusSM: 2,
|
||||
colorText: lightDefaultTheme.fontColor.fc3,
|
||||
borderRadius: 2,
|
||||
paddingContentHorizontalLG: 0,
|
||||
paddingMD: 0,
|
||||
},
|
||||
Menu: {
|
||||
itemBg: lightDefaultTheme.backgroundColor.bg1,
|
||||
activeBarWidth: 0,
|
||||
activeBarHeight: 0,
|
||||
activeBarBorderWidth: 0,
|
||||
subMenuItemBorderRadius: 8,
|
||||
horizontalItemBorderRadius: 8,
|
||||
itemBorderRadius: 8,
|
||||
},
|
||||
},
|
||||
algorithm: theme.defaultAlgorithm,
|
||||
};
|
Loading…
Reference in new issue