aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/theme/ThemeProvider.tsx
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-19 15:42:58 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-19 21:38:23 +0200
commit6c32ec1af90cf7df179a688617a828eddcff8052 (patch)
treeb724173cd6ef1b622f6ae86054769ecf9fca4b81 /subprojects/frontend/src/theme/ThemeProvider.tsx
parentfeat(frontend): responsive editor styling (diff)
downloadrefinery-6c32ec1af90cf7df179a688617a828eddcff8052.tar.gz
refinery-6c32ec1af90cf7df179a688617a828eddcff8052.tar.zst
refinery-6c32ec1af90cf7df179a688617a828eddcff8052.zip
refactor(frontend): update theme
Diffstat (limited to 'subprojects/frontend/src/theme/ThemeProvider.tsx')
-rw-r--r--subprojects/frontend/src/theme/ThemeProvider.tsx346
1 files changed, 217 insertions, 129 deletions
diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx
index 82b8dfa9..5bc14704 100644
--- a/subprojects/frontend/src/theme/ThemeProvider.tsx
+++ b/subprojects/frontend/src/theme/ThemeProvider.tsx
@@ -4,13 +4,15 @@ import {
4 type Components, 4 type Components,
5 type CSSObject, 5 type CSSObject,
6 responsiveFontSizes, 6 responsiveFontSizes,
7 type Theme,
7 type ThemeOptions, 8 type ThemeOptions,
8 ThemeProvider as MaterialUiThemeProvider, 9 ThemeProvider as MaterialUiThemeProvider,
9 type TypographyStyle, 10 type TypographyStyle,
10 type TypographyVariantsOptions, 11 type TypographyVariantsOptions,
12 useTheme,
11} from '@mui/material/styles'; 13} from '@mui/material/styles';
12import { observer } from 'mobx-react-lite'; 14import { observer } from 'mobx-react-lite';
13import React, { type ReactNode } from 'react'; 15import React, { type ReactNode, createContext, useContext } from 'react';
14 16
15import { useRootStore } from '../RootStore'; 17import { useRootStore } from '../RootStore';
16 18
@@ -60,34 +62,44 @@ declare module '@mui/material/styles' {
60 } 62 }
61} 63}
62 64
63function getMUIThemeOptions(darkMode: boolean): ThemeOptions { 65const typography: TypographyVariantsOptions = {
64 const typography: TypographyVariantsOptions = { 66 editor: {
65 editor: { 67 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace',
66 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace', 68 fontFeatureSettings: '"liga", "calt"',
67 fontFeatureSettings: '"liga", "calt"', 69 fontSize: '1rem',
68 fontSize: '1rem', 70 fontWeight: 400,
69 fontWeight: 400, 71 lineHeight: 1.5,
70 lineHeight: 1.5, 72 letterSpacing: 0,
71 letterSpacing: 0, 73 textRendering: 'optimizeLegibility',
72 textRendering: 'optimizeLegibility', 74 },
73 }, 75};
74 };
75 76
76 const components: Components = { 77const components: Components = {
77 MuiButton: { 78 MuiButton: {
78 styleOverrides: { 79 styleOverrides: {
79 root: { borderRadius: '50em' }, 80 root: { '&.rounded': { borderRadius: '50em' } },
80 text: { padding: '6px 16px' }, 81 text: { '&.rounded': { padding: '6px 16px' } },
81 textSizeSmall: { padding: '4px 10px' }, 82 textSizeSmall: { '&.rounded': { padding: '4px 10px' } },
82 textSizeLarge: { padding: '8px 22px' }, 83 textSizeLarge: { '&.rounded': { padding: '8px 22px' } },
83 },
84 }, 84 },
85 MuiToggleButtonGroup: { 85 },
86 styleOverrides: { 86 MuiToggleButton: {
87 groupedHorizontal: { 87 styleOverrides: {
88 borderRadius: '50em', 88 root: { '&.iconOnly': { borderRadius: '100%' } },
89 ':first-of-type': { paddingLeft: 15 }, 89 },
90 ':last-of-type': { paddingRight: 15 }, 90 },
91 MuiToggleButtonGroup: {
92 styleOverrides: {
93 root: {
94 '&.rounded .MuiToggleButtonGroup-groupedHorizontal': {
95 ':first-of-type': {
96 paddingLeft: 15,
97 borderRadius: '50em 0 0 50em',
98 },
99 ':last-of-type': {
100 paddingRight: 15,
101 borderRadius: '0 50em 50em 0',
102 },
91 '&.MuiToggleButton-sizeSmall': { 103 '&.MuiToggleButton-sizeSmall': {
92 ':first-of-type': { paddingLeft: 9 }, 104 ':first-of-type': { paddingLeft: 9 },
93 ':last-of-type': { paddingRight: 9 }, 105 ':last-of-type': { paddingRight: 9 },
@@ -99,122 +111,198 @@ function getMUIThemeOptions(darkMode: boolean): ThemeOptions {
99 }, 111 },
100 }, 112 },
101 }, 113 },
114 },
115 MuiTooltip: {
116 styleOverrides: {
117 tooltip: {
118 background: alpha('#212121', 0.93),
119 color: '#fff',
120 },
121 arrow: {
122 color: alpha('#212121', 0.93),
123 },
124 },
125 },
126};
127
128function createResponsiveTheme(options: ThemeOptions): Theme {
129 return responsiveFontSizes(createTheme(options));
130}
131
132const lightTheme = createResponsiveTheme({
133 typography,
134 components,
135 palette: {
136 mode: 'light',
137 primary: { main: '#038a99' },
138 secondary: { main: '#e45649' },
139 error: { main: '#ca1243' },
140 warning: { main: '#c18401' },
141 success: { main: '#50a14f' },
142 info: { main: '#4078f2' },
143 background: {
144 default: '#ffffff',
145 paper: '#ffffff',
146 },
147 text: {
148 primary: '#35373e',
149 secondary: '#696c77',
150 disabled: '#8e8f97',
151 },
152 divider: alpha('#35373e', 0.21),
153 outer: {
154 background: '#fafafa',
155 border: '#d4d4d6',
156 },
157 highlight: {
158 number: '#0084bc',
159 parameter: '#6a3e3e',
160 comment: '#8e8f97',
161 activeLine: '#fafafa',
162 selection: '#c8e4fb',
163 lineNumber: '#8e8f97',
164 foldPlaceholder: alpha('#35373e', 0.08),
165 activeLintRange: alpha('#f2a60d', 0.28),
166 occurences: {
167 read: alpha('#35373e', 0.16),
168 write: alpha('#35373e', 0.16),
169 },
170 search: {
171 match: '#00bcd4',
172 selected: '#d500f9',
173 contrastText: '#ffffff',
174 },
175 },
176 },
177});
178
179const darkTheme = createResponsiveTheme({
180 typography,
181 components: {
182 ...components,
183 MuiSnackbarContent: {
184 styleOverrides: {
185 root: {
186 color: '#f00',
187 backgroundColor: '#000',
188 border: `10px solid #ff0`,
189 },
190 },
191 },
102 MuiTooltip: { 192 MuiTooltip: {
193 ...(components.MuiTooltip || {}),
103 styleOverrides: { 194 styleOverrides: {
195 ...(components.MuiTooltip?.styleOverrides || {}),
104 tooltip: { 196 tooltip: {
105 background: alpha('#212121', 0.93), 197 ...((components.MuiTooltip?.styleOverrides?.tooltip as
106 color: '#fff', 198 | CSSObject
107 }, 199 | undefined) || {}),
108 arrow: { 200 color: '#ebebff',
109 color: alpha('#212121', 0.93),
110 }, 201 },
111 }, 202 },
112 }, 203 },
113 }; 204 },
205 palette: {
206 mode: 'dark',
207 primary: { main: '#56b6c2' },
208 secondary: { main: '#be5046' },
209 error: { main: '#e06c75' },
210 warning: { main: '#e5c07b' },
211 success: { main: '#98c379' },
212 info: { main: '#61afef' },
213 background: {
214 default: '#282c34',
215 paper: '#21252b',
216 },
217 text: {
218 primary: '#ebebff',
219 secondary: '#abb2bf',
220 disabled: '#828997',
221 },
222 divider: alpha('#abb2bf', 0.24),
223 outer: {
224 background: '#21252b',
225 border: '#181a1f',
226 },
227 highlight: {
228 number: '#6188a6',
229 parameter: '#c8ae9d',
230 comment: '#828997',
231 activeLine: '#21252b',
232 selection: '#3e4453',
233 lineNumber: '#828997',
234 foldPlaceholder: alpha('#ebebff', 0.12),
235 activeLintRange: alpha('#fbc346', 0.28),
236 occurences: {
237 read: alpha('#ebebff', 0.24),
238 write: alpha('#ebebff', 0.24),
239 },
240 search: {
241 match: '#33eaff',
242 selected: '#dd33fa',
243 contrastText: '#21252b',
244 },
245 },
246 },
247});
114 248
115 return darkMode 249const ContrastThemeContext = createContext<Theme | undefined>(undefined);
116 ? { 250
117 typography, 251function ThemeAndContrastThemeProvider({
118 components: { 252 theme,
119 ...components, 253 contrastTheme,
120 MuiTooltip: { 254 children,
121 ...(components.MuiTooltip || {}), 255}: {
122 styleOverrides: { 256 theme: Theme;
123 ...(components.MuiTooltip?.styleOverrides || {}), 257 contrastTheme: Theme;
124 tooltip: { 258 children?: ReactNode;
125 ...((components.MuiTooltip?.styleOverrides?.tooltip as 259}): JSX.Element {
126 | CSSObject 260 return (
127 | undefined) || {}), 261 <MaterialUiThemeProvider theme={theme}>
128 color: '#ebebff', 262 <ContrastThemeContext.Provider value={contrastTheme}>
129 }, 263 {children}
130 }, 264 </ContrastThemeContext.Provider>
131 }, 265 </MaterialUiThemeProvider>
132 }, 266 );
133 palette: {
134 mode: 'dark',
135 primary: { main: '#56b6c2' },
136 error: { main: '#e06c75' },
137 warning: { main: '#e5c07b' },
138 success: { main: '#57a470' },
139 info: { main: '#52b8ff' },
140 background: {
141 default: '#282c34',
142 paper: '#21252b',
143 },
144 text: {
145 primary: '#ebebff',
146 secondary: '#abb2bf',
147 disabled: '#4b5263',
148 },
149 divider: alpha('#abb2bf', 0.16),
150 outer: {
151 background: '#21252b',
152 border: '#181a1f',
153 },
154 highlight: {
155 number: '#6188a6',
156 parameter: '#c8ae9d',
157 comment: '#6b717d',
158 activeLine: '#21252b',
159 selection: '#3e4453',
160 lineNumber: '#4b5263',
161 foldPlaceholder: alpha('#ebebff', 0.12),
162 activeLintRange: alpha('#fbc346', 0.28),
163 occurences: {
164 read: alpha('#ebebff', 0.24),
165 write: alpha('#ebebff', 0.24),
166 },
167 search: {
168 match: '#33eaff',
169 selected: '#dd33fa',
170 contrastText: '#21252b',
171 },
172 },
173 },
174 }
175 : {
176 typography,
177 components,
178 palette: {
179 mode: 'light',
180 primary: { main: '#0398a8' },
181 outer: {
182 background: '#f5f5f5',
183 border: '#cacaca',
184 },
185 highlight: {
186 number: '#3d79a2',
187 parameter: '#6a3e3e',
188 comment: 'rgba(0, 0, 0, 0.38)',
189 activeLine: '#f5f5f5',
190 selection: '#c8e4fb',
191 lineNumber: 'rgba(0, 0, 0, 0.38)',
192 foldPlaceholder: 'rgba(0, 0, 0, 0.12)',
193 activeLintRange: alpha('#ed6c02', 0.24),
194 occurences: {
195 read: 'rgba(0, 0, 0, 0.12)',
196 write: 'rgba(0, 0, 0, 0.12)',
197 },
198 search: {
199 match: '#00bcd4',
200 selected: '#d500f9',
201 contrastText: '#ffffff',
202 },
203 },
204 },
205 };
206} 267}
207 268
208function ThemeProvider({ children }: { children?: ReactNode }) { 269ThemeAndContrastThemeProvider.defaultProps = {
270 children: undefined,
271};
272
273export function ContrastThemeProvider({
274 children,
275}: {
276 children?: ReactNode;
277}): JSX.Element {
278 const theme = useTheme();
279 const contrastTheme = useContext(ContrastThemeContext);
280 if (!contrastTheme) {
281 throw new Error('ContrastThemeProvider must be used within ThemeProvider');
282 }
283 return (
284 <ThemeAndContrastThemeProvider theme={contrastTheme} contrastTheme={theme}>
285 {children}
286 </ThemeAndContrastThemeProvider>
287 );
288}
289
290ContrastThemeProvider.defaultProps = {
291 children: undefined,
292};
293
294function ThemeProvider({ children }: { children?: ReactNode }): JSX.Element {
209 const { 295 const {
210 themeStore: { darkMode }, 296 themeStore: { darkMode },
211 } = useRootStore(); 297 } = useRootStore();
212 298
213 const themeOptions = getMUIThemeOptions(darkMode);
214 const theme = responsiveFontSizes(createTheme(themeOptions));
215
216 return ( 299 return (
217 <MaterialUiThemeProvider theme={theme}>{children}</MaterialUiThemeProvider> 300 <ThemeAndContrastThemeProvider
301 theme={darkMode ? darkTheme : lightTheme}
302 contrastTheme={darkMode ? lightTheme : darkTheme}
303 >
304 {children}
305 </ThemeAndContrastThemeProvider>
218 ); 306 );
219} 307}
220 308