aboutsummaryrefslogtreecommitdiffstats
path: root/subprojects/frontend/src/Refinery.tsx
diff options
context:
space:
mode:
authorLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-30 19:07:05 +0200
committerLibravatar Kristóf Marussy <kristof@marussy.com>2023-08-30 19:07:05 +0200
commite41e0391ba843b85a5b2890db95121fa39426a05 (patch)
tree4927c919cf3077ba9abb2cf31155de4d227b3119 /subprojects/frontend/src/Refinery.tsx
parentrefactor(frontend): filter dialog formatting (diff)
downloadrefinery-e41e0391ba843b85a5b2890db95121fa39426a05.tar.gz
refinery-e41e0391ba843b85a5b2890db95121fa39426a05.tar.zst
refinery-e41e0391ba843b85a5b2890db95121fa39426a05.zip
feat(frontend): window pane switcher
Diffstat (limited to 'subprojects/frontend/src/Refinery.tsx')
-rw-r--r--subprojects/frontend/src/Refinery.tsx142
1 files changed, 2 insertions, 140 deletions
diff --git a/subprojects/frontend/src/Refinery.tsx b/subprojects/frontend/src/Refinery.tsx
index 099646f0..5ad16000 100644
--- a/subprojects/frontend/src/Refinery.tsx
+++ b/subprojects/frontend/src/Refinery.tsx
@@ -4,151 +4,13 @@
4 * SPDX-License-Identifier: EPL-2.0 4 * SPDX-License-Identifier: EPL-2.0
5 */ 5 */
6 6
7import MoreHorizIcon from '@mui/icons-material/MoreHoriz';
8import MoreVertIcon from '@mui/icons-material/MoreVert';
9import Box from '@mui/material/Box';
10import Grow from '@mui/material/Grow'; 7import Grow from '@mui/material/Grow';
11import Stack from '@mui/material/Stack'; 8import Stack from '@mui/material/Stack';
12import { alpha, useTheme } from '@mui/material/styles';
13import { SnackbarProvider } from 'notistack'; 9import { SnackbarProvider } from 'notistack';
14import { memo, useRef, useState } from 'react';
15import { useResizeDetector } from 'react-resize-detector';
16 10
17import TopBar from './TopBar'; 11import TopBar from './TopBar';
18import UpdateNotification from './UpdateNotification'; 12import UpdateNotification from './UpdateNotification';
19import EditorPane from './editor/EditorPane'; 13import WorkArea from './WorkArea';
20import GraphPane from './graph/GraphPane';
21
22const DirectionalSplitPane = memo(function SplitPanel({
23 horizontalSplit,
24}: {
25 horizontalSplit: boolean;
26}): JSX.Element {
27 const theme = useTheme();
28 const stackRef = useRef<HTMLDivElement>(null);
29 const sliderRef = useRef<HTMLDivElement>(null);
30 const [resizing, setResizing] = useState(false);
31 const [fraction, setFraction] = useState(0.5);
32
33 const direction = horizontalSplit ? 'column' : 'row';
34 const axis = horizontalSplit ? 'height' : 'width';
35 const primarySize = `calc(${fraction * 100}% - 0.5px)`;
36 const secondarySize = `calc(${(1 - fraction) * 100}% - 0.5px)`;
37
38 return (
39 <Stack direction={direction} height="100%" overflow="hidden" ref={stackRef}>
40 <Box {...{ [axis]: primarySize }}>
41 <EditorPane />
42 </Box>
43 <Box
44 sx={{
45 overflow: 'visible',
46 position: 'relative',
47 [axis]: '0px',
48 display: 'flex',
49 flexDirection: direction,
50 [horizontalSplit
51 ? 'borderBottom'
52 : 'borderRight']: `1px solid ${theme.palette.outer.border}`,
53 }}
54 >
55 <Box
56 ref={sliderRef}
57 sx={{
58 display: 'flex',
59 position: 'absolute',
60 [axis]: theme.spacing(2),
61 ...(horizontalSplit
62 ? {
63 top: theme.spacing(-1),
64 left: 0,
65 right: 0,
66 transform: 'translateY(0.5px)',
67 }
68 : {
69 left: theme.spacing(-1),
70 top: 0,
71 bottom: 0,
72 transform: 'translateX(0.5px)',
73 }),
74 zIndex: 999,
75 alignItems: 'center',
76 justifyContent: 'center',
77 color: theme.palette.text.secondary,
78 cursor: horizontalSplit ? 'ns-resize' : 'ew-resize',
79 '.MuiSvgIcon-root': {
80 opacity: resizing ? 1 : 0,
81 },
82 ...(resizing
83 ? {
84 background: alpha(
85 theme.palette.text.primary,
86 theme.palette.action.activatedOpacity,
87 ),
88 }
89 : {
90 '&:hover': {
91 background: alpha(
92 theme.palette.text.primary,
93 theme.palette.action.hoverOpacity,
94 ),
95 '.MuiSvgIcon-root': {
96 opacity: 1,
97 },
98 },
99 }),
100 }}
101 onPointerDown={(event) => {
102 if (event.button !== 0) {
103 return;
104 }
105 sliderRef.current?.setPointerCapture(event.pointerId);
106 setResizing(true);
107 }}
108 onPointerUp={(event) => {
109 if (event.button !== 0) {
110 return;
111 }
112 sliderRef.current?.releasePointerCapture(event.pointerId);
113 setResizing(false);
114 }}
115 onPointerMove={(event) => {
116 if (!resizing) {
117 return;
118 }
119 const container = stackRef.current;
120 if (container === null) {
121 return;
122 }
123 const rect = container.getBoundingClientRect();
124 const newFraction = horizontalSplit
125 ? (event.clientY - rect.top) / rect.height
126 : (event.clientX - rect.left) / rect.width;
127 setFraction(Math.min(0.9, Math.max(0.1, newFraction)));
128 }}
129 onDoubleClick={() => setFraction(0.5)}
130 >
131 {horizontalSplit ? <MoreHorizIcon /> : <MoreVertIcon />}
132 </Box>
133 </Box>
134 <Box {...{ [axis]: secondarySize }}>
135 <GraphPane />
136 </Box>
137 </Stack>
138 );
139});
140
141function SplitPane(): JSX.Element {
142 const { ref, width, height } = useResizeDetector();
143 const horizontalSplit =
144 width !== undefined && height !== undefined && height > width;
145
146 return (
147 <Box height="100%" overflow="auto" ref={ref}>
148 <DirectionalSplitPane horizontalSplit={horizontalSplit} />
149 </Box>
150 );
151}
152 14
153export default function Refinery(): JSX.Element { 15export default function Refinery(): JSX.Element {
154 return ( 16 return (
@@ -156,7 +18,7 @@ export default function Refinery(): JSX.Element {
156 <UpdateNotification /> 18 <UpdateNotification />
157 <Stack direction="column" height="100%" overflow="auto"> 19 <Stack direction="column" height="100%" overflow="auto">
158 <TopBar /> 20 <TopBar />
159 <SplitPane /> 21 <WorkArea />
160 </Stack> 22 </Stack>
161 </SnackbarProvider> 23 </SnackbarProvider>
162 ); 24 );