mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-29 06:35:24 +00:00
123 lines
4.5 KiB
TypeScript
123 lines
4.5 KiB
TypeScript
import React from "react";
|
|
import ReactMarkdown from "react-markdown";
|
|
import remarkGfm from "remark-gfm";
|
|
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
|
|
import { oneDark as syntaxTheme } from "react-syntax-highlighter/dist/esm/styles/prism";
|
|
|
|
interface MarkdownRendererProps {
|
|
content: string;
|
|
compact?: boolean;
|
|
}
|
|
|
|
export function MarkdownRenderer({
|
|
content,
|
|
compact = false,
|
|
}: MarkdownRendererProps) {
|
|
const h1Class = compact
|
|
? "text-2xl font-bold mb-4 mt-6 text-foreground border-b border-border pb-2"
|
|
: "text-3xl font-bold mb-6 mt-8 text-foreground border-b border-border pb-2";
|
|
const h2Class = compact
|
|
? "text-xl font-semibold mb-3 mt-5 text-foreground border-b border-border pb-1"
|
|
: "text-2xl font-semibold mb-4 mt-6 text-foreground border-b border-border pb-1";
|
|
const h3Class = compact
|
|
? "text-lg font-semibold mb-2 mt-4 text-foreground"
|
|
: "text-xl font-semibold mb-3 mt-4 text-foreground";
|
|
const h4Class = compact
|
|
? "text-base font-semibold mb-2 mt-3 text-foreground"
|
|
: "text-lg font-semibold mb-2 mt-3 text-foreground";
|
|
const pClass = compact
|
|
? "mb-3 text-foreground leading-relaxed"
|
|
: "mb-4 text-foreground leading-relaxed";
|
|
const listClass = compact
|
|
? "mb-3 ml-4 text-foreground"
|
|
: "mb-4 ml-6 text-foreground";
|
|
const quoteClass = compact
|
|
? "border-l-4 border-blue-500 pl-3 mb-3 italic text-muted-foreground bg-muted/30 py-1"
|
|
: "border-l-4 border-blue-500 pl-4 mb-4 italic text-muted-foreground bg-muted/30 py-2";
|
|
const tableWrapClass = compact
|
|
? "mb-3 overflow-x-auto thin-scrollbar"
|
|
: "mb-4 overflow-x-auto thin-scrollbar";
|
|
const tableClass = compact
|
|
? "min-w-full border border-border rounded-lg text-sm"
|
|
: "min-w-full border border-border rounded-lg";
|
|
const thClass = compact
|
|
? "px-3 py-2 text-left font-semibold text-foreground"
|
|
: "px-4 py-2 text-left font-semibold text-foreground";
|
|
const tdClass = compact
|
|
? "px-3 py-2 text-foreground"
|
|
: "px-4 py-2 text-foreground";
|
|
|
|
return (
|
|
<ReactMarkdown
|
|
remarkPlugins={[remarkGfm]}
|
|
components={{
|
|
code({ className, children, ...props }) {
|
|
const match = /language-(\w+)/.exec(className || "");
|
|
// v9 removed the `inline` flag; a fenced block always carries a
|
|
// language- class, an inline span never does.
|
|
const inline = !className;
|
|
return !inline && match ? (
|
|
<SyntaxHighlighter
|
|
style={syntaxTheme}
|
|
language={match[1]}
|
|
PreTag="div"
|
|
className="rounded-lg"
|
|
{...props}
|
|
>
|
|
{String(children).replace(/\n$/, "")}
|
|
</SyntaxHighlighter>
|
|
) : (
|
|
<code
|
|
className="bg-muted px-1 py-0.5 rounded text-sm font-mono"
|
|
{...props}
|
|
>
|
|
{children}
|
|
</code>
|
|
);
|
|
},
|
|
h1: ({ children }) => <h1 className={h1Class}>{children}</h1>,
|
|
h2: ({ children }) => <h2 className={h2Class}>{children}</h2>,
|
|
h3: ({ children }) => <h3 className={h3Class}>{children}</h3>,
|
|
h4: ({ children }) => <h4 className={h4Class}>{children}</h4>,
|
|
p: ({ children }) => <p className={pClass}>{children}</p>,
|
|
ul: ({ children }) => (
|
|
<ul className={`${listClass} list-disc`}>{children}</ul>
|
|
),
|
|
ol: ({ children }) => (
|
|
<ol className={`${listClass} list-decimal`}>{children}</ol>
|
|
),
|
|
li: ({ children }) => (
|
|
<li className="mb-1 text-foreground">{children}</li>
|
|
),
|
|
blockquote: ({ children }) => (
|
|
<blockquote className={quoteClass}>{children}</blockquote>
|
|
),
|
|
table: ({ children }) => (
|
|
<div className={tableWrapClass}>
|
|
<table className={tableClass}>{children}</table>
|
|
</div>
|
|
),
|
|
thead: ({ children }) => <thead className="bg-muted">{children}</thead>,
|
|
tbody: ({ children }) => <tbody>{children}</tbody>,
|
|
tr: ({ children }) => (
|
|
<tr className="border-b border-border">{children}</tr>
|
|
),
|
|
th: ({ children }) => <th className={thClass}>{children}</th>,
|
|
td: ({ children }) => <td className={tdClass}>{children}</td>,
|
|
a: ({ href, children }) => (
|
|
<a
|
|
href={href}
|
|
target="_blank"
|
|
rel="noopener noreferrer"
|
|
className="text-blue-600 hover:text-blue-800 underline"
|
|
>
|
|
{children}
|
|
</a>
|
|
),
|
|
}}
|
|
>
|
|
{content}
|
|
</ReactMarkdown>
|
|
);
|
|
}
|