// Adapted from jalcoui (MIT) — github.com/jal-co/ui 'use client'; import * as React from 'react'; import { useThemeColor } from '@djangocfg/ui-core/styles/palette'; import { ROW_HEIGHT, type GraphRow } from '../types'; import { pickLaneColor } from '../hooks/useLaneColors'; interface RailsProps { row: GraphRow; prevRow: GraphRow | null; railWidth: number; maxRails: number; laneColors: string[]; } /** * SVG renderer for the rail column of a single commit row. * * Draws four classes of geometry: * 1. Pass-through rails — straight vertical line top→bottom for any rail * that is active above *and* below this row and is not the commit rail. * 2. Commit rail incoming/outgoing — half-height verticals on the commit's * own rail, depending on whether the rail was active above/below. * 3. Fork-out curves — bezier from the commit's rail down to a freshly * allocated rail (a new branch coming off this commit). * 4. Merge curves — bezier from a source rail into the commit dot * (or from the dot down to a target rail). * * SVG fill/stroke values are hex strings resolved via the theme palette; * raw Tailwind classes do not work inside `stroke=`. */ export function Rails({ row, prevRow, railWidth, maxRails, laneColors }: RailsProps) { // Background color for the commit dot ring — matches the surface the row // is mounted on so the dot reads as "popped out" on every preset. const background = useThemeColor('background'); const w = maxRails * railWidth; const h = ROW_HEIGHT; const cy = h / 2; const rx = (rail: number) => rail * railWidth + railWidth / 2; const color = (rail: number) => pickLaneColor(laneColors, rail); const commitX = rx(row.rail); const activeAbove = new Set(); if (prevRow) { for (let r = 0; r < prevRow.rails.length; r++) { if (prevRow.rails[r] !== null) activeAbove.add(r); } } const activeBelow = new Set(); for (let r = 0; r < row.rails.length; r++) { if (row.rails[r] !== null) activeBelow.add(r); } const passThroughRails = Array.from(activeAbove).filter( (r) => r !== row.rail && activeBelow.has(r), ); const endingRails = Array.from(activeAbove).filter( (r) => r !== row.rail && !activeBelow.has(r), ); const forkEdges = row.edges.filter((e) => e.type === 'fork-out'); const mergeEdges = row.edges.filter((e) => e.type === 'merge-in'); return ( ); }