diff --git a/src/components/editor.tsx b/src/components/editor.tsx index 512e2a7..570098e 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -8,7 +8,7 @@ import { import { NodeModel, TreeGraphData, TreeModel } from "@/misc/b3type"; import * as b3util from "@/misc/b3util"; 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 G6, { G6GraphEvent, Item, TreeGraph } from "@antv/g6"; import { dialog } from "@electron/remote"; @@ -840,13 +840,13 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . > ); }; - const isMac = process.platform === "darwin"; + const arr: MenuProps["items"] = [ { label: (
{t("copy")}
-
{isMac ? "⌘ C" : "Ctrl+C"}
+
{isMacos ? "⌘ C" : "Ctrl+C"}
), key: "copy", @@ -855,7 +855,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . label: (
{t("paste")}
-
{isMac ? "⌘ V" : "Ctrl+V"}
+
{isMacos ? "⌘ V" : "Ctrl+V"}
), key: "paste", @@ -864,7 +864,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . label: (
{t("replace")}
-
{isMac ? "⇧ ⌘ V" : "Ctrl+Shift+V"}
+
{isMacos ? "⇧ ⌘ V" : "Ctrl+Shift+V"}
), key: "replace", @@ -873,7 +873,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . label: (
{t("insertNode")}
-
{isMac ? : "Enter"}
+
{isMacos ? : "Enter"}
), key: "insert", @@ -882,7 +882,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . label: (
{t("deleteNode")}
-
{isMac ? : "Backspace"}
+
{isMacos ? : "Backspace"}
), key: "delete", diff --git a/src/components/explorer.tsx b/src/components/explorer.tsx index 097c978..0903aa1 100644 --- a/src/components/explorer.tsx +++ b/src/components/explorer.tsx @@ -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 { modal } from "@/misc/hooks"; import { Hotkey, isHotkeyPressed, isMacos, useHotkeys } from "@/misc/keys"; @@ -10,9 +10,11 @@ import { ipcRenderer, shell } from "electron"; import * as fs from "fs"; import React, { FC, useEffect, useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; +import { BsBoxFill } from "react-icons/bs"; import { FaExclamationTriangle, FaSwatchbook } from "react-icons/fa"; import { FiCommand, FiDelete } from "react-icons/fi"; import { IoMdReturnLeft } from "react-icons/io"; +import { PiTreeStructureFill } from "react-icons/pi"; const { DirectoryTree } = Tree; @@ -29,7 +31,7 @@ type MenuEvent = | "move" | "duplicate"; -const findFile = (path: string | undefined, node: FileModel): FileModel | undefined => { +const findFile = (path: string | undefined, node: FileTreeType): FileTreeType | undefined => { if (!path) { return; } 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.children?.indexOf(node) >= 0) { 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) { return true; } @@ -103,13 +105,18 @@ const renameFile = (oldPath: string, newPath: string) => { return false; }; +const getSvgIcon = (path: string) => {}; + export const Explorer: FC = () => { const workspace = { close: useWorkspace((state) => state.close), editing: useWorkspace((state) => state.editing), editors: useWorkspace((state) => state.editors), - open: useWorkspace((state) => state.open), 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 [selectedKeys, setSelectedKeys] = useState([]); @@ -121,7 +128,54 @@ export const Explorer: FC = () => { const [contextMenu, setContextMenu] = useState([]); if (workspace.fileTree) { - workspace.fileTree.icon = ; + workspace.fileTree.icon = ( + + + + ); + } + + if (workspace.nodeTree) { + workspace.nodeTree.icon = ( + + + + ); + workspace.nodeTree.children?.forEach((catalog) => { + catalog.icon = ( + + + + ); + catalog.children?.forEach((node) => { + if (node.def?.icon) { + node.icon = ( + + + + ); + } else { + node.icon = ( + + {" "} + + ); + } + }); + }); } useEffect(() => { @@ -182,7 +236,7 @@ export const Explorer: FC = () => { } ); - const submitRename = (node: FileModel) => { + const submitRename = (node: FileTreeType) => { if (!newName) { if (fs.existsSync(node.path)) { node.editing = false; @@ -214,14 +268,14 @@ export const Explorer: FC = () => { setNewName(null); }; - const dispatch = (event: MenuEvent, node: FileModel, dest?: FileModel) => { + const dispatch = (event: MenuEvent, node: FileTreeType, dest?: FileTreeType) => { switch (event) { case "open": { workspace.open(node.path); break; } case "newFolder": { - const folderNode: FileModel = { + const folderNode: FileTreeType = { path: node.path + "/:", title: "", children: [], @@ -235,7 +289,7 @@ export const Explorer: FC = () => { break; } case "newFile": { - const folderNode: FileModel = { + const folderNode: FileTreeType = { path: node.path + "/.json", title: "", isLeaf: true, @@ -489,7 +543,7 @@ export const Explorer: FC = () => { > ); }; - const isMac = process.platform === "darwin"; + const arr: MenuProps["items"] = [ { label: ( @@ -503,7 +557,7 @@ export const Explorer: FC = () => { label: (
{t("copy")}
-
{isMac ? "⌘ C" : "Ctrl+C"}
+
{isMacos ? "⌘ C" : "Ctrl+C"}
), key: "copy", @@ -512,7 +566,7 @@ export const Explorer: FC = () => { label: (
{t("duplicate")}
-
{isMac ? "⌘ D" : "Ctrl+D"}
+
{isMacos ? "⌘ D" : "Ctrl+D"}
), key: "duplicate", @@ -520,7 +574,7 @@ export const Explorer: FC = () => { { label: ( -
{isMac ? t("revealFileOnMac") : t("revealFileOnWindows")}
+
{isMacos ? t("revealFileOnMac") : t("revealFileOnWindows")}
), key: "revealFile", @@ -529,8 +583,8 @@ export const Explorer: FC = () => { label: (
{t("rename")}
- {isMac && } - {!isMac &&
F2
} + {isMacos && } + {!isMacos &&
F2
}
), key: "rename", @@ -539,7 +593,7 @@ export const Explorer: FC = () => { label: (
{t("delete")}
- {isMac && ( + {isMacos && ( @@ -563,7 +617,7 @@ export const Explorer: FC = () => { > ); }; - const isMac = process.platform === "darwin"; + const arr: MenuProps["items"] = [ { label: ( @@ -584,7 +638,7 @@ export const Explorer: FC = () => { { label: ( -
{isMac ? t("revealFileOnMac") : t("revealFileOnWindows")}
+
{isMacos ? t("revealFileOnMac") : t("revealFileOnWindows")}
), key: "revealFile", @@ -593,7 +647,7 @@ export const Explorer: FC = () => { label: (
{t("paste")}
-
{isMac ? "⌘ V" : "Ctrl+V"}
+
{isMacos ? "⌘ V" : "Ctrl+V"}
), key: "paste", @@ -602,8 +656,8 @@ export const Explorer: FC = () => { label: (
{t("rename")}
- {isMac && } - {!isMac &&
F2
} + {isMacos && } + {!isMacos &&
F2
}
), key: "rename", @@ -612,7 +666,7 @@ export const Explorer: FC = () => { label: (
{t("delete")}
- {isMac && ( + {isMacos && ( @@ -626,6 +680,8 @@ export const Explorer: FC = () => { return arr; }, [t, copyFile]); + const nodeConfs = useMemo(() => {}, [workspace.nodeDefs]); + const onClick = (info: MenuInfo) => { const node = findFile(selectedKeys[0], workspace.fileTree!) ?? workspace.fileTree; if (node) { @@ -650,7 +706,11 @@ export const Explorer: FC = () => {
{t("explorer.title")}
- +
{ />
+ } + />
); diff --git a/src/components/inspector.tsx b/src/components/inspector.tsx index 00e926e..05d2a4f 100644 --- a/src/components/inspector.tsx +++ b/src/components/inspector.tsx @@ -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 { Hotkey } from "@/misc/keys"; +import { Hotkey, isMacos } from "@/misc/keys"; import Path from "@/misc/path"; import { AutoComplete, Divider, Flex, Form, Input, InputNumber, Select, Switch } from "antd"; import { DefaultOptionType } from "antd/es/select"; @@ -116,7 +116,10 @@ export const Inspector: FC = () => {
{t("tree.overview")}
-
+
@@ -197,7 +200,10 @@ export const Inspector: FC = () => {
{def.desc}
-
+
= () => { recent: useSetting((state) => state.recent), }; - const isMac = process.platform === "darwin"; const menuTemplate: MenuItemConstructorOptions[] = useMemo(() => { const recentWorkspaces: MenuItemConstructorOptions[] = settings.recent.map((path, i) => ({ id: "menu.file.recent" + i, @@ -70,7 +69,7 @@ export const Menu: FC = () => { })); return [ // { role: 'appMenu' } - ...(isMac + ...(isMacos ? [ { id: "menu.app", @@ -341,31 +340,15 @@ export const Menu: FC = () => { }, ], }, - // { - // 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[]; }, [t, workspace.workdir, settings.recent, workspace.editing]); - if (isMac) { + if (isMacos) { const menu = AppMenu.buildFromTemplate(menuTemplate); AppMenu.setApplicationMenu(menu); } - if (!process.env.VITE_DEV_SERVER_URL && isMac) { + if (!process.env.VITE_DEV_SERVER_URL && isMacos) { return
; } @@ -387,15 +370,15 @@ export const Menu: FC = () => { const keys = (option.accelerator?.split("+") ?? []).map((key) => { const lowerKey = key.toLowerCase(); if (lowerKey.indexOf("alt") !== -1) { - return isMac ? "⌥" : "Alt"; + return isMacos ? "⌥" : "Alt"; } else if ( lowerKey.indexOf("cmdorctrl") !== -1 || lowerKey.indexOf("ctrl") !== -1 || lowerKey.indexOf("meta") !== -1 ) { - return isMac ? "⌘" : "Ctrl"; + return isMacos ? "⌘" : "Ctrl"; } else if (lowerKey.indexOf("shift") !== -1) { - return isMac ? "⇧" : "Shift"; + return isMacos ? "⇧" : "Shift"; } else { return key.toUpperCase().replace("=", "+"); } @@ -423,7 +406,7 @@ export const Menu: FC = () => { )} {option.label}
-
{keys.join(isMac ? " " : "+")}
+
{keys.join(isMacos ? " " : "+")}
), key: option.id ?? "", diff --git a/src/components/workspace.tsx b/src/components/workspace.tsx index 9c83318..f1a0d85 100644 --- a/src/components/workspace.tsx +++ b/src/components/workspace.tsx @@ -1,7 +1,7 @@ import { useSetting } from "@/contexts/setting-context"; import { EditorStore, useWorkspace } from "@/contexts/workspace-context"; 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 { app } from "@electron/remote"; import { Button, Flex, Layout, Space, Tabs, Tag, Tooltip } from "antd"; @@ -41,7 +41,6 @@ export const Workspace: FC = () => { const [isShowingSave, setShowingSave] = useState(false); const { t } = useTranslation(); const forceUpdate = useForceUpdate(); - const isMac = process.platform === "darwin"; const { width = 0, height = 0 } = useWindowSize(); const keysRef = useHotkeys( @@ -333,8 +332,8 @@ export const Workspace: FC = () => { }} > {[ - { label: t("searchFile"), hotkeys: isMac ? "⌘ P" : "Ctrl + P" }, - { label: t("build"), hotkeys: isMac ? "⌘ B" : "Ctrl + B" }, + { label: t("searchFile"), hotkeys: isMacos ? "⌘ P" : "Ctrl + P" }, + { label: t("build"), hotkeys: isMacos ? "⌘ B" : "Ctrl + B" }, { label: t("insertNode"), hotkeys: "Enter" }, { label: t("deleteNode"), hotkeys: "Backspace" }, ].map((v) => ( diff --git a/src/contexts/workspace-context.ts b/src/contexts/workspace-context.ts index f810c9e..9064bff 100644 --- a/src/contexts/workspace-context.ts +++ b/src/contexts/workspace-context.ts @@ -68,14 +68,24 @@ export class EditorStore { } } -export type FileModel = { +export type FileTreeType = { path: string; title: string; icon?: React.ReactNode; desc?: string; isLeaf?: boolean; - children?: FileModel[]; + children?: FileTreeType[]; 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 = { @@ -98,7 +108,8 @@ export type WorkspaceStore = { path: string; allFiles: string[]; - fileTree?: FileModel; + nodeTree?: NodeTreeType; + fileTree?: FileTreeType; editors: EditorStore[]; editing?: EditorStore; @@ -143,7 +154,7 @@ const loadFileTree = (workdir: string, filename: string) => { return; } - const data: FileModel = { + const data: FileTreeType = { path: fullpath.replaceAll(Path.sep, "/"), title: Path.basename(filename), }; @@ -412,11 +423,15 @@ export const useWorkspace = create((set, get) => ({ loadTrees: () => { const workspace = get(); 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 }); const allFiles: string[] = []; - const collect = (fileNode?: FileModel) => { + const collect = (fileNode?: FileTreeType) => { if (fileNode?.isLeaf) { allFiles.push(fileNode.path); } @@ -429,10 +444,36 @@ export const useWorkspace = create((set, get) => ({ loadNodeDefs: () => { const workspace = get(); 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 = new Map(); 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); + } + catalog.children?.push({ + title: `${v.name}(${v.desc})`, + isLeaf: true, + def: v, + }); } - set({ nodeDefs: workspace.nodeDefs }); + 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"); }, diff --git a/src/index.scss b/src/index.scss index fdaee4f..e6e2acf 100644 --- a/src/index.scss +++ b/src/index.scss @@ -16,20 +16,24 @@ --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 { 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 { -webkit-app-region: drag; } diff --git a/src/misc/b3type.ts b/src/misc/b3type.ts index 595f9d0..a428f58 100644 --- a/src/misc/b3type.ts +++ b/src/misc/b3type.ts @@ -14,7 +14,7 @@ export interface NodeArg { } export interface NodeDef { name: string; - type?: string; + type: string; desc?: string; args?: NodeArg[]; input?: string[];