aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend
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 /subprojects/frontend
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
Diffstat (limited to 'subprojects/frontend')
-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
6 files changed, 115 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 {