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 {
|
export enum THEME_NAME {
|
||||||
DEFAULT = 'default',
|
DEFAULT = 'default',
|
||||||
DARK = 'dark',
|
DARK = 'dark',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StoreContext = createContext<{
|
export enum LANG_NAME {
|
||||||
|
ZH = 'zh',
|
||||||
|
EN = 'en',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MyContext = createContext<{
|
||||||
themeName: string;
|
themeName: string;
|
||||||
|
lang: LANG_NAME;
|
||||||
setThemeName: (name: THEME_NAME) => void;
|
setThemeName: (name: THEME_NAME) => void;
|
||||||
|
setLang: (lang: LANG_NAME) => void;
|
||||||
} | null>(null);
|
} | null>(null);
|
||||||
|
|
||||||
export const Store: React.FC<{
|
export const MyStore: React.FC<{
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}> = ({ children }) => {
|
}> = ({ children }) => {
|
||||||
const [themeName, setThemeName] = useState<string>(THEME_NAME.DEFAULT);
|
const [themeName, setThemeName] = useState<THEME_NAME>(THEME_NAME.DEFAULT);
|
||||||
return <StoreContext.Provider value={{ themeName, setThemeName }}>{children}</StoreContext.Provider>;
|
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 { useContext, useEffect } from 'react';
|
||||||
import { useLocalStorageState } from 'ahooks';
|
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 [isDark, setIsDark] = useLocalStorageState<boolean>('current-mode', { defaultValue: false });
|
||||||
const { setThemeName } = useContext<any>(MyThemeContext);
|
const { setThemeName } = useContext<any>(MyContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
isDark ? setThemeName(THEME_NAME.DARK) : setThemeName(THEME_NAME.DEFAULT);
|
isDark ? setThemeName(THEME_NAME.DARK) : setThemeName(THEME_NAME.DEFAULT);
|
||||||
}, [isDark, setThemeName]);
|
}, [isDark, setThemeName]);
|
||||||
|
|
||||||
return [setIsDark];
|
return { isDark, setIsDark };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useThemeMode;
|
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