mirror of
https://github.com/tiennm99/DocsGPT.git
synced 2026-10-12 16:15:14 +00:00
chore(deps): react-markdown 10
react-markdown 10 removed the `className` prop and no longer renders a wrapper element; passing className now throws at render time. Each of the three call sites gets an explicit wrapping div carrying the same classes, which reproduces the v9 DOM exactly. The large diff is re-indentation from the added wrapper. `git diff -w` shows the only substantive change per file is the moved className. Fixes the 19 tests that failed on the upgrade. 598 tests pass, build clean, lint unchanged.
This commit is contained in:
1 parent
cf1c9d542d
commit
6319b25b56
5 files changed
+334
-329
No files matched your search
Generated
+4
-4
@@ -36,7 +36,7 @@
|
||||
"react-force-graph-2d": "^1.29.1",
|
||||
"react-google-drive-picker": "^1.2.2",
|
||||
"react-i18next": "^17.0.13",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-redux": "^9.3.0",
|
||||
"react-router-dom": "^7.18.3",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
@@ -10425,9 +10425,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-markdown": {
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-9.1.0.tgz",
|
||||
"integrity": "sha512-xaijuJB0kzGiUdG7nc2MOMDUDBWPyGAjZtUrow9XxUeua8IqeP+VlIfAZ3bphpcLTnSZXz6z9jcVC/TCwbfgdw==",
|
||||
"version": "10.1.0",
|
||||
"resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-10.1.0.tgz",
|
||||
"integrity": "sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/hast": "^3.0.0",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
"react-force-graph-2d": "^1.29.1",
|
||||
"react-google-drive-picker": "^1.2.2",
|
||||
"react-i18next": "^17.0.13",
|
||||
"react-markdown": "^9.1.0",
|
||||
"react-markdown": "^10.1.0",
|
||||
"react-redux": "^9.3.0",
|
||||
"react-router-dom": "^7.18.3",
|
||||
"react-syntax-highlighter": "^16.1.1",
|
||||
|
||||
@@ -165,105 +165,106 @@ function NoteView({ data }: { data: NoteArtifactData }) {
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
{data.content ? (
|
||||
<ReactMarkdown
|
||||
className="flex flex-col gap-3 text-sm leading-normal wrap-break-word whitespace-pre-wrap text-gray-800 dark:text-gray-200"
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
code(props) {
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
node: _node,
|
||||
ref: _ref,
|
||||
...rest
|
||||
} = props;
|
||||
void _node;
|
||||
void _ref;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const language = match ? match[1] : '';
|
||||
<div className="flex flex-col gap-3 text-sm leading-normal wrap-break-word whitespace-pre-wrap text-gray-800 dark:text-gray-200">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
code(props) {
|
||||
const {
|
||||
children,
|
||||
className,
|
||||
node: _node,
|
||||
ref: _ref,
|
||||
...rest
|
||||
} = props;
|
||||
void _node;
|
||||
void _ref;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const language = match ? match[1] : '';
|
||||
|
||||
return match ? (
|
||||
<div className="group border-border relative my-2 overflow-hidden rounded-xl border">
|
||||
<div className="bg-muted flex items-center justify-between px-2 py-1">
|
||||
<span className="text-foreground dark:text-foreground text-xs font-medium">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(/\n$/, '')}
|
||||
/>
|
||||
return match ? (
|
||||
<div className="group border-border relative my-2 overflow-hidden rounded-xl border">
|
||||
<div className="bg-muted flex items-center justify-between px-2 py-1">
|
||||
<span className="text-foreground dark:text-foreground text-xs font-medium">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(/\n$/, '')}
|
||||
/>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={isDarkTheme ? vscDarkPlus : oneLight}
|
||||
customStyle={{
|
||||
margin: 0,
|
||||
borderRadius: 0,
|
||||
scrollbarWidth: 'thin',
|
||||
}}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
) : (
|
||||
<code
|
||||
className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal"
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={isDarkTheme ? vscDarkPlus : oneLight}
|
||||
customStyle={{
|
||||
margin: 0,
|
||||
borderRadius: 0,
|
||||
scrollbarWidth: 'thin',
|
||||
}}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
) : (
|
||||
<code
|
||||
className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal"
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul className="list-inside list-disc pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol className="list-inside list-decimal pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
a({ children, href }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
p({ children }) {
|
||||
return <p className="whitespace-pre-wrap">{children}</p>;
|
||||
},
|
||||
h1({ children }) {
|
||||
return <h1 className="text-xl font-bold">{children}</h1>;
|
||||
},
|
||||
h2({ children }) {
|
||||
return <h2 className="text-lg font-bold">{children}</h2>;
|
||||
},
|
||||
h3({ children }) {
|
||||
return <h3 className="text-base font-bold">{children}</h3>;
|
||||
},
|
||||
blockquote({ children }) {
|
||||
return (
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic dark:border-gray-600">
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{data.content}
|
||||
</ReactMarkdown>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul className="list-inside list-disc pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol className="list-inside list-decimal pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
a({ children, href }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
p({ children }) {
|
||||
return <p className="whitespace-pre-wrap">{children}</p>;
|
||||
},
|
||||
h1({ children }) {
|
||||
return <h1 className="text-xl font-bold">{children}</h1>;
|
||||
},
|
||||
h2({ children }) {
|
||||
return <h2 className="text-lg font-bold">{children}</h2>;
|
||||
},
|
||||
h3({ children }) {
|
||||
return <h3 className="text-base font-bold">{children}</h3>;
|
||||
},
|
||||
blockquote({ children }) {
|
||||
return (
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic dark:border-gray-600">
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{data.content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">Empty note</p>
|
||||
)}
|
||||
|
||||
@@ -9,66 +9,67 @@ import remarkGfm from 'remark-gfm';
|
||||
export default function MarkdownPreview({ content }: { content: string }) {
|
||||
return (
|
||||
<div className="h-full overflow-auto p-4">
|
||||
<ReactMarkdown
|
||||
className="flex flex-col gap-3 text-sm leading-normal break-words whitespace-pre-wrap text-gray-800 dark:text-gray-200"
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
a({ children, href }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul className="list-inside list-disc pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol className="list-inside list-decimal pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
h1({ children }) {
|
||||
return <h1 className="text-xl font-bold">{children}</h1>;
|
||||
},
|
||||
h2({ children }) {
|
||||
return <h2 className="text-lg font-bold">{children}</h2>;
|
||||
},
|
||||
h3({ children }) {
|
||||
return <h3 className="text-base font-bold">{children}</h3>;
|
||||
},
|
||||
code({ children, ...rest }) {
|
||||
return (
|
||||
<code
|
||||
className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal"
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
blockquote({ children }) {
|
||||
return (
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic dark:border-gray-600">
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
<div className="flex flex-col gap-3 text-sm leading-normal break-words whitespace-pre-wrap text-gray-800 dark:text-gray-200">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm]}
|
||||
components={{
|
||||
a({ children, href }) {
|
||||
return (
|
||||
<a
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-blue-600 hover:underline dark:text-blue-400"
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul className="list-inside list-disc pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol className="list-inside list-decimal pl-4 whitespace-normal">
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
h1({ children }) {
|
||||
return <h1 className="text-xl font-bold">{children}</h1>;
|
||||
},
|
||||
h2({ children }) {
|
||||
return <h2 className="text-lg font-bold">{children}</h2>;
|
||||
},
|
||||
h3({ children }) {
|
||||
return <h3 className="text-base font-bold">{children}</h3>;
|
||||
},
|
||||
code({ children, ...rest }) {
|
||||
return (
|
||||
<code
|
||||
className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal"
|
||||
{...rest}
|
||||
>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
blockquote({ children }) {
|
||||
return (
|
||||
<blockquote className="border-l-4 border-gray-300 pl-4 italic dark:border-gray-600">
|
||||
{children}
|
||||
</blockquote>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -184,177 +184,180 @@ export default function MarkdownAnswer({
|
||||
{contentSegments.map((segment, index) => (
|
||||
<Fragment key={index}>
|
||||
{segment.type === 'text' ? (
|
||||
<ReactMarkdown
|
||||
className="fade-in flex flex-col gap-3 leading-normal wrap-break-word whitespace-pre-wrap"
|
||||
remarkPlugins={[
|
||||
remarkGfm,
|
||||
[remarkMath, { singleDollarTextMath: false }],
|
||||
]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
urlTransform={sandboxUrlTransform}
|
||||
components={{
|
||||
a({ href, children }) {
|
||||
// A generated file is already on the turn as a download
|
||||
// chip, but the model links it with a `sandbox:`/`artifact:`
|
||||
// URL no browser can open. Point the link at the chip
|
||||
// instead, and never leave a dead anchor behind.
|
||||
const sandboxLink = resolveSandboxLink(
|
||||
href,
|
||||
artifacts,
|
||||
turnArtifacts,
|
||||
);
|
||||
if (sandboxLink.kind === 'plain') {
|
||||
return <>{children}</>;
|
||||
}
|
||||
if (sandboxLink.kind === 'artifact') {
|
||||
return renderArtifactChip(sandboxLink.artifact, children);
|
||||
}
|
||||
if (href?.startsWith('#cite-')) {
|
||||
const num = href.replace('#cite-', '');
|
||||
const sourceIdx = parseInt(num, 10) - 1;
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const el = document.getElementById(
|
||||
`source-${sourceIdx}`,
|
||||
);
|
||||
if (el) {
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
el.classList.add('ring-2', 'ring-purple-500');
|
||||
setTimeout(
|
||||
() =>
|
||||
el.classList.remove(
|
||||
'ring-2',
|
||||
'ring-purple-500',
|
||||
),
|
||||
2000,
|
||||
<div className="fade-in flex flex-col gap-3 leading-normal wrap-break-word whitespace-pre-wrap">
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[
|
||||
remarkGfm,
|
||||
[remarkMath, { singleDollarTextMath: false }],
|
||||
]}
|
||||
rehypePlugins={[rehypeKatex]}
|
||||
urlTransform={sandboxUrlTransform}
|
||||
components={{
|
||||
a({ href, children }) {
|
||||
// A generated file is already on the turn as a download
|
||||
// chip, but the model links it with a `sandbox:`/`artifact:`
|
||||
// URL no browser can open. Point the link at the chip
|
||||
// instead, and never leave a dead anchor behind.
|
||||
const sandboxLink = resolveSandboxLink(
|
||||
href,
|
||||
artifacts,
|
||||
turnArtifacts,
|
||||
);
|
||||
if (sandboxLink.kind === 'plain') {
|
||||
return <>{children}</>;
|
||||
}
|
||||
if (sandboxLink.kind === 'artifact') {
|
||||
return renderArtifactChip(sandboxLink.artifact, children);
|
||||
}
|
||||
if (href?.startsWith('#cite-')) {
|
||||
const num = href.replace('#cite-', '');
|
||||
const sourceIdx = parseInt(num, 10) - 1;
|
||||
return (
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const el = document.getElementById(
|
||||
`source-${sourceIdx}`,
|
||||
);
|
||||
}
|
||||
}}
|
||||
className="mx-0.5 h-5 min-w-5 rounded-full bg-purple-100 px-1.5 text-xs font-semibold text-purple-700 hover:bg-purple-200 dark:bg-purple-900/40 dark:text-purple-300 dark:hover:bg-purple-900/60"
|
||||
title={`Jump to source ${num}`}
|
||||
>
|
||||
{num}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
img({ src, alt }) {
|
||||
// `` is how a model
|
||||
// announces a plot it produced. react-markdown runs
|
||||
// urlTransform over `src` too, so without this the invented
|
||||
// scheme survives and renders a broken-image box beside the
|
||||
// chip that opens the very same file.
|
||||
const source = typeof src === 'string' ? src : undefined;
|
||||
const sandboxLink = resolveSandboxLink(
|
||||
source,
|
||||
artifacts,
|
||||
turnArtifacts,
|
||||
);
|
||||
if (sandboxLink.kind === 'artifact') {
|
||||
const { artifact } = sandboxLink;
|
||||
return renderArtifactChip(
|
||||
artifact,
|
||||
alt || artifact.label || 'Open file',
|
||||
);
|
||||
}
|
||||
if (sandboxLink.kind === 'plain') {
|
||||
return <>{alt ?? ''}</>;
|
||||
}
|
||||
return <img src={source} alt={alt} className="max-w-full" />;
|
||||
},
|
||||
code(props) {
|
||||
const { children, className, node, ref, ...rest } = props;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const language = match ? match[1] : '';
|
||||
|
||||
return match ? (
|
||||
<div className="group border-border relative overflow-hidden rounded-xl border">
|
||||
<div className="bg-muted flex items-center justify-between px-2 py-1">
|
||||
<span className="text-foreground dark:text-foreground text-xs font-medium">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(/\n$/, '')}
|
||||
/>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={isDarkTheme ? vscDarkPlus : oneLight}
|
||||
className="mt-0!"
|
||||
customStyle={{ margin: 0, borderRadius: 0 }}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
) : (
|
||||
<code className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul
|
||||
className={`list-inside list-disc pl-4 whitespace-normal ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol
|
||||
className={`list-inside list-decimal pl-4 whitespace-normal ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
table({ children }) {
|
||||
return (
|
||||
<div className="border-border relative overflow-x-auto rounded-lg border">
|
||||
<table className="dark:text-foreground w-full text-left text-gray-700">
|
||||
if (el) {
|
||||
el.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'center',
|
||||
});
|
||||
el.classList.add('ring-2', 'ring-purple-500');
|
||||
setTimeout(
|
||||
() =>
|
||||
el.classList.remove(
|
||||
'ring-2',
|
||||
'ring-purple-500',
|
||||
),
|
||||
2000,
|
||||
);
|
||||
}
|
||||
}}
|
||||
className="mx-0.5 h-5 min-w-5 rounded-full bg-purple-100 px-1.5 text-xs font-semibold text-purple-700 hover:bg-purple-200 dark:bg-purple-900/40 dark:text-purple-300 dark:hover:bg-purple-900/60"
|
||||
title={`Jump to source ${num}`}
|
||||
>
|
||||
{num}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="bg-muted text-foreground text-xs uppercase">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
return (
|
||||
<tr className="border-border odd:bg-card even:bg-muted border-b">
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
th({ children }) {
|
||||
return <th className="px-6 py-3">{children}</th>;
|
||||
},
|
||||
td({ children }) {
|
||||
return <td className="px-6 py-3">{children}</td>;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{segment.content}
|
||||
</ReactMarkdown>
|
||||
</a>
|
||||
);
|
||||
},
|
||||
img({ src, alt }) {
|
||||
// `` is how a model
|
||||
// announces a plot it produced. react-markdown runs
|
||||
// urlTransform over `src` too, so without this the invented
|
||||
// scheme survives and renders a broken-image box beside the
|
||||
// chip that opens the very same file.
|
||||
const source = typeof src === 'string' ? src : undefined;
|
||||
const sandboxLink = resolveSandboxLink(
|
||||
source,
|
||||
artifacts,
|
||||
turnArtifacts,
|
||||
);
|
||||
if (sandboxLink.kind === 'artifact') {
|
||||
const { artifact } = sandboxLink;
|
||||
return renderArtifactChip(
|
||||
artifact,
|
||||
alt || artifact.label || 'Open file',
|
||||
);
|
||||
}
|
||||
if (sandboxLink.kind === 'plain') {
|
||||
return <>{alt ?? ''}</>;
|
||||
}
|
||||
return (
|
||||
<img src={source} alt={alt} className="max-w-full" />
|
||||
);
|
||||
},
|
||||
code(props) {
|
||||
const { children, className, node, ref, ...rest } = props;
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const language = match ? match[1] : '';
|
||||
|
||||
return match ? (
|
||||
<div className="group border-border relative overflow-hidden rounded-xl border">
|
||||
<div className="bg-muted flex items-center justify-between px-2 py-1">
|
||||
<span className="text-foreground dark:text-foreground text-xs font-medium">
|
||||
{language}
|
||||
</span>
|
||||
<CopyButton
|
||||
textToCopy={String(children).replace(/\n$/, '')}
|
||||
/>
|
||||
</div>
|
||||
<SyntaxHighlighter
|
||||
{...rest}
|
||||
PreTag="div"
|
||||
language={language}
|
||||
style={isDarkTheme ? vscDarkPlus : oneLight}
|
||||
className="mt-0!"
|
||||
customStyle={{ margin: 0, borderRadius: 0 }}
|
||||
>
|
||||
{String(children).replace(/\n$/, '')}
|
||||
</SyntaxHighlighter>
|
||||
</div>
|
||||
) : (
|
||||
<code className="dark:bg-accent dark:text-foreground rounded-md bg-gray-200 px-2 py-1 text-xs font-normal whitespace-pre-line">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
ul({ children }) {
|
||||
return (
|
||||
<ul
|
||||
className={`list-inside list-disc pl-4 whitespace-normal ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
},
|
||||
ol({ children }) {
|
||||
return (
|
||||
<ol
|
||||
className={`list-inside list-decimal pl-4 whitespace-normal ${classes.list}`}
|
||||
>
|
||||
{children}
|
||||
</ol>
|
||||
);
|
||||
},
|
||||
table({ children }) {
|
||||
return (
|
||||
<div className="border-border relative overflow-x-auto rounded-lg border">
|
||||
<table className="dark:text-foreground w-full text-left text-gray-700">
|
||||
{children}
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
thead({ children }) {
|
||||
return (
|
||||
<thead className="bg-muted text-foreground text-xs uppercase">
|
||||
{children}
|
||||
</thead>
|
||||
);
|
||||
},
|
||||
tr({ children }) {
|
||||
return (
|
||||
<tr className="border-border odd:bg-card even:bg-muted border-b">
|
||||
{children}
|
||||
</tr>
|
||||
);
|
||||
},
|
||||
th({ children }) {
|
||||
return <th className="px-6 py-3">{children}</th>;
|
||||
},
|
||||
td({ children }) {
|
||||
return <td className="px-6 py-3">{children}</td>;
|
||||
},
|
||||
}}
|
||||
>
|
||||
{segment.content}
|
||||
</ReactMarkdown>
|
||||
</div>
|
||||
) : (
|
||||
<div className="my-4 w-full" style={{ minWidth: '100%' }}>
|
||||
<MermaidRenderer code={segment.content} isLoading={isStreaming} />
|
||||
|
||||
Reference in new issue
Block a user