aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-21 00:33:01 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2022-08-21 02:01:59 +0200
commit8ebc24a5ba1c87cb5cb14fbaff3bee329e30fc15 (patch)
tree2ea323c637ef371d4bdfc9ccc69460147dd1597b
parentfeat(frontend): try to match OS theme (diff)
downloadrefinery-8ebc24a5ba1c87cb5cb14fbaff3bee329e30fc15.tar.gz
refinery-8ebc24a5ba1c87cb5cb14fbaff3bee329e30fc15.tar.zst
refinery-8ebc24a5ba1c87cb5cb14fbaff3bee329e30fc15.zip
feat(frontend): overlay window controls
Might need manual intervention in browsers, e.g. https://docs.microsoft.com/en-us/microsoft-edge/progressive-web-apps-chromium/how-to/window-controls-overlay#enable-the-window-controls-overlay-api-in-microsoft-edge
-rw-r--r--subprojects/frontend/package.json2
-rw-r--r--subprojects/frontend/src/TopBar.tsx58
-rw-r--r--subprojects/frontend/src/WindowControlsOverlayColor.tsx21
-rw-r--r--subprojects/frontend/src/index.tsx2
-rw-r--r--subprojects/frontend/types/windowControlsOverlay.d.ts32
-rw-r--r--subprojects/frontend/vite.config.ts2
-rw-r--r--yarn.lock25
7 files changed, 140 insertions, 2 deletions
diff --git a/subprojects/frontend/package.json b/subprojects/frontend/package.json
index aa453cd0..448b9710 100644
--- a/subprojects/frontend/package.json
+++ b/subprojects/frontend/package.json
@@ -40,8 +40,10 @@
40 "@material-icons/svg": "^1.0.32", 40 "@material-icons/svg": "^1.0.32",
41 "@mui/icons-material": "5.8.4", 41 "@mui/icons-material": "5.8.4",
42 "@mui/material": "5.10.1", 42 "@mui/material": "5.10.1",
43 "@types/lodash-es": "^4.17.6",
43 "ansi-styles": "^6.1.0", 44 "ansi-styles": "^6.1.0",
44 "escape-string-regexp": "^5.0.0", 45 "escape-string-regexp": "^5.0.0",
46 "lodash-es": "^4.17.21",
45 "loglevel": "^1.8.0", 47 "loglevel": "^1.8.0",
46 "loglevel-plugin-prefix": "^0.8.4", 48 "loglevel-plugin-prefix": "^0.8.4",
47 "mobx": "^6.6.1", 49 "mobx": "^6.6.1",
diff --git a/subprojects/frontend/src/TopBar.tsx b/subprojects/frontend/src/TopBar.tsx
index 5ad80d40..4424e6b3 100644
--- a/subprojects/frontend/src/TopBar.tsx
+++ b/subprojects/frontend/src/TopBar.tsx
@@ -1,11 +1,47 @@
1import AppBar from '@mui/material/AppBar'; 1import AppBar from '@mui/material/AppBar';
2import Toolbar from '@mui/material/Toolbar'; 2import Toolbar from '@mui/material/Toolbar';
3import Typography from '@mui/material/Typography'; 3import Typography from '@mui/material/Typography';
4import React from 'react'; 4import { throttle } from 'lodash-es';
5import React, { useEffect, useMemo, useState } from 'react';
5 6
6import ToggleDarkModeButton from './ToggleDarkModeButton'; 7import ToggleDarkModeButton from './ToggleDarkModeButton';
7 8
9function useWindowControlsOverlayVisible(): boolean {
10 const [windowControlsOverlayVisible, setWindowControlsOverlayVisible] =
11 useState(false);
12 const updateWindowControlsOverlayVisible = useMemo(
13 () =>
14 throttle(
15 ({ visible }: WindowControlsOverlayGeometryChangeEvent) =>
16 setWindowControlsOverlayVisible(visible),
17 250,
18 ),
19 [],
20 );
21 useEffect(() => {
22 if ('windowControlsOverlay' in navigator) {
23 const { windowControlsOverlay } = navigator;
24 setWindowControlsOverlayVisible(windowControlsOverlay.visible);
25 windowControlsOverlay.addEventListener(
26 'geometrychange',
27 updateWindowControlsOverlayVisible,
28 );
29 return () => {
30 windowControlsOverlay.removeEventListener(
31 'geometrychange',
32 updateWindowControlsOverlayVisible,
33 );
34 };
35 }
36 // Nothing to clean up if `windowControlsOverlay` is unsupported.
37 return () => {};
38 }, [updateWindowControlsOverlayVisible]);
39 return windowControlsOverlayVisible;
40}
41
8export default function TopBar(): JSX.Element { 42export default function TopBar(): JSX.Element {
43 const overlayVisible = useWindowControlsOverlayVisible();
44
9 return ( 45 return (
10 <AppBar 46 <AppBar
11 position="static" 47 position="static"
@@ -14,9 +50,27 @@ export default function TopBar(): JSX.Element {
14 sx={(theme) => ({ 50 sx={(theme) => ({
15 background: theme.palette.outer.background, 51 background: theme.palette.outer.background,
16 borderBottom: `1px solid ${theme.palette.outer.border}`, 52 borderBottom: `1px solid ${theme.palette.outer.border}`,
53 appRegion: 'drag',
54 '.MuiButtonBase-root': {
55 appRegion: 'no-drag',
56 },
17 })} 57 })}
18 > 58 >
19 <Toolbar> 59 <Toolbar
60 sx={{
61 ...(overlayVisible
62 ? {
63 marginLeft: 'env(titlebar-area-x, 0)',
64 marginTop: 'env(titlebar-area-y, 0)',
65 width: 'env(titlebar-area-width, 100%)',
66 minHeight: 'env(titlebar-area-height, auto)',
67 }
68 : {
69 minHeight: 'auto',
70 }),
71 py: 0.5,
72 }}
73 >
20 <Typography variant="h6" component="h1" flexGrow={1}> 74 <Typography variant="h6" component="h1" flexGrow={1}>
21 Refinery 75 Refinery
22 </Typography> 76 </Typography>
diff --git a/subprojects/frontend/src/WindowControlsOverlayColor.tsx b/subprojects/frontend/src/WindowControlsOverlayColor.tsx
new file mode 100644
index 00000000..14eda566
--- /dev/null
+++ b/subprojects/frontend/src/WindowControlsOverlayColor.tsx
@@ -0,0 +1,21 @@
1import { useTheme } from '@mui/material/styles';
2import { useEffect } from 'react';
3
4export default function WindowControlsOverlayColor(): null {
5 const {
6 palette: {
7 outer: { background },
8 },
9 } = useTheme();
10 useEffect(() => {
11 document.head
12 .querySelectorAll('meta[name="theme-color"]')
13 .forEach((meta) => meta.remove());
14 const meta = document.createElement('meta');
15 meta.name = 'theme-color';
16 meta.content = background;
17 document.head.appendChild(meta);
18 }, [background]);
19
20 return null;
21}
diff --git a/subprojects/frontend/src/index.tsx b/subprojects/frontend/src/index.tsx
index a65821ef..460f6f77 100644
--- a/subprojects/frontend/src/index.tsx
+++ b/subprojects/frontend/src/index.tsx
@@ -6,6 +6,7 @@ import { createRoot } from 'react-dom/client';
6import Loading from './Loading'; 6import Loading from './Loading';
7import RegisterServiceWorker from './RegisterServiceWorker'; 7import RegisterServiceWorker from './RegisterServiceWorker';
8import RootStore, { RootStoreProvider } from './RootStore'; 8import RootStore, { RootStoreProvider } from './RootStore';
9import WindowControlsOverlayColor from './WindowControlsOverlayColor';
9import ThemeProvider from './theme/ThemeProvider'; 10import ThemeProvider from './theme/ThemeProvider';
10import getLogger from './utils/getLogger'; 11import getLogger from './utils/getLogger';
11 12
@@ -67,6 +68,7 @@ const app = (
67 <RootStoreProvider rootStore={rootStore}> 68 <RootStoreProvider rootStore={rootStore}>
68 <ThemeProvider> 69 <ThemeProvider>
69 <CssBaseline enableColorScheme /> 70 <CssBaseline enableColorScheme />
71 <WindowControlsOverlayColor />
70 <SnackbarProvider> 72 <SnackbarProvider>
71 <RegisterServiceWorker /> 73 <RegisterServiceWorker />
72 <Suspense fallback={<Loading />}> 74 <Suspense fallback={<Loading />}>
diff --git a/subprojects/frontend/types/windowControlsOverlay.d.ts b/subprojects/frontend/types/windowControlsOverlay.d.ts
new file mode 100644
index 00000000..d8f3182f
--- /dev/null
+++ b/subprojects/frontend/types/windowControlsOverlay.d.ts
@@ -0,0 +1,32 @@
1interface WindowControlsOverlayGeometryChangeEvent extends Event {
2 titlebarAreaRect: DOMRect;
3
4 visible: boolean;
5}
6
7interface WindowControlsOverlay {
8 readonly visible: boolean;
9
10 getTitlebarAreaRect(): DOMRect;
11
12 addEventListener(
13 type: 'geometrychange',
14 listener: (
15 this: WindowControlsOverlay,
16 event: WindowControlsOverlayGeometryChangeEvent,
17 ) => unknown,
18 options?: boolean | AddEventListenerOptions,
19 );
20
21 removeEventListener(
22 type: 'geometrychange',
23 listener: (
24 this: WindowControlsOverlay,
25 event: WindowControlsOverlayGeometryChangeEvent,
26 ) => unknown,
27 );
28}
29
30interface Navigator {
31 windowControlsOverlay?: WindowControlsOverlay;
32}
diff --git a/subprojects/frontend/vite.config.ts b/subprojects/frontend/vite.config.ts
index 6ec2d513..f2e0f15c 100644
--- a/subprojects/frontend/vite.config.ts
+++ b/subprojects/frontend/vite.config.ts
@@ -111,6 +111,8 @@ export default defineConfig({
111 description: 111 description:
112 'An efficient graph sovler for generating well-formed models', 112 'An efficient graph sovler for generating well-formed models',
113 theme_color: '#21252b', 113 theme_color: '#21252b',
114 display_override: ['window-controls-overlay'],
115 display: 'standalone',
114 background_color: '#21252b', 116 background_color: '#21252b',
115 icons: [ 117 icons: [
116 { 118 {
diff --git a/yarn.lock b/yarn.lock
index 472025aa..ca217f1a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2010,6 +2010,7 @@ __metadata:
2010 "@mui/material": 5.10.1 2010 "@mui/material": 5.10.1
2011 "@types/eslint": ^8.4.6 2011 "@types/eslint": ^8.4.6
2012 "@types/html-minifier-terser": ^7.0.0 2012 "@types/html-minifier-terser": ^7.0.0
2013 "@types/lodash-es": ^4.17.6
2013 "@types/node": ^18.7.8 2014 "@types/node": ^18.7.8
2014 "@types/prettier": ^2.7.0 2015 "@types/prettier": ^2.7.0
2015 "@types/react": ^18.0.17 2016 "@types/react": ^18.0.17
@@ -2031,6 +2032,7 @@ __metadata:
2031 eslint-plugin-react: ^7.30.1 2032 eslint-plugin-react: ^7.30.1
2032 eslint-plugin-react-hooks: ^4.6.0 2033 eslint-plugin-react-hooks: ^4.6.0
2033 html-minifier-terser: ^7.0.0 2034 html-minifier-terser: ^7.0.0
2035 lodash-es: ^4.17.21
2034 loglevel: ^1.8.0 2036 loglevel: ^1.8.0
2035 loglevel-plugin-prefix: ^0.8.4 2037 loglevel-plugin-prefix: ^0.8.4
2036 mobx: ^6.6.1 2038 mobx: ^6.6.1
@@ -2180,6 +2182,22 @@ __metadata:
2180 languageName: node 2182 languageName: node
2181 linkType: hard 2183 linkType: hard
2182 2184
2185"@types/lodash-es@npm:^4.17.6":
2186 version: 4.17.6
2187 resolution: "@types/lodash-es@npm:4.17.6"
2188 dependencies:
2189 "@types/lodash": "*"
2190 checksum: 9bd239dd525086e278821949ce12fbdd4f100a060fed9323fc7ad5661113e1641f28a7ebab617230ed3474680d8f4de705c1928b48252bb684be6ec9eed715db
2191 languageName: node
2192 linkType: hard
2193
2194"@types/lodash@npm:*":
2195 version: 4.14.184
2196 resolution: "@types/lodash@npm:4.14.184"
2197 checksum: 6d9a4d67f7f9d0ec3fd21174f3dd3d00629dc1227eb469450eace53adbc1f7e2330699c28d0fe093e5f0fef0f0e763098be1f779268857213224af082b62be21
2198 languageName: node
2199 linkType: hard
2200
2183"@types/node@npm:*, @types/node@npm:^18.7.8": 2201"@types/node@npm:*, @types/node@npm:^18.7.8":
2184 version: 18.7.8 2202 version: 18.7.8
2185 resolution: "@types/node@npm:18.7.8" 2203 resolution: "@types/node@npm:18.7.8"
@@ -4849,6 +4867,13 @@ __metadata:
4849 languageName: node 4867 languageName: node
4850 linkType: hard 4868 linkType: hard
4851 4869
4870"lodash-es@npm:^4.17.21":
4871 version: 4.17.21
4872 resolution: "lodash-es@npm:4.17.21"
4873 checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2
4874 languageName: node
4875 linkType: hard
4876
4852"lodash.debounce@npm:^4.0.8": 4877"lodash.debounce@npm:^4.0.8":
4853 version: 4.0.8 4878 version: 4.0.8
4854 resolution: "lodash.debounce@npm:4.0.8" 4879 resolution: "lodash.debounce@npm:4.0.8"