Add theme i18n component
This commit is contained in:
parent
0eb0b6f7f5
commit
6ee85aff1b
1960
package-lock.json
generated
1960
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -39,6 +39,7 @@
|
|||||||
"webpack-dev-server": "^4.7.2"
|
"webpack-dev-server": "^4.7.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fluentui/react": "^8.56.0",
|
||||||
"@juggle/resize-observer": "^3.3.1",
|
"@juggle/resize-observer": "^3.3.1",
|
||||||
"gl-matrix": "^3.4.3",
|
"gl-matrix": "^3.4.3",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
|
@ -14,6 +14,9 @@ class HeaderBar extends Component<IHeaderBarProps & IMixinSettingProps> {
|
|||||||
this.props.setting.setProps("themes",
|
this.props.setting.setProps("themes",
|
||||||
this.props.setting.themes === Themes.dark ? Themes.light : Themes.dark
|
this.props.setting.themes === Themes.dark ? Themes.light : Themes.dark
|
||||||
);
|
);
|
||||||
|
this.props.setting.setProps("language",
|
||||||
|
this.props.setting.language === "EN_US" ?'ZH_CN' : "EN_US"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
7
source/Component/Localization/Localization.scss
Normal file
7
source/Component/Localization/Localization.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
span.ZH_CN {
|
||||||
|
font-family: 'Microsoft Yahei', Verdana, Simsun, 'Segoe UI', Tahoma, Arial, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
span.EN_US {
|
||||||
|
font-family: 'Segoe UI Web Regular', 'Segoe UI', 'Segoe WP', Tahoma, Arial, sans-serif;
|
||||||
|
}
|
70
source/Component/Localization/Localization.tsx
Normal file
70
source/Component/Localization/Localization.tsx
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react";
|
||||||
|
import { useSetting, IMixinSettingProps, Language } from "@Context/Setting";
|
||||||
|
import "./Localization.scss";
|
||||||
|
|
||||||
|
import EN_US from "../../Localization/EN-US";
|
||||||
|
import ZH_CN from "../../Localization/ZH-CN";
|
||||||
|
|
||||||
|
const LanguageDataBase = {
|
||||||
|
EN_US, ZH_CN
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ILocalizationProps {
|
||||||
|
className?: string;
|
||||||
|
i18nKey: keyof typeof EN_US;
|
||||||
|
options?: Record<string, string>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function I18N(language: Language, key: keyof typeof EN_US, values?: Record<string, string>) {
|
||||||
|
let i18nValue = LanguageDataBase[language][key];
|
||||||
|
if (values) {
|
||||||
|
for (let valueKey in values) {
|
||||||
|
i18nValue = i18nValue.replaceAll(new RegExp(`\\{\\s*${valueKey}\\s*\\}`, "g"), values[valueKey]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return i18nValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地化组件
|
||||||
|
*/
|
||||||
|
@useSetting
|
||||||
|
class Localization extends Component<ILocalizationProps & IMixinSettingProps &
|
||||||
|
DetailedHTMLProps<
|
||||||
|
HTMLAttributes<HTMLSpanElement>, HTMLSpanElement
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
|
||||||
|
private handelLanguageChange = () => {
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
if (this.props.setting) {
|
||||||
|
this.props.setting.on("language", this.handelLanguageChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
if (this.props.setting) {
|
||||||
|
this.props.setting.off("language", this.handelLanguageChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
let language: Language = this.props.setting ? this.props.setting.language : "EN_US";
|
||||||
|
let classNameList: string[] = [];
|
||||||
|
if (this.props.className) classNameList.push(this.props.className);
|
||||||
|
classNameList.push(language);
|
||||||
|
let safeProps = {...this.props};
|
||||||
|
delete safeProps.className;
|
||||||
|
delete safeProps.setting;
|
||||||
|
delete (safeProps as any).i18nKey;
|
||||||
|
delete safeProps.options;
|
||||||
|
return <span {...safeProps} className={classNameList.join(" ")}>
|
||||||
|
{I18N(language, this.props.i18nKey, this.props.options)}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Localization, I18N };
|
80
source/Component/Theme/Theme.scss
Normal file
80
source/Component/Theme/Theme.scss
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
@import "@fluentui/react/dist/sass/References";
|
||||||
|
|
||||||
|
$lt-font-size-normal: $ms-font-size-14;
|
||||||
|
$lt-font-size-lvl3: $ms-font-size-18;
|
||||||
|
$lt-font-size-lvl2: $ms-font-size-24;
|
||||||
|
$lt-font-size-lvl1: $ms-font-size-32;
|
||||||
|
|
||||||
|
$lt-font-weight-normal: $ms-font-weight-regular;
|
||||||
|
$lt-font-weight-lvl3: $ms-font-weight-semibold;
|
||||||
|
$lt-font-weight-lvl2: $ms-font-weight-semibold;
|
||||||
|
$lt-font-weight-lvl1: $ms-font-weight-bold;
|
||||||
|
|
||||||
|
// 背景颜色
|
||||||
|
$lt-bg-color-lvl1-dark: $ms-color-gray140;
|
||||||
|
$lt-bg-color-lvl2-dark: $ms-color-gray150;
|
||||||
|
$lt-bg-color-lvl3-dark: $ms-color-gray160;
|
||||||
|
$lt-bg-color-lvl4-dark: $ms-color-gray180;
|
||||||
|
$lt-bg-color-lvl5-dark: $ms-color-gray200;
|
||||||
|
|
||||||
|
// 文字颜色
|
||||||
|
$lt-font-color-normal-dark: $ms-color-gray110;
|
||||||
|
$lt-font-color-lvl3-dark: $ms-color-gray100;
|
||||||
|
$lt-font-color-lvl2-dark: $ms-color-gray100;
|
||||||
|
$lt-font-color-lvl1-dark: $ms-color-gray90;
|
||||||
|
|
||||||
|
// 背景颜色
|
||||||
|
$lt-bg-color-lvl1-light: $ms-color-gray10;
|
||||||
|
$lt-bg-color-lvl2-light: $ms-color-gray20;
|
||||||
|
$lt-bg-color-lvl3-light: $ms-color-gray30;
|
||||||
|
$lt-bg-color-lvl4-light: $ms-color-gray50;
|
||||||
|
$lt-bg-color-lvl5-light: $ms-color-gray70;
|
||||||
|
|
||||||
|
// 文字颜色
|
||||||
|
$lt-font-color-normal-light: $ms-color-gray130;
|
||||||
|
$lt-font-color-lvl3-light: $ms-color-gray140;
|
||||||
|
$lt-font-color-lvl2-light: $ms-color-gray140;
|
||||||
|
$lt-font-color-lvl1-light: $ms-color-gray150;
|
||||||
|
|
||||||
|
div.dark, div.light {
|
||||||
|
transition: all 300ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dark.background-lvl1 { background-color: $lt-bg-color-lvl1-dark; }
|
||||||
|
div.dark.background-lvl2 { background-color: $lt-bg-color-lvl2-dark; }
|
||||||
|
div.dark.background-lvl3 { background-color: $lt-bg-color-lvl3-dark; }
|
||||||
|
div.dark.background-lvl4 { background-color: $lt-bg-color-lvl4-dark; }
|
||||||
|
div.dark.background-lvl5 { background-color: $lt-bg-color-lvl5-dark; }
|
||||||
|
|
||||||
|
div.light.background-lvl1 { background-color: $lt-bg-color-lvl1-light; }
|
||||||
|
div.light.background-lvl2 { background-color: $lt-bg-color-lvl2-light; }
|
||||||
|
div.light.background-lvl3 { background-color: $lt-bg-color-lvl3-light; }
|
||||||
|
div.light.background-lvl4 { background-color: $lt-bg-color-lvl4-light; }
|
||||||
|
div.light.background-lvl5 { background-color: $lt-bg-color-lvl5-light; }
|
||||||
|
|
||||||
|
div.font-normal {
|
||||||
|
font-size: $lt-font-size-normal;
|
||||||
|
font-weight: $lt-font-weight-normal;
|
||||||
|
}
|
||||||
|
div.font-lvl3 {
|
||||||
|
font-size: $lt-font-size-lvl3;
|
||||||
|
font-weight: $lt-font-weight-lvl3;
|
||||||
|
}
|
||||||
|
div.font-lvl2 {
|
||||||
|
font-size: $lt-font-size-lvl2;
|
||||||
|
font-weight: $lt-font-weight-lvl2;
|
||||||
|
}
|
||||||
|
div.font-lvl1 {
|
||||||
|
font-size: $lt-font-size-lvl1;
|
||||||
|
font-weight: $lt-font-weight-lvl1;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.dark.font-normal { color: $lt-font-color-normal-dark; }
|
||||||
|
div.dark.font-lvl3 { color: $lt-font-color-lvl3-dark; }
|
||||||
|
div.dark.font-lvl2 { color: $lt-font-color-lvl2-dark; }
|
||||||
|
div.dark.font-lvl1 { color: $lt-font-color-lvl1-dark; }
|
||||||
|
|
||||||
|
div.light.font-normal { color: $lt-font-color-normal-light; }
|
||||||
|
div.light.font-lvl3 { color: $lt-font-color-lvl3-light; }
|
||||||
|
div.light.font-lvl2 { color: $lt-font-color-lvl2-light; }
|
||||||
|
div.light.font-lvl1 { color: $lt-font-color-lvl1-light; }
|
85
source/Component/Theme/Theme.tsx
Normal file
85
source/Component/Theme/Theme.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import { useSetting, Themes, IMixinSettingProps } from "@Context/Setting";
|
||||||
|
import { Component, ReactNode, DetailedHTMLProps, HTMLAttributes } from "react";
|
||||||
|
import "./Theme.scss";
|
||||||
|
|
||||||
|
enum FontLevel {
|
||||||
|
normal = "normal",
|
||||||
|
Level3 = "lvl3",
|
||||||
|
Level2 = "lvl2",
|
||||||
|
Level1 = "lvl1"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum BackgroundLevel {
|
||||||
|
Level5 = "lvl5",
|
||||||
|
Level4 = "lvl4",
|
||||||
|
Level3 = "lvl3",
|
||||||
|
Level2 = "lvl2",
|
||||||
|
Level1 = "lvl1"
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IThemeProps {
|
||||||
|
className?: string;
|
||||||
|
fontLevel?: FontLevel;
|
||||||
|
backgroundLevel?: BackgroundLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 主题切换
|
||||||
|
*/
|
||||||
|
@useSetting
|
||||||
|
class Theme extends Component<
|
||||||
|
IThemeProps & IMixinSettingProps & DetailedHTMLProps<
|
||||||
|
HTMLAttributes<HTMLDivElement>, HTMLDivElement
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
|
||||||
|
private handelThemeChange = () => {
|
||||||
|
this.forceUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentDidMount() {
|
||||||
|
if (this.props.setting) {
|
||||||
|
this.props.setting.on("themes", this.handelThemeChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillUnmount() {
|
||||||
|
if (this.props.setting) {
|
||||||
|
this.props.setting.off("themes", this.handelThemeChange);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): ReactNode {
|
||||||
|
|
||||||
|
const setting = this.props.setting;
|
||||||
|
const classNameList: string[] = [];
|
||||||
|
|
||||||
|
if (this.props.className) {
|
||||||
|
classNameList.push(this.props.className);
|
||||||
|
}
|
||||||
|
|
||||||
|
const theme = setting ? setting.themes : Themes.dark;
|
||||||
|
classNameList.push(theme === Themes.light ? "light" : "dark");
|
||||||
|
|
||||||
|
if (this.props.fontLevel) {
|
||||||
|
classNameList.push(`font-${this.props.fontLevel}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.backgroundLevel) {
|
||||||
|
classNameList.push(`background-${this.props.backgroundLevel}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const propsObj = {...this.props};
|
||||||
|
delete propsObj.className;
|
||||||
|
delete propsObj.setting;
|
||||||
|
delete propsObj.backgroundLevel;
|
||||||
|
delete propsObj.fontLevel;
|
||||||
|
|
||||||
|
return <div {...propsObj} className={`${classNameList.join(" ")}`}>
|
||||||
|
{ this.props.children }
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Theme;
|
||||||
|
export { Theme, FontLevel, BackgroundLevel };
|
@ -9,6 +9,8 @@ enum Themes {
|
|||||||
dark = 2
|
dark = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Language = "ZH_CN" | "EN_US";
|
||||||
|
|
||||||
class Setting extends Emitter<
|
class Setting extends Emitter<
|
||||||
Setting & {change: keyof Setting}
|
Setting & {change: keyof Setting}
|
||||||
> {
|
> {
|
||||||
@ -16,7 +18,12 @@ class Setting extends Emitter<
|
|||||||
/**
|
/**
|
||||||
* 主题
|
* 主题
|
||||||
*/
|
*/
|
||||||
public themes: Themes = Themes.light;
|
public themes: Themes = Themes.dark;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语言
|
||||||
|
*/
|
||||||
|
public language: Language = "EN_US";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置参数
|
* 设置参数
|
||||||
@ -53,6 +60,6 @@ function useSetting<R extends RenderComponent>(components: R): R {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Themes, Setting, SettingContext, useSetting,
|
Themes, Setting, SettingContext, useSetting, Language,
|
||||||
IMixinSettingProps, SettingProvider, SettingConsumer
|
IMixinSettingProps, SettingProvider, SettingConsumer
|
||||||
};
|
};
|
5
source/Localization/EN-US.ts
Normal file
5
source/Localization/EN-US.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const EN_US = {
|
||||||
|
"EN_US": "English (US)",
|
||||||
|
"ZH_CN": "Chinese (Simplified)"
|
||||||
|
}
|
||||||
|
export default EN_US;
|
5
source/Localization/ZH-CN.ts
Normal file
5
source/Localization/ZH-CN.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
const ZH_CN = {
|
||||||
|
"EN_US": "英语 (美国)",
|
||||||
|
"ZH_CN": "中文 (简体)"
|
||||||
|
}
|
||||||
|
export default ZH_CN;
|
@ -1,6 +1,8 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { SettingProvider, Setting } from "@Context/Setting";
|
import { SettingProvider, Setting } from "@Context/Setting";
|
||||||
import { HeaderBar } from "@Component/HeaderBar/HeaderBar";
|
import { HeaderBar } from "@Component/HeaderBar/HeaderBar";
|
||||||
|
import { Theme, FontLevel, BackgroundLevel } from "@Component/Theme/Theme";
|
||||||
|
import { Localization } from "@Component/Localization/Localization";
|
||||||
import { Entry } from "../Entry/Entry";
|
import { Entry } from "../Entry/Entry";
|
||||||
import "./SimulatorWeb.scss";
|
import "./SimulatorWeb.scss";
|
||||||
|
|
||||||
@ -22,6 +24,14 @@ class SimulatorWeb extends Component {
|
|||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
return <SettingProvider value={this.setting}>
|
return <SettingProvider value={this.setting}>
|
||||||
<HeaderBar/>
|
<HeaderBar/>
|
||||||
|
<Theme
|
||||||
|
className="test"
|
||||||
|
fontLevel={FontLevel.Level2}
|
||||||
|
backgroundLevel={BackgroundLevel.Level1}
|
||||||
|
>
|
||||||
|
Theme
|
||||||
|
</Theme>
|
||||||
|
<Localization i18nKey="EN_US"/>
|
||||||
</SettingProvider>
|
</SettingProvider>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
"compileOnSave": true,
|
"compileOnSave": true,
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
|
"resolveJsonModule": true,
|
||||||
"alwaysStrict": true,
|
"alwaysStrict": true,
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
Loading…
Reference in New Issue
Block a user