refactor: align canvas image toolbar with available features
This commit is contained in:
parent
435fbd10f7
commit
c80b46d43c
@ -2,7 +2,7 @@
|
||||
|
||||
import React, { useState, useRef, useEffect, useCallback } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { ImagePlus, Loader2, AlertCircle, MoreVertical, Scissors, Eraser, Sparkles, Expand, Maximize2, Move3D, Layers, Download, Trash2, RefreshCw, Pencil, MessageSquarePlus, Crosshair, Check, X, Type, StickyNote } from "lucide-react";
|
||||
import { ImagePlus, Loader2, AlertCircle, MoreVertical, MoreHorizontal, Scissors, Eraser, Sparkles, Expand, Maximize2, Move3D, Download, Trash2, RefreshCw, Pencil, MessageSquarePlus, Crosshair, Check, X, Type, StickyNote } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
DropdownMenu,
|
||||
@ -1617,10 +1617,6 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
|
||||
<Move3D className="h-4 w-4 mr-2" />
|
||||
角度编辑
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('scene-fusion')}>
|
||||
<Layers className="h-4 w-4 mr-2" />
|
||||
详情替换
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('prompt-regenerate')}>
|
||||
<RefreshCw className="h-4 w-4 mr-2" />
|
||||
提示词重绘
|
||||
@ -1732,7 +1728,7 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
|
||||
{isSelected && !isMultiSelected && data.src && !isEditingTitle && typeof document !== 'undefined' && createPortal(
|
||||
<TooltipProvider delayDuration={200}>
|
||||
<div
|
||||
className="fixed flex items-center gap-0.5 rounded-full shadow-xl px-2 py-1 z-[9999] bg-white/95 border border-gray-200 text-gray-800 dark:bg-gray-900/95 dark:border-gray-700 dark:text-gray-100"
|
||||
className="fixed z-[9999] flex items-center gap-1 rounded-[22px] border border-slate-300 bg-slate-50/95 px-3 py-2 text-gray-800 shadow-[0_8px_24px_rgba(15,23,42,0.14)] backdrop-blur-sm dark:border-slate-600 dark:bg-slate-900/95 dark:text-gray-100"
|
||||
style={{
|
||||
top: getToolbarPosition().top,
|
||||
left: getToolbarPosition().left,
|
||||
@ -1743,226 +1739,127 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{/* 添加到对话 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing || isAddingToChat}
|
||||
className="h-8 w-8 rounded-full hover:bg-blue-50 text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300 dark:hover:bg-blue-900/30 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={handleAddToChat}
|
||||
>
|
||||
{isAddingToChat ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<MessageSquarePlus className="h-4 w-4" />
|
||||
)}
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">添加到对话</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 🆕 物品拾取 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-orange-50 text-orange-600 hover:text-orange-700 dark:text-orange-400 dark:hover:text-orange-300 dark:hover:bg-orange-900/30 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => {
|
||||
setPickerMode(true, node.id);
|
||||
toast.info('点击图片中的物品进行拾取');
|
||||
}}
|
||||
>
|
||||
<Crosshair className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">拾取物品</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 分隔线 */}
|
||||
<div className="h-5 w-px bg-gray-200 dark:bg-gray-700 mx-0.5" />
|
||||
|
||||
{/* 放大/高清 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('enhance')}
|
||||
>
|
||||
<span className="text-[10px] font-medium text-gray-500 border border-gray-300 rounded px-1 dark:text-gray-200 dark:border-gray-600">HD</span>
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">高清放大</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 移除背景/抠图 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('rmbg')}
|
||||
>
|
||||
<Scissors className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">移除背景</TooltipContent>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing || isAddingToChat}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={handleAddToChat}
|
||||
>
|
||||
{isAddingToChat ? (
|
||||
<Loader2 className="mr-1.5 h-4 w-4 animate-spin" />
|
||||
) : (
|
||||
<MessageSquarePlus className="mr-1.5 h-4 w-4 text-blue-600" />
|
||||
)}
|
||||
添加到对话
|
||||
</Button>
|
||||
|
||||
{/* 去水印 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('watermark')}
|
||||
>
|
||||
<Eraser className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">去水印</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 文字编辑 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing || isDetectingText || isApplyingTextEdit}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('text-edit')}
|
||||
>
|
||||
<Type className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">编辑文字</TooltipContent>
|
||||
</Tooltip>
|
||||
<div className="mx-1 h-5 w-px bg-slate-200 dark:bg-slate-700" />
|
||||
|
||||
{/* 图片备注 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className={cn(
|
||||
"h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none",
|
||||
data.note && "text-amber-600 dark:text-amber-300"
|
||||
)}
|
||||
onClick={() => handleAction('note')}
|
||||
>
|
||||
<StickyNote className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">图片备注</TooltipContent>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={() => handleAction('enhance')}
|
||||
>
|
||||
<span className="mr-1.5 rounded-md border border-slate-300 px-1.5 text-[11px] leading-5 text-slate-600 dark:border-slate-500 dark:text-slate-100">HD</span>
|
||||
放大
|
||||
</Button>
|
||||
|
||||
{/* 提示词重绘 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={() => handleAction('rmbg')}
|
||||
>
|
||||
<Scissors className="mr-1.5 h-4 w-4" />
|
||||
移除背景
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={() => handleAction('watermark')}
|
||||
>
|
||||
<Eraser className="mr-1.5 h-4 w-4" />
|
||||
擦除
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={() => {
|
||||
setPickerMode(true, node.id);
|
||||
toast.info('点击图片中的物品进行拾取');
|
||||
}}
|
||||
>
|
||||
<Crosshair className="mr-1.5 h-4 w-4 text-orange-600" />
|
||||
拾取物品
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
disabled={isProcessing || isDetectingText || isApplyingTextEdit}
|
||||
className="h-9 rounded-xl px-3 text-[13px] font-medium text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={() => handleAction('text-edit')}
|
||||
>
|
||||
<Type className="mr-1.5 h-4 w-4" />
|
||||
编辑文字
|
||||
</Button>
|
||||
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('prompt-regenerate')}
|
||||
className="h-9 w-9 rounded-xl text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
>
|
||||
<RefreshCw className="h-4 w-4" />
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">提示词重绘</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 角度编辑 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('angle')}
|
||||
>
|
||||
<Move3D className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">角度编辑</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 扩展 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('extend')}
|
||||
>
|
||||
<Expand className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">图片扩展</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 尺寸调整 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={() => handleAction('resize')}
|
||||
>
|
||||
<Maximize2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">尺寸调整</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 下载 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-gray-100 dark:hover:bg-white/10 disabled:opacity-50 disabled:pointer-events-none"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">下载图片</TooltipContent>
|
||||
</Tooltip>
|
||||
|
||||
{/* 删除 */}
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-8 w-8 rounded-full hover:bg-red-50 text-red-500 hover:text-red-600 dark:text-red-400 dark:hover:text-red-300 dark:hover:bg-red-900/30 disabled:opacity-50 disabled:pointer-events-none"
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="center" side="bottom">
|
||||
<DropdownMenuItem onClick={() => handleAction('note')}>
|
||||
<StickyNote className="mr-2 h-4 w-4" />
|
||||
图片备注
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('prompt-regenerate')}>
|
||||
<RefreshCw className="mr-2 h-4 w-4" />
|
||||
提示词重绘
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('angle')}>
|
||||
<Move3D className="mr-2 h-4 w-4" />
|
||||
角度编辑
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('extend')}>
|
||||
<Expand className="mr-2 h-4 w-4" />
|
||||
图片扩展
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => handleAction('resize')}>
|
||||
<Maximize2 className="mr-2 h-4 w-4" />
|
||||
尺寸调整
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
className="text-red-600 focus:text-red-700"
|
||||
onClick={() => deleteNode(node.id)}
|
||||
>
|
||||
<Trash2 className="h-4 w-4" />
|
||||
</Button>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom" className="text-xs">删除</TooltipContent>
|
||||
</Tooltip>
|
||||
<Trash2 className="mr-2 h-4 w-4" />
|
||||
删除
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
disabled={isProcessing}
|
||||
className="h-9 w-9 rounded-xl text-slate-700 hover:bg-white hover:text-slate-900 dark:text-slate-100 dark:hover:bg-white/10"
|
||||
onClick={handleDownload}
|
||||
>
|
||||
<Download className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</TooltipProvider>,
|
||||
document.body
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user