{#each parentLinks.shared as group (group.key)} {@const aCenter = nodeCenter(group.parentA)} {@const bCenter = nodeCenter(group.parentB)} {@const childCenters = group.childIds .map((id) => nodeCenter(id)) .filter((c): c is { x: number; y: number } => c !== null)} {#if aCenter && bCenter && childCenters.length > 0} {@const midX = (aCenter.x + bCenter.x) / 2} {@const parentBottomY = aCenter.y + NODE_H / 2} {@const childTopY = childCenters[0].y - NODE_H / 2} {@const barY = (parentBottomY + childTopY) / 2} {@const xs = childCenters.map((c) => c.x)} {@const minX = Math.min(midX, ...xs)} {@const maxX = Math.max(midX, ...xs)} {#if minX !== maxX} {/if} {#each childCenters as cc, i (group.childIds[i])} {/each} {/if} {/each} {#each parentLinks.single as link (link.key)} {@const parentCenter = nodeCenter(link.parentId)} {@const childCenter = nodeCenter(link.childId)} {#if parentCenter && childCenter} {@const parentBottomY = parentCenter.y + NODE_H / 2} {@const childTopY = childCenter.y - NODE_H / 2} {@const barY = (parentBottomY + childTopY) / 2} {#if parentCenter.x !== childCenter.x} {/if} {/if} {/each} {#each spouseEdges as e (e.id)} {@const aCenter = nodeCenter(e.personId)} {@const bCenter = nodeCenter(e.relatedPersonId)} {#if aCenter && bCenter} {/if} {/each} {#each nodes as node (node.id)} {@const pos = layout.positions.get(node.id)} {#if pos} {@const isSelected = selectedId === node.id} {@const isFocused = focusedId === node.id} onSelect(node.id)} onkeydown={(e) => handleNodeKey(e, node.id)} onfocus={() => (focusedId = node.id)} onblur={() => (focusedId = null)} class="cursor-pointer focus:outline-none" > {#if isFocused} {/if} {#if isSelected} {/if} {node.displayName} {#if node.birthYear || node.deathYear} {node.birthYear ?? '?'}–{node.deathYear ?? ''} {/if} {/if} {/each}