{Math.round(zoomLevel * 100)}%
Nodes: {nodes.length} Edges: {edges.length}
{ selectedNode = null; }} >
{#each edges as edge (edge.id)} {@const sourceNode = nodes.find(n => n.id === edge.source)} {@const targetNode = nodes.find(n => n.id === edge.target)} {#if sourceNode && targetNode} {@const points = getConnectionPoints(sourceNode, targetNode)} deleteEdge(edge.id)} /> deleteEdge(edge.id)} > ✕ {/if} {/each} {#if isConnecting && connectionStart} {@const startNode = nodes.find(n => n.id === connectionStart)} {#if startNode} {/if} {/if} {#each nodes as node (node.id)} {@const config = getComponentConfig(node.type)}
handleMouseDown(e, node)} on:click={(e) => handleNodeClick(e, node)} >
{config.icon} {node.data.display_name || node.data.label}
{#if propertyFields[node.type]} {#each propertyFields[node.type].slice(0, 3) as field}
{#if field.type === 'select'} {:else if field.type === 'number'} updateNodeProperty(node.id, field.key, Number(e.target.value))} on:click|stopPropagation /> {:else if field.type === 'checkbox'} {:else if field.type === 'textarea'} {:else} updateNodeProperty(node.id, field.key, e.target.value)} on:click|stopPropagation /> {/if}
{/each} {:else}
Ready
{/if}
{#if node.data.template} {@const templateHandles = Object.entries(node.data.template).filter(([_, handle]) => handle.is_handle)} {#each templateHandles as [handleId, handle], index} {#if handle.type === 'string' || handle.type === 'object' || handle.type === 'list' || handle.type === 'file'}
(handle.type === 'object') && endConnection(e, node.id)} on:mousedown={(e) => (handle.type === 'string' || handle.type === 'list' || handle.type === 'file') && startConnection(e, node.id)} title={`${handle.display_name || handleId} (${handle.type})`} >
{/if} {/each} {@const hasInputHandles = templateHandles.some(([_, h]) => h.type === 'object')} {@const hasOutputHandles = templateHandles.some(([_, h]) => h.type === 'string' || h.type === 'list' || h.type === 'file')} {#if !hasInputHandles}
endConnection(e, node.id)} title="Input" >
{/if} {#if !hasOutputHandles}
startConnection(e, node.id)} title="Output" >
{/if} {:else}
endConnection(e, node.id)} title="Input" >
startConnection(e, node.id)} title="Output" >
{/if}
{/each}
{#if !propertyPanelCollapsed}

Properties

{/if}
{#if !propertyPanelCollapsed}
{#if selectedNode && propertyFields[selectedNode.type]}

{selectedNode.data.display_name || selectedNode.data.label}

TYPE: {selectedNode.type.toUpperCase()}

{#each propertyFields[selectedNode.type] as field}
{#if field.help} {field.help} {/if} {#if field.type === 'text'} updateNodeProperty(selectedNode.id, field.key, e.target.value)} /> {:else if field.type === 'number'} updateNodeProperty(selectedNode.id, field.key, Number(e.target.value))} /> {:else if field.type === 'checkbox'} {:else if field.type === 'select'} {:else if field.type === 'textarea'} {/if}
{/each}
{:else}
🎯

Select a node to edit properties

Click on any node to configure its detailed settings
{/if}
{/if}