77 lines
3.3 KiB
TypeScript
77 lines
3.3 KiB
TypeScript
import { memo } from "react";
|
|
import ReactMarkdown from "react-markdown";
|
|
|
|
interface MarkdownPreviewProps {
|
|
content: string;
|
|
className?: string;
|
|
}
|
|
|
|
function MarkdownPreview({ content, className = "" }: MarkdownPreviewProps) {
|
|
return (
|
|
<div className={`min-h-24 max-h-96 overflow-y-auto p-4 prose prose-sm max-w-none ${className}`}>
|
|
<ReactMarkdown
|
|
components={{
|
|
h1: ({ children }) => <h1 className="text-2xl font-bold mt-4 mb-2">{children}</h1>,
|
|
h2: ({ children }) => <h2 className="text-xl font-bold mt-3 mb-2">{children}</h2>,
|
|
h3: ({ children }) => <h3 className="text-lg font-bold mt-3 mb-2">{children}</h3>,
|
|
h4: ({ children }) => <h4 className="text-base font-bold mt-2 mb-1">{children}</h4>,
|
|
h5: ({ children }) => <h5 className="text-sm font-bold mt-2 mb-1">{children}</h5>,
|
|
h6: ({ children }) => <h6 className="text-xs font-bold mt-2 mb-1">{children}</h6>,
|
|
p: ({ children }) => <p className="mb-2">{children}</p>,
|
|
ul: ({ children }) => <ul className="list-disc list-inside mb-2 ml-4">{children}</ul>,
|
|
ol: ({ children }) => <ol className="list-decimal list-inside mb-2 ml-4">{children}</ol>,
|
|
li: ({ children }) => <li className="mb-1">{children}</li>,
|
|
blockquote: ({ children }) => (
|
|
<blockquote className="border-l-4 border-gray-300 pl-4 italic my-2">{children}</blockquote>
|
|
),
|
|
code: ({ className, children, ...props }) => {
|
|
const isInline = !className;
|
|
return isInline ? (
|
|
<code className="bg-gray-100 px-1 py-0.5 rounded text-sm font-mono" {...props}>
|
|
{children}
|
|
</code>
|
|
) : (
|
|
<code className="block bg-gray-100 p-2 rounded text-sm font-mono overflow-x-auto" {...props}>
|
|
{children}
|
|
</code>
|
|
);
|
|
},
|
|
pre: ({ children }) => (
|
|
<pre className="bg-gray-100 p-2 rounded text-sm font-mono overflow-x-auto mb-2">
|
|
{children}
|
|
</pre>
|
|
),
|
|
a: ({ href, children }) => (
|
|
<a href={href} className="text-blue-600 hover:underline" target="_blank" rel="noopener noreferrer">
|
|
{children}
|
|
</a>
|
|
),
|
|
strong: ({ children }) => <strong className="font-bold">{children}</strong>,
|
|
em: ({ children }) => <em className="italic">{children}</em>,
|
|
hr: () => <hr className="my-4 border-gray-300" />,
|
|
table: ({ children }) => (
|
|
<div className="overflow-x-auto my-2">
|
|
<table className="min-w-full border border-gray-300">{children}</table>
|
|
</div>
|
|
),
|
|
thead: ({ children }) => <thead className="bg-gray-100">{children}</thead>,
|
|
tbody: ({ children }) => <tbody>{children}</tbody>,
|
|
tr: ({ children }) => <tr className="border-b border-gray-300">{children}</tr>,
|
|
th: ({ children }) => (
|
|
<th className="border border-gray-300 px-4 py-2 text-left font-bold">
|
|
{children}
|
|
</th>
|
|
),
|
|
td: ({ children }) => (
|
|
<td className="border border-gray-300 px-4 py-2">{children}</td>
|
|
),
|
|
}}
|
|
>
|
|
{content}
|
|
</ReactMarkdown>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default memo(MarkdownPreview);
|
|
|