import { ExternalLink } from "lucide-react"; import { memo, useState } from "react"; import { Button } from "@/components/ui/button"; import { Card } from "@/components/ui/card"; import { DropdownMenu, DropdownMenuContent, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { getConnectorIcon } from "./ConnectorComponents"; import type { Source } from "./types"; type CitationProps = { citationId: number; citationText: string; position: number; source: Source | null; }; /** * Citation component to handle individual citations */ export const Citation = memo(({ citationId, citationText, position, source }: CitationProps) => { const [open, setOpen] = useState(false); const citationKey = `citation-${citationId}-${position}`; if (!source) return <>{citationText}; return ( {citationId} {open && (
{getConnectorIcon(source.connectorType || "")}

{source.title}

{source.description}

{source.url}
)}
); }); Citation.displayName = "Citation"; /** * Function to render text with citations */ export const renderTextWithCitations = ( text: string, getCitationSource: (id: number) => Source | null ) => { // Regular expression to find citation patterns like [1], [2], etc. const citationRegex = /\[(\d+)\]/g; const parts = []; let lastIndex = 0; let match: RegExpExecArray | null = citationRegex.exec(text); let position = 0; while (match !== null) { // Add text before the citation if (match.index > lastIndex) { parts.push(text.substring(lastIndex, match.index)); } // Add the citation component const citationId = parseInt(match[1], 10); parts.push( ); lastIndex = match.index + match[0].length; position++; match = citationRegex.exec(text); } // Add any remaining text after the last citation if (lastIndex < text.length) { parts.push(text.substring(lastIndex)); } return parts; };