feat: 图片工具栏改为纯图标模式,悬停显示功能名称

- 移除工具栏按钮的文字标签,只显示图标
- 使用 Tooltip 组件在鼠标悬停时显示功能名称
- 将下载和删除按钮从下拉菜单移到工具栏直接显示
- 工具栏更紧凑,视觉更简洁
This commit is contained in:
Your Name 2026-02-02 11:07:52 +08:00
parent ed71477f15
commit dbed4020c0

View File

@ -20,6 +20,7 @@ import {
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip";
import { toast } from "sonner";
import { useCanvasStore } from "@/store/canvas";
import { imageGenerationService } from "@/services/canvas";
@ -594,150 +595,178 @@ export function ImageNode({ node, isSelected }: ImageNodeProps) {
{/* 工具栏使用 Portal 渲染到 body,避免被裁剪 */}
{isSelected && data.src && !isProcessing && typeof document !== 'undefined' && createPortal(
<div
className="fixed flex items-center gap-0.5 bg-white border border-gray-200 rounded-full shadow-xl px-3 py-1.5 z-[9999]"
style={{
top: getToolbarPosition().top,
left: getToolbarPosition().left,
transform: 'translateX(-50%)',
pointerEvents: 'auto',
}}
onClick={(e) => e.stopPropagation()}
>
{/* 🆕 添加到对话 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-blue-50 text-blue-600 hover:text-blue-700"
onClick={() => {
addPendingChatAttachment({
url: data.src!,
name: data.prompt || '画布图片',
contentType: 'image/jpeg',
});
toast.success('已添加到对话框');
<TooltipProvider delayDuration={200}>
<div
className="fixed flex items-center gap-0.5 bg-white border border-gray-200 rounded-full shadow-xl px-2 py-1 z-[9999]"
style={{
top: getToolbarPosition().top,
left: getToolbarPosition().left,
transform: 'translateX(-50%)',
pointerEvents: 'auto',
}}
title="添加到对话框"
onClick={(e) => e.stopPropagation()}
>
<MessageSquarePlus className="h-4 w-4" />
<span>对话</span>
</Button>
{/* 分隔线 */}
<div className="h-5 w-px bg-gray-200 mx-1" />
{/* 放大/高清 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('enhance')}
title="高清放大"
>
<span className="text-[10px] font-medium text-gray-500 border border-gray-300 rounded px-1">HD</span>
<span>放大</span>
</Button>
{/* 移除背景/抠图 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('rmbg')}
title="移除背景"
>
<Scissors className="h-4 w-4" />
<span>移除背景</span>
</Button>
{/* 场景融合 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('scene-fusion')}
title="场景融合"
>
<Layers className="h-4 w-4" />
<span>场景</span>
</Button>
{/* 角度编辑 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('angle')}
title="角度编辑"
>
<Move3D className="h-4 w-4" />
<span>角度</span>
</Button>
{/* 扩展 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('extend')}
title="图片扩展"
>
<Expand className="h-4 w-4" />
<span>扩展</span>
</Button>
{/* 尺寸调整 */}
<Button
variant="ghost"
size="sm"
className="h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100"
onClick={() => handleAction('resize')}
title="尺寸调整"
>
<Maximize2 className="h-4 w-4" />
<span>调整</span>
</Button>
{/* 图片标注 */}
<Button
variant="ghost"
size="sm"
className={`h-9 px-3 text-xs gap-1.5 rounded-full hover:bg-gray-100 ${data.hasAnnotations ? 'text-primary' : ''}`}
onClick={() => handleAction('annotate')}
title="标注图片重点区域"
>
<Pencil className="h-4 w-4" />
<span>标注</span>
</Button>
{/* 更多操作 */}
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button
variant="ghost"
size="sm"
className="h-9 px-2 rounded-full hover:bg-gray-100"
title="更多"
>
<MoreVertical className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem onClick={handleDownload}>
<Download className="h-4 w-4 mr-2" />
下载图片
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem
onClick={() => deleteNode(node.id)}
className="text-destructive focus:text-destructive"
>
<Trash2 className="h-4 w-4 mr-2" />
删除
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>,
{/* 添加到对话 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-blue-50 text-blue-600 hover:text-blue-700"
onClick={() => {
addPendingChatAttachment({
url: data.src!,
name: data.prompt || '画布图片',
contentType: 'image/jpeg',
});
toast.success('已添加到对话框');
}}
>
<MessageSquarePlus className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">添加到对话</TooltipContent>
</Tooltip>
{/* 分隔线 */}
<div className="h-5 w-px bg-gray-200 mx-0.5" />
{/* 放大/高清 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-gray-100"
onClick={() => handleAction('enhance')}
>
<span className="text-[10px] font-medium text-gray-500 border border-gray-300 rounded px-1">HD</span>
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">高清放大</TooltipContent>
</Tooltip>
{/* 移除背景/抠图 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-gray-100"
onClick={() => handleAction('rmbg')}
>
<Scissors className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">移除背景</TooltipContent>
</Tooltip>
{/* 场景融合 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-gray-100"
onClick={() => handleAction('scene-fusion')}
>
<Layers className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">场景融合</TooltipContent>
</Tooltip>
{/* 角度编辑 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-gray-100"
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"
className="h-8 w-8 rounded-full hover:bg-gray-100"
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"
className="h-8 w-8 rounded-full hover:bg-gray-100"
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"
className={cn("h-8 w-8 rounded-full hover:bg-gray-100", data.hasAnnotations && "text-primary")}
onClick={() => handleAction('annotate')}
>
<Pencil className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">标注重点区域</TooltipContent>
</Tooltip>
{/* 下载 */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 rounded-full hover:bg-gray-100"
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"
className="h-8 w-8 rounded-full hover:bg-red-50 text-red-500 hover:text-red-600"
onClick={() => deleteNode(node.id)}
>
<Trash2 className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom" className="text-xs">删除</TooltipContent>
</Tooltip>
</div>
</TooltipProvider>,
document.body
)}