chatbot-ui/components/messages/message-markdown.tsx

66 lines
2.0 KiB
TypeScript

import React, { FC } from "react"
import remarkGfm from "remark-gfm"
import remarkMath from "remark-math"
import { MessageCodeBlock } from "./message-codeblock"
import { MessageMarkdownMemoized } from "./message-markdown-memoized"
interface MessageMarkdownProps {
content: string
}
export const MessageMarkdown: FC<MessageMarkdownProps> = ({ content }) => {
return (
<MessageMarkdownMemoized
className="prose dark:prose-invert prose-p:leading-relaxed prose-pre:p-0 min-w-full space-y-6 break-words"
remarkPlugins={[remarkGfm, remarkMath]}
components={{
p({ children }) {
return <p className="mb-2 last:mb-0">{children}</p>
},
img({ node, ...props }) {
return <img className="max-w-[67%]" {...props} />
},
code({ node, className, children, ...props }) {
const childArray = React.Children.toArray(children)
const firstChild = childArray[0] as React.ReactElement
const firstChildAsString = React.isValidElement(firstChild)
? (firstChild as React.ReactElement).props.children
: firstChild
if (firstChildAsString === "▍") {
return <span className="mt-1 animate-pulse cursor-default"></span>
}
if (typeof firstChildAsString === "string") {
childArray[0] = firstChildAsString.replace("`▍`", "▍")
}
const match = /language-(\w+)/.exec(className || "")
if (
typeof firstChildAsString === "string" &&
!firstChildAsString.includes("\n")
) {
return (
<code className={className} {...props}>
{childArray}
</code>
)
}
return (
<MessageCodeBlock
key={Math.random()}
language={(match && match[1]) || ""}
value={String(childArray).replace(/\n$/, "")}
{...props}
/>
)
}
}}
>
{content}
</MessageMarkdownMemoized>
)
}