diff options
Diffstat (limited to 'apps/web/components/ui/markdown/markdown-readonly.tsx')
| -rw-r--r-- | apps/web/components/ui/markdown/markdown-readonly.tsx | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/apps/web/components/ui/markdown/markdown-readonly.tsx b/apps/web/components/ui/markdown/markdown-readonly.tsx new file mode 100644 index 00000000..29077480 --- /dev/null +++ b/apps/web/components/ui/markdown/markdown-readonly.tsx @@ -0,0 +1,57 @@ +import React from "react"; +import CopyBtn from "@/components/ui/copy-button"; +import { cn } from "@/lib/utils"; +import Markdown from "react-markdown"; +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; +import { dracula } from "react-syntax-highlighter/dist/cjs/styles/prism"; +import remarkBreaks from "remark-breaks"; +import remarkGfm from "remark-gfm"; + +function PreWithCopyBtn({ className, ...props }: React.ComponentProps<"pre">) { + const ref = React.useRef<HTMLPreElement>(null); + return ( + <span className="group relative"> + <CopyBtn + className="absolute right-1 top-1 m-1 hidden text-white group-hover:block" + getStringToCopy={() => { + return ref.current?.textContent ?? ""; + }} + /> + <pre ref={ref} className={cn(className, "")} {...props} /> + </span> + ); +} + +export function MarkdownReadonly({ children: markdown }: { children: string }) { + return ( + <Markdown + remarkPlugins={[remarkGfm, remarkBreaks]} + className="prose dark:prose-invert" + components={{ + pre({ ...props }) { + return <PreWithCopyBtn {...props} />; + }, + code({ className, children, ...props }) { + const match = /language-(\w+)/.exec(className ?? ""); + return match ? ( + // @ts-expect-error -- Refs are not compatible for some reason + <SyntaxHighlighter + PreTag="div" + language={match[1]} + {...props} + style={dracula} + > + {String(children).replace(/\n$/, "")} + </SyntaxHighlighter> + ) : ( + <code className={className} {...props}> + {children} + </code> + ); + }, + }} + > + {markdown} + </Markdown> + ); +} |
