import { app } from "@electron/remote"; import { useKeyPress } from "ahooks"; import { Button, Flex, Layout, Space, Tabs, Tag, Tooltip } from "antd"; import { FC, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { FaExclamationTriangle } from "react-icons/fa"; import { PiTreeStructureFill } from "react-icons/pi"; import { VscNewFolder, VscRepo } from "react-icons/vsc"; import useForceUpdate from "use-force-update"; import { useWindowSize } from "usehooks-ts"; import { useShallow } from "zustand/react/shallow"; import { useSetting } from "../contexts/setting-context"; import { EditorStore, useWorkspace } from "../contexts/workspace-context"; import { modal } from "../misc/hooks"; import { Hotkey, isMacos, setInputFocus, useKeyDown } from "../misc/keys"; import Path from "../misc/path"; import { Editor } from "./editor"; import { Explorer } from "./explorer"; import { Inspector } from "./inspector"; import { TitleBar } from "./titlebar"; const { Header, Content, Sider } = Layout; export const Workspace: FC = () => { const workspace = useWorkspace( useShallow((state) => ({ save: state.save, editors: state.editors, modifiedTime: state.modifiedTime, isShowingSearch: state.isShowingSearch, onShowingSearch: state.onShowingSearch, openProject: state.openProject, buildProject: state.buildProject, close: state.close, createProject: state.createProject, edit: state.edit, editing: state.editing, fileTree: state.fileTree, find: state.find, })) ); const { settings } = useSetting(useShallow((state) => ({ settings: state.data }))); const [isShowingAlert, setShowingAlert] = useState(false); const { t } = useTranslation(); const forceUpdate = useForceUpdate(); const { width = 0, height = 0 } = useWindowSize(); const keysRef = useRef(null); useKeyDown(Hotkey.Build, keysRef, (event) => { event.preventDefault(); workspace.buildProject(); }); useKeyDown(Hotkey.Save, keysRef, (event) => { event.preventDefault(); workspace.save(); }); useKeyPress(Hotkey.CloseEditor, (event) => { event.preventDefault(); }); useKeyDown(Hotkey.CloseEditor, null, (event) => { if (workspace.editing) { event.preventDefault(); if (workspace.editing.unsave) { showSaveDialog(workspace.editing); } else { workspace.close(workspace.editing.path); } } keysRef.current?.focus(); }); useKeyDown(Hotkey.SearchTree, keysRef, (event) => { event.preventDefault(); workspace.onShowingSearch(true); }); useKeyDown(Hotkey.SearchNode, keysRef, (event) => { event.preventDefault(); workspace.editing?.dispatch("searchNode"); }); useKeyDown(Hotkey.JumpNode, keysRef, (event) => { event.preventDefault(); workspace.editing?.dispatch("jumpNode"); }); useEffect(() => { if (!workspace.isShowingSearch && !isShowingAlert) { keysRef.current?.focus(); } }, [workspace.isShowingSearch]); useEffect(() => { const editor = workspace.editing; if (editor?.alertReload) { if (isShowingAlert) { return; } setShowingAlert(true); const alert = modal.confirm({ centered: true, content: (
{t("workspace.reloadFile", { name: Path.basename(editor.path) })}
), footer: ( ), }); } }, [workspace.editing, workspace.modifiedTime]); const showSaveDialog = (editor: EditorStore) => { if (isShowingAlert) { return; } setShowingAlert(true); const alert = modal.confirm({ centered: true, content: (
{t("workspace.saveOnClose", { name: Path.basename(editor.path) })}
), footer: ( ), }); }; const showSaveAllDialog = (unsaves: EditorStore[]) => { if (isShowingAlert) { return; } setShowingAlert(true); const alert = modal.confirm({ centered: true, content: (
{unsaves.length === 1 && (
{t("workspace.saveOnClose", { name: Path.basename(unsaves[0].path) })}
)} {unsaves.length > 1 && ( <>
{t("workspace.saveAllOnClose", { count: unsaves.length })}
{unsaves.map((editor) => (
{Path.basename(editor.path)}
))}
)}
), footer: ( ), }); }; window.onbeforeunload = (e) => { const unsaves = workspace.editors.filter((editor) => editor.unsave); if (unsaves.length) { showSaveAllDialog(unsaves); return false; } }; return (
{ setInputFocus(e.target); }} > {workspace.fileTree && ( )} {!workspace.fileTree && (
Behavior3 Editor
{t("start")}
workspace.createProject()} > {t("createProject")} workspace.openProject()} > {t("openProject")}
{t("recent")}
{settings.recent.map((path) => { const homedir = app.getPath("home"); return (
workspace.openProject(path)} style={{ color: "var(--ant-color-primary)", fontWeight: "500", cursor: "pointer", marginRight: "15px", }} > {Path.basename(path)} {Path.dirname(path).replace(homedir, "~")}
); })}
)} {workspace.editors.length === 0 && ( {[ { label: t("searchFile"), hotkeys: isMacos ? "⌘ P" : "Ctrl + P" }, { label: t("build"), hotkeys: isMacos ? "⌘ B" : "Ctrl + B" }, { label: t("searchNode"), hotkeys: isMacos ? "⌘ F" : "Ctrl + F" }, { label: t("insertNode"), hotkeys: "Enter" }, { label: t("deleteNode"), hotkeys: "Backspace" }, ].map((v) => ( {v.label} {v.hotkeys.split(" ").map((key, index) => (
{key === "+" &&
+
} {key !== "+" && ( {key} )}
))}
))}
)} {workspace.editors.length > 0 && ( { if (action === "remove") { const path = activeKey as string; const editor = workspace.find(path); if (editor && editor.unsave) { showSaveDialog(editor); } else { workspace.close(path); } } }} onChange={(activeKey) => { workspace.edit(activeKey); }} items={workspace.editors.map((v) => { return { label: ( {v.path}} > {`${Path.basename(v.path)}${v.unsave ? "*" : ""}`} ), key: v.path, children: , }; })} /> )}
); };