Files
codetutor/frontend/src/components/visualizations-new/data-structures/linked-list-view.tsx
T

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>
);
}