aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2024-04-12 16:59:31 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2024-04-12 17:39:52 +0200
commitd087a0abc83c07c067d7ac7afff1acc57dad6220 (patch)
treee317ed7d5bd576efbb3af51be89bd3bfa5e00115
parentrefactor(frontend): friendlier table view messages (diff)
downloadrefinery-d087a0abc83c07c067d7ac7afff1acc57dad6220.tar.gz
refinery-d087a0abc83c07c067d7ac7afff1acc57dad6220.tar.zst
refinery-d087a0abc83c07c067d7ac7afff1acc57dad6220.zip
feat(frontend): add tooltips to buttons
-rw-r--r--subprojects/frontend/src/ToggleDarkModeButton.tsx13
-rw-r--r--subprojects/frontend/src/TopBar.tsx20
-rw-r--r--subprojects/frontend/src/editor/ConnectButton.tsx51
-rw-r--r--subprojects/frontend/src/editor/EditorButtons.tsx187
-rw-r--r--subprojects/frontend/src/editor/SearchToolbar.tsx94
-rw-r--r--subprojects/frontend/src/graph/SlideInPanel.tsx21
-rw-r--r--subprojects/frontend/src/graph/VisibilityPanel.tsx2
-rw-r--r--subprojects/frontend/src/graph/ZoomButtons.tsx38
-rw-r--r--subprojects/frontend/src/graph/export/ExportPanel.tsx2
-rw-r--r--subprojects/frontend/src/theme/ThemeProvider.tsx3
10 files changed, 238 insertions, 193 deletions
diff --git a/subprojects/frontend/src/ToggleDarkModeButton.tsx b/subprojects/frontend/src/ToggleDarkModeButton.tsx
index 7a835e61..58238cab 100644
--- a/subprojects/frontend/src/ToggleDarkModeButton.tsx
+++ b/subprojects/frontend/src/ToggleDarkModeButton.tsx
@@ -7,6 +7,7 @@
7import DarkModeIcon from '@mui/icons-material/DarkMode'; 7import DarkModeIcon from '@mui/icons-material/DarkMode';
8import LightModeIcon from '@mui/icons-material/LightMode'; 8import LightModeIcon from '@mui/icons-material/LightMode';
9import IconButton from '@mui/material/IconButton'; 9import IconButton from '@mui/material/IconButton';
10import Tooltip from '@mui/material/Tooltip';
10import { observer } from 'mobx-react-lite'; 11import { observer } from 'mobx-react-lite';
11 12
12import { useRootStore } from './RootStoreProvider'; 13import { useRootStore } from './RootStoreProvider';
@@ -16,12 +17,10 @@ export default observer(function ToggleDarkModeButton(): JSX.Element {
16 const { darkMode } = themeStore; 17 const { darkMode } = themeStore;
17 18
18 return ( 19 return (
19 <IconButton 20 <Tooltip title={darkMode ? 'Switch to light mode' : 'Switch to dark mode'}>
20 color="inherit" 21 <IconButton color="inherit" onClick={() => themeStore.toggleDarkMode()}>
21 onClick={() => themeStore.toggleDarkMode()} 22 {darkMode ? <LightModeIcon /> : <DarkModeIcon />}
22 aria-label={darkMode ? 'Switch to light mode' : 'Switch to dark mode'} 23 </IconButton>
23 > 24 </Tooltip>
24 {darkMode ? <LightModeIcon /> : <DarkModeIcon />}
25 </IconButton>
26 ); 25 );
27}); 26});
diff --git a/subprojects/frontend/src/TopBar.tsx b/subprojects/frontend/src/TopBar.tsx
index 6c9c4f7e..e41f956e 100644
--- a/subprojects/frontend/src/TopBar.tsx
+++ b/subprojects/frontend/src/TopBar.tsx
@@ -9,6 +9,7 @@ import AppBar from '@mui/material/AppBar';
9import IconButton from '@mui/material/IconButton'; 9import IconButton from '@mui/material/IconButton';
10import Stack from '@mui/material/Stack'; 10import Stack from '@mui/material/Stack';
11import Toolbar from '@mui/material/Toolbar'; 11import Toolbar from '@mui/material/Toolbar';
12import Tooltip from '@mui/material/Tooltip';
12import Typography from '@mui/material/Typography'; 13import Typography from '@mui/material/Typography';
13import { styled, useTheme } from '@mui/material/styles'; 14import { styled, useTheme } from '@mui/material/styles';
14import useMediaQuery from '@mui/material/useMediaQuery'; 15import useMediaQuery from '@mui/material/useMediaQuery';
@@ -134,7 +135,7 @@ export default observer(function TopBar(): JSX.Element {
134 py: 0.5, 135 py: 0.5,
135 }} 136 }}
136 > 137 >
137 <RefineryIcon size={24} /> 138 <RefineryIcon size={32} />
138 <Typography variant="h6" component="h1" pl={1}> 139 <Typography variant="h6" component="h1" pl={1}>
139 Refinery {import.meta.env.DEV && <DevModeBadge>Dev</DevModeBadge>} 140 Refinery {import.meta.env.DEV && <DevModeBadge>Dev</DevModeBadge>}
140 </Typography> 141 </Typography>
@@ -172,14 +173,15 @@ export default observer(function TopBar(): JSX.Element {
172 > 173 >
173 <GenerateButton editorStore={editorStore} hideWarnings={!veryLarge} /> 174 <GenerateButton editorStore={editorStore} hideWarnings={!veryLarge} />
174 {large && ( 175 {large && (
175 <IconButton 176 <Tooltip title="Check us out at GitHub">
176 aria-label="GitHub" 177 <IconButton
177 href="https://github.com/graphs4value/refinery" 178 href="https://github.com/graphs4value/refinery"
178 target="_blank" 179 target="_blank"
179 color="inherit" 180 color="inherit"
180 > 181 >
181 <GitHubIcon /> 182 <GitHubIcon />
182 </IconButton> 183 </IconButton>
184 </Tooltip>
183 )} 185 )}
184 </Stack> 186 </Stack>
185 <ToggleDarkModeButton /> 187 <ToggleDarkModeButton />
diff --git a/subprojects/frontend/src/editor/ConnectButton.tsx b/subprojects/frontend/src/editor/ConnectButton.tsx
index eed6fbc7..d08fbb4d 100644
--- a/subprojects/frontend/src/editor/ConnectButton.tsx
+++ b/subprojects/frontend/src/editor/ConnectButton.tsx
@@ -9,6 +9,7 @@ import CloudOffIcon from '@mui/icons-material/CloudOff';
9import SyncIcon from '@mui/icons-material/Sync'; 9import SyncIcon from '@mui/icons-material/Sync';
10import SyncProblemIcon from '@mui/icons-material/SyncProblem'; 10import SyncProblemIcon from '@mui/icons-material/SyncProblem';
11import IconButton from '@mui/material/IconButton'; 11import IconButton from '@mui/material/IconButton';
12import Tooltip from '@mui/material/Tooltip';
12import { keyframes, styled } from '@mui/material/styles'; 13import { keyframes, styled } from '@mui/material/styles';
13import { observer } from 'mobx-react-lite'; 14import { observer } from 'mobx-react-lite';
14 15
@@ -37,37 +38,51 @@ export default observer(function ConnectButton({
37 (editorStore.opening || editorStore.opened) 38 (editorStore.opening || editorStore.opened)
38 ) { 39 ) {
39 return ( 40 return (
40 <IconButton 41 <Tooltip
41 onClick={() => editorStore.disconnect()} 42 title={
42 aria-label="Disconnect" 43 editorStore.opening
43 color="inherit" 44 ? 'Connecting (click to cancel)'
45 : 'Connected (click to disconnect)'
46 }
44 > 47 >
45 {editorStore.opening ? ( 48 <IconButton
46 <AnimatedSyncIcon fontSize="small" /> 49 onClick={() => editorStore.disconnect()}
47 ) : ( 50 aria-label="Disconnect"
48 <CloudIcon fontSize="small" /> 51 color="inherit"
49 )} 52 >
50 </IconButton> 53 {editorStore.opening ? (
54 <AnimatedSyncIcon fontSize="small" />
55 ) : (
56 <CloudIcon fontSize="small" />
57 )}
58 </IconButton>
59 </Tooltip>
51 ); 60 );
52 } 61 }
53 62
63 let title: string;
54 let disconnectedIcon: JSX.Element; 64 let disconnectedIcon: JSX.Element;
55 if (editorStore === undefined) { 65 if (editorStore === undefined) {
66 title = 'Connecting';
56 disconnectedIcon = <SyncIcon fontSize="small" />; 67 disconnectedIcon = <SyncIcon fontSize="small" />;
57 } else if (editorStore.connectionErrors.length > 0) { 68 } else if (editorStore.connectionErrors.length > 0) {
69 title = 'Connection error (click to retry)';
58 disconnectedIcon = <SyncProblemIcon fontSize="small" />; 70 disconnectedIcon = <SyncProblemIcon fontSize="small" />;
59 } else { 71 } else {
72 title = 'Disconnected (click to connect)';
60 disconnectedIcon = <CloudOffIcon fontSize="small" />; 73 disconnectedIcon = <CloudOffIcon fontSize="small" />;
61 } 74 }
62 75
63 return ( 76 return (
64 <IconButton 77 <Tooltip title={title}>
65 disabled={editorStore === undefined} 78 <IconButton
66 onClick={() => editorStore?.connect()} 79 disabled={editorStore === undefined}
67 aria-label="Connect" 80 onClick={() => editorStore?.connect()}
68 color="inherit" 81 aria-label="Connect"
69 > 82 color="inherit"
70 {disconnectedIcon} 83 >
71 </IconButton> 84 {disconnectedIcon}
85 </IconButton>
86 </Tooltip>
72 ); 87 );
73}); 88});
diff --git a/subprojects/frontend/src/editor/EditorButtons.tsx b/subprojects/frontend/src/editor/EditorButtons.tsx
index 4afba607..50cd51dc 100644
--- a/subprojects/frontend/src/editor/EditorButtons.tsx
+++ b/subprojects/frontend/src/editor/EditorButtons.tsx
@@ -22,6 +22,7 @@ import IconButton from '@mui/material/IconButton';
22import Stack from '@mui/material/Stack'; 22import Stack from '@mui/material/Stack';
23import ToggleButton from '@mui/material/ToggleButton'; 23import ToggleButton from '@mui/material/ToggleButton';
24import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'; 24import ToggleButtonGroup from '@mui/material/ToggleButtonGroup';
25import Tooltip from '@mui/material/Tooltip';
25import { observer } from 'mobx-react-lite'; 26import { observer } from 'mobx-react-lite';
26 27
27import ConnectButton from './ConnectButton'; 28import ConnectButton from './ConnectButton';
@@ -49,103 +50,113 @@ export default observer(function EditorButtons({
49}): JSX.Element { 50}): JSX.Element {
50 return ( 51 return (
51 <Stack direction="row" flexGrow={1}> 52 <Stack direction="row" flexGrow={1}>
52 <IconButton 53 <Tooltip title="Open">
53 disabled={editorStore === undefined}
54 onClick={() => editorStore?.openFile()}
55 aria-label="Open"
56 color="inherit"
57 >
58 <FileOpenIcon fontSize="small" />
59 </IconButton>
60 <IconButton
61 disabled={editorStore === undefined || !editorStore.unsavedChanges}
62 onClick={() => editorStore?.saveFile()}
63 aria-label="Save"
64 color="inherit"
65 >
66 <SaveIcon fontSize="small" />
67 </IconButton>
68 {'showSaveFilePicker' in window && (
69 <IconButton 54 <IconButton
70 disabled={editorStore === undefined} 55 disabled={editorStore === undefined}
71 onClick={() => editorStore?.saveFileAs()} 56 onClick={() => editorStore?.openFile()}
72 aria-label="Save as"
73 color="inherit" 57 color="inherit"
74 > 58 >
75 <SaveAsIcon fontSize="small" /> 59 <FileOpenIcon fontSize="small" />
76 </IconButton> 60 </IconButton>
77 )} 61 </Tooltip>
78 <IconButton 62 <Tooltip title="Save">
79 disabled={editorStore === undefined || !editorStore.canUndo} 63 <IconButton
80 onClick={() => editorStore?.undo()} 64 disabled={editorStore === undefined || !editorStore.unsavedChanges}
81 aria-label="Undo" 65 onClick={() => editorStore?.saveFile()}
82 color="inherit" 66 color="inherit"
83 sx={{ ml: 1 }}
84 >
85 <UndoIcon fontSize="small" />
86 </IconButton>
87 <IconButton
88 disabled={editorStore === undefined || !editorStore.canRedo}
89 onClick={() => editorStore?.redo()}
90 aria-label="Redo"
91 color="inherit"
92 >
93 <RedoIcon fontSize="small" />
94 </IconButton>
95 <ToggleButtonGroup size="small" className="rounded" sx={{ mx: 1 }}>
96 <ToggleButton
97 selected={editorStore?.showLineNumbers ?? false}
98 disabled={editorStore === undefined}
99 onClick={() => editorStore?.toggleLineNumbers()}
100 aria-label="Show line numbers"
101 value="show-line-numbers"
102 >
103 <FormatListNumberedIcon fontSize="small" />
104 </ToggleButton>
105 <ToggleButton
106 selected={editorStore?.colorIdentifiers ?? false}
107 disabled={editorStore === undefined}
108 onClick={() => editorStore?.toggleColorIdentifiers()}
109 aria-label="Color identifiers"
110 value="color-identifiers"
111 > 67 >
112 <LooksIcon fontSize="small" /> 68 <SaveIcon fontSize="small" />
113 </ToggleButton> 69 </IconButton>
114 <ToggleButton 70 </Tooltip>
115 selected={editorStore?.searchPanel?.state ?? false} 71 {'showSaveFilePicker' in window && (
116 disabled={editorStore === undefined} 72 <Tooltip title={`Save as\u2026`}>
117 onClick={() => editorStore?.searchPanel?.toggle()} 73 <IconButton
118 aria-label="Show find/replace" 74 disabled={editorStore === undefined}
119 {...(editorStore !== undefined && 75 onClick={() => editorStore?.saveFileAs()}
120 editorStore.searchPanel.state && { 76 color="inherit"
121 'aria-controls': editorStore.searchPanel.id, 77 >
122 })} 78 <SaveAsIcon fontSize="small" />
123 value="show-search-panel" 79 </IconButton>
80 </Tooltip>
81 )}
82 <Tooltip title="Undo">
83 <IconButton
84 disabled={editorStore === undefined || !editorStore.canUndo}
85 onClick={() => editorStore?.undo()}
86 color="inherit"
87 sx={{ ml: 1 }}
124 > 88 >
125 <SearchIcon fontSize="small" /> 89 <UndoIcon fontSize="small" />
126 </ToggleButton> 90 </IconButton>
127 <ToggleButton 91 </Tooltip>
128 selected={editorStore?.lintPanel?.state ?? false} 92 <Tooltip title="Redo">
129 disabled={editorStore === undefined} 93 <IconButton
130 onClick={() => editorStore?.lintPanel.toggle()} 94 disabled={editorStore === undefined || !editorStore.canRedo}
131 aria-label="Show diagnostics panel" 95 onClick={() => editorStore?.redo()}
132 {...(editorStore !== undefined && 96 color="inherit"
133 editorStore.lintPanel.state && {
134 'aria-controls': editorStore.lintPanel.id,
135 })}
136 value="show-lint-panel"
137 > 97 >
138 {getLintIcon(editorStore?.delayedErrors?.highestDiagnosticLevel)} 98 <RedoIcon fontSize="small" />
139 </ToggleButton> 99 </IconButton>
100 </Tooltip>
101 <ToggleButtonGroup size="small" className="rounded" sx={{ mx: 1 }}>
102 <Tooltip title="Line numbers">
103 <ToggleButton
104 selected={editorStore?.showLineNumbers ?? false}
105 disabled={editorStore === undefined}
106 onClick={() => editorStore?.toggleLineNumbers()}
107 value="show-line-numbers"
108 >
109 <FormatListNumberedIcon fontSize="small" />
110 </ToggleButton>
111 </Tooltip>
112 <Tooltip title="Color identifiers">
113 <ToggleButton
114 selected={editorStore?.colorIdentifiers ?? false}
115 disabled={editorStore === undefined}
116 onClick={() => editorStore?.toggleColorIdentifiers()}
117 value="color-identifiers"
118 >
119 <LooksIcon fontSize="small" />
120 </ToggleButton>
121 </Tooltip>
122 <Tooltip title="Find and replace">
123 <ToggleButton
124 selected={editorStore?.searchPanel?.state ?? false}
125 disabled={editorStore === undefined}
126 onClick={() => editorStore?.searchPanel?.toggle()}
127 {...(editorStore !== undefined &&
128 editorStore.searchPanel.state && {
129 'aria-controls': editorStore.searchPanel.id,
130 })}
131 value="show-search-panel"
132 >
133 <SearchIcon fontSize="small" />
134 </ToggleButton>
135 </Tooltip>
136 <Tooltip title="Diagnostics panel">
137 <ToggleButton
138 selected={editorStore?.lintPanel?.state ?? false}
139 disabled={editorStore === undefined}
140 onClick={() => editorStore?.lintPanel.toggle()}
141 {...(editorStore !== undefined &&
142 editorStore.lintPanel.state && {
143 'aria-controls': editorStore.lintPanel.id,
144 })}
145 value="show-lint-panel"
146 >
147 {getLintIcon(editorStore?.delayedErrors?.highestDiagnosticLevel)}
148 </ToggleButton>
149 </Tooltip>
140 </ToggleButtonGroup> 150 </ToggleButtonGroup>
141 <IconButton 151 <Tooltip title="Automatic format">
142 disabled={editorStore === undefined || !editorStore.opened} 152 <IconButton
143 onClick={() => editorStore?.formatText()} 153 disabled={editorStore === undefined || !editorStore.opened}
144 aria-label="Automatic format" 154 onClick={() => editorStore?.formatText()}
145 color="inherit" 155 color="inherit"
146 > 156 >
147 <FormatPaintIcon fontSize="small" /> 157 <FormatPaintIcon fontSize="small" />
148 </IconButton> 158 </IconButton>
159 </Tooltip>
149 <ConnectButton editorStore={editorStore} /> 160 <ConnectButton editorStore={editorStore} />
150 </Stack> 161 </Stack>
151 ); 162 );
diff --git a/subprojects/frontend/src/editor/SearchToolbar.tsx b/subprojects/frontend/src/editor/SearchToolbar.tsx
index 4ae7e893..bfdff234 100644
--- a/subprojects/frontend/src/editor/SearchToolbar.tsx
+++ b/subprojects/frontend/src/editor/SearchToolbar.tsx
@@ -17,15 +17,14 @@ import Stack from '@mui/material/Stack';
17import TextField from '@mui/material/TextField'; 17import TextField from '@mui/material/TextField';
18import ToggleButton from '@mui/material/ToggleButton'; 18import ToggleButton from '@mui/material/ToggleButton';
19import Toolbar from '@mui/material/Toolbar'; 19import Toolbar from '@mui/material/Toolbar';
20import Tooltip from '@mui/material/Tooltip';
20import { styled } from '@mui/material/styles'; 21import { styled } from '@mui/material/styles';
21import useMediaQuery from '@mui/material/useMediaQuery';
22import { observer } from 'mobx-react-lite'; 22import { observer } from 'mobx-react-lite';
23import { useCallback, useState } from 'react'; 23import { useCallback, useState } from 'react';
24import { useResizeDetector } from 'react-resize-detector';
24 25
25import type SearchPanelStore from './SearchPanelStore'; 26import type SearchPanelStore from './SearchPanelStore';
26 27
27const SPLIT_MEDIA_QUERY = '@media (max-width: 1200px)';
28
29const DimLabel = styled(FormControlLabel)(({ theme }) => ({ 28const DimLabel = styled(FormControlLabel)(({ theme }) => ({
30 '.MuiFormControlLabel-label': { 29 '.MuiFormControlLabel-label': {
31 ...theme.typography.body2, 30 ...theme.typography.body2,
@@ -43,7 +42,8 @@ export default observer(function SearchToolbar({
43 query: { search, valid, caseSensitive, literal, regexp, replace }, 42 query: { search, valid, caseSensitive, literal, regexp, replace },
44 invalidRegexp, 43 invalidRegexp,
45 } = searchPanelStore; 44 } = searchPanelStore;
46 const split = useMediaQuery(SPLIT_MEDIA_QUERY); 45 const { width, ref } = useResizeDetector();
46 const split = width !== undefined && width <= 1200;
47 const [showRepalceState, setShowReplaceState] = useState(false); 47 const [showRepalceState, setShowReplaceState] = useState(false);
48 48
49 const showReplace = !split || showRepalceState || replace !== ''; 49 const showReplace = !split || showRepalceState || replace !== '';
@@ -61,16 +61,19 @@ export default observer(function SearchToolbar({
61 <Toolbar 61 <Toolbar
62 variant="dense" 62 variant="dense"
63 sx={{ py: 0.5, alignItems: 'center', minHeight: 'auto' }} 63 sx={{ py: 0.5, alignItems: 'center', minHeight: 'auto' }}
64 ref={ref}
64 > 65 >
65 <Stack 66 <Stack
66 direction={split ? 'column' : 'row'} 67 direction={split ? 'column' : 'row'}
67 sx={{ 68 sx={{
68 alignItems: 'center', 69 alignItems: 'center',
69 flexGrow: 1, 70 flexGrow: 1,
70 [SPLIT_MEDIA_QUERY]: { 71 ...(split
71 alignItems: 'start', 72 ? {
72 gap: 0.5, 73 alignItems: 'start',
73 }, 74 gap: 0.5,
75 }
76 : {}),
74 }} 77 }}
75 > 78 >
76 <Stack direction="row" flexWrap="wrap" alignItems="center" rowGap={0.5}> 79 <Stack direction="row" flexWrap="wrap" alignItems="center" rowGap={0.5}>
@@ -121,22 +124,24 @@ export default observer(function SearchToolbar({
121 mr={1} 124 mr={1}
122 rowGap={0.5} 125 rowGap={0.5}
123 > 126 >
124 <IconButton 127 <Tooltip title="Previous match">
125 aria-label="Previous" 128 <IconButton
126 disabled={!valid} 129 disabled={!valid}
127 onClick={() => searchPanelStore.findPrevious()} 130 onClick={() => searchPanelStore.findPrevious()}
128 color="inherit" 131 color="inherit"
129 > 132 >
130 <KeyboardArrowUpIcon fontSize="small" /> 133 <KeyboardArrowUpIcon fontSize="small" />
131 </IconButton> 134 </IconButton>
132 <IconButton 135 </Tooltip>
133 aria-label="Next" 136 <Tooltip title="Next match">
134 disabled={!valid} 137 <IconButton
135 onClick={() => searchPanelStore.findNext()} 138 disabled={!valid}
136 color="inherit" 139 onClick={() => searchPanelStore.findNext()}
137 > 140 color="inherit"
138 <KeyboardArrowDownIcon fontSize="small" /> 141 >
139 </IconButton> 142 <KeyboardArrowDownIcon fontSize="small" />
143 </IconButton>
144 </Tooltip>
140 </Stack> 145 </Stack>
141 <Stack 146 <Stack
142 direction="row" 147 direction="row"
@@ -187,24 +192,25 @@ export default observer(function SearchToolbar({
187 label="Regexp" 192 label="Regexp"
188 /> 193 />
189 {split && ( 194 {split && (
190 <ToggleButton 195 <Tooltip title="Replace">
191 value="show-replace" 196 <ToggleButton
192 selected={showReplace} 197 value="show-replace"
193 onClick={() => { 198 selected={showReplace}
194 if (showReplace) { 199 onClick={() => {
195 searchPanelStore.updateQuery({ replace: '' }); 200 if (showReplace) {
196 setShowReplaceState(false); 201 searchPanelStore.updateQuery({ replace: '' });
197 } else { 202 setShowReplaceState(false);
198 setShowReplaceState(true); 203 } else {
199 } 204 setShowReplaceState(true);
200 }} 205 }
201 aria-label="Show replace options" 206 }}
202 aria-controls={replaceId} 207 aria-controls={replaceId}
203 size="small" 208 size="small"
204 className="iconOnly" 209 className="iconOnly"
205 > 210 >
206 <FindReplaceIcon fontSize="small" /> 211 <FindReplaceIcon fontSize="small" />
207 </ToggleButton> 212 </ToggleButton>
213 </Tooltip>
208 )} 214 )}
209 </Stack> 215 </Stack>
210 </Stack> 216 </Stack>
@@ -263,9 +269,7 @@ export default observer(function SearchToolbar({
263 alignSelf="stretch" 269 alignSelf="stretch"
264 alignItems="start" 270 alignItems="start"
265 mt="1px" 271 mt="1px"
266 sx={{ 272 sx={split ? { display: 'none' } : {}}
267 [SPLIT_MEDIA_QUERY]: { display: 'none' },
268 }}
269 > 273 >
270 <IconButton 274 <IconButton
271 aria-label="Close find/replace" 275 aria-label="Close find/replace"
diff --git a/subprojects/frontend/src/graph/SlideInPanel.tsx b/subprojects/frontend/src/graph/SlideInPanel.tsx
index 2c189b5b..47bbe0a6 100644
--- a/subprojects/frontend/src/graph/SlideInPanel.tsx
+++ b/subprojects/frontend/src/graph/SlideInPanel.tsx
@@ -8,6 +8,7 @@ import Dialog from '@mui/material/Dialog';
8import IconButton from '@mui/material/IconButton'; 8import IconButton from '@mui/material/IconButton';
9import Paper from '@mui/material/Paper'; 9import Paper from '@mui/material/Paper';
10import Slide from '@mui/material/Slide'; 10import Slide from '@mui/material/Slide';
11import Tooltip from '@mui/material/Tooltip';
11import { styled } from '@mui/material/styles'; 12import { styled } from '@mui/material/styles';
12import React, { useCallback, useId, useState } from 'react'; 13import React, { useCallback, useId, useState } from 'react';
13 14
@@ -58,15 +59,19 @@ export default function SlideInPanel({
58 59
59 return ( 60 return (
60 <SlideInPanelRoot anchor={anchor}> 61 <SlideInPanelRoot anchor={anchor}>
61 <IconButton 62 <Tooltip
62 role="switch" 63 title={iconLabel}
63 aria-checked={show} 64 placement={anchor === 'left' ? 'right' : 'left'}
64 aria-controls={dialog ? undefined : id}
65 aria-label={iconLabel}
66 onClick={() => setShow(!show)}
67 > 65 >
68 {icon(show)} 66 <IconButton
69 </IconButton> 67 role="switch"
68 aria-checked={show}
69 aria-controls={dialog ? undefined : id}
70 onClick={() => setShow(!show)}
71 >
72 {icon(show)}
73 </IconButton>
74 </Tooltip>
70 {dialog ? ( 75 {dialog ? (
71 <Dialog open={show} onClose={close} maxWidth="xl"> 76 <Dialog open={show} onClose={close} maxWidth="xl">
72 <SlideInDialog close={close} dialog title={title} buttons={buttons}> 77 <SlideInDialog close={close} dialog title={title} buttons={buttons}>
diff --git a/subprojects/frontend/src/graph/VisibilityPanel.tsx b/subprojects/frontend/src/graph/VisibilityPanel.tsx
index 210ff5d5..8474b7be 100644
--- a/subprojects/frontend/src/graph/VisibilityPanel.tsx
+++ b/subprojects/frontend/src/graph/VisibilityPanel.tsx
@@ -199,7 +199,7 @@ function VisibilityPanel({
199 dialog={dialog} 199 dialog={dialog}
200 title="Customize view" 200 title="Customize view"
201 icon={icon} 201 icon={icon}
202 iconLabel="Show filter panel" 202 iconLabel="Filter panel"
203 buttons={ 203 buttons={
204 <> 204 <>
205 <Button 205 <Button
diff --git a/subprojects/frontend/src/graph/ZoomButtons.tsx b/subprojects/frontend/src/graph/ZoomButtons.tsx
index 83938cf4..b292a617 100644
--- a/subprojects/frontend/src/graph/ZoomButtons.tsx
+++ b/subprojects/frontend/src/graph/ZoomButtons.tsx
@@ -10,6 +10,7 @@ import RemoveIcon from '@mui/icons-material/Remove';
10import IconButton from '@mui/material/IconButton'; 10import IconButton from '@mui/material/IconButton';
11import Stack from '@mui/material/Stack'; 11import Stack from '@mui/material/Stack';
12import ToggleButton from '@mui/material/ToggleButton'; 12import ToggleButton from '@mui/material/ToggleButton';
13import Tooltip from '@mui/material/Tooltip';
13 14
14import type { ChangeZoomCallback, SetFitZoomCallback } from './ZoomCanvas'; 15import type { ChangeZoomCallback, SetFitZoomCallback } from './ZoomCanvas';
15 16
@@ -28,22 +29,27 @@ export default function ZoomButtons({
28 p={1} 29 p={1}
29 sx={{ position: 'absolute', bottom: 0, right: 0 }} 30 sx={{ position: 'absolute', bottom: 0, right: 0 }}
30 > 31 >
31 <IconButton aria-label="Zoom in" onClick={() => changeZoom(2)}> 32 <Tooltip title="Zoom in" placement="left">
32 <AddIcon fontSize="small" /> 33 <IconButton onClick={() => changeZoom(2)}>
33 </IconButton> 34 <AddIcon fontSize="small" />
34 <IconButton aria-label="Zoom out" onClick={() => changeZoom(0.5)}> 35 </IconButton>
35 <RemoveIcon fontSize="small" /> 36 </Tooltip>
36 </IconButton> 37 <Tooltip title="Zoom out" placement="left">
37 <ToggleButton 38 <IconButton onClick={() => changeZoom(0.5)}>
38 value="show-replace" 39 <RemoveIcon fontSize="small" />
39 selected={fitZoom} 40 </IconButton>
40 onClick={() => setFitZoom(!fitZoom)} 41 </Tooltip>
41 aria-label="Fit screen" 42 <Tooltip title="Fit screen" placement="left">
42 size="small" 43 <ToggleButton
43 className="iconOnly" 44 value="show-replace"
44 > 45 selected={fitZoom}
45 <CropFreeIcon fontSize="small" /> 46 onClick={() => setFitZoom(!fitZoom)}
46 </ToggleButton> 47 size="small"
48 className="iconOnly"
49 >
50 <CropFreeIcon fontSize="small" />
51 </ToggleButton>
52 </Tooltip>
47 </Stack> 53 </Stack>
48 ); 54 );
49} 55}
diff --git a/subprojects/frontend/src/graph/export/ExportPanel.tsx b/subprojects/frontend/src/graph/export/ExportPanel.tsx
index 8d82b95c..81bd9081 100644
--- a/subprojects/frontend/src/graph/export/ExportPanel.tsx
+++ b/subprojects/frontend/src/graph/export/ExportPanel.tsx
@@ -135,7 +135,7 @@ function ExportPanel({
135 dialog={dialog} 135 dialog={dialog}
136 title="Export diagram" 136 title="Export diagram"
137 icon={icon} 137 icon={icon}
138 iconLabel="Show export panel" 138 iconLabel={`Export image\u2026`}
139 buttons={buttons} 139 buttons={buttons}
140 > 140 >
141 <SwitchButtonGroup size="small" className="rounded"> 141 <SwitchButtonGroup size="small" className="rounded">
diff --git a/subprojects/frontend/src/theme/ThemeProvider.tsx b/subprojects/frontend/src/theme/ThemeProvider.tsx
index 6905fb4b..1d70dbaf 100644
--- a/subprojects/frontend/src/theme/ThemeProvider.tsx
+++ b/subprojects/frontend/src/theme/ThemeProvider.tsx
@@ -206,6 +206,9 @@ function createResponsiveTheme(
206 tooltip: { 206 tooltip: {
207 background: alpha('#212121', 0.93), 207 background: alpha('#212121', 0.93),
208 color: '#fff', 208 color: '#fff',
209 fontSize: '0.875rem',
210 lineHeight: 1.43,
211 letterSpacing: '0.01071em',
209 }, 212 },
210 arrow: { 213 arrow: {
211 color: alpha('#212121', 0.93), 214 color: alpha('#212121', 0.93),