From d32c457990ea573db4ac956fdd9fd76217b4c9c3 Mon Sep 17 00:00:00 2001 From: George Shi Date: Tue, 30 Apr 2024 09:58:06 +0800 Subject: [PATCH] add ctrl/command + g to jump node by id --- public/locales/en.json | 1 + public/locales/zh.json | 1 + src/components/editor.tsx | 179 ++++++++++++++++++++---------- src/components/workspace.tsx | 6 +- src/contexts/workspace-context.ts | 35 +++--- src/misc/keys.ts | 3 +- 6 files changed, 148 insertions(+), 77 deletions(-) diff --git a/public/locales/en.json b/public/locales/en.json index d278267..5cdd47b 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -19,6 +19,7 @@ "hide": "Hide Behavior3", "hideOthers": "Hide Others", "insertNode": "Insert Node", + "jumpNode": "Jump Node", "language": "Language", "moveToTrash": "Move to Trash", "newFile": "New File...", diff --git a/public/locales/zh.json b/public/locales/zh.json index db1241b..de3ca5f 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -19,6 +19,7 @@ "hide": "隐藏 Behavior3", "hideOthers": "隐藏其它", "insertNode": "插入节点", + "jumpNode": "跳转节点", "language": "语言", "moveToTrash": "移至回收站", "newFile": "新建行为树...", diff --git a/src/components/editor.tsx b/src/components/editor.tsx index d46e817..1a73edf 100644 --- a/src/components/editor.tsx +++ b/src/components/editor.tsx @@ -15,10 +15,10 @@ import { ArrowDownOutlined, ArrowUpOutlined, CloseOutlined } from "@ant-design/i import G6, { G6GraphEvent, Item, TreeGraph } from "@antv/g6"; import { dialog } from "@electron/remote"; 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 * 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 { FiDelete } from "react-icons/fi"; import { IoMdReturnLeft } from "react-icons/io"; @@ -40,6 +40,8 @@ interface FilterOption { filterStr: string; filterCase: boolean; filterFocus: boolean; + filterType: string; + placeholder: string; } const createMenu = () => { @@ -131,6 +133,7 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . workdir: useWorkspace((state) => state.workdir), }; + const searchIptRef = useRef(null); const graphRef = useRef(null); const sizeRef = useRef(null); const editorSize = useSize(sizeRef); @@ -144,6 +147,8 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . filterStr: "", filterCase: false, filterFocus: false, + filterType: "", + placeholder: "" }); const onSearchChange = (option: FilterOption) => { @@ -231,32 +236,38 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . node.highlightGray = option.filterFocus; if (option.filterStr) { let found = false; - if (includeString(node.name, option) || includeString(node.desc || node.def.desc, option)) { - found = true; - } else if (node.input) { - for (const str of node.input) { - if (includeString(str, option)) { - found = true; - break; - } + if (option.filterType === "nodeId") { + if (option.filterStr === node.id) { + found = true } - } 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)) { + } else { + if (includeString(node.name, option) || includeString(node.desc || node.def.desc, option)) { 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) { @@ -1008,7 +1019,11 @@ export const Editor: FC = ({ onUpdate: updateState, data: editor, . break; } case "searchNode": { - setShowingSearch(true); + searchByType(""); + break; + } + case "jumpNode": { + searchByType("nodeId"); break; } case "editSubtree": { @@ -1075,6 +1090,42 @@ export const Editor: FC = ({ 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 (
= ({ onUpdate: updateState, data: editor, . }} > = ({ onUpdate: updateState, data: editor, . index: 0, }) } - onKeyDown={(e) => e.code === Hotkey.Enter && nextResult()} + onKeyDown={ handleKeyDown } suffix={ -
-