156 lines
7.2 KiB
TypeScript
156 lines
7.2 KiB
TypeScript
"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 { TextBlock } from "@/types/page";
|
|
|
|
export default function TextBlockView(props: TextBlock) {
|
|
return (
|
|
<article className="prose prose-gray max-w-none dark:prose-invert">
|
|
<div className="text-gray-700 dark:text-gray-300 leading-relaxed">
|
|
<ReactMarkdown
|
|
remarkPlugins={[remarkGfm, remarkMath]}
|
|
rehypePlugins={[rehypeKatex, rehypePrism]}
|
|
components={{
|
|
// 自定义代码块样式
|
|
code({ inline, className, children, ...props }: any) {
|
|
const match = /language-(\w+)/.exec(className || '');
|
|
return !inline && match ? (
|
|
<pre className="bg-gray-100 dark:bg-gray-800 rounded-lg p-4 overflow-x-auto">
|
|
<code className={className} {...props}>
|
|
{children}
|
|
</code>
|
|
</pre>
|
|
) : (
|
|
<code className="bg-gray-100 dark:bg-gray-700 px-1 py-0.5 rounded text-sm" {...props}>
|
|
{children}
|
|
</code>
|
|
);
|
|
},
|
|
// 自定义链接样式
|
|
a({ href, children }: any) {
|
|
return (
|
|
<a
|
|
href={href}
|
|
className="text-blue-600 dark:text-blue-400 hover:underline transition-colors"
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
>
|
|
{children}
|
|
</a>
|
|
);
|
|
},
|
|
// 自定义表格样式
|
|
table({ children }: any) {
|
|
return (
|
|
<div className="overflow-x-auto">
|
|
<table className="min-w-full border-collapse border border-gray-300 dark:border-gray-600">
|
|
{children}
|
|
</table>
|
|
</div>
|
|
);
|
|
},
|
|
th({ children }: any) {
|
|
return (
|
|
<th className="border border-gray-300 dark:border-gray-600 px-4 py-2 bg-gray-100 dark:bg-gray-700 font-semibold">
|
|
{children}
|
|
</th>
|
|
);
|
|
},
|
|
td({ children }: any) {
|
|
return (
|
|
<td className="border border-gray-300 dark:border-gray-600 px-4 py-2">
|
|
{children}
|
|
</td>
|
|
);
|
|
},
|
|
// 自定义引用样式
|
|
blockquote({ children }: any) {
|
|
return (
|
|
<blockquote className="border-l-4 border-blue-500 pl-4 py-2 bg-blue-50 dark:bg-blue-900/20 italic">
|
|
{children}
|
|
</blockquote>
|
|
);
|
|
},
|
|
// 自定义列表样式
|
|
ul({ children }: any) {
|
|
return (
|
|
<ul className="list-disc list-inside space-y-1">
|
|
{children}
|
|
</ul>
|
|
);
|
|
},
|
|
ol({ children }: any) {
|
|
return (
|
|
<ol className="list-decimal list-inside space-y-1">
|
|
{children}
|
|
</ol>
|
|
);
|
|
},
|
|
// 自定义标题样式
|
|
h1({ children }: any) {
|
|
return (
|
|
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-4 mt-6">
|
|
{children}
|
|
</h1>
|
|
);
|
|
},
|
|
h2({ children }: any) {
|
|
return (
|
|
<h2 className="text-2xl font-bold text-gray-900 dark:text-gray-100 mb-3 mt-5">
|
|
{children}
|
|
</h2>
|
|
);
|
|
},
|
|
h3({ children }: any) {
|
|
return (
|
|
<h3 className="text-xl font-bold text-gray-900 dark:text-gray-100 mb-2 mt-4">
|
|
{children}
|
|
</h3>
|
|
);
|
|
},
|
|
h4({ children }: any) {
|
|
return (
|
|
<h4 className="text-lg font-bold text-gray-900 dark:text-gray-100 mb-2 mt-3">
|
|
{children}
|
|
</h4>
|
|
);
|
|
},
|
|
h5({ children }: any) {
|
|
return (
|
|
<h5 className="text-base font-bold text-gray-900 dark:text-gray-100 mb-1 mt-2">
|
|
{children}
|
|
</h5>
|
|
);
|
|
},
|
|
h6({ children }: any) {
|
|
return (
|
|
<h6 className="text-sm font-bold text-gray-900 dark:text-gray-100 mb-1 mt-2">
|
|
{children}
|
|
</h6>
|
|
);
|
|
},
|
|
// 自定义段落样式
|
|
p({ children }: any) {
|
|
return (
|
|
<p className="mb-4 leading-relaxed">
|
|
{children}
|
|
</p>
|
|
);
|
|
},
|
|
// 自定义分割线样式
|
|
hr() {
|
|
return (
|
|
<hr className="my-8 border-gray-300 dark:border-gray-600" />
|
|
);
|
|
}
|
|
}}
|
|
>
|
|
{props.markdown}
|
|
</ReactMarkdown>
|
|
</div>
|
|
</article>
|
|
);
|
|
}
|