aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/editor/EditorTheme.ts
diff options
context:
space:
mode:
Diffstat (limited to 'subprojects/frontend/src/editor/EditorTheme.ts')
-rw-r--r--subprojects/frontend/src/editor/EditorTheme.ts342
1 files changed, 342 insertions, 0 deletions
diff --git a/subprojects/frontend/src/editor/EditorTheme.ts b/subprojects/frontend/src/editor/EditorTheme.ts
new file mode 100644
index 00000000..8d98e832
--- /dev/null
+++ b/subprojects/frontend/src/editor/EditorTheme.ts
@@ -0,0 +1,342 @@
1import errorSVG from '@material-icons/svg/svg/error/baseline.svg?raw';
2import expandMoreSVG from '@material-icons/svg/svg/expand_more/baseline.svg?raw';
3import infoSVG from '@material-icons/svg/svg/info/baseline.svg?raw';
4import warningSVG from '@material-icons/svg/svg/warning/baseline.svg?raw';
5import { alpha, styled } from '@mui/material/styles';
6
7import editorClassNames from './editorClassNames';
8
9function svgURL(svg: string): string {
10 return `url('data:image/svg+xml;utf8,${svg}')`;
11}
12
13export default styled('div', {
14 name: 'EditorTheme',
15 shouldForwardProp: (propName) => propName !== 'showLineNumbers',
16})<{ showLineNumbers: boolean }>(({ theme, showLineNumbers }) => {
17 let codeMirrorLintStyle: Record<string, unknown> = {};
18 (
19 [
20 {
21 severity: 'error',
22 icon: errorSVG,
23 },
24 {
25 severity: 'warning',
26 icon: warningSVG,
27 },
28 {
29 severity: 'info',
30 icon: infoSVG,
31 },
32 ] as const
33 ).forEach(({ severity, icon }) => {
34 const palette = theme.palette[severity];
35 const color = palette.main;
36 const iconStyle = {
37 background: color,
38 maskImage: svgURL(icon),
39 maskSize: '16px 16px',
40 height: 16,
41 width: 16,
42 };
43 const tooltipColor =
44 theme.palette.mode === 'dark' ? palette.main : palette.light;
45 codeMirrorLintStyle = {
46 ...codeMirrorLintStyle,
47 [`.cm-lintRange-${severity}`]: {
48 backgroundImage: 'none',
49 textDecoration: `underline wavy ${color}`,
50 textDecorationSkipInk: 'none',
51 },
52 [`.cm-diagnostic-${severity}`]: {
53 marginLeft: 0,
54 padding: '4px 8px 4px 32px',
55 borderLeft: 'none',
56 position: 'relative',
57 '::before': {
58 ...iconStyle,
59 content: '" "',
60 position: 'absolute',
61 top: 6,
62 left: 8,
63 },
64 },
65 [`.cm-tooltip .cm-diagnostic-${severity}::before`]: {
66 background: tooltipColor,
67 },
68 [`.cm-lint-marker-${severity}`]: {
69 ...iconStyle,
70 display: 'block',
71 margin: '4px 0',
72 // Remove original CodeMirror icon.
73 content: '""',
74 '::before': {
75 // Remove original CodeMirror icon.
76 content: '""',
77 display: 'none',
78 },
79 },
80 };
81 });
82
83 return {
84 background: theme.palette.background.default,
85 '&, .cm-editor': {
86 height: '100%',
87 },
88 '.cm-content': {
89 padding: 0,
90 },
91 '.cm-scroller': {
92 color: theme.palette.text.secondary,
93 },
94 '.cm-scroller, .cm-tooltip-autocomplete, .cm-completionLabel, .cm-completionDetail':
95 {
96 ...theme.typography.body1,
97 fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace',
98 fontFeatureSettings: '"liga", "calt"',
99 letterSpacing: 0,
100 textRendering: 'optimizeLegibility',
101 },
102 '.cm-gutters': {
103 background: 'transparent',
104 color: theme.palette.text.disabled,
105 border: 'none',
106 },
107 '.cm-specialChar': {
108 color: theme.palette.secondary.main,
109 },
110 '.cm-activeLine': {
111 background: theme.palette.highlight.activeLine,
112 },
113 '.cm-gutter-lint': {
114 width: 16,
115 '.cm-gutterElement': {
116 padding: 0,
117 },
118 },
119 '.cm-foldGutter': {
120 opacity: 0,
121 width: 16,
122 transition: theme.transitions.create('opacity', {
123 duration: theme.transitions.duration.short,
124 }),
125 '@media (hover: none)': {
126 opacity: 1,
127 },
128 },
129 '.cm-gutters:hover .cm-foldGutter': {
130 opacity: 1,
131 },
132 [`.${editorClassNames.foldMarker}`]: {
133 display: 'block',
134 margin: '4px 0',
135 padding: 0,
136 maskImage: svgURL(expandMoreSVG),
137 maskSize: '16px 16px',
138 height: 16,
139 width: 16,
140 background: theme.palette.text.primary,
141 border: 'none',
142 cursor: 'pointer',
143 },
144 [`.${editorClassNames.foldMarkerClosed}`]: {
145 transform: 'rotate(-90deg)',
146 },
147 '.cm-activeLineGutter': {
148 background: 'transparent',
149 },
150 '.cm-lineNumbers': {
151 ...(!showLineNumbers && {
152 display: 'none !important',
153 }),
154 '.cm-activeLineGutter': {
155 color: theme.palette.text.primary,
156 },
157 },
158 '.cm-cursor, .cm-cursor-primary': {
159 borderLeft: `2px solid ${theme.palette.primary.main}`,
160 },
161 '.cm-selectionBackground': {
162 background: theme.palette.highlight.selection,
163 },
164 '.cm-focused': {
165 outline: 'none',
166 '.cm-selectionBackground': {
167 background: theme.palette.highlight.selection,
168 },
169 },
170 '.cm-panels-top': {
171 color: theme.palette.text.secondary,
172 borderBottom: `1px solid ${theme.palette.outer.border}`,
173 marginBottom: theme.spacing(1),
174 },
175 '.cm-panel': {
176 position: 'relative',
177 overflow: 'hidden',
178 background: theme.palette.outer.background,
179 borderTop: `1px solid ${theme.palette.outer.border}`,
180 '&, & button, & input': {
181 fontFamily: theme.typography.fontFamily,
182 },
183 'button[name="close"]': {
184 background: 'transparent',
185 color: theme.palette.text.secondary,
186 cursor: 'pointer',
187 },
188 },
189 '.cm-panel.cm-panel-lint': {
190 borderTop: `1px solid ${theme.palette.outer.border}`,
191 borderBottom: 'none',
192 'button[name="close"]': {
193 // Close button interferes with scrollbar, so we better hide it.
194 // The panel can still be closed from the toolbar.
195 display: 'none',
196 },
197 ul: {
198 maxHeight: 'max(112px, 20vh)',
199 li: {
200 cursor: 'pointer',
201 color: theme.palette.text.primary,
202 },
203 '.cm-diagnostic': {
204 ...theme.typography.body2,
205 '&[aria-selected="true"]': {
206 color: theme.palette.text.primary,
207 background: 'transparent',
208 fontWeight: 700,
209 },
210 ':hover': {
211 background: alpha(
212 theme.palette.text.primary,
213 theme.palette.action.hoverOpacity,
214 ),
215 },
216 },
217 },
218 },
219 [`.${editorClassNames.foldPlaceholder}`]: {
220 ...theme.typography.body1,
221 padding: 0,
222 fontFamily: 'inherit',
223 fontFeatureSettings: '"liga", "calt"',
224 color: theme.palette.text.secondary,
225 backgroundColor: alpha(
226 theme.palette.text.secondary,
227 theme.palette.action.focusOpacity,
228 ),
229 border: 'none',
230 cursor: 'pointer',
231 transition: theme.transitions.create(['background-color', 'color'], {
232 duration: theme.transitions.duration.short,
233 }),
234 '&:hover': {
235 color: theme.palette.text.primary,
236 backgroundColor: alpha(
237 theme.palette.text.secondary,
238 theme.palette.action.focusOpacity + theme.palette.action.hoverOpacity,
239 ),
240 },
241 },
242 '.tok-comment': {
243 fontStyle: 'italic',
244 color: theme.palette.highlight.comment,
245 },
246 '.tok-number': {
247 color: theme.palette.highlight.number,
248 },
249 '.tok-string': {
250 color: theme.palette.secondary,
251 },
252 '.tok-keyword': {
253 color: theme.palette.primary.main,
254 },
255 '.tok-typeName, .tok-atom': {
256 color: theme.palette.text.primary,
257 },
258 '.tok-variableName': {
259 color: theme.palette.highlight.parameter,
260 },
261 '.tok-problem-node': {
262 '&, & .tok-variableName': {
263 color: theme.palette.text.secondary,
264 },
265 },
266 '.tok-problem-individual': {
267 '&, & .tok-variableName': {
268 color: theme.palette.text.primary,
269 },
270 },
271 '.tok-problem-abstract, .tok-problem-new': {
272 fontStyle: 'italic',
273 },
274 '.tok-problem-containment': {
275 fontWeight: 700,
276 },
277 '.tok-problem-error': {
278 '&, & .tok-typeName': {
279 color: theme.palette.error.main,
280 },
281 },
282 '.tok-problem-builtin': {
283 '&, & .tok-typeName, & .tok-atom, & .tok-variableName': {
284 color: theme.palette.primary.main,
285 fontWeight: 400,
286 fontStyle: 'normal',
287 },
288 },
289 '.cm-tooltip.cm-tooltip-autocomplete': {
290 background: theme.palette.background.paper,
291 borderRadius: theme.shape.borderRadius,
292 overflow: 'hidden',
293 ...(theme.palette.mode === 'dark' && {
294 // https://github.com/mui/material-ui/blob/10c72729c7d03bab8cdce6eb422642684c56dca2/packages/mui-material/src/Paper/Paper.js#L18
295 backgroundImage:
296 'linear-gradient(rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.07))',
297 }),
298 boxShadow: theme.shadows[2],
299 '.cm-completionIcon': {
300 color: theme.palette.text.secondary,
301 },
302 '.cm-completionLabel': {
303 color: theme.palette.text.primary,
304 },
305 '.cm-completionDetail': {
306 color: theme.palette.text.secondary,
307 fontStyle: 'normal',
308 },
309 'li[aria-selected="true"]': {
310 background: alpha(
311 theme.palette.text.primary,
312 theme.palette.action.focusOpacity,
313 ),
314 '.cm-completionIcon, .cm-completionLabel, .cm-completionDetail': {
315 color: theme.palette.text.primary,
316 },
317 },
318 },
319 '.cm-tooltip.cm-tooltip-hover, .cm-tooltip.cm-tooltip-lint': {
320 ...theme.typography.body2,
321 // https://github.com/mui/material-ui/blob/dee9529f7a298c54ae760761112c3ae9ba082137/packages/mui-material/src/Tooltip/Tooltip.js#L121-L125
322 background: alpha(theme.palette.grey[700], 0.92),
323 borderRadius: theme.shape.borderRadius,
324 color: theme.palette.common.white,
325 overflow: 'hidden',
326 maxWidth: 400,
327 },
328 '.cm-completionIcon': {
329 width: 16,
330 padding: 0,
331 marginRight: '0.5em',
332 textAlign: 'center',
333 },
334 ...codeMirrorLintStyle,
335 '.cm-problem-read': {
336 background: theme.palette.highlight.occurences.read,
337 },
338 '.cm-problem-write': {
339 background: theme.palette.highlight.occurences.write,
340 },
341 };
342});