Browse Source

refactor: make SplitGridNode full-bleed with overlay controls

Switch to fullBleed BaseNode so the image preview fills the entire
node area. Move grid config, Settings, and Split controls into an
absolute-positioned overlay at the bottom with backdrop blur,
matching the pattern used by PromptConstructorNode and other
full-bleed nodes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
6a6dc82ad9
  1. 122
      src/components/nodes/SplitGridNode.tsx

122
src/components/nodes/SplitGridNode.tsx

@ -36,36 +36,39 @@ export function SplitGridNode({ id, data, selected }: NodeProps<SplitGridNodeTyp
}, [id, regenerateNode]); }, [id, regenerateNode]);
return ( return (
<BaseNode <>
id={id} <BaseNode
selected={selected} id={id}
hasError={nodeData.status === "error"} selected={selected}
> hasError={nodeData.status === "error"}
{/* Image input handle */} fullBleed
<Handle >
type="target" {/* Image input handle */}
position={Position.Left} <Handle
id="image" type="target"
data-handletype="image" position={Position.Left}
/> id="image"
data-handletype="image"
style={{ zIndex: 10 }}
/>
{/* Reference output handle for visual links to child nodes */} {/* Reference output handle for visual links to child nodes */}
<Handle <Handle
type="source" type="source"
position={Position.Right} position={Position.Right}
id="reference" id="reference"
data-handletype="reference" data-handletype="reference"
className="!bg-gray-500" className="!bg-gray-500"
/> style={{ zIndex: 10 }}
/>
<div className="flex-1 flex flex-col min-h-0 gap-2"> {/* Full-bleed preview area */}
{/* Preview/Status area */}
{nodeData.sourceImage ? ( {nodeData.sourceImage ? (
<div className="relative w-full flex-1 min-h-0"> <div className="relative w-full h-full">
<img <img
src={nodeData.sourceImage} src={nodeData.sourceImage}
alt="Source grid" alt="Source grid"
className="w-full h-full object-contain rounded" className="w-full h-full object-cover rounded-lg"
/> />
{/* Grid overlay visualization */} {/* Grid overlay visualization */}
<div <div
@ -85,7 +88,7 @@ export function SplitGridNode({ id, data, selected }: NodeProps<SplitGridNodeTyp
</div> </div>
{/* Loading overlay */} {/* Loading overlay */}
{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 rounded-lg flex items-center justify-center">
<svg className="w-6 h-6 animate-spin text-white" fill="none" viewBox="0 0 24 24"> <svg className="w-6 h-6 animate-spin text-white" fill="none" viewBox="0 0 24 24">
<circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" /> <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="3" />
<path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" /> <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" />
@ -94,7 +97,7 @@ export function SplitGridNode({ id, data, selected }: NodeProps<SplitGridNodeTyp
)} )}
</div> </div>
) : ( ) : (
<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 rounded-lg">
{nodeData.status === "error" ? ( {nodeData.status === "error" ? (
<span className="text-[10px] text-red-400 text-center px-2"> <span className="text-[10px] text-red-400 text-center px-2">
{nodeData.error || "Error"} {nodeData.error || "Error"}
@ -117,40 +120,43 @@ export function SplitGridNode({ id, data, selected }: NodeProps<SplitGridNodeTyp
</div> </div>
)} )}
{/* Config summary */} {/* Controls overlay pinned at bottom */}
<div className="flex items-center justify-between text-[10px] text-neutral-400 shrink-0"> <div className="absolute bottom-0 left-0 right-0 z-10 px-3 py-2 bg-neutral-900/80 backdrop-blur-sm rounded-b-lg space-y-1">
<span>{nodeData.gridRows}x{nodeData.gridCols} grid ({nodeData.targetCount} images)</span> {/* Config summary */}
<button <div className="flex items-center justify-between text-[10px] text-neutral-400">
onClick={handleOpenSettings} <span>{nodeData.gridRows}x{nodeData.gridCols} grid ({nodeData.targetCount} images)</span>
className="text-blue-400 hover:text-blue-300 transition-colors" <button
> onClick={handleOpenSettings}
Settings className="nodrag nopan text-blue-400 hover:text-blue-300 transition-colors"
</button> >
</div> Settings
</button>
</div>
{/* Child node count / status */} {/* Child node count / status */}
<div className="flex items-center justify-between shrink-0"> <div className="flex items-center justify-between">
{nodeData.isConfigured ? ( {nodeData.isConfigured ? (
<div className="text-[10px] text-neutral-500"> <div className="text-[10px] text-neutral-500">
{nodeData.childNodeIds.length} generate sets created {nodeData.childNodeIds.length} generate sets created
</div> </div>
) : ( ) : (
<div className="text-[10px] text-amber-400"> <div className="text-[10px] text-amber-400">
Not configured - click Settings Not configured - click Settings
</div> </div>
)} )}
{/* Split button */} {/* Split button */}
<button <button
onClick={handleSplit} onClick={handleSplit}
disabled={isRunning || !nodeData.isConfigured} disabled={isRunning || !nodeData.isConfigured}
className="px-2 py-0.5 text-[10px] border border-white hover:bg-white hover:text-neutral-900 disabled:border-neutral-600 disabled:text-neutral-600 disabled:cursor-not-allowed text-white rounded transition-colors" className="nodrag nopan px-2 py-0.5 text-[10px] border border-white hover:bg-white hover:text-neutral-900 disabled:border-neutral-600 disabled:text-neutral-600 disabled:cursor-not-allowed text-white rounded transition-colors"
title={!nodeData.isConfigured ? "Configure node first" : "Split grid"} title={!nodeData.isConfigured ? "Configure node first" : "Split grid"}
> >
Split Split
</button> </button>
</div>
</div> </div>
</div> </BaseNode>
{/* Settings Modal */} {/* Settings Modal */}
{showSettings && ( {showSettings && (
@ -160,6 +166,6 @@ export function SplitGridNode({ id, data, selected }: NodeProps<SplitGridNodeTyp
onClose={handleCloseSettings} onClose={handleCloseSettings}
/> />
)} )}
</BaseNode> </>
); );
} }

Loading…
Cancel
Save