"use client"; import { api } from "@/lib/api"; import { useChatStore } from "@/lib/chatStore"; import { useQuery } from "@tanstack/react-query"; import clsx from "clsx"; import { useEffect } from "react"; import ReactMarkdown from "react-markdown"; /** * View-source drawer. Shown when the user clicks a source chip or an inline * citation. Renders the full markdown of a doc, plus the option to "Pin this * source" — which scopes follow-up questions to that doc via /ask. */ export function SourceDrawer({ open, docId, docName, onClose, }: { open: boolean; docId: string | null; docName?: string | null; onClose: () => void; }) { const activeId = useChatStore((s) => s.activeId); const conv = useChatStore((s) => (s.activeId ? s.conversations[s.activeId] : null)); const pinDoc = useChatStore((s) => s.pinDoc); const newConversationPinned = useChatStore((s) => s.newConversationPinned); const { data, isLoading, error } = useQuery({ queryKey: ["doc-content", docId], queryFn: () => api.getDocumentContent(docId as string), enabled: open && !!docId, staleTime: 60_000, }); // ESC to close useEffect(() => { if (!open) return; const onKey = (e: KeyboardEvent) => { if (e.key === "Escape") onClose(); }; window.addEventListener("keydown", onKey); return () => window.removeEventListener("keydown", onKey); }, [open, onClose]); const isPinned = conv?.pinnedDocId === docId; const cleanName = (n: string | null | undefined) => (n ?? "").replace(/_\d{6,}$/, ""); const displayName = data?.name ? cleanName(data.name) : cleanName(docName); const handlePin = () => { if (!docId || !activeId) return; if (isPinned) pinDoc(activeId, null, null); else pinDoc(activeId, docId, data?.name ?? docName ?? null); }; const handleNewScoped = () => { if (!docId) return; newConversationPinned(docId, data?.name ?? docName ?? ""); onClose(); }; return ( <> {/* Scrim */}
> ); }