81 lines
2.5 KiB
TypeScript
81 lines
2.5 KiB
TypeScript
'use client';
|
|
|
|
import { cn } from '@/lib/utils';
|
|
import type { LinkedListState, LinkedListPointerState } from '@/lib/visualizations/types';
|
|
import { LinkedListNode } from '../primitives/linked-list-node';
|
|
import { LinkedListPointer } from '../primitives/linked-list-pointer';
|
|
|
|
interface LinkedListViewProps {
|
|
list: LinkedListState;
|
|
pointers: LinkedListPointerState[];
|
|
className?: string;
|
|
}
|
|
|
|
const NODE_WIDTH = 40; // w-10 = 40px
|
|
const ARROW_WIDTH = 22; // 16px line + 6px arrow head
|
|
|
|
export function LinkedListView({
|
|
list,
|
|
pointers,
|
|
className,
|
|
}: LinkedListViewProps) {
|
|
// Calculate total width for proper pointer alignment
|
|
const totalWidth = list.nodes.length * NODE_WIDTH + (list.nodes.length - 1) * ARROW_WIDTH;
|
|
|
|
// Group pointers by nodeIndex to calculate offsets for overlapping pointers
|
|
const pointersByIndex = pointers.reduce((acc, pointer) => {
|
|
const idx = pointer.nodeIndex;
|
|
if (!acc[idx]) acc[idx] = [];
|
|
acc[idx].push(pointer);
|
|
return acc;
|
|
}, {} as Record<number, LinkedListPointerState[]>);
|
|
|
|
// Calculate horizontal offset for each pointer
|
|
const getPointerOffset = (pointer: LinkedListPointerState): number => {
|
|
const pointersAtIndex = pointersByIndex[pointer.nodeIndex] || [];
|
|
if (pointersAtIndex.length <= 1) return 0;
|
|
|
|
const pointerIdx = pointersAtIndex.findIndex(p => p.id === pointer.id);
|
|
const totalPointers = pointersAtIndex.length;
|
|
const spacing = 28; // px between overlapping pointers
|
|
// Center the group: offset from center based on position
|
|
return (pointerIdx - (totalPointers - 1) / 2) * spacing;
|
|
};
|
|
|
|
return (
|
|
<div className={cn('flex flex-col items-center', className)}>
|
|
{list.label && (
|
|
<span className="mb-2 text-sm font-medium text-foreground-muted">
|
|
{list.label}
|
|
</span>
|
|
)}
|
|
|
|
<div className="relative" style={{ width: totalWidth }}>
|
|
{/* Pointers row */}
|
|
<div className="relative mb-1 h-8">
|
|
{pointers.map((pointer) => (
|
|
<LinkedListPointer
|
|
key={pointer.id}
|
|
pointer={pointer}
|
|
nodeWidth={NODE_WIDTH}
|
|
arrowWidth={ARROW_WIDTH}
|
|
horizontalOffset={getPointerOffset(pointer)}
|
|
/>
|
|
))}
|
|
</div>
|
|
|
|
{/* Linked list nodes */}
|
|
<div className="flex items-center">
|
|
{list.nodes.map((node, index) => (
|
|
<LinkedListNode
|
|
key={node.id}
|
|
node={node}
|
|
isLast={index === list.nodes.length - 1}
|
|
/>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|