Markdown.tsx54 lines · main
1import { PropsWithChildren } from 'react'
2import ReactMarkdown, { type Options } from 'react-markdown'
3import remarkGfm from 'remark-gfm'
4import { cn } from 'ui'
5
6import { InlineLink } from '@/components/ui/InlineLink'
7
8interface MarkdownProps extends Omit<Options, 'children' | 'node'> {
9 className?: string
10 /** @deprecated Should remove this and just take `children` instead */
11 content?: string
12 extLinks?: boolean
13}
14
15const H3 = ({
16 children,
17}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>) => (
18 <h3 className="mb-1">{children}</h3>
19)
20const Code = ({
21 children,
22}: React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>) => (
23 <code className="text-code-inline">{children}</code>
24)
25const A = ({
26 href,
27 children,
28}: React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>) => (
29 <InlineLink href={href ?? '/'}>{children}</InlineLink>
30)
31
32export const Markdown = ({
33 children,
34 className,
35 content = '',
36 extLinks = false,
37 ...props
38}: PropsWithChildren<MarkdownProps>) => {
39 return (
40 <div className={cn('text-sm', className)}>
41 <ReactMarkdown
42 remarkPlugins={[remarkGfm]}
43 components={{
44 h3: H3,
45 code: Code,
46 a: A,
47 }}
48 {...props}
49 >
50 {(children as string) ?? content}
51 </ReactMarkdown>
52 </div>
53 )
54}