2024-06-20 15:43:14 +02:00
|
|
|
import React, { useEffect, useState } from "react";
|
2024-06-20 20:11:00 +02:00
|
|
|
import { useMonaco, type Monaco } from "@monaco-editor/react";
|
2024-06-20 15:43:14 +02:00
|
|
|
import FileView from "./playground/FileView";
|
2024-06-20 20:11:00 +02:00
|
|
|
import Editor from "./playground/Editor";
|
2024-06-20 15:43:14 +02:00
|
|
|
|
|
|
|
import "@styles/playground.scss";
|
|
|
|
|
|
|
|
import mainFileContent from "@assets/playground/main.shu?raw";
|
2024-06-20 20:11:00 +02:00
|
|
|
import packTomlContent from "@assets/playground/pack.toml?raw";
|
|
|
|
|
2024-06-20 15:43:14 +02:00
|
|
|
import Header from "./playground/Header";
|
|
|
|
|
|
|
|
export type File = {
|
|
|
|
language?: string;
|
|
|
|
content: string;
|
|
|
|
};
|
|
|
|
export type Directory = {
|
|
|
|
dirs?: { [key: string]: Directory };
|
|
|
|
files?: { [key: string]: File };
|
|
|
|
};
|
|
|
|
export type SetState<T> = React.Dispatch<React.SetStateAction<T>>;
|
|
|
|
|
|
|
|
export default function Playground() {
|
|
|
|
const rootDir: Directory = {
|
|
|
|
dirs: {
|
|
|
|
src: {
|
|
|
|
files: {
|
|
|
|
"main.shu": {
|
|
|
|
content: mainFileContent,
|
2024-06-20 20:11:00 +02:00
|
|
|
language: "shulkerscript",
|
2024-06-20 15:43:14 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2024-06-20 20:11:00 +02:00
|
|
|
dist: {
|
|
|
|
files: {
|
|
|
|
"test.mcfunction": {
|
|
|
|
content: "",
|
|
|
|
language: "mcfunction",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2024-06-20 15:43:14 +02:00
|
|
|
},
|
|
|
|
files: {
|
|
|
|
"pack.toml": {
|
2024-06-20 20:11:00 +02:00
|
|
|
content: packTomlContent,
|
2024-06-20 15:43:14 +02:00
|
|
|
language: "toml",
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const [fileName, setFileName] = useState("src/main.shu");
|
|
|
|
const file = getFile(rootDir, fileName)!;
|
|
|
|
|
|
|
|
const monaco = useMonaco();
|
|
|
|
useEffect(() => {
|
|
|
|
if (monaco) {
|
|
|
|
loadFiles(monaco, rootDir);
|
|
|
|
}
|
|
|
|
}, [monaco]);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<>
|
|
|
|
<main
|
|
|
|
className="playground not-content"
|
|
|
|
style={{
|
|
|
|
maxWidth: "95vw",
|
|
|
|
marginInline: "auto",
|
|
|
|
marginTop: "0.5cm",
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
<Header />
|
|
|
|
<FileView
|
|
|
|
className="file-view"
|
|
|
|
root={rootDir}
|
|
|
|
fileName={fileName}
|
|
|
|
setSelectedFileName={setFileName}
|
|
|
|
/>
|
2024-06-20 20:11:00 +02:00
|
|
|
<Editor fileName={fileName} file={file} />
|
2024-06-20 15:43:14 +02:00
|
|
|
</main>
|
|
|
|
</>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFile(root: Directory, path: string): File | null {
|
|
|
|
if (path.includes("/")) {
|
|
|
|
let dir = root;
|
|
|
|
const split = path.split("/");
|
|
|
|
let last = split.pop()!;
|
|
|
|
|
|
|
|
for (const dirName of split) {
|
|
|
|
if (dir.dirs) {
|
|
|
|
dir = dir.dirs[dirName];
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return dir.files?.[last] ?? null;
|
|
|
|
}
|
|
|
|
|
|
|
|
return root.files?.[path] ?? null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadFiles(monaco: Monaco, dir: Directory, prefix = "") {
|
|
|
|
for (const [name, d] of Object.entries(dir.dirs ?? {})) {
|
|
|
|
loadFiles(monaco, d, prefix + name + "/");
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const [name, file] of Object.entries(dir.files ?? {})) {
|
|
|
|
loadFile(monaco, file, prefix + name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function loadFile(monaco: Monaco, file: File, name: string) {
|
|
|
|
const uri = monaco.Uri.parse(name);
|
|
|
|
if (!monaco.editor.getModel(uri)) {
|
|
|
|
monaco.editor.createModel(file.content, file.language, uri);
|
|
|
|
}
|
|
|
|
}
|