"use client"; import React, { useState } from "react"; import { Check, Copy } from "lucide-react"; import ReactMarkdown from "react-markdown"; import type { PluggableList } from "unified"; import remarkGfm from "remark-gfm"; import rehypeRaw from "rehype-raw"; import rehypeSanitize from "rehype-sanitize"; import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism"; import { extractMarkdownHeadings } from "@/lib/markdown-headings"; import { cn } from "@/lib/utils"; type MarkdownSize = "sm" | "base" | "lg"; type MarkdownProps = { content?: string; allowHtml?: boolean; className?: string; dir?: "rtl" | "ltr"; justify?: boolean; size?: MarkdownSize; }; function CodeBlock({ className, children, }: { className?: string; children: React.ReactNode; }) { const [copied, setCopied] = useState(false); const language = /language-([\w-]+)/.exec(className || "")?.[1] || "text"; const code = String(children).replace(/\n$/, ""); const copyCode = async () => { if (!navigator.clipboard) return; await navigator.clipboard.writeText(code); setCopied(true); window.setTimeout(() => setCopied(false), 1600); }; return (
{language}
{code}
); } export default function Markdown({ content = "", allowHtml = false, className = "", dir = "rtl", justify = false, size = "sm", }: MarkdownProps) { const rehypePlugins: PluggableList | undefined = allowHtml ? [rehypeRaw, rehypeSanitize] : undefined; const headings = extractMarkdownHeadings(content); let headingIndex = 0; const baseSizeClass = size === "sm" ? "text-sm" : size === "lg" ? "text-lg" : "text-base"; const hScale = size === "sm" ? { h1: "text-xl", h2: "text-lg", h3: "text-base", h4: "text-base" } : size === "base" ? { h1: "text-3xl", h2: "text-2xl", h3: "text-xl", h4: "text-lg" } : { h1: "text-4xl", h2: "text-3xl", h3: "text-2xl", h4: "text-xl" }; const justifyStyle: React.CSSProperties | undefined = justify ? { textAlign: "justify", textJustify: "inter-word" } : undefined; const nextHeadingId = (level: 1 | 2 | 3) => { while (headingIndex < headings.length) { const heading = headings[headingIndex]; headingIndex += 1; if (heading.level === level) return heading.id; } return undefined; }; return (

, h2: (p) =>

, h3: (p) =>

, h4: (p) =>

, p: (p) =>

, a: (p) => , ul: (p) =>