aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-13 23:49:06 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-15 18:03:58 +0200
commitc7abf6e90285857344d7e4f85553a89df971fc3c (patch)
tree1e86b700d7314a40c26612e2f6aa54de19f86108 /subprojects/frontend
parentfeat(frontend): light/dark mode switch (diff)
downloadrefinery-c7abf6e90285857344d7e4f85553a89df971fc3c.tar.gz
refinery-c7abf6e90285857344d7e4f85553a89df971fc3c.tar.zst
refinery-c7abf6e90285857344d7e4f85553a89df971fc3c.zip
refactor(frondend): dark theme tweaks
Diffstat (limited to 'subprojects/frontend')
-rw-r--r--subprojects/frontend/package.json5
-rw-r--r--subprojects/frontend/src/App.tsx12
-rw-r--r--subprojects/frontend/src/TopBar.tsx20
-rw-r--r--subprojects/frontend/src/editor/EditorButtons.tsx34
-rw-r--r--subprojects/frontend/src/editor/EditorParent.ts46
-rw-r--r--subprojects/frontend/src/editor/GenerateButton.tsx7
-rw-r--r--subprojects/frontend/src/theme/ThemeProvider.tsx66
-rw-r--r--subprojects/frontend/vite.config.ts2
8 files changed, 108 insertions, 84 deletions
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json
index d5e9bef4..9bfcbad4 100644
--- a/subprojects/frontend/package.json
+++ b/subprojects/frontend/package.json
@@ -31,6 +31,7 @@
31 "@codemirror/view": "^6.2.0", 31 "@codemirror/view": "^6.2.0",
32 "@emotion/react": "^11.10.0", 32 "@emotion/react": "^11.10.0",
33 "@emotion/styled": "^11.10.0", 33 "@emotion/styled": "^11.10.0",
34 "@fontsource/inter": "^4.5.12",
34 "@fontsource/jetbrains-mono": "^4.5.10", 35 "@fontsource/jetbrains-mono": "^4.5.10",
35 "@fontsource/roboto": "^4.5.8", 36 "@fontsource/roboto": "^4.5.8",
36 "@lezer/common": "^1.0.0", 37 "@lezer/common": "^1.0.0",
@@ -52,7 +53,7 @@
52 "devDependencies": { 53 "devDependencies": {
53 "@lezer/generator": "^1.1.1", 54 "@lezer/generator": "^1.1.1",
54 "@types/eslint": "^8.4.5", 55 "@types/eslint": "^8.4.5",
55 "@types/node": "^18.7.2", 56 "@types/node": "^18.7.3",
56 "@types/prettier": "^2.7.0", 57 "@types/prettier": "^2.7.0",
57 "@types/react": "^18.0.17", 58 "@types/react": "^18.0.17",
58 "@types/react-dom": "^18.0.6", 59 "@types/react-dom": "^18.0.6",
@@ -64,7 +65,7 @@
64 "eslint-config-airbnb": "^19.0.4", 65 "eslint-config-airbnb": "^19.0.4",
65 "eslint-config-airbnb-typescript": "^17.0.0", 66 "eslint-config-airbnb-typescript": "^17.0.0",
66 "eslint-config-prettier": "^8.5.0", 67 "eslint-config-prettier": "^8.5.0",
67 "eslint-import-resolver-typescript": "^3.4.0", 68 "eslint-import-resolver-typescript": "^3.4.1",
68 "eslint-plugin-import": "^2.26.0", 69 "eslint-plugin-import": "^2.26.0",
69 "eslint-plugin-jsx-a11y": "^6.6.1", 70 "eslint-plugin-jsx-a11y": "^6.6.1",
70 "eslint-plugin-prettier": "^4.2.1", 71 "eslint-plugin-prettier": "^4.2.1",
diff --git a/subprojects/frontend/src/App.tsx b/subprojects/frontend/src/App.tsx
index 12cf9311..12c66eb9 100644
--- a/subprojects/frontend/src/App.tsx
+++ b/subprojects/frontend/src/App.tsx
@@ -1,4 +1,5 @@
1import Box from '@mui/material/Box'; 1import Box from '@mui/material/Box';
2import Toolbar from '@mui/material/Toolbar';
2import React from 'react'; 3import React from 'react';
3 4
4import TopBar from './TopBar'; 5import TopBar from './TopBar';
@@ -10,16 +11,11 @@ export default function App(): JSX.Element {
10 return ( 11 return (
11 <Box display="flex" flexDirection="column" sx={{ height: '100vh' }}> 12 <Box display="flex" flexDirection="column" sx={{ height: '100vh' }}>
12 <TopBar /> 13 <TopBar />
13 <Box 14 <Toolbar variant="dense">
14 display="flex"
15 justifyContent="space-between"
16 alignItems="center"
17 p={1}
18 >
19 <EditorButtons /> 15 <EditorButtons />
20 <GenerateButton /> 16 <GenerateButton />
21 </Box> 17 </Toolbar>
22 <Box flexGrow={1} flexShrink={1} sx={{ overflow: 'auto' }}> 18 <Box flexGrow={1} flexShrink={1} overflow="auto">
23 <EditorArea /> 19 <EditorArea />
24 </Box> 20 </Box>
25 </Box> 21 </Box>
diff --git a/subprojects/frontend/src/TopBar.tsx b/subprojects/frontend/src/TopBar.tsx
index 5ac74e7a..af571a1e 100644
--- a/subprojects/frontend/src/TopBar.tsx
+++ b/subprojects/frontend/src/TopBar.tsx
@@ -1,6 +1,4 @@
1import MenuIcon from '@mui/icons-material/Menu';
2import AppBar from '@mui/material/AppBar'; 1import AppBar from '@mui/material/AppBar';
3import IconButton from '@mui/material/IconButton';
4import Toolbar from '@mui/material/Toolbar'; 2import Toolbar from '@mui/material/Toolbar';
5import Typography from '@mui/material/Typography'; 3import Typography from '@mui/material/Typography';
6import React from 'react'; 4import React from 'react';
@@ -9,16 +7,16 @@ import ToggleDarkModeButton from './ToggleDarkModeButton';
9 7
10export default function TopBar(): JSX.Element { 8export default function TopBar(): JSX.Element {
11 return ( 9 return (
12 <AppBar position="static" color="primary"> 10 <AppBar
11 position="static"
12 elevation={0}
13 color="transparent"
14 sx={(theme) => ({
15 background: theme.palette.highlight.activeLine,
16 borderBottom: `1px solid ${theme.palette.divider2}`,
17 })}
18 >
13 <Toolbar> 19 <Toolbar>
14 <IconButton
15 edge="start"
16 sx={{ mr: 2 }}
17 color="inherit"
18 aria-label="menu"
19 >
20 <MenuIcon />
21 </IconButton>
22 <Typography variant="h6" component="h1" flexGrow={1}> 20 <Typography variant="h6" component="h1" flexGrow={1}>
23 Refinery 21 Refinery
24 </Typography> 22 </Typography>
diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx
index 652ca71e..1412a314 100644
--- a/subprojects/frontend/src/editor/EditorButtons.tsx
+++ b/subprojects/frontend/src/editor/EditorButtons.tsx
@@ -36,24 +36,22 @@ function EditorButtons(): JSX.Element {
36 const { editorStore } = useRootStore(); 36 const { editorStore } = useRootStore();
37 37
38 return ( 38 return (
39 <Stack direction="row" spacing={1}> 39 <Stack direction="row" flexGrow={1}>
40 <Stack direction="row" alignItems="center"> 40 <IconButton
41 <IconButton 41 disabled={!editorStore.canUndo}
42 disabled={!editorStore.canUndo} 42 onClick={() => editorStore.undo()}
43 onClick={() => editorStore.undo()} 43 aria-label="Undo"
44 aria-label="Undo" 44 >
45 > 45 <UndoIcon fontSize="small" />
46 <UndoIcon fontSize="small" /> 46 </IconButton>
47 </IconButton> 47 <IconButton
48 <IconButton 48 disabled={!editorStore.canRedo}
49 disabled={!editorStore.canRedo} 49 onClick={() => editorStore.redo()}
50 onClick={() => editorStore.redo()} 50 aria-label="Redo"
51 aria-label="Redo" 51 >
52 > 52 <RedoIcon fontSize="small" />
53 <RedoIcon fontSize="small" /> 53 </IconButton>
54 </IconButton> 54 <ToggleButtonGroup size="small" sx={{ mx: 1 }}>
55 </Stack>
56 <ToggleButtonGroup size="small">
57 <ToggleButton 55 <ToggleButton
58 selected={editorStore.showLineNumbers} 56 selected={editorStore.showLineNumbers}
59 onClick={() => editorStore.toggleLineNumbers()} 57 onClick={() => editorStore.toggleLineNumbers()}
diff --git a/subprojects/frontend/src/editor/EditorParent.ts b/subprojects/frontend/src/editor/EditorParent.ts
index 805065fc..3742b89c 100644
--- a/subprojects/frontend/src/editor/EditorParent.ts
+++ b/subprojects/frontend/src/editor/EditorParent.ts
@@ -1,22 +1,5 @@
1import { alpha, styled } from '@mui/material/styles'; 1import { alpha, styled } from '@mui/material/styles';
2 2
3/**
4 * Returns a squiggly underline background image encoded as a CSS `url()` data URI with Base64.
5 *
6 * Based on
7 * https://github.com/codemirror/lint/blob/f524b4a53b0183bb343ac1e32b228d28030d17af/src/lint.ts#L501
8 *
9 * @param color the color of the underline
10 * @returns the CSS `url()`
11 */
12function underline(color: string) {
13 const svg = `<svg xmlns="http://www.w3.org/2000/svg" width="6" height="3">
14 <path d="m0 3 l2 -2 l1 0 l2 2 l1 0" stroke="${color}" fill="none" stroke-width=".7"/>
15 </svg>`;
16 const svgBase64 = window.btoa(svg);
17 return `url('data:image/svg+xml;base64,${svgBase64}')`;
18}
19
20export default styled('div', { 3export default styled('div', {
21 name: 'EditorParent', 4 name: 'EditorParent',
22 shouldForwardProp: (propName) => propName !== 'showLineNumbers', 5 shouldForwardProp: (propName) => propName !== 'showLineNumbers',
@@ -28,7 +11,9 @@ export default styled('div', {
28 borderLeftColor: color, 11 borderLeftColor: color,
29 }; 12 };
30 codeMirrorLintStyle[`.cm-lintRange-${severity}`] = { 13 codeMirrorLintStyle[`.cm-lintRange-${severity}`] = {
31 backgroundImage: underline(color), 14 backgroundImage: 'none',
15 textDecoration: `underline wavy ${color}`,
16 textDecorationSkipInk: 'none',
32 }; 17 };
33 }); 18 });
34 19
@@ -42,10 +27,9 @@ export default styled('div', {
42 }, 27 },
43 '.cm-scroller, .cm-tooltip-autocomplete, .cm-completionLabel, .cm-completionDetail': 28 '.cm-scroller, .cm-tooltip-autocomplete, .cm-completionLabel, .cm-completionDetail':
44 { 29 {
45 fontSize: 16, 30 ...theme.typography.body1,
46 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace', 31 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace',
47 fontFeatureSettings: '"liga", "calt"', 32 fontFeatureSettings: '"liga", "calt"',
48 fontWeight: 400,
49 letterSpacing: 0, 33 letterSpacing: 0,
50 textRendering: 'optimizeLegibility', 34 textRendering: 'optimizeLegibility',
51 }, 35 },
@@ -61,7 +45,7 @@ export default styled('div', {
61 color: theme.palette.secondary.main, 45 color: theme.palette.secondary.main,
62 }, 46 },
63 '.cm-activeLine': { 47 '.cm-activeLine': {
64 background: alpha(theme.palette.text.secondary, 0.06), 48 background: theme.palette.highlight.activeLine,
65 }, 49 },
66 '.cm-foldGutter': { 50 '.cm-foldGutter': {
67 color: alpha(theme.palette.text.primary, 0), 51 color: alpha(theme.palette.text.primary, 0),
@@ -103,10 +87,10 @@ export default styled('div', {
103 }, 87 },
104 '.cm-panel': { 88 '.cm-panel': {
105 '&, & button, & input': { 89 '&, & button, & input': {
106 fontFamily: '"Roboto","Helvetica","Arial",sans-serif', 90 fontFamily: theme.typography.fontFamily,
107 }, 91 },
108 background: theme.palette.background.paper, 92 background: theme.palette.background.default,
109 borderTop: `1px solid ${theme.palette.divider}`, 93 borderTop: `1px solid ${theme.palette.divider2}`,
110 'button[name="close"]': { 94 'button[name="close"]': {
111 background: 'transparent', 95 background: 'transparent',
112 color: theme.palette.text.secondary, 96 color: theme.palette.text.secondary,
@@ -114,6 +98,7 @@ export default styled('div', {
114 }, 98 },
115 }, 99 },
116 '.cm-panel.cm-panel-lint': { 100 '.cm-panel.cm-panel-lint': {
101 boderBottom: 'none',
117 'button[name="close"]': { 102 'button[name="close"]': {
118 // Close button interferes with scrollbar, so we better hide it. 103 // Close button interferes with scrollbar, so we better hide it.
119 // The panel can still be closed from the toolbar. 104 // The panel can still be closed from the toolbar.
@@ -121,18 +106,13 @@ export default styled('div', {
121 }, 106 },
122 ul: { 107 ul: {
123 li: { 108 li: {
124 borderBottom: `1px solid ${theme.palette.divider}`,
125 cursor: 'pointer', 109 cursor: 'pointer',
126 color: theme.palette.text.primary, 110 color: theme.palette.text.primary,
127 }, 111 },
128 '[aria-selected]': { 112 '[aria-selected], &:focus [aria-selected]': {
129 background: theme.palette.selection.main, 113 background: theme.palette.selection.main,
130 color: theme.palette.selection.contrastText, 114 color: theme.palette.selection.contrastText,
131 }, 115 },
132 '&:focus [aria-selected]': {
133 background: theme.palette.primary.main,
134 color: theme.palette.primary.contrastText,
135 },
136 }, 116 },
137 }, 117 },
138 '.cm-foldPlaceholder': { 118 '.cm-foldPlaceholder': {
@@ -159,7 +139,7 @@ export default styled('div', {
159 }, 139 },
160 '.tok-comment': { 140 '.tok-comment': {
161 fontStyle: 'italic', 141 fontStyle: 'italic',
162 color: theme.palette.text.disabled, 142 color: theme.palette.highlight.comment,
163 }, 143 },
164 '.tok-number': { 144 '.tok-number': {
165 color: theme.palette.highlight.number, 145 color: theme.palette.highlight.number,
@@ -225,9 +205,9 @@ export default styled('div', {
225 fontStyle: 'normal', 205 fontStyle: 'normal',
226 }, 206 },
227 '[aria-selected]': { 207 '[aria-selected]': {
228 background: `${theme.palette.selection.main} !important`, 208 background: `${theme.palette.primary.main} !important`,
229 '.cm-completionIcon, .cm-completionLabel, .cm-completionDetail': { 209 '.cm-completionIcon, .cm-completionLabel, .cm-completionDetail': {
230 color: theme.palette.selection.contrastText, 210 color: theme.palette.primary.contrastText,
231 }, 211 },
232 }, 212 },
233 }, 213 },
diff --git a/subprojects/frontend/src/editor/GenerateButton.tsx b/subprojects/frontend/src/editor/GenerateButton.tsx
index fc337da9..4d5c4e44 100644
--- a/subprojects/frontend/src/editor/GenerateButton.tsx
+++ b/subprojects/frontend/src/editor/GenerateButton.tsx
@@ -22,11 +22,7 @@ function GenerateButton(): JSX.Element {
22 22
23 if (errorCount > 0) { 23 if (errorCount > 0) {
24 return ( 24 return (
25 <Button 25 <Button color="error" onClick={() => editorStore.toggleLintPanel()}>
26 variant="outlined"
27 color="error"
28 onClick={() => editorStore.toggleLintPanel()}
29 >
30 {summary} 26 {summary}
31 </Button> 27 </Button>
32 ); 28 );
@@ -34,7 +30,6 @@ function GenerateButton(): JSX.Element {
34 30
35 return ( 31 return (
36 <Button 32 <Button
37 variant="outlined"
38 color={warningCount > 0 ? 'warning' : 'primary'} 33 color={warningCount > 0 ? 'warning' : 'primary'}
39 startIcon={<PlayArrowIcon />} 34 startIcon={<PlayArrowIcon />}
40 > 35 >
diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx
index 1b8e49f0..9a8fdd44 100644
--- a/subprojects/frontend/src/theme/ThemeProvider.tsx
+++ b/subprojects/frontend/src/theme/ThemeProvider.tsx
@@ -1,41 +1,76 @@
1import { 1import {
2 alpha,
2 createTheme, 3 createTheme,
4 type Components,
3 responsiveFontSizes, 5 responsiveFontSizes,
4 type ThemeOptions, 6 type ThemeOptions,
5 ThemeProvider as MaterialUiThemeProvider, 7 ThemeProvider as MaterialUiThemeProvider,
6} from '@mui/material/styles'; 8} from '@mui/material/styles';
7import { observer } from 'mobx-react-lite'; 9import { observer } from 'mobx-react-lite';
8import React, { type CSSProperties, type ReactNode } from 'react'; 10import React, { type ReactNode } from 'react';
9 11
10import { useRootStore } from '../RootStore'; 12import { useRootStore } from '../RootStore';
11 13
12import EditorTheme from './EditorTheme'; 14import EditorTheme from './EditorTheme';
13 15
14interface HighlightStyles { 16interface HighlightStyles {
15 number: CSSProperties['color']; 17 number: string;
16 parameter: CSSProperties['color']; 18 parameter: string;
19 comment: string;
20 activeLine: string;
17 occurences: { 21 occurences: {
18 read: CSSProperties['color']; 22 read: string;
19 write: CSSProperties['color']; 23 write: string;
20 }; 24 };
21} 25}
22 26
23declare module '@mui/material/styles' { 27declare module '@mui/material/styles' {
24 interface Palette { 28 interface Palette {
29 divider2: string;
25 selection: Palette['primary']; 30 selection: Palette['primary'];
26 highlight: HighlightStyles; 31 highlight: HighlightStyles;
27 } 32 }
28 33
29 interface PaletteOptions { 34 interface PaletteOptions {
35 divider2: string;
30 selection: PaletteOptions['primary']; 36 selection: PaletteOptions['primary'];
31 highlight: HighlightStyles; 37 highlight: HighlightStyles;
32 } 38 }
33} 39}
34 40
35function getMUIThemeOptions(currentTheme: EditorTheme): ThemeOptions { 41function getMUIThemeOptions(currentTheme: EditorTheme): ThemeOptions {
42 const components: Components = {
43 MuiButton: {
44 styleOverrides: {
45 root: { borderRadius: '50em' },
46 text: { padding: '6px 16px' },
47 textSizeSmall: { padding: '4px 10px' },
48 textSizeLarge: { padding: '8px 22px' },
49 },
50 },
51 MuiToggleButtonGroup: {
52 styleOverrides: {
53 groupedHorizontal: {
54 borderRadius: '50em',
55 ':first-of-type': { paddingLeft: 15 },
56 ':last-of-type': { paddingRight: 15 },
57 '&.MuiToggleButton-sizeSmall': {
58 ':first-of-type': { paddingLeft: 9 },
59 ':last-of-type': { paddingRight: 9 },
60 },
61 '&.MuiToggleButton-sizeLarge': {
62 ':first-of-type': { paddingLeft: 21 },
63 ':last-of-type': { paddingRight: 21 },
64 },
65 },
66 },
67 },
68 };
69
36 switch (currentTheme) { 70 switch (currentTheme) {
37 case EditorTheme.Light: 71 case EditorTheme.Light:
38 return { 72 return {
73 components,
39 palette: { 74 palette: {
40 mode: 'light', 75 mode: 'light',
41 primary: { main: '#0097a7' }, 76 primary: { main: '#0097a7' },
@@ -43,9 +78,12 @@ function getMUIThemeOptions(currentTheme: EditorTheme): ThemeOptions {
43 main: '#c8e4fb', 78 main: '#c8e4fb',
44 contrastText: '#000', 79 contrastText: '#000',
45 }, 80 },
81 divider2: '#d7d7d7',
46 highlight: { 82 highlight: {
47 number: '#1976d2', 83 number: '#1976d2',
48 parameter: '#6a3e3e', 84 parameter: '#6a3e3e',
85 comment: alpha('#000', 0.38),
86 activeLine: '#f5f5f5',
49 occurences: { 87 occurences: {
50 read: '#ceccf7', 88 read: '#ceccf7',
51 write: '#f0d8a8', 89 write: '#f0d8a8',
@@ -55,9 +93,25 @@ function getMUIThemeOptions(currentTheme: EditorTheme): ThemeOptions {
55 }; 93 };
56 case EditorTheme.Dark: 94 case EditorTheme.Dark:
57 return { 95 return {
96 components,
58 palette: { 97 palette: {
59 mode: 'dark', 98 mode: 'dark',
60 primary: { main: '#56b6c2' }, 99 primary: { main: '#56b6c2' },
100 error: { main: '#e06c75' },
101 warning: { main: '#e5c07b' },
102 success: { main: '#57a470' },
103 info: { main: '#52b8ff' },
104 background: {
105 default: '#282c34',
106 paper: '#21252b',
107 },
108 text: {
109 primary: '#ebebff',
110 secondary: '#abb2bf',
111 disabled: '#4b5263',
112 },
113 divider: alpha('#abb2bf', 0.16),
114 divider2: '#181a1f',
61 selection: { 115 selection: {
62 main: '#3e4453', 116 main: '#3e4453',
63 contrastText: '#fff', 117 contrastText: '#fff',
@@ -65,6 +119,8 @@ function getMUIThemeOptions(currentTheme: EditorTheme): ThemeOptions {
65 highlight: { 119 highlight: {
66 number: '#6188a6', 120 number: '#6188a6',
67 parameter: '#c8ae9d', 121 parameter: '#c8ae9d',
122 comment: '#6b717d',
123 activeLine: '#21252b',
68 occurences: { 124 occurences: {
69 read: 'rgba(255, 255, 255, 0.15)', 125 read: 'rgba(255, 255, 255, 0.15)',
70 write: 'rgba(255, 255, 128, 0.4)', 126 write: 'rgba(255, 255, 128, 0.4)',
diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts
index 9cb426cf..d97b0ac9 100644
--- a/subprojects/frontend/vite.config.ts
+++ b/subprojects/frontend/vite.config.ts
@@ -50,7 +50,7 @@ export default defineConfig({
50 files: [ 50 files: [
51 { 51 {
52 match: 52 match:
53 /(?:jetbrains-mono-latin-variable-wghtOnly-(?:italic|normal)|roboto-latin-(400|500)-normal).+\.woff2/, 53 /(?:jetbrains-mono-latin-variable-wghtOnly-(?:italic|normal)|roboto-latin-(?:400|500)-normal).+\.woff2/,
54 attributes: { 54 attributes: {
55 type: 'font/woff2', 55 type: 'font/woff2',
56 as: 'font', 56 as: 'font',