Skip to content

Commit 0625e62

Browse files
authored
core: ui refactor (#68)
* core: ui refactor 1. top toolbar 2. editor hightlight 3. implement delete btn * refactor: result position * Update nginx.conf * refactor: add rules * refactor: update editor theme
1 parent 39b4500 commit 0625e62

File tree

5 files changed

+214
-94
lines changed

5 files changed

+214
-94
lines changed

ui/src/components/Canvas.tsx

Lines changed: 100 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,7 @@ import PlayArrowIcon from "@mui/icons-material/PlayArrow";
2929
import Stack from "@mui/material/Stack";
3030
import Button from "@mui/material/Button";
3131
import CircleIcon from "@mui/icons-material/Circle";
32-
import ViewComfyIcon from "@mui/icons-material/ViewComfy";
33-
32+
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
3433
import Grid from "@mui/material/Grid";
3534

3635
import Moveable from "react-moveable";
@@ -47,6 +46,8 @@ import { useNodesStateSynced } from "../lib/nodes";
4746
import { MyMonaco } from "./MyMonaco";
4847
import { useApolloClient } from "@apollo/client";
4948
import { CanvasContextMenu } from "./CanvasContextMenu";
49+
import ToolBox, { ToolTypes } from "./Toolbox";
50+
import styles from "./canvas.style.js";
5051

5152
const nanoid = customAlphabet(nolookalikes, 10);
5253

@@ -89,7 +90,8 @@ const ScopeNode = memo<Props>(({ data, id, isConnectable }) => {
8990
sx={{
9091
width: "100%",
9192
height: "100%",
92-
border: "1px solid black",
93+
border: "solid 1px #d6dee6",
94+
borderRadius: "4px",
9395
}}
9496
className="custom-drag-handle"
9597
>
@@ -200,18 +202,24 @@ function ResultBlock({ pod, id }) {
200202
{pod.result.html ? (
201203
<div dangerouslySetInnerHTML={{ __html: pod.result.html }}></div>
202204
) : (
203-
pod.result.text && (
204-
<Box>
205-
<Box sx={{ display: "flex" }} bgcolor="lightgray">
206-
Result: [{pod.result.count}]:
207-
</Box>
208-
<Box>
209-
<Box component="pre" whiteSpace="pre-wrap">
210-
{pod.result.text}
205+
<>
206+
{!pod.error && (
207+
<Box
208+
color="rgb(0, 183, 87)"
209+
sx={{
210+
padding: "6px",
211+
zIndex: 200,
212+
}}
213+
>
214+
<Box sx={styles["result-status__success"]}>
215+
<CheckCircleIcon
216+
style={{ marginTop: "5px" }}
217+
fontSize="inherit"
218+
/>
211219
</Box>
212220
</Box>
213-
</Box>
214-
)
221+
)}
222+
</>
215223
)}
216224
{pod.result.image && (
217225
<img
@@ -221,30 +229,33 @@ function ResultBlock({ pod, id }) {
221229
)}
222230
</Box>
223231
)}
224-
{pod.stdout && (
225-
<Box overflow="scroll" border="1px">
226-
{/* TODO separate stdout and stderr */}
227-
<Box bgcolor="lightgray">Stdout</Box>
228-
<Box whiteSpace="pre-wrap" fontSize="sm">
232+
233+
{pod.running && <CircularProgress />}
234+
<Box overflow="scroll" maxHeight="145px" border="1px">
235+
{/* <Box bgcolor="lightgray">Error</Box> */}
236+
{pod.stdout && (
237+
<Box whiteSpace="pre-wrap" sx={{fontSize: 10}}>
229238
<Ansi>{pod.stdout}</Ansi>
230239
</Box>
231-
</Box>
232-
)}
233-
{pod.running && <CircularProgress />}
234-
{pod.error && (
235-
<Box overflow="scroll" border="1px">
236-
<Box bgcolor="lightgray">Error</Box>
237-
<Box color="red">{pod.error.evalue}</Box>
238-
{pod.error.stacktrace && (
239-
<Box>
240-
<Box>StackTrace</Box>
241-
<Box whiteSpace="pre-wrap" fontSize="small">
242-
<Ansi>{pod.error.stacktrace.join("\n")}</Ansi>
243-
</Box>
240+
)}
241+
{pod?.result?.text && pod?.result?.count > 0 && (
242+
<Box sx={{ display: "flex", fontSize: 10, flexDirection: "row", alignItems: 'center' }}>
243+
<Box>Result[{pod.result.count}]:</Box>
244+
<Box component="pre" whiteSpace="pre-wrap">
245+
{pod.result.text}
244246
</Box>
245-
)}
246-
</Box>
247-
)}
247+
</Box>
248+
)}
249+
{pod?.error && <Box color="red">{pod?.error?.evalue}</Box>}
250+
{pod?.error?.stacktrace && (
251+
<Box>
252+
<Box>StackTrace</Box>
253+
<Box whiteSpace="pre-wrap" sx={{fontSize: 10}}>
254+
<Ansi>{pod.error.stacktrace.join("\n")}</Ansi>
255+
</Box>
256+
</Box>
257+
)}
258+
</Box>
248259
</Box>
249260
);
250261
}
@@ -260,7 +271,9 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
260271
translate: [0, 0],
261272
});
262273
// right, bottom
263-
const [layout, setLayout] = useState("right");
274+
const [layout, setLayout] = useState("bottom");
275+
const isRightLayout = layout === "right";
276+
const [isEditorBlur, setIsEditorBlur] = useState(true);
264277
const { setNodes } = useReactFlow();
265278
// const selected = useStore(store, (state) => state.selected);
266279
const setSelected = useStore(store, (state) => state.setSelected);
@@ -270,24 +283,46 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
270283
const showResult = useStore(
271284
store,
272285
(state) =>
273-
state.pods[id].running ||
274-
state.pods[id].result ||
275-
state.pods[id].error ||
276-
state.pods[id].stdout ||
277-
state.pods[id].stderr
286+
state.pods[id]?.running ||
287+
state.pods[id]?.result ||
288+
state.pods[id]?.error ||
289+
state.pods[id]?.stdout ||
290+
state.pods[id]?.stderr
278291
);
292+
const nodesMap = useStore(store, (state) => state.ydoc.getMap<Node>("pods"));
293+
const apolloClient = useApolloClient();
294+
const deletePod = useStore(store, (state) => state.deletePod);
295+
const deleteNodeById = (id) => {
296+
deletePod(apolloClient, { id: id, toDelete: [] });
297+
nodesMap.delete(id);
298+
};
299+
const runToolBoxTask = (type, data) => {
300+
switch (type) {
301+
case ToolTypes.delete:
302+
deleteNodeById(id);
303+
break;
304+
case ToolTypes.play:
305+
wsRun(data.id);
306+
break;
307+
case ToolTypes.layout:
308+
setLayout(layout === "bottom" ? "right" : "bottom");
309+
break;
310+
}
311+
};
279312

280313
useEffect(() => {
281314
setTarget(ref.current);
282315
}, []);
283-
// if (!pod) return <Box>ERROR</Box>;
316+
if (!pod) return null;
284317
return (
285318
<Box
286319
sx={{
287-
border: "solid 1px black",
320+
border: "solid 1px #d6dee6",
321+
borderRadius: "4px",
288322
width: "100%",
289323
height: "100%",
290-
backgroundColor: "white",
324+
backgroundColor: "rgb(244, 246, 248)",
325+
borderColor: isEditorBlur ? "#d6dee6" : "#3182ce",
291326
}}
292327
ref={ref}
293328
>
@@ -316,45 +351,9 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
316351
isConnectable={isConnectable}
317352
/>
318353
{/* The header of code pods. */}
319-
<Box
320-
className="custom-drag-handle"
321-
bgcolor={"rgb(225,225,225)"}
322-
sx={{ display: "flex" }}
323-
>
324-
{/* Code: {data?.label} */}
325-
{/* pod */}
326-
<Box sx={{ display: "flex", flexGrow: 1 }}>
327-
<IconButton size="small">
328-
<CircleIcon sx={{ color: "red" }} fontSize="inherit" />
329-
</IconButton>
330-
</Box>
331-
<Box sx={{ display: "flex" }}>
332-
<Box sx={{ display: "flex" }}>
333-
<Tooltip title="Run (shift-enter)">
334-
<IconButton
335-
size="small"
336-
sx={{ color: "green" }}
337-
onClick={() => {
338-
wsRun(id);
339-
}}
340-
>
341-
<PlayArrowIcon fontSize="inherit" />
342-
</IconButton>
343-
</Tooltip>
344-
</Box>
345-
<Box sx={{ display: "flex" }}>
346-
<Tooltip title="Change layout">
347-
<IconButton
348-
size="small"
349-
onClick={() => {
350-
setLayout(layout === "bottom" ? "right" : "bottom");
351-
}}
352-
>
353-
<ViewComfyIcon fontSize="inherit" />
354-
</IconButton>
355-
</Tooltip>
356-
</Box>
357-
</Box>
354+
<Box className="custom-drag-handle">
355+
<Box sx={styles["pod-index"]}>[{pod.index}]</Box>
356+
<ToolBox data={{ id }} onRunTask={runToolBoxTask}></ToolBox>
358357
</Box>
359358
<Box
360359
sx={{
@@ -378,21 +377,31 @@ const CodeNode = memo<Props>(({ data, id, isConnectable }) => {
378377
);
379378
}}
380379
>
381-
<MyMonaco id={id} gitvalue="" />
380+
<MyMonaco
381+
id={id}
382+
gitvalue=""
383+
onBlur={() => {
384+
setIsEditorBlur(true);
385+
}}
386+
onFocus={() => {
387+
setIsEditorBlur(false);
388+
}}
389+
/>
382390
{showResult && (
383391
<Box
384392
className="nowheel"
385393
sx={{
394+
border: "solid 1px #d6dee6",
395+
borderRadius: "4px",
386396
position: "absolute",
387-
top: layout === "right" ? 0 : "100%",
388-
left: layout === "right" ? "100%" : 0,
389-
maxHeight: "100%",
390-
maxWidth: "100%",
391-
minWidth: "100px",
392-
overflow: "scroll",
397+
top: isRightLayout ? 0 : "100%",
398+
left: isRightLayout ? "100%" : 0,
399+
maxHeight: "158px",
400+
minWidth: isRightLayout ? "200px" : "100%",
401+
boxSizing: "border-box",
393402
backgroundColor: "white",
394-
border: "solid 1px blue",
395403
zIndex: 100,
404+
padding: "0 10px",
396405
}}
397406
>
398407
<ResultBlock pod={pod} id={id} />
@@ -564,7 +573,7 @@ export function Canvas() {
564573
addPod(apolloClient, {
565574
id,
566575
parent: "ROOT",
567-
index: 0,
576+
index: nodesMap.size + 1,
568577
type: type === "code" ? "CODE" : "DECK",
569578
lang: "python",
570579
x: position.x,

ui/src/components/MyMonaco.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,23 @@ import { useStore } from "zustand";
66
import { RepoContext } from "../lib/store";
77
import { MonacoBinding } from "y-monaco";
88

9+
const theme: monaco.editor.IStandaloneThemeData = {
10+
base: "vs",
11+
inherit: true,
12+
rules: [],
13+
colors: {
14+
"editor.background": "#f3f3f340",
15+
"editor.lineHighlightBackground": "#f3f3f340",
16+
},
17+
};
18+
monaco.editor.defineTheme("codepod", theme);
919
monaco.languages.setLanguageConfiguration("julia", {
1020
indentationRules: {
1121
increaseIndentPattern:
1222
/^(\s*|.*=\s*|.*@\w*\s*)[\w\s]*(?:["'`][^"'`]*["'`])*[\w\s]*\b(if|while|for|function|macro|(mutable\s+)?struct|abstract\s+type|primitive\s+type|let|quote|try|begin|.*\)\s*do|else|elseif|catch|finally)\b(?!(?:.*\bend\b[^\]]*)|(?:[^[]*\].*)$).*$/,
1323
decreaseIndentPattern: /^\s*(end|else|elseif|catch|finally)\b.*$/,
1424
},
1525
});
16-
1726
function construct_indent(pos, indent) {
1827
return [
1928
{
@@ -302,11 +311,15 @@ async function updateGitGutter(editor) {
302311
interface MyMonacoProps {
303312
id: string;
304313
gitvalue: string;
314+
onBlur?: Function;
315+
onFocus?: Function;
305316
}
306317

307318
export const MyMonaco = memo<MyMonacoProps>(function MyMonaco({
308319
id = "0",
309320
gitvalue = null,
321+
onBlur = () => {},
322+
onFocus = () => {},
310323
}) {
311324
// there's no racket language support
312325
const store = useContext(RepoContext);
@@ -359,6 +372,12 @@ export const MyMonaco = memo<MyMonacoProps>(function MyMonaco({
359372
editor.layout();
360373
// onLayout(`${contentHeight}px`);
361374
};
375+
editor.onDidBlurEditorText(() => {
376+
onBlur();
377+
});
378+
editor.onDidFocusEditorText(() => {
379+
onFocus();
380+
});
362381
editor.onDidContentSizeChange(updateHeight);
363382
// FIXME clean up?
364383
editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Enter, function () {
@@ -402,7 +421,7 @@ export const MyMonaco = memo<MyMonacoProps>(function MyMonaco({
402421
<MonacoEditor
403422
language={lang}
404423
// value={value}
405-
// theme="vs-dark"
424+
theme="codepod"
406425
options={{
407426
selectOnLineNumbers: true,
408427
// This scrollBeyondLastLine is super important. Without this, it will

0 commit comments

Comments
 (0)