Skip to content

Commit f437d4c

Browse files
committed
Add resizable panels to webR REPL app
1 parent a543b3e commit f437d4c

12 files changed

+94
-91
lines changed

src/package-lock.json

+17-7
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"react-accessible-treeview": "^2.6.1",
7070
"react-dom": "^18.2.0",
7171
"react-icons": "^4.10.1",
72+
"react-resizable-panels": "^2.0.19",
7273
"tsx": "^4.0.0",
7374
"xmlhttprequest-ssl": "^2.1.0",
7475
"xterm": "^5.1.0",

src/repl/App.css

+8-42
Original file line numberDiff line numberDiff line change
@@ -14,54 +14,20 @@ body {
1414
}
1515

1616
.repl {
17-
display: grid;
18-
grid-template-columns: repeat(2, 1fr);
19-
grid-template-rows: repeat(6, 1fr);
2017
width: 100vw;
2118
height: 100vh;
2219
}
2320

24-
.editor {
25-
grid-row: 1 / 5;
26-
grid-column: 1;
27-
overflow: auto;
28-
border-style: solid;
29-
border-color: var(--bg-secondary);
30-
border-width: 0px 2px 2px 0px;
31-
padding-top: 5px;
21+
div[data-panel] {
22+
display: flex;
23+
flex-direction: column;
3224
}
3325

34-
.term {
35-
grid-row-start: 5;
36-
grid-row-end: -1;
37-
grid-column: 1;
38-
border-style: solid;
39-
background-color: var(--bg-primary);
40-
border-color: var(--bg-secondary);
41-
border-width: 2px 2px 0px 0px;
42-
overflow: hidden;
43-
padding: 0px 5px;
26+
div[data-resize-handle] {
27+
padding: 2px;
28+
background-color: var(--bg-secondary);
4429
}
4530

46-
.editor[style*='display: none']~.term {
47-
grid-row-start: 1;
48-
}
49-
50-
.files {
51-
grid-row: 1 / 3;
52-
grid-column: 2;
53-
border-style: solid;
54-
border-color: var(--bg-secondary);
55-
border-width: 0px 0px 2px 2px;
56-
overflow: auto;
57-
padding: 5px 0;
58-
}
59-
60-
.plot {
61-
grid-row: 3 / -1;
62-
grid-column: 2;
63-
border-style: solid;
64-
border-color: var(--bg-secondary);
65-
border-width: 2px 0px 0px 2px;
66-
overflow: hidden;
31+
.d-none + div[data-resize-handle] {
32+
display: none !important;
6733
}

src/repl/App.tsx

+22-8
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Editor from './components/Editor';
55
import Plot from './components/Plot';
66
import Files from './components/Files';
77
import { Readline } from 'xterm-readline';
8+
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
89
import { WebR } from '../webR/webr-main';
910
import { CanvasMessage, PagerMessage } from '../webR/webr-chan';
1011
import './App.css';
@@ -73,14 +74,27 @@ async function handlePagerMessage(msg: PagerMessage) {
7374
function App() {
7475
return (
7576
<div className='repl'>
76-
<Editor
77-
webR={webR}
78-
terminalInterface={terminalInterface}
79-
filesInterface={filesInterface}
80-
/>
81-
<Files webR={webR} filesInterface={filesInterface} />
82-
<Terminal webR={webR} terminalInterface={terminalInterface} />
83-
<Plot plotInterface={plotInterface} />
77+
<PanelGroup direction="horizontal">
78+
<Panel defaultSize={50} minSize={20}>
79+
<PanelGroup autoSaveId="conditional" direction="vertical">
80+
<Editor
81+
webR={webR}
82+
terminalInterface={terminalInterface}
83+
filesInterface={filesInterface}
84+
/>
85+
<PanelResizeHandle />
86+
<Terminal webR={webR} terminalInterface={terminalInterface} />
87+
</PanelGroup>
88+
</Panel>
89+
<PanelResizeHandle />
90+
<Panel minSize={20}>
91+
<PanelGroup direction="vertical">
92+
<Files webR={webR} filesInterface={filesInterface} />
93+
<PanelResizeHandle />
94+
<Plot plotInterface={plotInterface} />
95+
</PanelGroup>
96+
</Panel>
97+
</PanelGroup>
8498
</div>
8599
);
86100
}

src/repl/components/Editor.css

+11-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
.editor {
1+
#editor {
22
position: relative;
3-
display: grid;
4-
grid-template-rows: auto 1fr;
53
}
64

75
.editor-header {
86
display: flex;
97
justify-content: space-between;
108
align-items: center;
119
border-bottom: 1px solid var(--bg-dark);
12-
padding: 0 5px;
10+
padding: 5px 5px 0 5px;
11+
}
12+
13+
.editor-container {
14+
flex: 1;
15+
overflow: auto;
1316
}
1417

1518
.editor-actions {
@@ -94,11 +97,6 @@
9497
color: var(--primary);
9598
}
9699

97-
.editor-container {
98-
min-width: 0;
99-
min-height: 0;
100-
}
101-
102100
.cm-editor {
103101
border: none;
104102
outline: none;
@@ -110,3 +108,7 @@
110108
border: none;
111109
outline: none;
112110
}
111+
112+
.d-none {
113+
display: none !important;
114+
}

src/repl/components/Editor.tsx

+9-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { EditorState, Compartment, Prec } from '@codemirror/state';
66
import { autocompletion, CompletionContext } from '@codemirror/autocomplete';
77
import { keymap } from '@codemirror/view';
88
import { indentWithTab } from '@codemirror/commands';
9+
import { Panel } from 'react-resizable-panels';
910
import { FilesInterface, TerminalInterface } from '../App';
1011
import { r } from 'codemirror-lang-r';
1112
import './Editor.css';
@@ -341,13 +342,14 @@ export function Editor({
341342
};
342343
}, [files, syncActiveFileState, activeFile, editorView]);
343344

344-
const displayStyle = files.length === 0 ? { display: 'none' } : undefined;
345-
346345
return (
347-
<div role="region"
346+
<Panel
347+
id="editor"
348+
role="region"
348349
aria-label="Editor Pane"
349-
className="editor"
350-
style={displayStyle}
350+
order={1}
351+
minSize={20}
352+
className={files.length === 0 ? "d-none" : ""}
351353
>
352354
<div className="editor-header">
353355
<FileTabs
@@ -364,7 +366,7 @@ export function Editor({
364366
ref={editorRef}
365367
>
366368
</div>
367-
<p style={{ display: 'none' }} id="editor-desc">
369+
<p className="d-none" id="editor-desc">
368370
This component is an instance of the <a href="https://codemirror.net/">CodeMirror</a> interactive text editor.
369371
The editor has been configured so that the Tab key controls the indentation of code.
370372
To move focus away from the editor, press the Escape key, and then press the Tab key directly after it.
@@ -382,7 +384,7 @@ export function Editor({
382384
<FaRegSave aria-hidden="true" className="icon" /> Save
383385
</button>}
384386
</div>
385-
</div>
387+
</Panel>
386388
);
387389
}
388390

src/repl/components/Files.css

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
.files {
2-
display: grid;
3-
grid-template-rows: auto 1fr;
1+
#files {
2+
padding: 5px 0;
43
}
54

65
.files-header {
@@ -34,6 +33,7 @@
3433
user-select: none;
3534
padding: 0 10px;
3635
overflow: auto;
36+
flex-grow: 1;
3737
color: var(--primary);
3838
}
3939

src/repl/components/Files.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, { ChangeEventHandler } from 'react';
22
import * as Fa from 'react-icons/fa';
33
import TreeView, { flattenTree, INode, ITreeViewProps } from 'react-accessible-treeview';
4+
import { Panel } from 'react-resizable-panels';
45
import { WebR, WebRError } from '../../webR/webr-main';
56
import type { FSNode } from '../../webR/webr-main';
67
import { FilesInterface } from '../App';
@@ -235,7 +236,7 @@ export function Files({
235236
/>;
236237

237238
return (
238-
<div role="region" aria-label="Files Pane" className='files'>
239+
<Panel id="files" role="region" aria-label="Files Pane" defaultSize={35} minSize={20}>
239240
<div className="files-header">
240241
<div
241242
role="toolbar"
@@ -288,7 +289,7 @@ export function Files({
288289
<div aria-label="WebAssembly Filesystem" className="directory">
289290
{treeData[0].name ? treeView : undefined}
290291
</div>
291-
</div>
292+
</Panel>
292293
);
293294
}
294295

src/repl/components/Plot.css

+1-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
.plot {
2-
display: grid;
3-
grid-template-rows: auto 1fr;
4-
}
5-
61
.plot-background {
72
background-color: var(--bg-dark);
3+
flex-grow: 1;
84
display: flex;
95
justify-content: center;
106
align-items: center;

src/repl/components/Plot.tsx

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React from 'react';
22
import './Plot.css';
33
import { PlotInterface } from '../App';
44
import { FaArrowCircleLeft, FaArrowCircleRight, FaRegSave, FaTrashAlt } from 'react-icons/fa';
5+
import { Panel } from 'react-resizable-panels';
56

67
export function Plot({
78
plotInterface,
@@ -67,7 +68,7 @@ export function Plot({
6768
const prevPlot = () => setSelectedCanvas((selectedCanvas === null) ? null : selectedCanvas - 1);
6869

6970
return (
70-
<div role="region" aria-label="Plotting Pane" className="plot">
71+
<Panel id="plot" role="region" aria-label="Plotting Pane" minSize={20}>
7172
<div className="plot-header">
7273
<div role="toolbar" aria-label="Plotting Toolbar" className="plot-actions">
7374
<button
@@ -111,7 +112,7 @@ export function Plot({
111112
<div className='plot-background'>
112113
<div ref={plotContainerRef} className="plot-container"></div>
113114
</div>
114-
</div>
115+
</Panel>
115116
);
116117
}
117118

src/repl/components/Terminal.css

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#terminal {
2+
background-color: var(--bg-primary);
3+
padding: 0px 5px;
4+
}
5+
6+
.terminal-container {
7+
flex-grow: 1;
8+
overflow: auto;
9+
}

src/repl/components/Terminal.tsx

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import React from 'react';
2+
import './Terminal.css';
23
import { Terminal as XTerminal } from 'xterm';
34
import { Readline } from 'xterm-readline';
45
import { FitAddon } from 'xterm-addon-fit';
6+
import { Panel } from 'react-resizable-panels';
57
import { TerminalInterface } from '../App';
68
import { WebR } from '../../webR/webr-main';
79
import 'xterm/css/xterm.css';
@@ -99,12 +101,11 @@ export function Terminal({
99101
};
100102
}, [readline, terminalInterface]);
101103

102-
return <div
103-
role="region"
104-
aria-label="Terminal Pane"
105-
ref={divRef}
106-
className='term'
107-
></div>;
104+
return (
105+
<Panel id="terminal" role="region" aria-label="Terminal Pane" order={2} minSize={20}>
106+
<div className="terminal-container" ref={divRef}></div>
107+
</Panel>
108+
);
108109
}
109110

110111
export default Terminal;

0 commit comments

Comments
 (0)