feat: preview components

This commit is contained in:
tao.chen
2026-08-11 15:02:16 +08:00
parent 5969f2f749
commit b44d057241
4 changed files with 203 additions and 27 deletions
@@ -7,7 +7,10 @@ import type {
} from "../../services/api";
import { scriptIcon } from "./WorkspaceTree";
import type { MouseEvent as ReactMouseEvent, RefObject } from "react";
import { useRef, useEffect } from "react";
import Editor from "@monaco-editor/react";
import { useRef, useLayoutEffect } from "react";
import { useScriptWorkspaceStore } from "./state/scriptWorkspaceStore";
type ToastState = {
tone: "success" | "error" | "info";
@@ -129,9 +132,9 @@ export function ScriptWorkspace({
left: direction === "left" ? -scrollAmount : scrollAmount,
behavior: "smooth",
});
};
};
useEffect(() => {
useLayoutEffect(() => {
const tabbar = tabbarRef.current;
if (!tabbar) return;
const activeTab = tabbar.querySelector(".editor-tab--active") as HTMLElement | null;
@@ -232,13 +235,11 @@ export function ScriptWorkspace({
</button>
<span className={`stage-badge${isEditing ? " is-editing" : ""}`}>
<span />
{isEditing
? isNotebook
? "Demo 无锁模式 · Kernel 已连接"
: "Demo 无锁模式 · 编辑中"
: latestVersion
{
latestVersion
? `最新 ${latestVersion.version_label}`
: "工作副本已就绪"}
: "工作副本已就绪"
}
</span>
</div>
</div>
@@ -378,13 +379,13 @@ export function ScriptWorkspace({
<span>Python </span>
<em>{isEditing ? "Jupyter 中可编辑" : "平台只读预览"}</em>
</div>
<PythonPreview />
<PythonPreview workspaceId={script.workspace_id} filePath={`${script.script_id}.py`}/>
</div>
<div className="integrity-row">
<span>
<Icon name="check" size={15} />
{isEditing ? "Demo 无锁编辑会话已连接" : "工作副本已同步"}
{/*{isEditing ? "Demo 无锁编辑会话已连接" : "工作副本已同步"}*/}
</span>
<span>SHA-256&nbsp; {shortHash(script.content_hash)}</span>
<span>
@@ -403,19 +404,59 @@ export function ScriptWorkspace({
);
}
function PythonPreview() {
interface PythonPreviewProps {
workspaceId: string;
filePath: string;
}
export function PythonPreview({
workspaceId,
filePath,
}: PythonPreviewProps) {
const previewKey = `${workspaceId}::${filePath}`;
const storeKey = useScriptWorkspaceStore((s) => s.previewKey);
const previewCode = useScriptWorkspaceStore((s) => s.previewCode);
const previewCodeSize = useScriptWorkspaceStore((s) => s.previewCodeSize);
const previewLoading = useScriptWorkspaceStore((s) => s.previewLoading);
const previewError = useScriptWorkspaceStore((s) => s.previewError);
const loadPreview = useScriptWorkspaceStore((s) => s.loadPreview);
useLayoutEffect(() => {
void loadPreview(workspaceId, filePath);
}, [previewKey]);
if (storeKey !== previewKey) {
return <div>Loading...</div>;
}
if (previewLoading) {
return <div>Loading...</div>;
}
if (previewError) {
return <div>Failed to load: {previewError}</div>;
}
return (
<div className="python-preview">
<div className="line-numbers">
1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9
</div>
<pre>
<span className="code-comment">&quot;&quot;&quot;&quot;&quot;&quot;</span>
{"\n\n"}<b>def</b> <span className="code-function">main</span>() -&gt; <b>None</b>:
{"\n"} print(<i>&quot;Hello, Model Platform!&quot;</i>)
{"\n\n\n"}<b>if</b> __name__ == <i>&quot;__main__&quot;</i>:
{"\n"} main()
</pre>
</div>
<Editor
height="550px"
language="python"
value={previewCode ?? ""}
theme="vs"
options={{
readOnly: true,
domReadOnly: true,
minimap: {
enabled: previewCodeSize !== null && previewCodeSize > 1000,
},
lineNumbers: "off",
folding: true,
wordWrap: "on",
contextmenu: false,
dragAndDrop: false,
automaticLayout: true,
renderLineHighlight: "none",
}}
/>
);
}