Merge pull request #22 from GeorgeShiZZZ/master
add ctrl/command + g to jump node by id
This commit is contained in:
6 files changed
+148
-77
No files matched your search
@@ -19,6 +19,7 @@
|
|||||||
"hide": "Hide Behavior3",
|
"hide": "Hide Behavior3",
|
||||||
"hideOthers": "Hide Others",
|
"hideOthers": "Hide Others",
|
||||||
"insertNode": "Insert Node",
|
"insertNode": "Insert Node",
|
||||||
|
"jumpNode": "Jump Node",
|
||||||
"language": "Language",
|
"language": "Language",
|
||||||
"moveToTrash": "Move to Trash",
|
"moveToTrash": "Move to Trash",
|
||||||
"newFile": "New File...",
|
"newFile": "New File...",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"hide": "隐藏 Behavior3",
|
"hide": "隐藏 Behavior3",
|
||||||
"hideOthers": "隐藏其它",
|
"hideOthers": "隐藏其它",
|
||||||
"insertNode": "插入节点",
|
"insertNode": "插入节点",
|
||||||
|
"jumpNode": "跳转节点",
|
||||||
"language": "语言",
|
"language": "语言",
|
||||||
"moveToTrash": "移至回收站",
|
"moveToTrash": "移至回收站",
|
||||||
"newFile": "新建行为树...",
|
"newFile": "新建行为树...",
|
||||||
|
|||||||
+120
-59
@@ -15,10 +15,10 @@ import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/i
|
|||||||
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";
|
||||||
import { useSize } from "ahooks";
|
import { useSize } from "ahooks";
|
||||||
import { Button, Dropdown, Flex, FlexProps, Input, MenuProps } from "antd";
|
import { Button, Dropdown, Flex, FlexProps, Input, InputRef, MenuProps } from "antd";
|
||||||
import { clipboard } from "electron";
|
import { clipboard } from "electron";
|
||||||
import * as fs from "fs";
|
import * as fs from "fs";
|
||||||
import React, { FC, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import React, { FC, KeyboardEvent, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { FiDelete } from "react-icons/fi";
|
import { FiDelete } from "react-icons/fi";
|
||||||
import { IoMdReturnLeft } from "react-icons/io";
|
import { IoMdReturnLeft } from "react-icons/io";
|
||||||
@@ -40,6 +40,8 @@ interface FilterOption {
|
|||||||
filterStr: string;
|
filterStr: string;
|
||||||
filterCase: boolean;
|
filterCase: boolean;
|
||||||
filterFocus: boolean;
|
filterFocus: boolean;
|
||||||
|
filterType: string;
|
||||||
|
placeholder: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const createMenu = () => {
|
const createMenu = () => {
|
||||||
@@ -131,6 +133,7 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
workdir: useWorkspace((state) => state.workdir),
|
workdir: useWorkspace((state) => state.workdir),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const searchIptRef = useRef<InputRef>(null);
|
||||||
const graphRef = useRef(null);
|
const graphRef = useRef(null);
|
||||||
const sizeRef = useRef(null);
|
const sizeRef = useRef(null);
|
||||||
const editorSize = useSize(sizeRef);
|
const editorSize = useSize(sizeRef);
|
||||||
@@ -144,6 +147,8 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
filterStr: "",
|
filterStr: "",
|
||||||
filterCase: false,
|
filterCase: false,
|
||||||
filterFocus: false,
|
filterFocus: false,
|
||||||
|
filterType: "",
|
||||||
|
placeholder: ""
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSearchChange = (option: FilterOption) => {
|
const onSearchChange = (option: FilterOption) => {
|
||||||
@@ -231,32 +236,38 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
node.highlightGray = option.filterFocus;
|
node.highlightGray = option.filterFocus;
|
||||||
if (option.filterStr) {
|
if (option.filterStr) {
|
||||||
let found = false;
|
let found = false;
|
||||||
if (includeString(node.name, option) || includeString(node.desc || node.def.desc, option)) {
|
if (option.filterType === "nodeId") {
|
||||||
found = true;
|
if (option.filterStr === node.id) {
|
||||||
} else if (node.input) {
|
found = true
|
||||||
for (const str of node.input) {
|
|
||||||
if (includeString(str, option)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if (node.args) {
|
} else {
|
||||||
for (const str in node.args) {
|
if (includeString(node.name, option) || includeString(node.desc || node.def.desc, option)) {
|
||||||
if (includeString(str, option)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (node.output) {
|
|
||||||
for (const str of node.output) {
|
|
||||||
if (includeString(str, option)) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (node.path) {
|
|
||||||
if (includeString(node.path, option)) {
|
|
||||||
found = true;
|
found = true;
|
||||||
|
} else if (node.input) {
|
||||||
|
for (const str of node.input) {
|
||||||
|
if (includeString(str, option)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.args) {
|
||||||
|
for (const str in node.args) {
|
||||||
|
if (includeString(str, option)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.output) {
|
||||||
|
for (const str of node.output) {
|
||||||
|
if (includeString(str, option)) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (node.path) {
|
||||||
|
if (includeString(node.path, option)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (found) {
|
if (found) {
|
||||||
@@ -1008,7 +1019,11 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "searchNode": {
|
case "searchNode": {
|
||||||
setShowingSearch(true);
|
searchByType("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case "jumpNode": {
|
||||||
|
searchByType("nodeId");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "editSubtree": {
|
case "editSubtree": {
|
||||||
@@ -1075,6 +1090,42 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const searchByType = (type: string) => {
|
||||||
|
let placeholder = ""
|
||||||
|
const filterType = type
|
||||||
|
// todo multiple parameter format judgment
|
||||||
|
switch (type) {
|
||||||
|
case "nodeId":
|
||||||
|
placeholder = t("jumpNode")
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
placeholder = t("searchNode")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (!showingSearch) {
|
||||||
|
setFilterOption({ ...filterOption, placeholder, filterType })
|
||||||
|
setShowingSearch(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (filterOption.filterType === type) return searchIptRef.current?.focus()
|
||||||
|
setShowingSearch(false)
|
||||||
|
setTimeout(() => {
|
||||||
|
setShowingSearch(true)
|
||||||
|
setFilterOption({ ...filterOption, placeholder, filterType })
|
||||||
|
searchIptRef.current?.focus()
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.code === Hotkey.Enter) {
|
||||||
|
nextResult()
|
||||||
|
} else if ((e.ctrlKey || e.metaKey) && e.code === "KeyF") {
|
||||||
|
searchByType("")
|
||||||
|
} else if ((e.ctrlKey || e.metaKey) && e.code === "KeyG") {
|
||||||
|
searchByType("nodeId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...props}
|
{...props}
|
||||||
@@ -1104,6 +1155,8 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Input
|
<Input
|
||||||
|
ref={searchIptRef}
|
||||||
|
placeholder={ filterOption.placeholder }
|
||||||
autoFocus
|
autoFocus
|
||||||
size="small"
|
size="small"
|
||||||
style={{
|
style={{
|
||||||
@@ -1119,24 +1172,26 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
index: 0,
|
index: 0,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onKeyDown={(e) => e.code === Hotkey.Enter && nextResult()}
|
onKeyDown={ handleKeyDown }
|
||||||
suffix={
|
suffix={
|
||||||
<Flex gap="2px" style={{ alignItems: "center" }}>
|
<Flex gap="2px" style={{ alignItems: "center" }}>
|
||||||
<Button
|
{filterOption.filterType !== "nodeId" && (
|
||||||
type="text"
|
<Button
|
||||||
size="small"
|
type="text"
|
||||||
className={mergeClassNames(
|
size="small"
|
||||||
"b3-editor-button-filter",
|
className={mergeClassNames(
|
||||||
filterOption.filterCase && "b3-editor-button-filter-selected"
|
"b3-editor-button-filter",
|
||||||
)}
|
filterOption.filterCase && "b3-editor-button-filter-selected"
|
||||||
icon={<VscCaseSensitive style={{ width: "18px", height: "18px" }} />}
|
)}
|
||||||
onClick={() =>
|
icon={<VscCaseSensitive style={{ width: "18px", height: "18px" }} />}
|
||||||
onSearchChange({
|
onClick={() =>
|
||||||
...filterOption,
|
onSearchChange({
|
||||||
filterCase: !filterOption.filterCase,
|
...filterOption,
|
||||||
})
|
filterCase: !filterOption.filterCase,
|
||||||
}
|
})
|
||||||
/>
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
size="small"
|
size="small"
|
||||||
@@ -1160,22 +1215,26 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
? `${filterOption.index + 1}/${filterOption.results.length}`
|
? `${filterOption.index + 1}/${filterOption.results.length}`
|
||||||
: ""}
|
: ""}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
{filterOption.filterType !== "nodeId" && (
|
||||||
icon={<ArrowDownOutlined />}
|
<Button
|
||||||
type="text"
|
icon={<ArrowDownOutlined />}
|
||||||
size="small"
|
type="text"
|
||||||
style={{ width: "30px" }}
|
size="small"
|
||||||
disabled={filterOption.results.length == 0}
|
style={{ width: "30px" }}
|
||||||
onClick={nextResult}
|
disabled={filterOption.results.length == 0}
|
||||||
/>
|
onClick={nextResult}
|
||||||
<Button
|
/>
|
||||||
icon={<ArrowUpOutlined />}
|
)}
|
||||||
type="text"
|
{filterOption.filterType !== "nodeId" && (
|
||||||
size="small"
|
<Button
|
||||||
style={{ width: "30px" }}
|
icon={<ArrowUpOutlined />}
|
||||||
disabled={filterOption.results.length == 0}
|
type="text"
|
||||||
onClick={prevResult}
|
size="small"
|
||||||
/>
|
style={{ width: "30px" }}
|
||||||
|
disabled={filterOption.results.length == 0}
|
||||||
|
onClick={prevResult}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Button
|
<Button
|
||||||
icon={<CloseOutlined />}
|
icon={<CloseOutlined />}
|
||||||
type="text"
|
type="text"
|
||||||
@@ -1189,6 +1248,8 @@ export const Editor: FC<EditorProps> = ({ onUpdate: updateState, data: editor, .
|
|||||||
filterCase: false,
|
filterCase: false,
|
||||||
filterFocus: false,
|
filterFocus: false,
|
||||||
filterStr: "",
|
filterStr: "",
|
||||||
|
filterType: "",
|
||||||
|
placeholder: ""
|
||||||
});
|
});
|
||||||
keysRef.current?.focus();
|
keysRef.current?.focus();
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export const Workspace: FC = () => {
|
|||||||
const { width = 0, height = 0 } = useWindowSize();
|
const { width = 0, height = 0 } = useWindowSize();
|
||||||
|
|
||||||
const keysRef = useHotkeys<HTMLDivElement>(
|
const keysRef = useHotkeys<HTMLDivElement>(
|
||||||
[Hotkey.Save, Hotkey.CloseEditor, Hotkey.SearchTree, Hotkey.Build, Hotkey.SearchNode],
|
[Hotkey.Save, Hotkey.CloseEditor, Hotkey.SearchTree, Hotkey.Build, Hotkey.SearchNode, Hotkey.JumpNode],
|
||||||
(event) => {
|
(event) => {
|
||||||
if (isHotkeyPressed(Hotkey.Save)) {
|
if (isHotkeyPressed(Hotkey.Save)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -67,6 +67,9 @@ export const Workspace: FC = () => {
|
|||||||
} else if (isHotkeyPressed(Hotkey.SearchNode)) {
|
} else if (isHotkeyPressed(Hotkey.SearchNode)) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
workspace.editing?.dispatch("searchNode");
|
workspace.editing?.dispatch("searchNode");
|
||||||
|
} else if (isHotkeyPressed(Hotkey.JumpNode)) {
|
||||||
|
event.preventDefault()
|
||||||
|
workspace.editing?.dispatch("jumpNode")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -338,6 +341,7 @@ export const Workspace: FC = () => {
|
|||||||
{ label: t("searchFile"), hotkeys: isMacos ? "⌘ P" : "Ctrl + P" },
|
{ label: t("searchFile"), hotkeys: isMacos ? "⌘ P" : "Ctrl + P" },
|
||||||
{ label: t("build"), hotkeys: isMacos ? "⌘ B" : "Ctrl + B" },
|
{ label: t("build"), hotkeys: isMacos ? "⌘ B" : "Ctrl + B" },
|
||||||
{ label: t("searchNode"), hotkeys: isMacos ? "⌘ F" : "Ctrl + F" },
|
{ label: t("searchNode"), hotkeys: isMacos ? "⌘ F" : "Ctrl + F" },
|
||||||
|
{ label: t("jumpNode"), hotkeys: isMacos ? "⌘ G" : "Ctrl + G" },
|
||||||
{ label: t("insertNode"), hotkeys: "Enter" },
|
{ label: t("insertNode"), hotkeys: "Enter" },
|
||||||
{ label: t("deleteNode"), hotkeys: "Backspace" },
|
{ label: t("deleteNode"), hotkeys: "Backspace" },
|
||||||
].map((v) => (
|
].map((v) => (
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ let buildDir: string | undefined;
|
|||||||
|
|
||||||
interface BatchScript {
|
interface BatchScript {
|
||||||
processTree?(tree: TreeModel): TreeModel;
|
processTree?(tree: TreeModel): TreeModel;
|
||||||
|
|
||||||
processNode?(node: NodeModel, tree: TreeModel): NodeModel;
|
processNode?(node: NodeModel, tree: TreeModel): NodeModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,6 +27,7 @@ export type EditEvent =
|
|||||||
| "replace"
|
| "replace"
|
||||||
| "delete"
|
| "delete"
|
||||||
| "insert"
|
| "insert"
|
||||||
|
| "jumpNode"
|
||||||
| "undo"
|
| "undo"
|
||||||
| "redo"
|
| "redo"
|
||||||
| "reload"
|
| "reload"
|
||||||
@@ -143,13 +145,13 @@ export type WorkspaceStore = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const loadFileTree = (workdir: string, filename: string) => {
|
const loadFileTree = (workdir: string, filename: string) => {
|
||||||
const fullpath = fs.realpathSync(`${workdir}/${filename}`);
|
const fullpath = fs.realpathSync(`${ workdir }/${ filename }`);
|
||||||
if (!fs.existsSync(fullpath)) {
|
if (!fs.existsSync(fullpath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const stat = fs.statSync(fullpath);
|
const stat = fs.statSync(fullpath);
|
||||||
if (!(stat.isDirectory() || fullpath.endsWith(".json"))) {
|
if (!( stat.isDirectory() || fullpath.endsWith(".json") )) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,13 +164,13 @@ const loadFileTree = (workdir: string, filename: string) => {
|
|||||||
data.children = [];
|
data.children = [];
|
||||||
const files = fs.readdirSync(data.path);
|
const files = fs.readdirSync(data.path);
|
||||||
files.forEach((v) => {
|
files.forEach((v) => {
|
||||||
const child = loadFileTree(workdir, `${filename}/${v}`);
|
const child = loadFileTree(workdir, `${ filename }/${ v }`);
|
||||||
if (child) {
|
if (child) {
|
||||||
data.children?.push(child);
|
data.children?.push(child);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
data.children.sort((a, b) => {
|
data.children.sort((a, b) => {
|
||||||
if ((a.children && b.children) || (!a.children && !b.children)) {
|
if (( a.children && b.children ) || ( !a.children && !b.children )) {
|
||||||
return a.title.localeCompare(b.title);
|
return a.title.localeCompare(b.title);
|
||||||
} else {
|
} else {
|
||||||
return a.children ? -1 : 1;
|
return a.children ? -1 : 1;
|
||||||
@@ -186,7 +188,7 @@ const saveFile = (editor?: EditorStore) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
export const useWorkspace = create<WorkspaceStore>((set, get) => ( {
|
||||||
allFiles: [],
|
allFiles: [],
|
||||||
fileTree: undefined,
|
fileTree: undefined,
|
||||||
editors: [],
|
editors: [],
|
||||||
@@ -208,15 +210,15 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
if (!fs.existsSync(path)) {
|
if (!fs.existsSync(path)) {
|
||||||
useSetting.getState().removeRecent(path);
|
useSetting.getState().removeRecent(path);
|
||||||
}
|
}
|
||||||
message.error(`load workspace error: ${path}`);
|
message.error(`load workspace error: ${ path }`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
createProject: () => {
|
createProject: () => {
|
||||||
const path = dialog.showSaveDialogSync({
|
const path = dialog.showSaveDialogSync({
|
||||||
properties: ["showOverwriteConfirmation", "createDirectory"],
|
properties: [ "showOverwriteConfirmation", "createDirectory" ],
|
||||||
filters: [{ name: "Behavior3 Workspace", extensions: ["b3-workspace"] }],
|
filters: [ { name: "Behavior3 Workspace", extensions: [ "b3-workspace" ] } ],
|
||||||
});
|
});
|
||||||
if (path) {
|
if (path) {
|
||||||
const workspace = get();
|
const workspace = get();
|
||||||
@@ -232,7 +234,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
const win = BrowserWindow.getFocusedWindow();
|
const win = BrowserWindow.getFocusedWindow();
|
||||||
if (win) {
|
if (win) {
|
||||||
const path = dialog.showOpenDialogSync(win, {
|
const path = dialog.showOpenDialogSync(win, {
|
||||||
filters: [{ name: "workspace", extensions: ["b3-workspace"] }],
|
filters: [ { name: "workspace", extensions: [ "b3-workspace" ] } ],
|
||||||
});
|
});
|
||||||
if (path?.length) {
|
if (path?.length) {
|
||||||
ipcRenderer.invoke("open-win", path[0]);
|
ipcRenderer.invoke("open-win", path[0]);
|
||||||
@@ -246,7 +248,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
if (workspace.path)
|
if (workspace.path)
|
||||||
if (!buildDir) {
|
if (!buildDir) {
|
||||||
buildDir = dialog.showOpenDialogSync({
|
buildDir = dialog.showOpenDialogSync({
|
||||||
properties: ["openDirectory", "createDirectory"],
|
properties: [ "openDirectory", "createDirectory" ],
|
||||||
})?.[0];
|
})?.[0];
|
||||||
}
|
}
|
||||||
if (buildDir) {
|
if (buildDir) {
|
||||||
@@ -279,9 +281,9 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
batchProject: () => {
|
batchProject: () => {
|
||||||
const workspace = get();
|
const workspace = get();
|
||||||
const scriptPath = dialog.showOpenDialogSync({
|
const scriptPath = dialog.showOpenDialogSync({
|
||||||
properties: ["openFile"],
|
properties: [ "openFile" ],
|
||||||
defaultPath: workspace.workdir,
|
defaultPath: workspace.workdir,
|
||||||
filters: [{ name: "Javascript", extensions: ["js"] }],
|
filters: [ { name: "Javascript", extensions: [ "js" ] } ],
|
||||||
})?.[0];
|
})?.[0];
|
||||||
if (scriptPath) {
|
if (scriptPath) {
|
||||||
try {
|
try {
|
||||||
@@ -327,7 +329,7 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
workspace.edit(editor.path);
|
workspace.edit(editor.path);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
message.error(`invalid file: ${path}`);
|
message.error(`invalid file: ${ path }`);
|
||||||
}
|
}
|
||||||
} else if (workspace.editing !== editor) {
|
} else if (workspace.editing !== editor) {
|
||||||
workspace.edit(editor.path);
|
workspace.edit(editor.path);
|
||||||
@@ -387,7 +389,8 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
saveFile(workspace.editing);
|
saveFile(workspace.editing);
|
||||||
},
|
},
|
||||||
|
|
||||||
saveAs: () => {},
|
saveAs: () => {
|
||||||
|
},
|
||||||
|
|
||||||
saveAll: () => {
|
saveAll: () => {
|
||||||
const workspace = get();
|
const workspace = get();
|
||||||
@@ -442,7 +445,7 @@ 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 nodeDefs: Map<string, NodeDef> = new Map();
|
const nodeDefs: Map<string, NodeDef> = new Map();
|
||||||
for (const v of nodeDefData) {
|
for (const v of nodeDefData) {
|
||||||
nodeDefs.set(v.name, v);
|
nodeDefs.set(v.name, v);
|
||||||
@@ -476,4 +479,4 @@ export const useWorkspace = create<WorkspaceStore>((set, get) => ({
|
|||||||
const workspace = get();
|
const workspace = get();
|
||||||
return workspace.nodeDefs.has(name);
|
return workspace.nodeDefs.has(name);
|
||||||
},
|
},
|
||||||
}));
|
} ));
|
||||||
+2
-1
@@ -33,7 +33,7 @@ export function useHotkeys<T extends HTMLElement>(
|
|||||||
keys: Keys,
|
keys: Keys,
|
||||||
callback: HotkeyCallback,
|
callback: HotkeyCallback,
|
||||||
options?: OptionsOrDependencyArray,
|
options?: OptionsOrDependencyArray,
|
||||||
dependencies?: OptionsOrDependencyArray
|
dependencies?: OptionsOrDependencyArray,
|
||||||
): MutableRefObject<RefType<T>> {
|
): MutableRefObject<RefType<T>> {
|
||||||
if (keys instanceof Array) {
|
if (keys instanceof Array) {
|
||||||
keys = keys.filter((v) => !!v);
|
keys = keys.filter((v) => !!v);
|
||||||
@@ -52,6 +52,7 @@ export const Hotkey = {
|
|||||||
Escape: Key.Escape,
|
Escape: Key.Escape,
|
||||||
F2: Key.F2,
|
F2: Key.F2,
|
||||||
Insert: Key.Insert,
|
Insert: Key.Insert,
|
||||||
|
JumpNode: hotkey("ctrl+g"),
|
||||||
MacDelete: isMacos ? hotkey("ctrl+backspace") : "",
|
MacDelete: isMacos ? hotkey("ctrl+backspace") : "",
|
||||||
Paste: hotkey("ctrl+v"),
|
Paste: hotkey("ctrl+v"),
|
||||||
Redo: isMacos ? hotkey("shift+ctrl+z") : hotkey("ctrl+y"),
|
Redo: isMacos ? hotkey("shift+ctrl+z") : hotkey("ctrl+y"),
|
||||||
|
|||||||
Reference in new issue
Block a user