show node definitions in explorer
This commit is contained in:
1 parent
ccdaa22c85
commit
5dab8220a5
8 files changed
+182
-83
No files matched your search
@@ -8,7 +8,7 @@ import {
|
|||||||
import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type";
|
import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type";
|
||||||
import * as b3util from "@/misc/b3util";
|
import * as b3util from "@/misc/b3util";
|
||||||
import { message } from "@/misc/hooks";
|
import { message } from "@/misc/hooks";
|
||||||
import { Hotkey, isHotkeyPressed, useHotkeys } from "@/misc/keys";
|
import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys";
|
||||||
import Path from "@/misc/path";
|
import Path from "@/misc/path";
|
||||||
import G6, { G6GraphEvent, Item, TreeGraph } from "@antv/g6";
|
import G6, { G6GraphEvent, Item, TreeGraph } from "@antv/g6";
|
||||||
import { dialog } from "@electron/remote";
|
import { dialog } from "@electron/remote";
|
||||||
@@ -840,13 +840,13 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
></Flex>
|
></Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const isMac = process.platform === "darwin";
|
|
||||||
const arr: MenuProps["items"] = [
|
const arr: MenuProps["items"] = [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("copy")}</div>
|
<div>{t("copy")}</div>
|
||||||
<div>{isMac ? "⌘ C" : "Ctrl+C"}</div>
|
<div>{isMacos ? "⌘ C" : "Ctrl+C"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "copy",
|
key: "copy",
|
||||||
@@ -855,7 +855,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("paste")}</div>
|
<div>{t("paste")}</div>
|
||||||
<div>{isMac ? "⌘ V" : "Ctrl+V"}</div>
|
<div>{isMacos ? "⌘ V" : "Ctrl+V"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "paste",
|
key: "paste",
|
||||||
@@ -864,7 +864,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("replace")}</div>
|
<div>{t("replace")}</div>
|
||||||
<div>{isMac ? "⇧ ⌘ V" : "Ctrl+Shift+V"} </div>
|
<div>{isMacos ? "⇧ ⌘ V" : "Ctrl+Shift+V"} </div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "replace",
|
key: "replace",
|
||||||
@@ -873,7 +873,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("insertNode")}</div>
|
<div>{t("insertNode")}</div>
|
||||||
<div>{isMac ? <IoMdReturnLeft /> : "Enter"}</div>
|
<div>{isMacos ? <IoMdReturnLeft /> : "Enter"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "insert",
|
key: "insert",
|
||||||
@@ -882,7 +882,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("deleteNode")}</div>
|
<div>{t("deleteNode")}</div>
|
||||||
<div>{isMac ? <FiDelete /> : "Backspace"}</div>
|
<div>{isMacos ? <FiDelete /> : "Backspace"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "delete",
|
key: "delete",
|
||||||
|
|||||||
+90
-24
@@ -1,4 +1,4 @@
|
|||||||
import { FileModel, useWorkspace } from "@/contexts/workspace-context";
|
import { FileTreeType, useWorkspace } from "@/contexts/workspace-context";
|
||||||
import * as b3util from "@/misc/b3util";
|
import * as b3util from "@/misc/b3util";
|
||||||
import { modal } from "@/misc/hooks";
|
import { modal } from "@/misc/hooks";
|
||||||
import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys";
|
import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys";
|
||||||
@@ -10,9 +10,11 @@ import { ipcRenderer, shell } from "electron";
|
|||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import React, { FC, useEffect, useMemo, useState } from "react";
|
import React, { FC, useEffect, useMemo, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { BsBoxFill } from "react-icons/bs";
|
||||||
import { FaExclamationTriangle, FaSwatchbook } from "react-icons/fa";
|
import { FaExclamationTriangle, FaSwatchbook } from "react-icons/fa";
|
||||||
import { FiCommand, FiDelete } from "react-icons/fi";
|
import { FiCommand, FiDelete } from "react-icons/fi";
|
||||||
import { IoMdReturnLeft } from "react-icons/io";
|
import { IoMdReturnLeft } from "react-icons/io";
|
||||||
|
import { PiTreeStructureFill } from "react-icons/pi";
|
||||||
|
|
||||||
const { DirectoryTree } = Tree;
|
const { DirectoryTree } = Tree;
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ type MenuEvent =
|
|||||||
| "move"
|
| "move"
|
||||||
| "duplicate";
|
| "duplicate";
|
||||||
|
|
||||||
const findFile = (path: string | undefined, node: FileModel): FileModel | undefined => {
|
const findFile = (path: string | undefined, node: FileTreeType): FileTreeType | undefined => {
|
||||||
if (!path) {
|
if (!path) {
|
||||||
return;
|
return;
|
||||||
} else if (node.path === path) {
|
} else if (node.path === path) {
|
||||||
@@ -45,7 +47,7 @@ const findFile = (path: string | undefined, node: FileModel): FileModel | undefi
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const findParent = (node: FileModel, parent?: FileModel): FileModel | undefined => {
|
const findParent = (node: FileTreeType, parent?: FileTreeType): FileTreeType | undefined => {
|
||||||
if (parent && parent.children) {
|
if (parent && parent.children) {
|
||||||
if (parent.children?.indexOf(node) >= 0) {
|
if (parent.children?.indexOf(node) >= 0) {
|
||||||
return parent;
|
return parent;
|
||||||
@@ -59,7 +61,7 @@ const findParent = (node: FileModel, parent?: FileModel): FileModel | undefined
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const resolveKeys = (path: string, node: FileModel, keys: React.Key[]) => {
|
const resolveKeys = (path: string, node: FileTreeType, keys: React.Key[]) => {
|
||||||
if (node.path === path) {
|
if (node.path === path) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -103,13 +105,18 @@ const renameFile = (oldPath: string, newPath: string) => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getSvgIcon = (path: string) => {};
|
||||||
|
|
||||||
export const Explorer: FC = () => {
|
export const Explorer: FC = () => {
|
||||||
const workspace = {
|
const workspace = {
|
||||||
close: useWorkspace((state) => state.close),
|
close: useWorkspace((state) => state.close),
|
||||||
editing: useWorkspace((state) => state.editing),
|
editing: useWorkspace((state) => state.editing),
|
||||||
editors: useWorkspace((state) => state.editors),
|
editors: useWorkspace((state) => state.editors),
|
||||||
open: useWorkspace((state) => state.open),
|
|
||||||
fileTree: useWorkspace((state) => state.fileTree),
|
fileTree: useWorkspace((state) => state.fileTree),
|
||||||
|
nodeDefs: useWorkspace((state) => state.nodeDefs),
|
||||||
|
nodeTree: useWorkspace((state) => state.nodeTree),
|
||||||
|
workdir: useWorkspace((state) => state.workdir),
|
||||||
|
open: useWorkspace((state) => state.open),
|
||||||
};
|
};
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
|
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
|
||||||
@@ -121,7 +128,54 @@ export const Explorer: FC = () => {
|
|||||||
const [contextMenu, setContextMenu] = useState<ItemType[]>([]);
|
const [contextMenu, setContextMenu] = useState<ItemType[]>([]);
|
||||||
|
|
||||||
if (workspace.fileTree) {
|
if (workspace.fileTree) {
|
||||||
workspace.fileTree.icon = <FaSwatchbook style={{ marginTop: "5px" }} />;
|
workspace.fileTree.icon = (
|
||||||
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
|
<FaSwatchbook />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (workspace.nodeTree) {
|
||||||
|
workspace.nodeTree.icon = (
|
||||||
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
|
<PiTreeStructureFill size={19} />
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
workspace.nodeTree.children?.forEach((catalog) => {
|
||||||
|
catalog.icon = (
|
||||||
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
|
<img
|
||||||
|
className="b3-node-icon"
|
||||||
|
style={{ width: "14px", height: "14px", color: "white" }}
|
||||||
|
src={`/icons/${catalog.title}.svg`}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
catalog.children?.forEach((node) => {
|
||||||
|
if (node.def?.icon) {
|
||||||
|
node.icon = (
|
||||||
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
|
<img
|
||||||
|
className="b3-node-icon"
|
||||||
|
key={catalog.title}
|
||||||
|
style={{ width: "13px", height: "13px", color: "white" }}
|
||||||
|
src={
|
||||||
|
process.env.VITE_DEV_SERVER_URL && isMacos
|
||||||
|
? `${Path.basename(workspace.workdir)}/${node.def?.icon}`
|
||||||
|
: `${workspace.workdir}/${node.def?.icon}`
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
node.icon = (
|
||||||
|
<Flex justify="center" align="center" style={{ height: "100%" }}>
|
||||||
|
<BsBoxFill style={{ width: "12px", height: "12px", color: "white" }} />{" "}
|
||||||
|
</Flex>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -182,7 +236,7 @@ export const Explorer: FC = () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const submitRename = (node: FileModel) => {
|
const submitRename = (node: FileTreeType) => {
|
||||||
if (!newName) {
|
if (!newName) {
|
||||||
if (fs.existsSync(node.path)) {
|
if (fs.existsSync(node.path)) {
|
||||||
node.editing = false;
|
node.editing = false;
|
||||||
@@ -214,14 +268,14 @@ export const Explorer: FC = () => {
|
|||||||
setNewName(null);
|
setNewName(null);
|
||||||
};
|
};
|
||||||
|
|
||||||
const dispatch = (event: MenuEvent, node: FileModel, dest?: FileModel) => {
|
const dispatch = (event: MenuEvent, node: FileTreeType, dest?: FileTreeType) => {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case "open": {
|
case "open": {
|
||||||
workspace.open(node.path);
|
workspace.open(node.path);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "newFolder": {
|
case "newFolder": {
|
||||||
const folderNode: FileModel = {
|
const folderNode: FileTreeType = {
|
||||||
path: node.path + "/:",
|
path: node.path + "/:",
|
||||||
title: "",
|
title: "",
|
||||||
children: [],
|
children: [],
|
||||||
@@ -235,7 +289,7 @@ export const Explorer: FC = () => {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "newFile": {
|
case "newFile": {
|
||||||
const folderNode: FileModel = {
|
const folderNode: FileTreeType = {
|
||||||
path: node.path + "/.json",
|
path: node.path + "/.json",
|
||||||
title: "",
|
title: "",
|
||||||
isLeaf: true,
|
isLeaf: true,
|
||||||
@@ -489,7 +543,7 @@ export const Explorer: FC = () => {
|
|||||||
></Flex>
|
></Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const isMac = process.platform === "darwin";
|
|
||||||
const arr: MenuProps["items"] = [
|
const arr: MenuProps["items"] = [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
@@ -503,7 +557,7 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("copy")}</div>
|
<div>{t("copy")}</div>
|
||||||
<div>{isMac ? "⌘ C" : "Ctrl+C"}</div>
|
<div>{isMacos ? "⌘ C" : "Ctrl+C"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "copy",
|
key: "copy",
|
||||||
@@ -512,7 +566,7 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("duplicate")}</div>
|
<div>{t("duplicate")}</div>
|
||||||
<div>{isMac ? "⌘ D" : "Ctrl+D"}</div>
|
<div>{isMacos ? "⌘ D" : "Ctrl+D"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "duplicate",
|
key: "duplicate",
|
||||||
@@ -520,7 +574,7 @@ export const Explorer: FC = () => {
|
|||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{isMac ? t("revealFileOnMac") : t("revealFileOnWindows")}</div>
|
<div>{isMacos ? t("revealFileOnMac") : t("revealFileOnWindows")}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "revealFile",
|
key: "revealFile",
|
||||||
@@ -529,8 +583,8 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("rename")}</div>
|
<div>{t("rename")}</div>
|
||||||
{isMac && <IoMdReturnLeft />}
|
{isMacos && <IoMdReturnLeft />}
|
||||||
{!isMac && <div>F2</div>}
|
{!isMacos && <div>F2</div>}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "rename",
|
key: "rename",
|
||||||
@@ -539,7 +593,7 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("delete")}</div>
|
<div>{t("delete")}</div>
|
||||||
{isMac && (
|
{isMacos && (
|
||||||
<Space size={6}>
|
<Space size={6}>
|
||||||
<FiCommand />
|
<FiCommand />
|
||||||
<FiDelete />
|
<FiDelete />
|
||||||
@@ -563,7 +617,7 @@ export const Explorer: FC = () => {
|
|||||||
></Flex>
|
></Flex>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
const isMac = process.platform === "darwin";
|
|
||||||
const arr: MenuProps["items"] = [
|
const arr: MenuProps["items"] = [
|
||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
@@ -584,7 +638,7 @@ export const Explorer: FC = () => {
|
|||||||
{
|
{
|
||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{isMac ? t("revealFileOnMac") : t("revealFileOnWindows")}</div>
|
<div>{isMacos ? t("revealFileOnMac") : t("revealFileOnWindows")}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "revealFile",
|
key: "revealFile",
|
||||||
@@ -593,7 +647,7 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div style={{ color: copyFile ? "inherit" : "gray" }}>{t("paste")}</div>
|
<div style={{ color: copyFile ? "inherit" : "gray" }}>{t("paste")}</div>
|
||||||
<div style={{ color: copyFile ? "inherit" : "gray" }}>{isMac ? "⌘ V" : "Ctrl+V"}</div>
|
<div style={{ color: copyFile ? "inherit" : "gray" }}>{isMacos ? "⌘ V" : "Ctrl+V"}</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "paste",
|
key: "paste",
|
||||||
@@ -602,8 +656,8 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("rename")}</div>
|
<div>{t("rename")}</div>
|
||||||
{isMac && <IoMdReturnLeft />}
|
{isMacos && <IoMdReturnLeft />}
|
||||||
{!isMac && <div>F2</div>}
|
{!isMacos && <div>F2</div>}
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
),
|
),
|
||||||
key: "rename",
|
key: "rename",
|
||||||
@@ -612,7 +666,7 @@ export const Explorer: FC = () => {
|
|||||||
label: (
|
label: (
|
||||||
<MenuItem>
|
<MenuItem>
|
||||||
<div>{t("delete")}</div>
|
<div>{t("delete")}</div>
|
||||||
{isMac && (
|
{isMacos && (
|
||||||
<Space size={6}>
|
<Space size={6}>
|
||||||
<FiCommand />
|
<FiCommand />
|
||||||
<FiDelete />
|
<FiDelete />
|
||||||
@@ -626,6 +680,8 @@ export const Explorer: FC = () => {
|
|||||||
return arr;
|
return arr;
|
||||||
}, [t, copyFile]);
|
}, [t, copyFile]);
|
||||||
|
|
||||||
|
const nodeConfs = useMemo(() => {}, [workspace.nodeDefs]);
|
||||||
|
|
||||||
const onClick = (info: MenuInfo) => {
|
const onClick = (info: MenuInfo) => {
|
||||||
const node = findFile(selectedKeys[0], workspace.fileTree!) ?? workspace.fileTree;
|
const node = findFile(selectedKeys[0], workspace.fileTree!) ?? workspace.fileTree;
|
||||||
if (node) {
|
if (node) {
|
||||||
@@ -650,7 +706,11 @@ export const Explorer: FC = () => {
|
|||||||
<div style={{ padding: "12px 24px" }}>
|
<div style={{ padding: "12px 24px" }}>
|
||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("explorer.title")}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("explorer.title")}</span>
|
||||||
</div>
|
</div>
|
||||||
<Flex vertical style={{ overflow: "auto", height: "100%", paddingBottom: "20px" }}>
|
<Flex
|
||||||
|
vertical
|
||||||
|
className={isMacos ? undefined : "b3-overflow"}
|
||||||
|
style={{ overflow: "auto", height: "100%", paddingBottom: "20px" }}
|
||||||
|
>
|
||||||
<Dropdown menu={{ items: contextMenu, onClick }} trigger={["contextMenu"]}>
|
<Dropdown menu={{ items: contextMenu, onClick }} trigger={["contextMenu"]}>
|
||||||
<div>
|
<div>
|
||||||
<DirectoryTree
|
<DirectoryTree
|
||||||
@@ -728,6 +788,12 @@ export const Explorer: FC = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
<DirectoryTree
|
||||||
|
tabIndex={-1}
|
||||||
|
fieldNames={{ key: "title" }}
|
||||||
|
treeData={workspace.nodeTree ? [workspace.nodeTree] : []}
|
||||||
|
switcherIcon={<DownOutlined />}
|
||||||
|
/>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Flex>
|
</Flex>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { EditNode, EditTree, FileModel, useWorkspace } from "@/contexts/workspace-context";
|
import { EditNode, EditTree, FileTreeType, useWorkspace } from "@/contexts/workspace-context";
|
||||||
import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type";
|
import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type";
|
||||||
import { Hotkey } from "@/misc/keys";
|
import { Hotkey, isMacos } from "@/misc/keys";
|
||||||
import Path from "@/misc/path";
|
import Path from "@/misc/path";
|
||||||
import { AutoComplete, Divider, Flex, Form, Input, InputNumber, Select, Switch } from "antd";
|
import { AutoComplete, Divider, Flex, Form, Input, InputNumber, Select, Switch } from "antd";
|
||||||
import { DefaultOptionType } from "antd/es/select";
|
import { DefaultOptionType } from "antd/es/select";
|
||||||
@@ -116,7 +116,10 @@ export const Inspector: FC = () => {
|
|||||||
<div style={{ padding: "12px 24px" }}>
|
<div style={{ padding: "12px 24px" }}>
|
||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("tree.overview")}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{t("tree.overview")}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ overflow: "auto", height: "100%", padding: "24px" }}>
|
<div
|
||||||
|
className={isMacos ? undefined : "b3-overflow"}
|
||||||
|
style={{ overflow: "auto", height: "100%", padding: "24px" }}
|
||||||
|
>
|
||||||
<Form form={form} labelCol={{ span: 8 }} onFinish={finish}>
|
<Form form={form} labelCol={{ span: 8 }} onFinish={finish}>
|
||||||
<Form.Item name="name" label={t("tree.name")}>
|
<Form.Item name="name" label={t("tree.name")}>
|
||||||
<Input disabled={true} />
|
<Input disabled={true} />
|
||||||
@@ -197,7 +200,10 @@ export const Inspector: FC = () => {
|
|||||||
<div style={{ padding: "12px 24px" }}>
|
<div style={{ padding: "12px 24px" }}>
|
||||||
<span style={{ fontSize: "18px", fontWeight: "600" }}>{def.desc}</span>
|
<span style={{ fontSize: "18px", fontWeight: "600" }}>{def.desc}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ overflow: "auto", height: "100%", padding: "24px" }}>
|
<div
|
||||||
|
className={isMacos ? undefined : "b3-overflow"}
|
||||||
|
style={{ overflow: "auto", height: "100%", padding: "24px" }}
|
||||||
|
>
|
||||||
<Form
|
<Form
|
||||||
form={form}
|
form={form}
|
||||||
wrapperCol={{ span: "auto" }}
|
wrapperCol={{ span: "auto" }}
|
||||||
|
|||||||
+8
-25
@@ -2,7 +2,7 @@ import { useSetting } from "@/contexts/setting-context";
|
|||||||
import { useWorkspace } from "@/contexts/workspace-context";
|
import { useWorkspace } from "@/contexts/workspace-context";
|
||||||
import * as b3util from "@/misc/b3util";
|
import * as b3util from "@/misc/b3util";
|
||||||
import i18n from "@/misc/i18n";
|
import i18n from "@/misc/i18n";
|
||||||
import { Hotkey, sendInputEvent } from "@/misc/keys";
|
import { Hotkey, isMacos, sendInputEvent } from "@/misc/keys";
|
||||||
import { CheckOutlined } from "@ant-design/icons";
|
import { CheckOutlined } from "@ant-design/icons";
|
||||||
import { Menu as AppMenu, BrowserWindow, app, dialog } from "@electron/remote";
|
import { Menu as AppMenu, BrowserWindow, app, dialog } from "@electron/remote";
|
||||||
import { Button, DropDownProps, Dropdown, Flex, FlexProps, LayoutProps, Space } from "antd";
|
import { Button, DropDownProps, Dropdown, Flex, FlexProps, LayoutProps, Space } from "antd";
|
||||||
@@ -61,7 +61,6 @@ export const Menu: FC<LayoutProps> = () => {
|
|||||||
recent: useSetting((state) => state.recent),
|
recent: useSetting((state) => state.recent),
|
||||||
};
|
};
|
||||||
|
|
||||||
const isMac = process.platform === "darwin";
|
|
||||||
const menuTemplate: MenuItemConstructorOptions[] = useMemo(() => {
|
const menuTemplate: MenuItemConstructorOptions[] = useMemo(() => {
|
||||||
const recentWorkspaces: MenuItemConstructorOptions[] = settings.recent.map((path, i) => ({
|
const recentWorkspaces: MenuItemConstructorOptions[] = settings.recent.map((path, i) => ({
|
||||||
id: "menu.file.recent" + i,
|
id: "menu.file.recent" + i,
|
||||||
@@ -70,7 +69,7 @@ export const Menu: FC<LayoutProps> = () => {
|
|||||||
}));
|
}));
|
||||||
return [
|
return [
|
||||||
// { role: 'appMenu' }
|
// { role: 'appMenu' }
|
||||||
...(isMac
|
...(isMacos
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
id: "menu.app",
|
id: "menu.app",
|
||||||
@@ -341,31 +340,15 @@ export const Menu: FC<LayoutProps> = () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
// {
|
|
||||||
// id: "menu.window",
|
|
||||||
// label: t("menu.window"),
|
|
||||||
// submenu: [
|
|
||||||
// { id: "menu.window.minimize", role: "minimize" },
|
|
||||||
// { id: "menu.window.zoom", role: "zoom" },
|
|
||||||
// ...(isMac
|
|
||||||
// ? [
|
|
||||||
// { type: "separator" },
|
|
||||||
// { id: "menu.window.front", role: "front" },
|
|
||||||
// { type: "separator" },
|
|
||||||
// { id: "menu.window.window", role: "window" },
|
|
||||||
// ]
|
|
||||||
// : [{ id: "menu.window.close", role: "close" }]),
|
|
||||||
// ],
|
|
||||||
// },
|
|
||||||
] as MenuItemConstructorOptions[];
|
] as MenuItemConstructorOptions[];
|
||||||
}, [t, workspace.workdir, settings.recent, workspace.editing]);
|
}, [t, workspace.workdir, settings.recent, workspace.editing]);
|
||||||
|
|
||||||
if (isMac) {
|
if (isMacos) {
|
||||||
const menu = AppMenu.buildFromTemplate(menuTemplate);
|
const menu = AppMenu.buildFromTemplate(menuTemplate);
|
||||||
AppMenu.setApplicationMenu(menu);
|
AppMenu.setApplicationMenu(menu);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!process.env.VITE_DEV_SERVER_URL && isMac) {
|
if (!process.env.VITE_DEV_SERVER_URL && isMacos) {
|
||||||
return <div />;
|
return <div />;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,15 +370,15 @@ export const Menu: FC<LayoutProps> = () => {
|
|||||||
const keys = (option.accelerator?.split("+") ?? []).map((key) => {
|
const keys = (option.accelerator?.split("+") ?? []).map((key) => {
|
||||||
const lowerKey = key.toLowerCase();
|
const lowerKey = key.toLowerCase();
|
||||||
if (lowerKey.indexOf("alt") !== -1) {
|
if (lowerKey.indexOf("alt") !== -1) {
|
||||||
return isMac ? "⌥" : "Alt";
|
return isMacos ? "⌥" : "Alt";
|
||||||
} else if (
|
} else if (
|
||||||
lowerKey.indexOf("cmdorctrl") !== -1 ||
|
lowerKey.indexOf("cmdorctrl") !== -1 ||
|
||||||
lowerKey.indexOf("ctrl") !== -1 ||
|
lowerKey.indexOf("ctrl") !== -1 ||
|
||||||
lowerKey.indexOf("meta") !== -1
|
lowerKey.indexOf("meta") !== -1
|
||||||
) {
|
) {
|
||||||
return isMac ? "⌘" : "Ctrl";
|
return isMacos ? "⌘" : "Ctrl";
|
||||||
} else if (lowerKey.indexOf("shift") !== -1) {
|
} else if (lowerKey.indexOf("shift") !== -1) {
|
||||||
return isMac ? "⇧" : "Shift";
|
return isMacos ? "⇧" : "Shift";
|
||||||
} else {
|
} else {
|
||||||
return key.toUpperCase().replace("=", "+");
|
return key.toUpperCase().replace("=", "+");
|
||||||
}
|
}
|
||||||
@@ -423,7 +406,7 @@ export const Menu: FC<LayoutProps> = () => {
|
|||||||
)}
|
)}
|
||||||
{option.label}
|
{option.label}
|
||||||
</div>
|
</div>
|
||||||
<div>{keys.join(isMac ? " " : "+")}</div>
|
<div>{keys.join(isMacos ? " " : "+")}</div>
|
||||||
</MenuItemLabel>
|
</MenuItemLabel>
|
||||||
),
|
),
|
||||||
key: option.id ?? "",
|
key: option.id ?? "",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useSetting } from "@/contexts/setting-context";
|
import { useSetting } from "@/contexts/setting-context";
|
||||||
import { EditorStore, useWorkspace } from "@/contexts/workspace-context";
|
import { EditorStore, useWorkspace } from "@/contexts/workspace-context";
|
||||||
import { modal } from "@/misc/hooks";
|
import { modal } from "@/misc/hooks";
|
||||||
import { Hotkey, isHotkeyPressed, setInputFocus, useHotkeys } from "@/misc/keys";
|
import { Hotkey, isHotkeyPressed, isMacos, setInputFocus, useHotkeys } from "@/misc/keys";
|
||||||
import Path from "@/misc/path";
|
import Path from "@/misc/path";
|
||||||
import { app } from "@electron/remote";
|
import { app } from "@electron/remote";
|
||||||
import { Button, Flex, Layout, Space, Tabs, Tag, Tooltip } from "antd";
|
import { Button, Flex, Layout, Space, Tabs, Tag, Tooltip } from "antd";
|
||||||
@@ -41,7 +41,6 @@ export const Workspace: FC = () => {
|
|||||||
const [isShowingSave, setShowingSave] = useState(false);
|
const [isShowingSave, setShowingSave] = useState(false);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const forceUpdate = useForceUpdate();
|
const forceUpdate = useForceUpdate();
|
||||||
const isMac = process.platform === "darwin";
|
|
||||||
const { width = 0, height = 0 } = useWindowSize();
|
const { width = 0, height = 0 } = useWindowSize();
|
||||||
|
|
||||||
const keysRef = useHotkeys<HTMLDivElement>(
|
const keysRef = useHotkeys<HTMLDivElement>(
|
||||||
@@ -333,8 +332,8 @@ export const Workspace: FC = () => {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{[
|
{[
|
||||||
{ label: t("searchFile"), hotkeys: isMac ? "⌘ P" : "Ctrl + P" },
|
{ label: t("searchFile"), hotkeys: isMacos ? "⌘ P" : "Ctrl + P" },
|
||||||
{ label: t("build"), hotkeys: isMac ? "⌘ B" : "Ctrl + B" },
|
{ label: t("build"), hotkeys: isMacos ? "⌘ B" : "Ctrl + B" },
|
||||||
{ label: t("insertNode"), hotkeys: "Enter" },
|
{ label: t("insertNode"), hotkeys: "Enter" },
|
||||||
{ label: t("deleteNode"), hotkeys: "Backspace" },
|
{ label: t("deleteNode"), hotkeys: "Backspace" },
|
||||||
].map((v) => (
|
].map((v) => (
|
||||||
|
|||||||
@@ -68,14 +68,24 @@ export class EditorStore {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FileModel = {
|
export type FileTreeType = {
|
||||||
path: string;
|
path: string;
|
||||||
title: string;
|
title: string;
|
||||||
icon?: React.ReactNode;
|
icon?: React.ReactNode;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
isLeaf?: boolean;
|
isLeaf?: boolean;
|
||||||
children?: FileModel[];
|
children?: FileTreeType[];
|
||||||
editing?: boolean;
|
editing?: boolean;
|
||||||
|
style?: React.CSSProperties;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type NodeTreeType = {
|
||||||
|
title: string;
|
||||||
|
def?: NodeDef;
|
||||||
|
icon?: React.ReactNode;
|
||||||
|
isLeaf?: boolean;
|
||||||
|
children?: NodeTreeType[];
|
||||||
|
style?: React.CSSProperties;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type EditNode = {
|
export type EditNode = {
|
||||||
@@ -98,7 +108,8 @@ export type WorkspaceStore = {
|
|||||||
path: string;
|
path: string;
|
||||||
|
|
||||||
allFiles: string[];
|
allFiles: string[];
|
||||||
fileTree?: FileModel;
|
nodeTree?: NodeTreeType;
|
||||||
|
fileTree?: FileTreeType;
|
||||||
editors: EditorStore[];
|
editors: EditorStore[];
|
||||||
editing?: EditorStore;
|
editing?: EditorStore;
|
||||||
|
|
||||||
@@ -143,7 +154,7 @@ const loadFileTree = (workdir: string, filename: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: FileModel = {
|
const data: FileTreeType = {
|
||||||
path: fullpath.replaceAll(Path.sep, "/"),
|
path: fullpath.replaceAll(Path.sep, "/"),
|
||||||
title: Path.basename(filename),
|
title: Path.basename(filename),
|
||||||
};
|
};
|
||||||
@@ -412,11 +423,15 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
loadTrees: () => {
|
loadTrees: () => {
|
||||||
const workspace = get();
|
const workspace = get();
|
||||||
const data = loadFileTree(workspace.workdir, ".")!;
|
const data = loadFileTree(workspace.workdir, ".")!;
|
||||||
data.title = Path.basename(workspace.workdir);
|
data.title = Path.basename(workspace.workdir).toUpperCase();
|
||||||
|
data.style = {
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px",
|
||||||
|
};
|
||||||
set({ fileTree: data });
|
set({ fileTree: data });
|
||||||
|
|
||||||
const allFiles: string[] = [];
|
const allFiles: string[] = [];
|
||||||
const collect = (fileNode?: FileModel) => {
|
const collect = (fileNode?: FileTreeType) => {
|
||||||
if (fileNode?.isLeaf) {
|
if (fileNode?.isLeaf) {
|
||||||
allFiles.push(fileNode.path);
|
allFiles.push(fileNode.path);
|
||||||
}
|
}
|
||||||
@@ -429,10 +444,36 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
loadNodeDefs: () => {
|
loadNodeDefs: () => {
|
||||||
const workspace = get();
|
const workspace = get();
|
||||||
const nodeDefData = readJson(`${workspace.workdir}/node-config.b3-setting`) as NodeDef[];
|
const nodeDefData = readJson(`${workspace.workdir}/node-config.b3-setting`) as NodeDef[];
|
||||||
|
const nodeTree: NodeTreeType = {
|
||||||
|
title: "NODES",
|
||||||
|
children: [],
|
||||||
|
style: {
|
||||||
|
fontWeight: "bold",
|
||||||
|
fontSize: "13px",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const nodeDefs: Map<string, NodeDef> = new Map();
|
||||||
for (const v of nodeDefData) {
|
for (const v of nodeDefData) {
|
||||||
workspace.nodeDefs.set(v.name, v);
|
nodeDefs.set(v.name, v);
|
||||||
|
let catalog: NodeTreeType | undefined = nodeTree.children?.find((nt) => nt.title === v.type);
|
||||||
|
if (!catalog) {
|
||||||
|
catalog = {
|
||||||
|
title: v.type,
|
||||||
|
children: [],
|
||||||
|
};
|
||||||
|
nodeTree.children?.push(catalog);
|
||||||
}
|
}
|
||||||
set({ nodeDefs: workspace.nodeDefs });
|
catalog.children?.push({
|
||||||
|
title: `${v.name}(${v.desc})`,
|
||||||
|
isLeaf: true,
|
||||||
|
def: v,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
nodeTree.children?.sort((a, b) => a.title.localeCompare(b.title));
|
||||||
|
nodeTree.children?.forEach((child) =>
|
||||||
|
child.children?.sort((a, b) => a.title.localeCompare(b.title))
|
||||||
|
);
|
||||||
|
set({ nodeDefs, nodeTree });
|
||||||
workspace.editing?.dispatch?.("reload");
|
workspace.editing?.dispatch?.("reload");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+14
-10
@@ -16,20 +16,24 @@
|
|||||||
--b3-color-border: #30363d;
|
--b3-color-border: #30363d;
|
||||||
}
|
}
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
|
||||||
width: 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
::-webkit-scrollbar-thumb {
|
|
||||||
background: #30363d;
|
|
||||||
border-radius: 9px;
|
|
||||||
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.b3-node-icon {
|
||||||
|
filter: invert(100%) sepia(5%) saturate(1%) hue-rotate(320deg) brightness(104%) contrast(100%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.b3-overflow::-webkit-scrollbar {
|
||||||
|
width: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.b3-overflow::-webkit-scrollbar-thumb {
|
||||||
|
background: #30363d;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: inset006pxrgba(0, 0, 0, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
.b3-drag-region {
|
.b3-drag-region {
|
||||||
-webkit-app-region: drag;
|
-webkit-app-region: drag;
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ export interface NodeArg {
|
|||||||
}
|
}
|
||||||
export interface NodeDef {
|
export interface NodeDef {
|
||||||
name: string;
|
name: string;
|
||||||
type?: string;
|
type: string;
|
||||||
desc?: string;
|
desc?: string;
|
||||||
args?: NodeArg[];
|
args?: NodeArg[];
|
||||||
input?: string[];
|
input?: string[];
|
||||||
|
|||||||
Reference in new issue
Block a user