aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/editor
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-18 02:08:21 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-18 02:08:21 +0200
commit675f7271642bdddbc008d22678e277c72032bdcd (patch)
tree765e1d2ccf44a1f3ec90590797c3465c1f5b1042 /subprojects/frontend/src/editor
parentfix(frontend): search panel fixes (diff)
downloadrefinery-675f7271642bdddbc008d22678e277c72032bdcd.tar.gz
refinery-675f7271642bdddbc008d22678e277c72032bdcd.tar.zst
refinery-675f7271642bdddbc008d22678e277c72032bdcd.zip
feat(frontend): responsive editor styling
Diffstat (limited to 'subprojects/frontend/src/editor')
-rw-r--r--subprojects/frontend/src/editor/EditorButtons.tsx3
-rw-r--r--subprojects/frontend/src/editor/EditorTheme.ts48
-rw-r--r--subprojects/frontend/src/editor/SearchPanelStore.ts8
-rw-r--r--subprojects/frontend/src/editor/SearchToolbar.tsx108
4 files changed, 126 insertions, 41 deletions
diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx
index 95da52c8..bed6afa8 100644
--- a/subprojects/frontend/src/editor/EditorButtons.tsx
+++ b/subprojects/frontend/src/editor/EditorButtons.tsx
@@ -41,6 +41,7 @@ function EditorButtons(): JSX.Element {
41 disabled={!editorStore.canUndo} 41 disabled={!editorStore.canUndo}
42 onClick={() => editorStore.undo()} 42 onClick={() => editorStore.undo()}
43 aria-label="Undo" 43 aria-label="Undo"
44 color="inherit"
44 > 45 >
45 <UndoIcon fontSize="small" /> 46 <UndoIcon fontSize="small" />
46 </IconButton> 47 </IconButton>
@@ -48,6 +49,7 @@ function EditorButtons(): JSX.Element {
48 disabled={!editorStore.canRedo} 49 disabled={!editorStore.canRedo}
49 onClick={() => editorStore.redo()} 50 onClick={() => editorStore.redo()}
50 aria-label="Redo" 51 aria-label="Redo"
52 color="inherit"
51 > 53 >
52 <RedoIcon fontSize="small" /> 54 <RedoIcon fontSize="small" />
53 </IconButton> 55 </IconButton>
@@ -87,6 +89,7 @@ function EditorButtons(): JSX.Element {
87 <IconButton 89 <IconButton
88 onClick={() => editorStore.formatText()} 90 onClick={() => editorStore.formatText()}
89 aria-label="Automatic format" 91 aria-label="Automatic format"
92 color="inherit"
90 > 93 >
91 <FormatPaint fontSize="small" /> 94 <FormatPaint fontSize="small" />
92 </IconButton> 95 </IconButton>
diff --git a/subprojects/frontend/src/editor/EditorTheme.ts b/subprojects/frontend/src/editor/EditorTheme.ts
index c983a378..fe5ba58e 100644
--- a/subprojects/frontend/src/editor/EditorTheme.ts
+++ b/subprojects/frontend/src/editor/EditorTheme.ts
@@ -14,20 +14,28 @@ export default styled('div', {
14 name: 'EditorTheme', 14 name: 'EditorTheme',
15 shouldForwardProp: (propName) => propName !== 'showLineNumbers', 15 shouldForwardProp: (propName) => propName !== 'showLineNumbers',
16})<{ showLineNumbers: boolean }>(({ theme, showLineNumbers }) => { 16})<{ showLineNumbers: boolean }>(({ theme, showLineNumbers }) => {
17 const editorFontStyle = {
18 ...theme.typography.editor,
19 [theme.breakpoints.down('sm')]: {
20 fontSize: '0.875rem',
21 lineHeight: 1.43,
22 },
23 };
24
17 const generalStyle: CSSObject = { 25 const generalStyle: CSSObject = {
18 background: theme.palette.background.default, 26 background: theme.palette.background.default,
19 '&, .cm-editor': { 27 '&, .cm-editor': {
20 height: '100%', 28 height: '100%',
21 }, 29 },
22 '.cm-scroller': { 30 '.cm-scroller': {
23 ...theme.typography.editor,
24 color: theme.palette.text.secondary, 31 color: theme.palette.text.secondary,
25 }, 32 },
26 '.cm-gutters': { 33 '.cm-gutters': {
27 background: 'transparent', 34 background: theme.palette.background.default,
28 border: 'none', 35 border: 'none',
29 }, 36 },
30 '.cm-content': { 37 '.cm-content': {
38 ...editorFontStyle,
31 padding: 0, 39 padding: 0,
32 }, 40 },
33 '.cm-activeLine': { 41 '.cm-activeLine': {
@@ -138,6 +146,7 @@ export default styled('div', {
138 146
139 const lineNumberStyle: CSSObject = { 147 const lineNumberStyle: CSSObject = {
140 '.cm-lineNumbers': { 148 '.cm-lineNumbers': {
149 ...editorFontStyle,
141 color: theme.palette.highlight.lineNumber, 150 color: theme.palette.highlight.lineNumber,
142 ...(!showLineNumbers && { 151 ...(!showLineNumbers && {
143 display: 'none !important', 152 display: 'none !important',
@@ -157,7 +166,7 @@ export default styled('div', {
157 borderBottom: `1px solid ${theme.palette.outer.border}`, 166 borderBottom: `1px solid ${theme.palette.outer.border}`,
158 marginBottom: theme.spacing(1), 167 marginBottom: theme.spacing(1),
159 }, 168 },
160 '.cm-panel, .cm-panel.cm-search': { 169 '.cm-panel': {
161 color: theme.palette.text.primary, 170 color: theme.palette.text.primary,
162 background: theme.palette.outer.background, 171 background: theme.palette.outer.background,
163 borderTop: `1px solid ${theme.palette.outer.border}`, 172 borderTop: `1px solid ${theme.palette.outer.border}`,
@@ -207,12 +216,21 @@ export default styled('div', {
207 [`.cm-tooltip .cm-diagnostic-${severity}::before`]: { 216 [`.cm-tooltip .cm-diagnostic-${severity}::before`]: {
208 background: tooltipColor, 217 background: tooltipColor,
209 }, 218 },
219 [`.cm-panel.cm-panel-lint .cm-diagnostic-${severity}::before`]: {
220 top: 8,
221 [theme.breakpoints.down('sm')]: {
222 top: 6,
223 },
224 },
210 [`.cm-lint-marker-${severity}`]: { 225 [`.cm-lint-marker-${severity}`]: {
211 ...iconStyle, 226 ...iconStyle,
212 display: 'block', 227 display: 'block',
213 margin: '4px 0', 228 margin: '4px 0',
214 // Remove original CodeMirror icon. 229 // Remove original CodeMirror icon.
215 content: '""', 230 content: '""',
231 [theme.breakpoints.down('sm')]: {
232 margin: '2px 0',
233 },
216 '::before': { 234 '::before': {
217 // Remove original CodeMirror icon. 235 // Remove original CodeMirror icon.
218 content: '""', 236 content: '""',
@@ -247,13 +265,16 @@ export default styled('div', {
247 display: 'none', 265 display: 'none',
248 }, 266 },
249 ul: { 267 ul: {
250 maxHeight: `max(${28 * 4}px, 20vh)`, 268 maxHeight: `max(${32 * 4}px, 20vh)`,
251 li: { 269 li: {
252 cursor: 'pointer', 270 cursor: 'pointer',
253 color: theme.palette.text.primary, 271 color: theme.palette.text.primary,
254 }, 272 },
255 '.cm-diagnostic': { 273 '.cm-diagnostic': {
256 ...theme.typography.body2, 274 ...theme.typography.body1,
275 [theme.breakpoints.down('sm')]: {
276 ...theme.typography.body2,
277 },
257 '&[aria-selected="true"]': { 278 '&[aria-selected="true"]': {
258 color: theme.palette.text.primary, 279 color: theme.palette.text.primary,
259 background: 'transparent', 280 background: 'transparent',
@@ -264,6 +285,9 @@ export default styled('div', {
264 theme.palette.text.primary, 285 theme.palette.text.primary,
265 theme.palette.action.hoverOpacity, 286 theme.palette.action.hoverOpacity,
266 ), 287 ),
288 '@media (hover: none)': {
289 background: 'transparent',
290 },
267 }, 291 },
268 }, 292 },
269 }, 293 },
@@ -301,12 +325,15 @@ export default styled('div', {
301 background: theme.palette.text.primary, 325 background: theme.palette.text.primary,
302 border: 'none', 326 border: 'none',
303 cursor: 'pointer', 327 cursor: 'pointer',
328 [theme.breakpoints.down('sm')]: {
329 margin: '2px 0',
330 },
304 }, 331 },
305 [`.${editorClassNames.foldMarkerClosed}`]: { 332 [`.${editorClassNames.foldMarkerClosed}`]: {
306 transform: 'rotate(-90deg)', 333 transform: 'rotate(-90deg)',
307 }, 334 },
308 [`.${editorClassNames.foldPlaceholder}`]: { 335 [`.${editorClassNames.foldPlaceholder}`]: {
309 ...theme.typography.editor, 336 ...editorFontStyle,
310 padding: 0, 337 padding: 0,
311 fontFamily: 'inherit', 338 fontFamily: 'inherit',
312 background: 'transparent', 339 background: 'transparent',
@@ -326,13 +353,16 @@ export default styled('div', {
326 theme.palette.highlight.foldPlaceholder, 353 theme.palette.highlight.foldPlaceholder,
327 theme.palette.action.hoverOpacity, 354 theme.palette.action.hoverOpacity,
328 ), 355 ),
356 '@media (hover: none)': {
357 backgroundColor: 'transparent',
358 },
329 }, 359 },
330 }, 360 },
331 }; 361 };
332 362
333 const completionStyle: CSSObject = { 363 const completionStyle: CSSObject = {
334 '.cm-tooltip.cm-tooltip-autocomplete': { 364 '.cm-tooltip.cm-tooltip-autocomplete': {
335 ...theme.typography.editor, 365 ...editorFontStyle,
336 background: theme.palette.background.paper, 366 background: theme.palette.background.paper,
337 borderRadius: theme.shape.borderRadius, 367 borderRadius: theme.shape.borderRadius,
338 overflow: 'hidden', 368 overflow: 'hidden',
@@ -346,11 +376,11 @@ export default styled('div', {
346 color: theme.palette.text.secondary, 376 color: theme.palette.text.secondary,
347 }, 377 },
348 '.cm-completionLabel': { 378 '.cm-completionLabel': {
349 ...theme.typography.editor, 379 ...editorFontStyle,
350 color: theme.palette.text.primary, 380 color: theme.palette.text.primary,
351 }, 381 },
352 '.cm-completionDetail': { 382 '.cm-completionDetail': {
353 ...theme.typography.editor, 383 ...editorFontStyle,
354 color: theme.palette.text.secondary, 384 color: theme.palette.text.secondary,
355 fontStyle: 'normal', 385 fontStyle: 'normal',
356 }, 386 },
diff --git a/subprojects/frontend/src/editor/SearchPanelStore.ts b/subprojects/frontend/src/editor/SearchPanelStore.ts
index 43a571e5..8dd02ae6 100644
--- a/subprojects/frontend/src/editor/SearchPanelStore.ts
+++ b/subprojects/frontend/src/editor/SearchPanelStore.ts
@@ -7,7 +7,6 @@ import {
7 replaceAll, 7 replaceAll,
8 replaceNext, 8 replaceNext,
9 SearchQuery, 9 SearchQuery,
10 selectMatches,
11 setSearchQuery, 10 setSearchQuery,
12} from '@codemirror/search'; 11} from '@codemirror/search';
13import { action, computed, makeObservable, observable, override } from 'mobx'; 12import { action, computed, makeObservable, observable, override } from 'mobx';
@@ -31,7 +30,8 @@ export default class SearchPanelStore extends PanelStore {
31 updateQuery: action, 30 updateQuery: action,
32 findNext: action, 31 findNext: action,
33 findPrevious: action, 32 findPrevious: action,
34 selectMatches: action, 33 replaceNext: action,
34 replaceAll: action,
35 }); 35 });
36 } 36 }
37 37
@@ -82,10 +82,6 @@ export default class SearchPanelStore extends PanelStore {
82 this.store.doCommand(findPrevious); 82 this.store.doCommand(findPrevious);
83 } 83 }
84 84
85 selectMatches(): void {
86 this.store.doCommand(selectMatches);
87 }
88
89 replaceNext(): void { 85 replaceNext(): void {
90 this.store.doCommand(replaceNext); 86 this.store.doCommand(replaceNext);
91 } 87 }
diff --git a/subprojects/frontend/src/editor/SearchToolbar.tsx b/subprojects/frontend/src/editor/SearchToolbar.tsx
index dd7859c5..a5925328 100644
--- a/subprojects/frontend/src/editor/SearchToolbar.tsx
+++ b/subprojects/frontend/src/editor/SearchToolbar.tsx
@@ -2,7 +2,6 @@ import CloseIcon from '@mui/icons-material/Close';
2import FindReplaceIcon from '@mui/icons-material/FindReplace'; 2import FindReplaceIcon from '@mui/icons-material/FindReplace';
3import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; 3import KeyboardArrowDownIcon from '@mui/icons-material/KeyboardArrowDown';
4import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp'; 4import KeyboardArrowUpIcon from '@mui/icons-material/KeyboardArrowUp';
5import SearchIcon from '@mui/icons-material/Search';
6import Button from '@mui/material/Button'; 5import Button from '@mui/material/Button';
7import Checkbox from '@mui/material/Checkbox'; 6import Checkbox from '@mui/material/Checkbox';
8import FormControlLabel from '@mui/material/FormControlLabel'; 7import FormControlLabel from '@mui/material/FormControlLabel';
@@ -10,20 +9,31 @@ import FormHelperText from '@mui/material/FormHelperText';
10import IconButton from '@mui/material/IconButton'; 9import IconButton from '@mui/material/IconButton';
11import Stack from '@mui/material/Stack'; 10import Stack from '@mui/material/Stack';
12import TextField from '@mui/material/TextField'; 11import TextField from '@mui/material/TextField';
12import ToggleButton from '@mui/material/ToggleButton';
13import Toolbar from '@mui/material/Toolbar'; 13import Toolbar from '@mui/material/Toolbar';
14import useMediaQuery from '@mui/material/useMediaQuery';
14import { observer } from 'mobx-react-lite'; 15import { observer } from 'mobx-react-lite';
15import React, { useCallback } from 'react'; 16import React, { useCallback, useState } from 'react';
16 17
17import type SearchPanelStore from './SearchPanelStore'; 18import type SearchPanelStore from './SearchPanelStore';
18 19
20const SPLIT_MEDIA_QUERY = '@media (max-width: 1200px)';
21const ABBREVIATE_MEDIA_QUERY = '@media (max-width: 720px)';
22
19function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element { 23function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
20 const { 24 const {
21 id: panelId, 25 id: panelId,
22 query: { search, valid, caseSensitive, literal, regexp, replace }, 26 query: { search, valid, caseSensitive, literal, regexp, replace },
23 invalidRegexp, 27 invalidRegexp,
24 } = store; 28 } = store;
29 const split = useMediaQuery(SPLIT_MEDIA_QUERY);
30 const abbreviate = useMediaQuery(ABBREVIATE_MEDIA_QUERY);
31 const [showRepalceState, setShowReplaceState] = useState(false);
32
33 const showReplace = !split || showRepalceState || replace !== '';
25 34
26 const searchHelperId = `${panelId}-search-helper`; 35 const searchHelperId = `${panelId}-search-helper`;
36 const replaceId = `${panelId}-replace`;
27 37
28 const searchFieldRef = useCallback( 38 const searchFieldRef = useCallback(
29 (element: HTMLInputElement | null) => 39 (element: HTMLInputElement | null) =>
@@ -32,13 +42,20 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
32 ); 42 );
33 43
34 return ( 44 return (
35 <Toolbar variant="dense" sx={{ py: 0.5, alignItems: 'flex-start' }}> 45 <Toolbar
46 variant="dense"
47 sx={{ py: 0.5, alignItems: 'center', minHeight: 'auto' }}
48 >
36 <Stack 49 <Stack
37 direction="row" 50 direction={split ? 'column' : 'row'}
38 flexWrap="wrap" 51 sx={{
39 alignItems="center" 52 alignItems: 'center',
40 rowGap={0.5} 53 flexGrow: 1,
41 flexGrow={1} 54 [SPLIT_MEDIA_QUERY]: {
55 alignItems: 'start',
56 gap: 0.5,
57 },
58 }}
42 > 59 >
43 <Stack direction="row" flexWrap="wrap" alignItems="center" rowGap={0.5}> 60 <Stack direction="row" flexWrap="wrap" alignItems="center" rowGap={0.5}>
44 <TextField 61 <TextField
@@ -65,7 +82,7 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
65 }} 82 }}
66 variant="standard" 83 variant="standard"
67 size="small" 84 size="small"
68 sx={{ my: 0.25, mr: 1 }} 85 sx={{ mt: '4px', mr: 1 }}
69 inputRef={searchFieldRef} 86 inputRef={searchFieldRef}
70 /> 87 />
71 {invalidRegexp && ( 88 {invalidRegexp && (
@@ -92,6 +109,7 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
92 aria-label="Previous" 109 aria-label="Previous"
93 disabled={!valid} 110 disabled={!valid}
94 onClick={() => store.findPrevious()} 111 onClick={() => store.findPrevious()}
112 color="inherit"
95 > 113 >
96 <KeyboardArrowUpIcon fontSize="small" /> 114 <KeyboardArrowUpIcon fontSize="small" />
97 </IconButton> 115 </IconButton>
@@ -99,19 +117,17 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
99 aria-label="Next" 117 aria-label="Next"
100 disabled={!valid} 118 disabled={!valid}
101 onClick={() => store.findNext()} 119 onClick={() => store.findNext()}
120 color="inherit"
102 > 121 >
103 <KeyboardArrowDownIcon fontSize="small" /> 122 <KeyboardArrowDownIcon fontSize="small" />
104 </IconButton> 123 </IconButton>
105 <Button
106 disabled={!valid}
107 onClick={() => store.selectMatches()}
108 color="inherit"
109 startIcon={<SearchIcon fontSize="inherit" />}
110 >
111 Find all
112 </Button>
113 </Stack> 124 </Stack>
114 <Stack direction="row" flexWrap="wrap" rowGap={0.5}> 125 <Stack
126 direction="row"
127 flexWrap="wrap"
128 alignItems="center"
129 rowGap={0.5}
130 >
115 <FormControlLabel 131 <FormControlLabel
116 control={ 132 control={
117 <Checkbox 133 <Checkbox
@@ -122,7 +138,8 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
122 size="small" 138 size="small"
123 /> 139 />
124 } 140 }
125 label="Match case" 141 aria-label="Match case"
142 label={abbreviate ? 'Case' : 'Match case'}
126 /> 143 />
127 <FormControlLabel 144 <FormControlLabel
128 control={ 145 control={
@@ -134,7 +151,8 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
134 size="small" 151 size="small"
135 /> 152 />
136 } 153 }
137 label="Literal" 154 aria-label="Literal"
155 label={abbreviate ? 'Lit' : 'Literal'}
138 /> 156 />
139 <FormControlLabel 157 <FormControlLabel
140 control={ 158 control={
@@ -148,9 +166,36 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
148 } 166 }
149 label="Regexp" 167 label="Regexp"
150 /> 168 />
169 {split && (
170 <ToggleButton
171 value="show-replace"
172 selected={showReplace}
173 onClick={() => {
174 if (showReplace) {
175 store.updateQuery({ replace: '' });
176 setShowReplaceState(false);
177 } else {
178 setShowReplaceState(true);
179 }
180 }}
181 aria-label="Show replace options"
182 aria-controls={replaceId}
183 size="small"
184 sx={{ borderRadius: '100%' }}
185 >
186 <FindReplaceIcon fontSize="small" />
187 </ToggleButton>
188 )}
151 </Stack> 189 </Stack>
152 </Stack> 190 </Stack>
153 <Stack direction="row" flexWrap="wrap" alignItems="center" rowGap={0.5}> 191 <Stack
192 id={replaceId}
193 direction="row"
194 flexWrap="wrap"
195 alignItems="center"
196 rowGap={0.5}
197 display={showReplace ? 'flex' : 'none'}
198 >
154 <TextField 199 <TextField
155 placeholder="Replace with" 200 placeholder="Replace with"
156 aria-label="Replace with" 201 aria-label="Replace with"
@@ -166,9 +211,14 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
166 }} 211 }}
167 variant="standard" 212 variant="standard"
168 size="small" 213 size="small"
169 sx={{ mr: 1 }} 214 sx={{ mt: '4px', mr: 1 }}
170 /> 215 />
171 <Stack direction="row" flexWrap="wrap" rowGap={0.5}> 216 <Stack
217 direction="row"
218 flexWrap="wrap"
219 alignItems="center"
220 rowGap={0.5}
221 >
172 <Button 222 <Button
173 disabled={!valid} 223 disabled={!valid}
174 onClick={() => store.replaceNext()} 224 onClick={() => store.replaceNext()}
@@ -188,9 +238,15 @@ function SearchToolbar({ store }: { store: SearchPanelStore }): JSX.Element {
188 </Stack> 238 </Stack>
189 </Stack> 239 </Stack>
190 </Stack> 240 </Stack>
191 <IconButton onClick={() => store.close()} sx={{ mt: '2px', ml: 1 }}> 241 <Stack direction="row" alignSelf="stretch" alignItems="start" mt="1px">
192 <CloseIcon fontSize="small" /> 242 <IconButton
193 </IconButton> 243 aria-label="Close find/replace"
244 onClick={() => store.close()}
245 color="inherit"
246 >
247 <CloseIcon fontSize="small" />
248 </IconButton>
249 </Stack>
194 </Toolbar> 250 </Toolbar>
195 ); 251 );
196} 252}