integrate codeedit loader (just hello world for now)

This commit is contained in:
sawka
2024-06-03 11:35:06 -07:00
parent 394b9dce23
commit 3c86bfea8d
11 changed files with 251 additions and 36 deletions
+8 -1
View File
@@ -1,9 +1,11 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import { CodeEditView } from "@/app/view/codeedit";
import { PlotView } from "@/app/view/plotview";
import { PreviewView } from "@/app/view/preview";
import { TerminalView } from "@/app/view/term";
import { ErrorBoundary } from "@/element/errorboundary";
import { CenteredDiv } from "@/element/quickelems";
import * as WOS from "@/store/wos";
import * as React from "react";
@@ -32,6 +34,7 @@ const Block = ({ tabId, blockId }: { tabId: string; blockId: string }) => {
let blockElem: JSX.Element = null;
const [blockData, blockDataLoading] = WOS.useWaveObjectValue<Block>(WOS.makeORef("block", blockId));
console.log("blockData: ", blockData);
if (blockDataLoading) {
blockElem = <CenteredDiv>Loading...</CenteredDiv>;
} else if (blockData.view === "term") {
@@ -40,6 +43,8 @@ const Block = ({ tabId, blockId }: { tabId: string; blockId: string }) => {
blockElem = <PreviewView blockId={blockId} />;
} else if (blockData.view === "plot") {
blockElem = <PlotView />;
} else if (blockData.view === "codeedit") {
blockElem = <CodeEditView />;
}
return (
<div className="block" ref={blockRef}>
@@ -53,7 +58,9 @@ const Block = ({ tabId, blockId }: { tabId: string; blockId: string }) => {
</div>
</div>
<div key="content" className="block-content">
<React.Suspense fallback={<CenteredDiv>Loading...</CenteredDiv>}>{blockElem}</React.Suspense>
<ErrorBoundary>
<React.Suspense fallback={<CenteredDiv>Loading...</CenteredDiv>}>{blockElem}</React.Suspense>
</ErrorBoundary>
</div>
</div>
);
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import React, { ReactNode } from "react";
export class ErrorBoundary extends React.Component<{ children: ReactNode }, { error: Error }> {
constructor(props) {
super(props);
this.state = { error: null };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
this.setState({ error: error });
}
render() {
const { error } = this.state;
if (error) {
const errorMsg = `Error: ${error?.message}\n\n${error?.stack}`;
return <pre className="error-boundary">{errorMsg}</pre>;
} else {
return <>{this.props.children}</>;
}
}
}
+9
View File
@@ -0,0 +1,9 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
.codeedit {
display: flex;
flex-direction: column;
height: 100%;
width: 100%;
}
+112
View File
@@ -0,0 +1,112 @@
// Copyright 2024, Command Line Inc.
// SPDX-License-Identifier: Apache-2.0
import "./codeedit.less";
import { globalStore } from "@/store/global";
import loader from "@monaco-editor/loader";
import { Editor, Monaco } from "@monaco-editor/react";
import * as jotai from "jotai";
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
import * as React from "react";
// there is a global monaco variable (TODO get the correct TS type)
declare var monaco: Monaco;
let monacoLoadedAtom = jotai.atom(false);
function loadMonaco() {
loader.config({ paths: { vs: "./monaco" } });
loader
.init()
.then(() => {
monaco.editor.defineTheme("wave-theme-dark", {
base: "hc-black",
inherit: true,
rules: [],
colors: {
"editor.background": "#000000",
},
});
monaco.editor.defineTheme("wave-theme-light", {
base: "hc-light",
inherit: true,
rules: [],
colors: {
"editor.background": "#fefefe",
},
});
globalStore.set(monacoLoadedAtom, true);
console.log("monaco loaded", monaco);
})
.catch((e) => {
console.error("error loading monaco", e);
});
}
// TODO: need to update these on theme change (pull from CSS vars)
document.addEventListener("DOMContentLoaded", () => {
setTimeout(loadMonaco, 30);
});
function defaultEditorOptions(): MonacoTypes.editor.IEditorOptions {
const opts: MonacoTypes.editor.IEditorOptions = {
scrollBeyondLastLine: false,
fontSize: 12,
fontFamily: "Hack",
};
return opts;
}
export function CodeEdit() {
const divRef = React.useRef<HTMLDivElement>(null);
const monacoRef = React.useRef<MonacoTypes.editor.IStandaloneCodeEditor | null>(null);
const theme = "wave-theme-dark";
const [divDims, setDivDims] = React.useState(null);
const monacoLoaded = jotai.useAtomValue(monacoLoadedAtom);
React.useEffect(() => {
if (!divRef.current) {
return;
}
const height = divRef.current.clientHeight;
const width = divRef.current.clientWidth;
setDivDims({ height, width });
}, [divRef.current]);
function handleEditorMount(editor: MonacoTypes.editor.IStandaloneCodeEditor) {
monacoRef.current = editor;
const monacoModel = editor.getModel();
monaco.editor.setModelLanguage(monacoModel, "text/markdown");
}
function handleEditorChange(newText: string, ev: MonacoTypes.editor.IModelContentChangedEvent) {
// TODO
}
const text = "Hello, world!";
const editorOpts = defaultEditorOptions();
return (
<div className="codeedit" ref={divRef}>
{divDims != null && monacoLoaded ? (
<Editor
theme={theme}
height={divDims.height}
defaultLanguage={"text/markdown"}
value={text}
onMount={handleEditorMount}
options={editorOpts}
onChange={handleEditorChange}
/>
) : null}
</div>
);
}
export function CodeEditView() {
return (
<div className="view-codeedit">
<CodeEdit />
</div>
);
}
+1 -2
View File
@@ -4,7 +4,6 @@
import { FileInfo } from "@/bindings/fileservice";
import { Table, createColumnHelper, flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
import * as jotai from "jotai";
import path from "path";
import React from "react";
import "./directorypreview.less";
@@ -108,7 +107,7 @@ function TableBody({ table, setFileName }: TableBodyProps) {
key={cell.id}
style={{ width: `calc(var(--col-${cell.column.id}-size) * 1px)` }}
>
{path.basename(cell.renderValue<any>())}
{cell.renderValue<any>()}
</div>
))}
</div>
+10
View File
@@ -26,6 +26,16 @@
}
}
.view-codeedit {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
overflow: hidden;
align-items: center;
justify-content: center;
}
.view-preview {
display: flex;
flex-direction: row;
+10
View File
@@ -84,6 +84,13 @@ function Widgets() {
createBlock(plotDef);
}
async function clickEdit() {
const editDef: BlockDef = {
view: "codeedit",
};
createBlock(editDef);
}
return (
<div className="workspace-widgets">
<div className="widget" onClick={() => clickTerminal()}>
@@ -104,6 +111,9 @@ function Widgets() {
<div className="widget" onClick={() => clickPlot()}>
<i className="fa fa-solid fa-chart-simple fa-fw" />
</div>
<div className="widget" onClick={() => clickEdit()}>
<i className="fa-sharp fa-solid fa-pen-to-square"></i>
</div>
<div className="widget no-hover">
<i className="fa fa-solid fa-plus fa-fw" />
</div>