import { Check, Copy } from "lucide-react"; import Image from "next/image"; import { useTheme } from "next-themes"; import React, { useEffect, useMemo, useRef, useState } from "react"; import ReactMarkdown from "react-markdown"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { oneDark, oneLight } from "react-syntax-highlighter/dist/cjs/styles/prism"; import rehypeRaw from "rehype-raw"; import rehypeSanitize from "rehype-sanitize"; import remarkGfm from "remark-gfm"; import { Button } from "@/components/ui/button"; import { cn } from "@/lib/utils"; import { Citation } from "./chat/Citation"; import type { Source } from "./chat/types"; import CopyButton from "./copy-button"; interface MarkdownViewerProps { content: string; className?: string; getCitationSource?: (id: number) => Source | null; type?: "user" | "ai"; } export function MarkdownViewer({ content, className, getCitationSource, type = "user", }: MarkdownViewerProps) { const ref = useRef(null); // Memoize the markdown components to prevent unnecessary re-renders const components = useMemo(() => { return { // Define custom components for markdown elements p: ({ node, children, ...props }: any) => { // If there's no getCitationSource function, just render normally if (!getCitationSource) { return (

{children}

); } // Process citations within paragraph content return (

{processCitationsInReactChildren(children, getCitationSource)}

); }, a: ({ node, children, ...props }: any) => { // Process citations within link content if needed const processedChildren = getCitationSource ? processCitationsInReactChildren(children, getCitationSource) : children; return ( {processedChildren} ); }, li: ({ node, children, ...props }: any) => { // Process citations within list item content const processedChildren = getCitationSource ? processCitationsInReactChildren(children, getCitationSource) : children; return
  • {processedChildren}
  • ; }, ul: ({ node, ...props }: any) =>