feat: add canvas tool panels (multi-grid, upscale, inpaint) and conditional grid mode
Add modal-based tool panels for multi-grid, super-resolution, and inpaint in canvas image-to-image workflow. Grid mode selector only appears for models that support multi-image generation (wan2.7-image, gpt-image-2). Also fixes merge conflict markers in CSS and adds missing toast import. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -182,6 +182,7 @@ import {
|
||||
} from "./canvasWorkflowDeserialize";
|
||||
import { CanvasNodeToolbar, CanvasNodeVideoPlayer, CanvasSelectChip } from "./canvasComponents";
|
||||
import type { CanvasNodeToolbarAction } from "./canvasComponents";
|
||||
import { CanvasMultiGridPanel, CanvasUpscalePanel, CanvasInpaintPanel } from "./canvasToolPanels";
|
||||
import { CanvasSmoothedProgressRing } from "./CanvasSmoothedProgressRing";
|
||||
|
||||
const canvasEnterpriseVideoModelOptions: CanvasOption[] = ENTERPRISE_VIDEO_MODEL_OPTIONS.map((option) => ({
|
||||
@@ -336,6 +337,7 @@ function CanvasPage({
|
||||
const [imageFocusNodeId, setImageFocusNodeId] = useState<string | null>(null);
|
||||
const [imageFocusDraft, setImageFocusDraft] = useState<CanvasImageFocusSelection | null>(null);
|
||||
const [imageFocusDrag, setImageFocusDrag] = useState<CanvasImageFocusDrag | null>(null);
|
||||
const [canvasToolModal, setCanvasToolModal] = useState<{ tool: "multiGrid" | "upscale" | "inpaint"; imageNode: CanvasImageNode } | null>(null);
|
||||
const [stylePickerImageNodeId, setStylePickerImageNodeId] = useState<string | null>(null);
|
||||
const [stylePickerCases, setStylePickerCases] = useState<CanvasStyleCase[]>([]);
|
||||
const [stylePickerLoading, setStylePickerLoading] = useState(false);
|
||||
@@ -4264,7 +4266,7 @@ function CanvasPage({
|
||||
setSelectedExistingCategory("");
|
||||
setSaveAssetOpen(true);
|
||||
}
|
||||
if (key === "upscale") void handleGenerateImageNode(imageNode.id);
|
||||
if (key === "upscale") setCanvasToolModal({ tool: "upscale", imageNode });
|
||||
}}
|
||||
moreActions={[
|
||||
{ key: "copy", label: "复制链接", icon: <CopyOutlined />, disabled: !imageNode.imageUrl },
|
||||
@@ -4570,16 +4572,42 @@ function CanvasPage({
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
className={imageNodeFocusActive ? "is-active" : ""}
|
||||
title="框选聚焦区域"
|
||||
title="多宫格生成"
|
||||
disabled={!imageNode.imageUrl}
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
openImageFocusMode(imageNode);
|
||||
setCanvasToolModal({ tool: "multiGrid", imageNode });
|
||||
}}
|
||||
>
|
||||
<BarsOutlined /><span>聚焦</span>
|
||||
<BarsOutlined /><span>多宫格</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
title="图片超分辨率"
|
||||
disabled={!imageNode.imageUrl}
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setCanvasToolModal({ tool: "upscale", imageNode });
|
||||
}}
|
||||
>
|
||||
<ThunderboltOutlined /><span>超分</span>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
title="局部重绘"
|
||||
disabled={!imageNode.imageUrl}
|
||||
onMouseDown={(event) => event.stopPropagation()}
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setCanvasToolModal({ tool: "inpaint", imageNode });
|
||||
}}
|
||||
>
|
||||
<EditOutlined /><span>局部重绘</span>
|
||||
</button>
|
||||
<button type="button" className="studio-canvas-image-composer__expand" aria-label="展开">↗</button>
|
||||
</div>
|
||||
@@ -5729,6 +5757,27 @@ function CanvasPage({
|
||||
</section>
|
||||
|
||||
</div>
|
||||
{canvasToolModal && (
|
||||
<div className="studio-canvas-tool-modal-overlay" onClick={() => setCanvasToolModal(null)}>
|
||||
<div className="studio-canvas-tool-modal" onClick={(e) => e.stopPropagation()} role="dialog" aria-modal="true" aria-label={canvasToolModal.tool === "multiGrid" ? "多宫格" : canvasToolModal.tool === "upscale" ? "超分" : "局部重绘"}>
|
||||
<header className="studio-canvas-tool-modal__header">
|
||||
<h3>{canvasToolModal.tool === "multiGrid" ? "多宫格生成" : canvasToolModal.tool === "upscale" ? "图片超分" : "局部重绘"}</h3>
|
||||
<button type="button" aria-label="关闭" onClick={() => setCanvasToolModal(null)}><CloseOutlined /></button>
|
||||
</header>
|
||||
<div className="studio-canvas-tool-modal__body">
|
||||
{canvasToolModal.tool === "multiGrid" && (
|
||||
<CanvasMultiGridPanel imageUrl={canvasToolModal.imageNode.imageUrl || ""} imageNode={canvasToolModal.imageNode} onComplete={(url) => { setImageNodes((nodes) => nodes.map((n) => n.id === canvasToolModal.imageNode.id ? { ...n, imageUrl: url } : n)); setCanvasToolModal(null); }} />
|
||||
)}
|
||||
{canvasToolModal.tool === "upscale" && (
|
||||
<CanvasUpscalePanel imageUrl={canvasToolModal.imageNode.imageUrl || ""} imageNode={canvasToolModal.imageNode} onComplete={(url) => { setImageNodes((nodes) => nodes.map((n) => n.id === canvasToolModal.imageNode.id ? { ...n, imageUrl: url } : n)); setCanvasToolModal(null); }} />
|
||||
)}
|
||||
{canvasToolModal.tool === "inpaint" && (
|
||||
<CanvasInpaintPanel imageUrl={canvasToolModal.imageNode.imageUrl || ""} imageNode={canvasToolModal.imageNode} onComplete={(url) => { setImageNodes((nodes) => nodes.map((n) => n.id === canvasToolModal.imageNode.id ? { ...n, imageUrl: url } : n)); setCanvasToolModal(null); }} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</WorkspacePageShell>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user