|
|
|
@ -91,9 +91,11 @@ export interface GenerateImageNodeViewProps { |
|
|
|
data: NanoBananaNodeData; |
|
|
|
selected?: boolean; |
|
|
|
renderInputHandle?: boolean; |
|
|
|
/** Suppress the empty-state delete capsule (e.g. when a wrapper already renders an upload toolbar). */ |
|
|
|
suppressEmptyStateDelete?: boolean; |
|
|
|
} |
|
|
|
|
|
|
|
export function GenerateImageNodeView({ id, data, selected, renderInputHandle = true }: GenerateImageNodeViewProps) { |
|
|
|
export function GenerateImageNodeView({ id, data, selected, renderInputHandle = true, suppressEmptyStateDelete = false }: GenerateImageNodeViewProps) { |
|
|
|
const nodeData = data; |
|
|
|
const { t } = useI18n(); |
|
|
|
const storedImage = (data as NanoBananaNodeData & { image?: string | null; previewImage?: string | null }).image ?? null; |
|
|
|
@ -173,6 +175,7 @@ export function GenerateImageNodeView({ id, data, selected, renderInputHandle = |
|
|
|
}, [id, modelOptions, nodeConfig.selectedModel, nodeData, updateImagePreference, updateNodeData]); |
|
|
|
|
|
|
|
const regenerateNode = useWorkflowStore((state) => state.regenerateNode); |
|
|
|
const removeNode = useWorkflowStore((state) => state.removeNode); |
|
|
|
const isRunning = useWorkflowStore((state) => state.runningNodeIds.has(id)); |
|
|
|
|
|
|
|
const handleRegenerate = useCallback(() => { |
|
|
|
@ -412,6 +415,24 @@ export function GenerateImageNodeView({ id, data, selected, renderInputHandle = |
|
|
|
const downloadImage = nodeData.outputImage || editableImage; |
|
|
|
const overlayImageDimensions = cropImageDimensions || asImageDimensions(nodeData.dimensions); |
|
|
|
const showSelectedActions = Boolean(selected && selectedNodeCount === 1 && editableImage); |
|
|
|
const showEmptyStateDelete = Boolean(selected && selectedNodeCount === 1 && !editableImage && !activeNodeTool && !suppressEmptyStateDelete); |
|
|
|
const emptyStateActions: NodeActionCapsuleAction[] = [ |
|
|
|
{ |
|
|
|
key: "delete", |
|
|
|
icon: ( |
|
|
|
<svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.8}> |
|
|
|
<path strokeLinecap="round" strokeLinejoin="round" d="M6 7h12M9 7V5h6v2m-8 0 1 13h8l1-13" /> |
|
|
|
</svg> |
|
|
|
), |
|
|
|
label: t("imageInput.remove"), |
|
|
|
tone: "danger", |
|
|
|
onClick: (event) => { |
|
|
|
event.preventDefault(); |
|
|
|
event.stopPropagation(); |
|
|
|
removeNode(id); |
|
|
|
}, |
|
|
|
}, |
|
|
|
]; |
|
|
|
const activeImageEditTool: ImageEditTool | null = |
|
|
|
activeNodeTool === "crop" || |
|
|
|
activeNodeTool === "outpainting" || |
|
|
|
@ -597,6 +618,7 @@ export function GenerateImageNodeView({ id, data, selected, renderInputHandle = |
|
|
|
/> |
|
|
|
|
|
|
|
{showSelectedActions && !activeNodeTool && <NodeActionCapsule actions={selectedActions} />} |
|
|
|
{showEmptyStateDelete && <NodeActionCapsule actions={emptyStateActions} />} |
|
|
|
|
|
|
|
<div |
|
|
|
ref={registerMediaFrame} |
|
|
|
|