From d0f4f930950c0b6d6c3bcd772e740c4eac16ff52 Mon Sep 17 00:00:00 2001 From: TianYun Date: Thu, 11 Jun 2026 11:21:28 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=A5=E6=9F=84=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ConnectionDropMenu.tsx | 51 ++------ src/components/GenerateNodeMenu.tsx | 1 - src/components/GlobalImageHistory.tsx | 17 ++- src/components/WorkflowCanvas.tsx | 46 +++---- .../__tests__/ConnectionDropMenu.test.tsx | 12 +- .../__tests__/FloatingActionBar.test.tsx | 5 +- src/components/nodeMenuVisibility.ts | 24 ---- src/utils/nodeConnectionRegistry.ts | 116 ++++++++++++++++++ src/utils/nodeHandles.ts | 111 ++--------------- 9 files changed, 177 insertions(+), 206 deletions(-) delete mode 100644 src/components/nodeMenuVisibility.ts create mode 100644 src/utils/nodeConnectionRegistry.ts diff --git a/src/components/ConnectionDropMenu.tsx b/src/components/ConnectionDropMenu.tsx index 4d84bfa3..ed0d7c2e 100644 --- a/src/components/ConnectionDropMenu.tsx +++ b/src/components/ConnectionDropMenu.tsx @@ -5,11 +5,10 @@ import { NodeType } from "@/types"; import { useI18n } from "@/i18n"; import { GenerateNodeIcon, VISIBLE_NODE_MENU_ITEMS } from "./GenerateNodeMenu"; import { - NODE_OUTPUT_MEDIA_TYPE_BY_NODE_TYPE, getNodeAcceptedInputMediaTypes, type NodeInputMediaType, - type NodeOutputMediaType, } from "@/utils/nodeHandles"; +import { CONNECTION_GROUP_SOURCE_NODES } from "@/utils/nodeConnectionRegistry"; // Actions are special menu items that trigger behavior instead of creating a node export type MenuAction = "splitGridImmediate" | "multiAngleImage"; @@ -58,37 +57,16 @@ const OUTPUT_HANDLE_MENU_ORDER: Partial item.type); -const NODE_INPUT_MEDIA_OVERRIDES: Partial> = { - smartText: ["text", "image", "video", "audio"], - smartImage: ["text", "image"], - smartVideo: ["text", "image", "video", "audio"], - smartAudio: ["text"], - promptConstructor: ["text"], - array: ["text"], - annotation: ["image"], - splitGrid: ["image"], - imageCompare: ["image"], - videoStitch: ["video", "audio"], - videoTrim: ["video"], - videoFrameGrab: ["video"], - easeCurve: ["video", "easeCurve"], - glbViewer: ["3d"], -}; - -const NODE_OUTPUT_MEDIA_OVERRIDES: Partial> = { - easeCurve: "video", -}; - const CONNECTION_MENU_ORDER: Partial> = { image: ["annotation", "smartImage", "smartVideo", "splitGrid", "splitGridImmediate", "imageCompare", "multiAngleImage", "smartText"], text: ["smartImage", "smartVideo", "smartAudio", "smartText", "promptConstructor", "array"], - video: ["videoStitch", "easeCurve", "videoFrameGrab", "smartVideo", "smartText"], + video: ["videoStitch", "easeCurve", "videoTrim", "videoFrameGrab", "smartVideo", "smartText"], audio: ["smartVideo", "videoStitch"], "3d": ["glbViewer"], easeCurve: ["easeCurve"], @@ -104,17 +82,13 @@ const uniqueOptions = (options: MenuOption[]): MenuOption[] => { }; const getAcceptedInputTypes = (nodeType: NodeType): NodeInputMediaType[] => { - return NODE_INPUT_MEDIA_OVERRIDES[nodeType] ?? getNodeAcceptedInputMediaTypes({ + return getNodeAcceptedInputMediaTypes({ id: `connection-menu-${nodeType}`, type: nodeType, data: {}, }); }; -const getProducedOutputType = (nodeType: NodeType): NodeOutputMediaType | "easeCurve" | null => { - return NODE_OUTPUT_MEDIA_OVERRIDES[nodeType] ?? NODE_OUTPUT_MEDIA_TYPE_BY_NODE_TYPE[nodeType] ?? null; -}; - const createVisibleNodeOption = (type: NodeType): MenuOption => ({ type, label: type, @@ -171,15 +145,16 @@ const getVisibleConnectionOptions = ( if (orderedOutputOptions) return uniqueOptions(orderedOutputOptions); } - const options = VISIBLE_CONNECTION_NODE_TYPES.flatMap((nodeType) => { - if (connectionType === "source") { - return getAcceptedInputTypes(nodeType).some((type) => handleTypeSet.has(type as ConnectionHandleType)) - ? [createVisibleNodeOption(nodeType)] - : []; - } + if (connectionType === "target") { + const groupedSourceNodes = handleTypes.flatMap((handleType) => ( + handleType === "easeCurve" ? ["easeCurve" as const] : CONNECTION_GROUP_SOURCE_NODES[handleType as keyof typeof CONNECTION_GROUP_SOURCE_NODES] ?? [] + )); + const visibleSourceNodes = groupedSourceNodes.filter((nodeType) => VISIBLE_CONNECTION_NODE_TYPES.includes(nodeType)); + return sortOptionsForHandle(uniqueOptions(visibleSourceNodes.map(createVisibleNodeOption)), handleTypes); + } - const producedType = getProducedOutputType(nodeType); - return producedType && handleTypeSet.has(producedType) + const options = VISIBLE_CONNECTION_NODE_TYPES.flatMap((nodeType) => { + return getAcceptedInputTypes(nodeType).some((type) => handleTypeSet.has(type as ConnectionHandleType)) ? [createVisibleNodeOption(nodeType)] : []; }); diff --git a/src/components/GenerateNodeMenu.tsx b/src/components/GenerateNodeMenu.tsx index 168005c6..6e180597 100644 --- a/src/components/GenerateNodeMenu.tsx +++ b/src/components/GenerateNodeMenu.tsx @@ -47,7 +47,6 @@ const OTHER_NODE_MENU_CATEGORIES: { labelKey: TranslationKey; nodes: GenerateNod { type: "videoTrim", labelKey: "node.videoTrim" }, { type: "videoFrameGrab", labelKey: "node.frameGrab" }, { type: "easeCurve", labelKey: "node.easeCurve" }, - { type: "glbViewer", labelKey: "node.glbViewer" }, ], }, ]; diff --git a/src/components/GlobalImageHistory.tsx b/src/components/GlobalImageHistory.tsx index ee396a3e..82d80a30 100644 --- a/src/components/GlobalImageHistory.tsx +++ b/src/components/GlobalImageHistory.tsx @@ -216,7 +216,15 @@ function HistorySidebar({ ); } -export function GlobalImageHistory() { +type GlobalImageHistoryProps = { + placement?: "floating" | "inline"; + className?: string; +}; + +export function GlobalImageHistory({ + placement = "floating", + className = "", +}: GlobalImageHistoryProps) { const [isOpen, setIsOpen] = useState(false); const [showSidebar, setShowSidebar] = useState(false); const [previewItem, setPreviewItem] = useState<{ item: ImageHistoryItem; alt: string } | null>(null); @@ -308,8 +316,13 @@ export function GlobalImageHistory() { if (history.length === 0) return null; + const placementClass = + placement === "inline" + ? "relative z-10" + : "absolute bottom-4 right-10 z-30"; + return ( -
+
{/* Trigger Button */}