diff options
Diffstat (limited to 'subprojects/frontend/src/editor/EditorParent.ts')
-rw-r--r-- | subprojects/frontend/src/editor/EditorParent.ts | 205 |
1 files changed, 205 insertions, 0 deletions
diff --git a/subprojects/frontend/src/editor/EditorParent.ts b/subprojects/frontend/src/editor/EditorParent.ts new file mode 100644 index 00000000..94ca24ea --- /dev/null +++ b/subprojects/frontend/src/editor/EditorParent.ts | |||
@@ -0,0 +1,205 @@ | |||
1 | import { styled } from '@mui/material/styles'; | ||
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 | */ | ||
12 | function 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 | |||
20 | export const EditorParent = styled('div')(({ theme }) => { | ||
21 | const codeMirrorLintStyle: Record<string, unknown> = {}; | ||
22 | (['error', 'warning', 'info'] as const).forEach((severity) => { | ||
23 | const color = theme.palette[severity].main; | ||
24 | codeMirrorLintStyle[`.cm-diagnostic-${severity}`] = { | ||
25 | borderLeftColor: color, | ||
26 | }; | ||
27 | codeMirrorLintStyle[`.cm-lintRange-${severity}`] = { | ||
28 | backgroundImage: underline(color), | ||
29 | }; | ||
30 | }); | ||
31 | |||
32 | return { | ||
33 | background: theme.palette.background.default, | ||
34 | '&, .cm-editor': { | ||
35 | height: '100%', | ||
36 | }, | ||
37 | '.cm-content': { | ||
38 | padding: 0, | ||
39 | }, | ||
40 | '.cm-scroller, .cm-tooltip-autocomplete, .cm-completionLabel, .cm-completionDetail': { | ||
41 | fontSize: 16, | ||
42 | fontFamily: '"JetBrains MonoVariable", "JetBrains Mono", monospace', | ||
43 | fontFeatureSettings: '"liga", "calt"', | ||
44 | fontWeight: 400, | ||
45 | letterSpacing: 0, | ||
46 | textRendering: 'optimizeLegibility', | ||
47 | }, | ||
48 | '.cm-scroller': { | ||
49 | color: theme.palette.text.secondary, | ||
50 | }, | ||
51 | '.cm-gutters': { | ||
52 | background: 'rgba(255, 255, 255, 0.1)', | ||
53 | color: theme.palette.text.disabled, | ||
54 | border: 'none', | ||
55 | }, | ||
56 | '.cm-specialChar': { | ||
57 | color: theme.palette.secondary.main, | ||
58 | }, | ||
59 | '.cm-activeLine': { | ||
60 | background: 'rgba(0, 0, 0, 0.3)', | ||
61 | }, | ||
62 | '.cm-activeLineGutter': { | ||
63 | background: 'transparent', | ||
64 | }, | ||
65 | '.cm-lineNumbers .cm-activeLineGutter': { | ||
66 | color: theme.palette.text.primary, | ||
67 | }, | ||
68 | '.cm-cursor, .cm-cursor-primary': { | ||
69 | borderColor: theme.palette.primary.main, | ||
70 | background: theme.palette.common.black, | ||
71 | }, | ||
72 | '.cm-selectionBackground': { | ||
73 | background: '#3e4453', | ||
74 | }, | ||
75 | '.cm-focused': { | ||
76 | outline: 'none', | ||
77 | '.cm-selectionBackground': { | ||
78 | background: '#3e4453', | ||
79 | }, | ||
80 | }, | ||
81 | '.cm-panels-top': { | ||
82 | color: theme.palette.text.secondary, | ||
83 | }, | ||
84 | '.cm-panel': { | ||
85 | '&, & button, & input': { | ||
86 | fontFamily: '"Roboto","Helvetica","Arial",sans-serif', | ||
87 | }, | ||
88 | background: theme.palette.background.paper, | ||
89 | borderTop: `1px solid ${theme.palette.divider}`, | ||
90 | 'button[name="close"]': { | ||
91 | background: 'transparent', | ||
92 | color: theme.palette.text.secondary, | ||
93 | cursor: 'pointer', | ||
94 | }, | ||
95 | }, | ||
96 | '.cm-panel.cm-panel-lint': { | ||
97 | 'button[name="close"]': { | ||
98 | // Close button interferes with scrollbar, so we better hide it. | ||
99 | // The panel can still be closed from the toolbar. | ||
100 | display: 'none', | ||
101 | }, | ||
102 | ul: { | ||
103 | li: { | ||
104 | borderBottom: `1px solid ${theme.palette.divider}`, | ||
105 | cursor: 'pointer', | ||
106 | }, | ||
107 | '[aria-selected]': { | ||
108 | background: '#3e4453', | ||
109 | color: theme.palette.text.primary, | ||
110 | }, | ||
111 | '&:focus [aria-selected]': { | ||
112 | background: theme.palette.primary.main, | ||
113 | color: theme.palette.primary.contrastText, | ||
114 | }, | ||
115 | }, | ||
116 | }, | ||
117 | '.cm-foldPlaceholder': { | ||
118 | background: theme.palette.background.paper, | ||
119 | borderColor: theme.palette.text.disabled, | ||
120 | color: theme.palette.text.secondary, | ||
121 | }, | ||
122 | '.cmt-comment': { | ||
123 | fontStyle: 'italic', | ||
124 | color: theme.palette.text.disabled, | ||
125 | }, | ||
126 | '.cmt-number': { | ||
127 | color: '#6188a6', | ||
128 | }, | ||
129 | '.cmt-string': { | ||
130 | color: theme.palette.secondary.dark, | ||
131 | }, | ||
132 | '.cmt-keyword': { | ||
133 | color: theme.palette.primary.main, | ||
134 | }, | ||
135 | '.cmt-typeName, .cmt-macroName, .cmt-atom': { | ||
136 | color: theme.palette.text.primary, | ||
137 | }, | ||
138 | '.cmt-variableName': { | ||
139 | color: '#c8ae9d', | ||
140 | }, | ||
141 | '.cmt-problem-node': { | ||
142 | '&, & .cmt-variableName': { | ||
143 | color: theme.palette.text.secondary, | ||
144 | }, | ||
145 | }, | ||
146 | '.cmt-problem-individual': { | ||
147 | '&, & .cmt-variableName': { | ||
148 | color: theme.palette.text.primary, | ||
149 | }, | ||
150 | }, | ||
151 | '.cmt-problem-abstract, .cmt-problem-new': { | ||
152 | fontStyle: 'italic', | ||
153 | }, | ||
154 | '.cmt-problem-containment': { | ||
155 | fontWeight: 700, | ||
156 | }, | ||
157 | '.cmt-problem-error': { | ||
158 | '&, & .cmt-typeName': { | ||
159 | color: theme.palette.error.main, | ||
160 | }, | ||
161 | }, | ||
162 | '.cmt-problem-builtin': { | ||
163 | '&, & .cmt-typeName, & .cmt-atom, & .cmt-variableName': { | ||
164 | color: theme.palette.primary.main, | ||
165 | fontWeight: 400, | ||
166 | fontStyle: 'normal', | ||
167 | }, | ||
168 | }, | ||
169 | '.cm-tooltip-autocomplete': { | ||
170 | background: theme.palette.background.paper, | ||
171 | boxShadow: `0px 2px 4px -1px rgb(0 0 0 / 20%), | ||
172 | 0px 4px 5px 0px rgb(0 0 0 / 14%), | ||
173 | 0px 1px 10px 0px rgb(0 0 0 / 12%)`, | ||
174 | '.cm-completionIcon': { | ||
175 | color: theme.palette.text.secondary, | ||
176 | }, | ||
177 | '.cm-completionLabel': { | ||
178 | color: theme.palette.text.primary, | ||
179 | }, | ||
180 | '.cm-completionDetail': { | ||
181 | color: theme.palette.text.secondary, | ||
182 | fontStyle: 'normal', | ||
183 | }, | ||
184 | '[aria-selected]': { | ||
185 | background: `${theme.palette.primary.main} !important`, | ||
186 | '.cm-completionIcon, .cm-completionLabel, .cm-completionDetail': { | ||
187 | color: theme.palette.primary.contrastText, | ||
188 | }, | ||
189 | }, | ||
190 | }, | ||
191 | '.cm-completionIcon': { | ||
192 | width: 16, | ||
193 | padding: 0, | ||
194 | marginRight: '0.5em', | ||
195 | textAlign: 'center', | ||
196 | }, | ||
197 | ...codeMirrorLintStyle, | ||
198 | '.cm-problem-write': { | ||
199 | background: 'rgba(255, 255, 128, 0.3)', | ||
200 | }, | ||
201 | '.cm-problem-read': { | ||
202 | background: 'rgba(255, 255, 255, 0.15)', | ||
203 | }, | ||
204 | }; | ||
205 | }); | ||