diff options
Diffstat (limited to 'subprojects/frontend/src/theme')
-rw-r--r-- | subprojects/frontend/src/theme/EditorTheme.ts | 47 | ||||
-rw-r--r-- | subprojects/frontend/src/theme/ThemeProvider.tsx | 15 | ||||
-rw-r--r-- | subprojects/frontend/src/theme/ThemeStore.ts | 64 |
3 files changed, 126 insertions, 0 deletions
diff --git a/subprojects/frontend/src/theme/EditorTheme.ts b/subprojects/frontend/src/theme/EditorTheme.ts new file mode 100644 index 00000000..294192fa --- /dev/null +++ b/subprojects/frontend/src/theme/EditorTheme.ts | |||
@@ -0,0 +1,47 @@ | |||
1 | import type { PaletteMode } from '@mui/material'; | ||
2 | |||
3 | import cssVariables from '../themeVariables.module.scss'; | ||
4 | |||
5 | export enum EditorTheme { | ||
6 | Light, | ||
7 | Dark, | ||
8 | } | ||
9 | |||
10 | export class EditorThemeData { | ||
11 | className: string; | ||
12 | |||
13 | paletteMode: PaletteMode; | ||
14 | |||
15 | toggleDarkMode: EditorTheme; | ||
16 | |||
17 | foreground!: string; | ||
18 | |||
19 | foregroundHighlight!: string; | ||
20 | |||
21 | background!: string; | ||
22 | |||
23 | primary!: string; | ||
24 | |||
25 | secondary!: string; | ||
26 | |||
27 | constructor(className: string, paletteMode: PaletteMode, toggleDarkMode: EditorTheme) { | ||
28 | this.className = className; | ||
29 | this.paletteMode = paletteMode; | ||
30 | this.toggleDarkMode = toggleDarkMode; | ||
31 | Reflect.ownKeys(this).forEach((key) => { | ||
32 | if (!Reflect.get(this, key)) { | ||
33 | const cssKey = `${this.className}--${key.toString()}`; | ||
34 | if (cssKey in cssVariables) { | ||
35 | Reflect.set(this, key, cssVariables[cssKey]); | ||
36 | } | ||
37 | } | ||
38 | }); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | export const DEFAULT_THEME = EditorTheme.Dark; | ||
43 | |||
44 | export const EDITOR_THEMES: { [key in EditorTheme]: EditorThemeData } = { | ||
45 | [EditorTheme.Light]: new EditorThemeData('light', 'light', EditorTheme.Dark), | ||
46 | [EditorTheme.Dark]: new EditorThemeData('dark', 'dark', EditorTheme.Light), | ||
47 | }; | ||
diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx new file mode 100644 index 00000000..f5b50be1 --- /dev/null +++ b/subprojects/frontend/src/theme/ThemeProvider.tsx | |||
@@ -0,0 +1,15 @@ | |||
1 | import { observer } from 'mobx-react-lite'; | ||
2 | import { ThemeProvider as MaterialUiThemeProvider } from '@mui/material/styles'; | ||
3 | import React from 'react'; | ||
4 | |||
5 | import { useRootStore } from '../RootStore'; | ||
6 | |||
7 | export const ThemeProvider: React.FC = observer(({ children }) => { | ||
8 | const { themeStore } = useRootStore(); | ||
9 | |||
10 | return ( | ||
11 | <MaterialUiThemeProvider theme={themeStore.materialUiTheme}> | ||
12 | {children} | ||
13 | </MaterialUiThemeProvider> | ||
14 | ); | ||
15 | }); | ||
diff --git a/subprojects/frontend/src/theme/ThemeStore.ts b/subprojects/frontend/src/theme/ThemeStore.ts new file mode 100644 index 00000000..ffaf6dde --- /dev/null +++ b/subprojects/frontend/src/theme/ThemeStore.ts | |||
@@ -0,0 +1,64 @@ | |||
1 | import { makeAutoObservable } from 'mobx'; | ||
2 | import { | ||
3 | Theme, | ||
4 | createTheme, | ||
5 | responsiveFontSizes, | ||
6 | } from '@mui/material/styles'; | ||
7 | |||
8 | import { | ||
9 | EditorTheme, | ||
10 | EditorThemeData, | ||
11 | DEFAULT_THEME, | ||
12 | EDITOR_THEMES, | ||
13 | } from './EditorTheme'; | ||
14 | |||
15 | export class ThemeStore { | ||
16 | currentTheme: EditorTheme = DEFAULT_THEME; | ||
17 | |||
18 | constructor() { | ||
19 | makeAutoObservable(this); | ||
20 | } | ||
21 | |||
22 | toggleDarkMode(): void { | ||
23 | this.currentTheme = this.currentThemeData.toggleDarkMode; | ||
24 | } | ||
25 | |||
26 | private get currentThemeData(): EditorThemeData { | ||
27 | return EDITOR_THEMES[this.currentTheme]; | ||
28 | } | ||
29 | |||
30 | get materialUiTheme(): Theme { | ||
31 | const themeData = this.currentThemeData; | ||
32 | const materialUiTheme = createTheme({ | ||
33 | palette: { | ||
34 | mode: themeData.paletteMode, | ||
35 | background: { | ||
36 | default: themeData.background, | ||
37 | paper: themeData.background, | ||
38 | }, | ||
39 | primary: { | ||
40 | main: themeData.primary, | ||
41 | }, | ||
42 | secondary: { | ||
43 | main: themeData.secondary, | ||
44 | }, | ||
45 | error: { | ||
46 | main: themeData.secondary, | ||
47 | }, | ||
48 | text: { | ||
49 | primary: themeData.foregroundHighlight, | ||
50 | secondary: themeData.foreground, | ||
51 | }, | ||
52 | }, | ||
53 | }); | ||
54 | return responsiveFontSizes(materialUiTheme); | ||
55 | } | ||
56 | |||
57 | get darkMode(): boolean { | ||
58 | return this.currentThemeData.paletteMode === 'dark'; | ||
59 | } | ||
60 | |||
61 | get className(): string { | ||
62 | return this.currentThemeData.className; | ||
63 | } | ||
64 | } | ||