"use client"; import React, { useEffect, useState } from "react"; import { useTheme } from "./ThemeContext"; interface CitationBeamOverlayProps { activeCitationIndex: number | null; } interface Coords { x1: number; y1: number; x2: number; y2: number; } export function CitationBeamOverlay({ activeCitationIndex }: CitationBeamOverlayProps) { const { resolvedTheme } = useTheme(); const [coords, setCoords] = useState(null); useEffect(() => { if (!activeCitationIndex) { setCoords(null); return; } const updateCoords = () => { const markerEl = document.getElementById(`citation-marker-${activeCitationIndex}`); const cardEl = document.getElementById(`citation-card-${activeCitationIndex}`); if (!markerEl || !cardEl) { setCoords(null); return; } const markerRect = markerEl.getBoundingClientRect(); const cardRect = cardEl.getBoundingClientRect(); // Ensure both elements are visible on screen if (markerRect.width === 0 || cardRect.width === 0) { setCoords(null); return; } setCoords({ x1: markerRect.left + markerRect.width / 2, y1: markerRect.top + markerRect.height / 2, x2: cardRect.left, y2: cardRect.top + cardRect.height / 2, }); }; updateCoords(); const handleScrollOrResize = () => updateCoords(); window.addEventListener("resize", handleScrollOrResize); window.addEventListener("scroll", handleScrollOrResize, true); return () => { window.removeEventListener("resize", handleScrollOrResize); window.removeEventListener("scroll", handleScrollOrResize, true); }; }, [activeCitationIndex]); if (!activeCitationIndex || !coords) return null; // Compute smooth bezier curve control points const dx = Math.abs(coords.x2 - coords.x1); const cx1 = coords.x1 + dx * 0.4; const cy1 = coords.y1; const cx2 = coords.x2 - dx * 0.4; const cy2 = coords.y2; const pathD = `M ${coords.x1} ${coords.y1} C ${cx1} ${cy1}, ${cx2} ${cy2}, ${coords.x2} ${coords.y2}`; const isGlass = resolvedTheme === "glass"; return ( ); }