@ -486,6 +486,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
selected = { selected }
selected = { selected }
isExecuting = { isRunning }
isExecuting = { isRunning }
hasError = { nodeData . status === "error" }
hasError = { nodeData . status === "error" }
fullBleed
>
>
{ /* Input handles - ALWAYS use same IDs and positions for connection stability */ }
{ /* Input handles - ALWAYS use same IDs and positions for connection stability */ }
{ /* Image input at 35%, Text input at 65% - never changes regardless of model */ }
{ /* Image input at 35%, Text input at 65% - never changes regardless of model */ }
@ -547,19 +548,18 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
Image
Image
< / div >
< / div >
< div className = "flex-1 flex flex-col min-h-0 gap-2 " >
< div className = "relative w-full h-full min-h-0 " >
{ /* Preview area */ }
{ /* Preview area */ }
{ nodeData . outputImage ? (
{ nodeData . outputImage ? (
< >
< >
< div className = "relative w-full flex-1 min-h-0" >
< img
< img
src = { nodeData . outputImage }
src = { nodeData . outputImage }
alt = "Generated"
alt = "Generated"
className = "w-full h-full object-contain rounded "
className = "w-full h-full object-cover "
/ >
/ >
{ /* Loading overlay for generation */ }
{ /* Loading overlay for generation */ }
{ nodeData . status === "loading" && (
{ nodeData . status === "loading" && (
< div className = "absolute inset-0 bg-neutral-900/70 rounded flex items-center justify-center" >
< div className = "absolute inset-0 bg-neutral-900/70 flex items-center justify-center" >
< svg
< svg
className = "w-6 h-6 animate-spin text-white"
className = "w-6 h-6 animate-spin text-white"
fill = "none"
fill = "none"
@ -583,7 +583,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
) }
) }
{ /* Error overlay when generation failed */ }
{ /* Error overlay when generation failed */ }
{ nodeData . status === "error" && (
{ nodeData . status === "error" && (
< div className = "absolute inset-0 bg-red-900/40 rounded flex flex-col items-center justify-center gap-1" >
< div className = "absolute inset-0 bg-red-900/40 flex flex-col items-center justify-center gap-1" >
< svg
< svg
className = "w-6 h-6 text-white"
className = "w-6 h-6 text-white"
fill = "none"
fill = "none"
@ -599,7 +599,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
) }
) }
{ /* Loading overlay for carousel navigation */ }
{ /* Loading overlay for carousel navigation */ }
{ isLoadingCarouselImage && (
{ isLoadingCarouselImage && (
< div className = "absolute inset-0 bg-neutral-900/50 rounded flex items-center justify-center" >
< div className = "absolute inset-0 bg-neutral-900/50 flex items-center justify-center" >
< svg
< svg
className = "w-4 h-4 animate-spin text-white"
className = "w-4 h-4 animate-spin text-white"
fill = "none"
fill = "none"
@ -621,6 +621,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
< / svg >
< / svg >
< / div >
< / div >
) }
) }
{ /* Clear button */ }
< div className = "absolute top-1 right-1" >
< div className = "absolute top-1 right-1" >
< button
< button
onClick = { handleClearImage }
onClick = { handleClearImage }
@ -632,28 +633,27 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
< / svg >
< / svg >
< / button >
< / button >
< / div >
< / div >
< / div >
{ /* Carousel controls - only show if there are multiple images */ }
{ /* Carousel controls - overlaid on image bottom */ }
{ hasCarouselImages && (
{ hasCarouselImages && (
< div className = "flex items-center justify-center gap-2 shrink-0 " >
< div className = "absolute bottom-0 left-0 right-0 flex items-center justify-center gap-2 py-1.5 bg-neutral-900/60 backdrop-blur-sm " >
< button
< button
onClick = { handleCarouselPrevious }
onClick = { handleCarouselPrevious }
disabled = { isLoadingCarouselImage }
disabled = { isLoadingCarouselImage }
className = "w-5 h-5 rounded bg-neutral-800 hover:bg-neutral-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center text-neutral-40 0 hover:text-white transition-colors"
className = "w-5 h-5 rounded hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center text-white/7 0 hover:text-white transition-colors"
title = "Previous image"
title = "Previous image"
>
>
< svg className = "w-3 h-3" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 } >
< svg className = "w-3 h-3" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 } >
< path strokeLinecap = "round" strokeLinejoin = "round" d = "M15 19l-7-7 7-7" / >
< path strokeLinecap = "round" strokeLinejoin = "round" d = "M15 19l-7-7 7-7" / >
< / svg >
< / svg >
< / button >
< / button >
< span className = "text-[10px] text-neutral-40 0 min-w-[32px] text-center" >
< span className = "text-[10px] text-white/7 0 min-w-[32px] text-center" >
{ ( nodeData . selectedHistoryIndex || 0 ) + 1 } / { ( nodeData . imageHistory || [ ] ) . length }
{ ( nodeData . selectedHistoryIndex || 0 ) + 1 } / { ( nodeData . imageHistory || [ ] ) . length }
< / span >
< / span >
< button
< button
onClick = { handleCarouselNext }
onClick = { handleCarouselNext }
disabled = { isLoadingCarouselImage }
disabled = { isLoadingCarouselImage }
className = "w-5 h-5 rounded bg-neutral-800 hover:bg-neutral-700 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center text-neutral-40 0 hover:text-white transition-colors"
className = "w-5 h-5 rounded hover:bg-white/10 disabled:opacity-50 disabled:cursor-not-allowed flex items-center justify-center text-white/7 0 hover:text-white transition-colors"
title = "Next image"
title = "Next image"
>
>
< svg className = "w-3 h-3" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 } >
< svg className = "w-3 h-3" fill = "none" viewBox = "0 0 24 24" stroke = "currentColor" strokeWidth = { 2 } >
@ -664,7 +664,7 @@ export function GenerateImageNode({ id, data, selected }: NodeProps<NanoBananaNo
) }
) }
< / >
< / >
) : (
) : (
< div className = "w-full flex-1 min-h-[112px] border border-dashed border-neutral-600 rounded flex flex-col items-center justify-center" >
< div className = "w-full h-full min-h-[112px] bg-neutral-900/40 flex flex-col items-center justify-center" >
{ nodeData . status === "loading" ? (
{ nodeData . status === "loading" ? (
< svg
< svg
className = "w-4 h-4 animate-spin text-neutral-400"
className = "w-4 h-4 animate-spin text-neutral-400"