Spaces:
Sleeping
Sleeping
| "use client"; | |
| import ReactMarkdown from "react-markdown"; | |
| import remarkGfm from "remark-gfm"; | |
| import remarkMath from "remark-math"; | |
| import rehypeKatex from "rehype-katex"; | |
| import rehypePrism from "rehype-prism-plus"; | |
| import type { Components } from "react-markdown"; | |
| import { cn } from "@/lib/utils"; | |
| interface MarkdownProps { | |
| children: string; | |
| className?: string; | |
| } | |
| export function Markdown({ children, className }: MarkdownProps) { | |
| const normalizeMathDelimiters = (src: string) => { | |
| const segments = src.split(/(```[\s\S]*?```)/g); | |
| return segments | |
| .map((seg) => (seg.startsWith("```") ? seg : seg.replace(/\$\$\$/g, "$$"))) | |
| .join(""); | |
| }; | |
| const content = normalizeMathDelimiters(children); | |
| const components: Components = { | |
| pre: ({ children, ...props }) => ( | |
| <pre {...props} className={cn("code-block", (props as any).className)}> | |
| {children} | |
| </pre> | |
| ), | |
| code: ({ children, className: codeClassName, ...props }) => { | |
| const isInline = !codeClassName; | |
| if (isInline) { | |
| return ( | |
| <code {...props} className={cn("inline-code", (props as any).className)}> | |
| {children} | |
| </code> | |
| ); | |
| } | |
| return ( | |
| <code {...props} className={codeClassName}> | |
| {children} | |
| </code> | |
| ); | |
| }, | |
| p: ({ children }) => <p>{children}</p>, | |
| ul: ({ children }) => <ul>{children}</ul>, | |
| ol: ({ children }) => <ol>{children}</ol>, | |
| li: ({ children }) => <li>{children}</li>, | |
| h1: ({ children }) => <h1>{children}</h1>, | |
| h2: ({ children }) => <h2>{children}</h2>, | |
| h3: ({ children }) => <h3>{children}</h3>, | |
| h4: ({ children }) => <h4>{children}</h4>, | |
| blockquote: ({ children }) => <blockquote>{children}</blockquote>, | |
| a: ({ children, href }) => ( | |
| <a href={href} target="_blank" rel="noopener noreferrer"> | |
| {children} | |
| </a> | |
| ), | |
| strong: ({ children }) => <strong>{children}</strong>, | |
| em: ({ children }) => <em>{children}</em>, | |
| hr: () => <hr />, | |
| table: ({ children }) => ( | |
| <div className="table-wrapper"> | |
| <table>{children}</table> | |
| </div> | |
| ), | |
| thead: ({ children }) => <thead>{children}</thead>, | |
| tbody: ({ children }) => <tbody>{children}</tbody>, | |
| tr: ({ children }) => <tr>{children}</tr>, | |
| th: ({ children }) => <th>{children}</th>, | |
| td: ({ children }) => <td>{children}</td>, | |
| }; | |
| return ( | |
| <ReactMarkdown | |
| className={cn("markdown-content", className)} | |
| remarkPlugins={[remarkGfm, remarkMath]} | |
| rehypePlugins={[rehypeKatex, rehypePrism]} | |
| components={components} | |
| > | |
| {content} | |
| </ReactMarkdown> | |
| ); | |
| } | |