From 9adb139bec8a674c0a97f917b8b9da083eb6319c Mon Sep 17 00:00:00 2001 From: ddCat <2695092045@qq.com> Date: Thu, 30 Jul 2026 21:31:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(canvas):=20=E5=9B=BE=E7=89=87=E8=8A=82?= =?UTF-8?q?=E7=82=B9=E5=B7=A5=E5=85=B7=E6=A0=8F=20-=20=E6=9B=B4=E5=A4=9A?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E6=94=AF=E6=8C=81=E7=9B=B4=E6=8E=A5=E6=89=A7?= =?UTF-8?q?=E8=A1=8C=E6=9C=AA=E5=9B=BA=E5=AE=9A=E5=B7=A5=E5=85=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #53 --- .../canvas/canvas-node-hover-toolbar.tsx | 48 +++++++++++++++++-- 1 file changed, 44 insertions(+), 4 deletions(-) diff --git a/web/src/components/canvas/canvas-node-hover-toolbar.tsx b/web/src/components/canvas/canvas-node-hover-toolbar.tsx index a7dba6b77..f0aed4901 100644 --- a/web/src/components/canvas/canvas-node-hover-toolbar.tsx +++ b/web/src/components/canvas/canvas-node-hover-toolbar.tsx @@ -1,5 +1,5 @@ -import { useEffect, useLayoutEffect, useMemo, useRef, useState, type ReactNode, type RefObject } from "react"; -import { App, Button, Input, Modal, Segmented, Tag } from "antd"; +import { useEffect, useLayoutEffect, useMemo, useRef, useState, type CSSProperties, type ReactNode, type RefObject } from "react"; +import { App, Button, Dropdown, Input, Modal, Segmented, Tag } from "antd"; import { Download, Ellipsis, FolderPlus, GalleryHorizontalEnd, Image as ImageIcon, Info, LoaderCircle, Lock, Maximize2, MessageSquare, Minus, Music2, Plus, RefreshCw, Settings2, Trash2, Unlock, Upload, UserRound, Video } from "lucide-react"; import { canvasThemes } from "@/lib/canvas-theme"; @@ -115,6 +115,7 @@ export function CanvasNodeHoverToolbar({ const [showDockLabels, setShowDockLabels] = useState(true); const [draftShowDockLabels, setDraftShowDockLabels] = useState(true); const [imageToolSettingsOpen, setImageToolSettingsOpen] = useState(false); + const [imageToolMenuOpen, setImageToolMenuOpen] = useState(false); const [anchor, setAnchor] = useState<{ left: number; top: number } | null>(null); const toolbarRef = useRef(null); const { message } = App.useApp(); @@ -139,6 +140,7 @@ export function CanvasNodeHoverToolbar({ useEffect(() => { setImageToolSettingsOpen(false); + setImageToolMenuOpen(false); }, [node?.id]); useLayoutEffect(() => { @@ -215,6 +217,7 @@ export function CanvasNodeHoverToolbar({ function openImageToolSettings() { onKeep(activeNode.id); + setImageToolMenuOpen(false); setDraftImageToolIds(quickImageToolIds); setDraftShowDockLabels(showDockLabels); setImageToolSettingsOpen(true); @@ -242,11 +245,11 @@ export function CanvasNodeHoverToolbar({ ]; const toolbarTools = hasImage ? [...baseToolbarTools, ...nodeToolbarTools].filter((tool) => quickImageToolIdSet.has(tool.id as ImageQuickToolId)) : [...baseToolbarTools, ...nodeToolbarTools]; const selectableImageToolbarTools = [...baseToolbarTools, ...nodeToolbarTools].filter((tool): tool is ToolbarTool & { id: ImageQuickToolId } => isImageQuickToolId(tool.id)); + const temporaryImageToolbarTools = selectableImageToolbarTools.filter((tool) => !quickImageToolIdSet.has(tool.id)); const dockItems: FloatingDockEntry[] = [ ...toolbarTools.map((tool) => ({ id: tool.id, label: tool.title, displayLabel: tool.label, icon: tool.icon, active: tool.active, danger: tool.danger, disabled: tool.disabled, onClick: () => tool.onClick() })), { kind: "separator", id: "node-state-separator" }, { id: "node-lock", label: node.metadata?.locked ? "解锁节点" : "锁定位置和尺寸", displayLabel: node.metadata?.locked ? "解锁" : "锁定", icon: node.metadata?.locked ? : , active: Boolean(node.metadata?.locked), onClick: () => onToggleLocked(node) }, - ...(hasImage && !simpleMode ? [{ id: "image-tools-settings", label: "自定义节点工具", displayLabel: "更多", icon: , onClick: openImageToolSettings }] : []), ]; const closeImageToolSettings = () => { @@ -254,6 +257,17 @@ export function CanvasNodeHoverToolbar({ onLeave(); }; + const runTemporaryImageTool = (tool: ToolbarTool) => { + setImageToolMenuOpen(false); + tool.onClick(); + }; + + const handleImageToolMenuOpenChange = (open: boolean) => { + setImageToolMenuOpen(open); + if (open) onKeep(activeNode.id); + else if (!imageToolSettingsOpen) onLeave(); + }; + const setDraftImageToolVisible = (id: ImageQuickToolId, visible: boolean) => { setDraftImageToolIds((current) => { const selected = new Set(current); @@ -286,13 +300,39 @@ export function CanvasNodeHoverToolbar({ style={{ left: anchor.left, top: anchor.top, width: "max-content", maxWidth: `min(calc(100% - 20px), ${showDockLabels ? 840 : 560}px)`, color: theme.node.text }} onMouseEnter={() => onKeep(node.id)} onMouseLeave={() => { - if (!imageToolSettingsOpen) onLeave(); + if (!imageToolSettingsOpen && !imageToolMenuOpen) onLeave(); }} onMouseDown={(event) => event.stopPropagation()} onPointerDown={(event) => event.stopPropagation()} >
{dockItems.length ? : null} + {hasImage && !simpleMode ? ( + ({ key: tool.id, icon: tool.icon, label: tool.label, danger: tool.danger, onClick: () => runTemporaryImageTool(tool) })), + ...(temporaryImageToolbarTools.length ? [{ type: "divider" as const }] : []), + { key: "manage-image-quick-tools", icon: , label: "管理快捷工具", onClick: openImageToolSettings }, + ], + }} + > + + + ) : null}
{hasImage ? (