From f798b55e7a30146a3eb06634ff476535b2bee7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Moritz=20H=C3=B6lting?= <87192362+moritz-hoelting@users.noreply.github.com> Date: Sun, 23 Jun 2024 21:22:03 +0200 Subject: [PATCH] implement file creation --- src/components/Playground.tsx | 86 ++++++++++++++++--- .../playground/FileView/AddFileDialog.tsx | 69 +++++++++++++++ .../playground/FileView/DirElement.tsx | 70 +++++++++++++-- .../playground/FileView/FileElement.tsx | 25 ++++-- src/components/playground/FileView/index.tsx | 39 ++++++++- src/pages/de/playground.astro | 5 ++ src/pages/playground.astro | 5 ++ src/styles/playground.scss | 4 + src/utils/playground.ts | 5 ++ 9 files changed, 284 insertions(+), 24 deletions(-) create mode 100644 src/components/playground/FileView/AddFileDialog.tsx diff --git a/src/components/Playground.tsx b/src/components/Playground.tsx index 419b006..ebc94ae 100644 --- a/src/components/Playground.tsx +++ b/src/components/Playground.tsx @@ -177,18 +177,31 @@ export default function Playground({ lang }: { lang: PlaygroundLang }) { root={rootDir} selectedFileName={fileName} setSelectedFileName={setFileName} + addFile={(name) => { + if (monaco) { + loadFile( + monaco, + updateRootDir, + { content: "" }, + name + ); + } + }} deleteFile={(name) => { if (monaco) { - console.log(name); - deleteFile(monaco, updateRootDir, name); - if (name === fileName) { - const newFile = monaco.editor - .getModels()[0] - ?.uri.path.slice(1); - if (newFile) { - setFileName(newFile); - } else { - setFileName(""); + if (name.endsWith("/")) { + deleteDir(monaco, updateRootDir, name); + } else { + deleteFile(monaco, updateRootDir, name); + if (name === fileName) { + const newFile = monaco.editor + .getModels()[0] + ?.uri.path.slice(1); + if (newFile) { + setFileName(newFile); + } else { + setFileName(""); + } } } } @@ -384,10 +397,59 @@ function deleteFile(monaco: Monaco, updater: Updater, name: string) { }); } -function renameFile(monaco: Monaco, updater: Updater, oldName: string, newName: string) { +function deleteDir(monaco: Monaco, updater: Updater, path: string) { + const parts = path.split("/").filter((s) => s !== ""); + const last = parts.pop()!; + + let current = getFiles(monaco); + for (const part of parts) { + if (!current.dirs) { + current.dirs = {}; + } + if (!current.dirs[part]) { + current.dirs[part] = {}; + } + current = current.dirs[part]; + } + + if (current.dirs) { + for (const [name, _] of Object.entries(current.dirs ?? {})) { + deleteDir(monaco, updater, path + name + "/"); + } + for (const [name, _] of Object.entries(current.files ?? {})) { + deleteFile(monaco, updater, path + name); + } + + delete current.dirs[last]; + } + + updater((dir) => { + let current = dir; + for (const part of parts) { + if (!current.dirs) { + current.dirs = {}; + } + if (!current.dirs[part]) { + current.dirs[part] = {}; + } + current = current.dirs[part]; + } + + if (current.dirs) { + delete current.dirs[last]; + } + }); +} + +function renameFile( + monaco: Monaco, + updater: Updater, + oldName: string, + newName: string +) { const file = getFile(getFiles(monaco), oldName); if (file) { deleteFile(monaco, updater, oldName); loadFile(monaco, updater, file, newName); } -} \ No newline at end of file +} diff --git a/src/components/playground/FileView/AddFileDialog.tsx b/src/components/playground/FileView/AddFileDialog.tsx new file mode 100644 index 0000000..abad997 --- /dev/null +++ b/src/components/playground/FileView/AddFileDialog.tsx @@ -0,0 +1,69 @@ +import { + Button, + Dialog, + DialogActions, + DialogContent, + DialogContentText, + DialogTitle, + TextField, +} from "@mui/material"; +import type { PlaygroundExplorerLang } from "@utils/playground"; + +export default function AddFileDialog({ + open, + handleClose, + addFile, + lang, + defaultPath, +}: { + open: boolean; + defaultPath: string; + lang: PlaygroundExplorerLang; + handleClose: () => void; + addFile: (filepath: string) => void; +}) { + return ( + ) => { + event.preventDefault(); + const formData = new FormData(event.currentTarget); + const formJson = Object.fromEntries( + (formData as any).entries() + ); + const filepath = formJson.filepath; + if (addFile) { + addFile(filepath); + } + handleClose(); + }, + }} + > + {lang.menu.add} + + + {lang.menu.addPrompt.message} + + + + + + + + + ); +} diff --git a/src/components/playground/FileView/DirElement.tsx b/src/components/playground/FileView/DirElement.tsx index a82826e..97d65ad 100644 --- a/src/components/playground/FileView/DirElement.tsx +++ b/src/components/playground/FileView/DirElement.tsx @@ -1,10 +1,19 @@ -import type { Directory, PlaygroundExplorerLang, SetState } from "@utils/playground"; +import type { + Directory, + PlaygroundExplorerLang, + SetState, +} from "@utils/playground"; import React, { useState } from "react"; import { GoChevronDown as ChevDown, GoChevronRight as ChevRight, } from "react-icons/go"; import FileElement from "./FileElement"; +import { + Menu, + MenuItem, +} from "@mui/material"; +import AddFileDialog from "./AddFileDialog"; export default function DirElement({ name, @@ -14,6 +23,7 @@ export default function DirElement({ selectedFileName, lang, setSelectedFileName, + addFile, deleteFile, renameFile, }: { @@ -24,6 +34,7 @@ export default function DirElement({ selectedFileName: string; lang: PlaygroundExplorerLang; setSelectedFileName: SetState; + addFile: (name: string) => void; deleteFile: (name: string) => void; renameFile: (oldName: string, newName: string) => void; }) { @@ -37,11 +48,32 @@ export default function DirElement({ Object.keys(currentDir.dirs ?? {}).length > 0 || Object.keys(currentDir.files ?? {}).length > 0; + const [anchorEl, setAnchorEl] = useState(null); + const contextOpen = Boolean(anchorEl); + const handleContext = (event: React.MouseEvent) => { + event.preventDefault(); + setAnchorEl(event.currentTarget); + }; + const handleContextClose = () => { + setAnchorEl(null); + }; + + const [addOpen, setAddOpen] = React.useState(false); + + const handleAddClose = () => { + setAddOpen(false); + }; + + const onDelete = () => { + deleteFile(fullPath + "/"); + }; + return (
+
); -} \ No newline at end of file +} diff --git a/src/components/playground/FileView/index.tsx b/src/components/playground/FileView/index.tsx index 7d614c2..9438efe 100644 --- a/src/components/playground/FileView/index.tsx +++ b/src/components/playground/FileView/index.tsx @@ -5,12 +5,16 @@ import type { } from "@utils/playground"; import DirElement from "./DirElement"; import FileElement from "./FileElement"; +import { Menu, MenuItem } from "@mui/material"; +import React, { useState } from "react"; +import AddFileDialog from "./AddFileDialog"; export default function FileView({ lang, root, selectedFileName, setSelectedFileName, + addFile, deleteFile, renameFile, className, @@ -19,13 +23,45 @@ export default function FileView({ root: Directory; selectedFileName: string; setSelectedFileName: SetState; + addFile: (name: string) => void; deleteFile: (name: string) => void; renameFile: (oldName: string, newName: string) => void; className?: string; }) { + const [anchorEl, setAnchorEl] = useState(null); + const contextOpen = Boolean(anchorEl); + const handleContext = (event: React.MouseEvent) => { + event.preventDefault(); + setAnchorEl(event.currentTarget); + }; + const handleContextClose = () => { + setAnchorEl(null); + }; + + const [addOpen, setAddOpen] = React.useState(false); + + const handleAddClose = () => { + setAddOpen(false); + }; + return (
-

{lang.title}

+

{lang.title}

+ + { + handleContextClose(); + setAddOpen(true); + }} + > + {lang.menu.add} + + +
{Object.entries(root.dirs ?? {}).map(([name, dir]) => { return ( @@ -37,6 +73,7 @@ export default function FileView({ selectedFileName={selectedFileName} lang={lang} setSelectedFileName={setSelectedFileName} + addFile={addFile} deleteFile={deleteFile} renameFile={renameFile} /> diff --git a/src/pages/de/playground.astro b/src/pages/de/playground.astro index 8a40dde..47daa84 100644 --- a/src/pages/de/playground.astro +++ b/src/pages/de/playground.astro @@ -16,6 +16,11 @@ const lang: PlaygroundLang = { explorer: { title: "Dateien", menu: { + add: "Datei hinzufügen", + addPrompt: { + label: "Dateipfad", + message: "Pfad eingeben, an dem die Datei erstellt werden soll." + }, delete: "Löschen", rename: "Umbenennen", renamePrompt: { diff --git a/src/pages/playground.astro b/src/pages/playground.astro index bf1e009..fc8b8f7 100644 --- a/src/pages/playground.astro +++ b/src/pages/playground.astro @@ -16,6 +16,11 @@ const lang: PlaygroundLang = { explorer: { title: "Explorer", menu: { + add: "Add file", + addPrompt: { + label: "File path", + message: "Enter the path you want the new file to be created at." + }, delete: "Delete", rename: "Rename", renamePrompt: { diff --git a/src/styles/playground.scss b/src/styles/playground.scss index 140a032..33c72a0 100644 --- a/src/styles/playground.scss +++ b/src/styles/playground.scss @@ -16,6 +16,10 @@ overflow-x: hidden; overflow-y: auto; + > h3 { + cursor: pointer; + } + .entries { button { border: none; diff --git a/src/utils/playground.ts b/src/utils/playground.ts index fc2ab8b..72cf775 100644 --- a/src/utils/playground.ts +++ b/src/utils/playground.ts @@ -15,6 +15,11 @@ export type PlaygroundHeaderLang = { export type PlaygroundExplorerLang = { title: string; menu: { + add: string; + addPrompt: { + message: string; + label: string; + } rename: string; renamePrompt: { message: string;