"use client"; import { ExternalLink, Globe } from "lucide-react"; import NextImage from "next/image"; import { Button } from "@/components/ui/button"; import { openSafeNavigationHref, sanitizeHref } from "../shared/media"; import { cn } from "./_adapter"; import { CitationHoverPopover } from "./citation-hover-popover"; import type { CitationVariant, SerializableCitation } from "./schema"; import { TYPE_ICONS } from "./type-icons"; const FALLBACK_LOCALE = "en-US"; function extractDomain(url: string): string | undefined { try { const urlObj = new URL(url); return urlObj.hostname.replace(/^www\./, ""); } catch { return undefined; } } function formatDate(isoString: string, locale: string): string { try { const date = new Date(isoString); return date.toLocaleDateString(locale, { year: "numeric", month: "short", }); } catch { return isoString; } } export interface CitationProps extends SerializableCitation { variant?: CitationVariant; className?: string; onNavigate?: (href: string, citation: SerializableCitation) => void; } export function Citation(props: CitationProps) { const { variant = "default", className, onNavigate, ...serializable } = props; const { id, href: rawHref, title, snippet, domain: providedDomain, favicon, author, publishedAt, type = "webpage", locale: providedLocale, } = serializable; const locale = providedLocale ?? FALLBACK_LOCALE; const sanitizedHref = sanitizeHref(rawHref); const domain = providedDomain ?? extractDomain(rawHref); const citationData: SerializableCitation = { ...serializable, href: sanitizedHref ?? rawHref, domain, locale, }; const TypeIcon = TYPE_ICONS[type] ?? Globe; const handleClick = () => { if (!sanitizedHref) return; if (onNavigate) { onNavigate(sanitizedHref, citationData); } else { openSafeNavigationHref(sanitizedHref); } }; const iconElement = favicon ? (