|
| 1 | +import Markdown, { Components } from "react-markdown"; |
| 2 | +import remarkGfm from "remark-gfm"; |
| 3 | +import { Prism as SyntaxHighlighter } from "react-syntax-highlighter"; |
| 4 | + |
| 5 | +export function StyledMarkdown({ content }: { content: string }) { |
| 6 | + return ( |
| 7 | + <Markdown remarkPlugins={[remarkGfm]} components={components}> |
| 8 | + {content} |
| 9 | + </Markdown> |
| 10 | + ); |
| 11 | +} |
| 12 | + |
| 13 | +// TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある |
| 14 | +const components: Components = { |
| 15 | + h1: ({ node, ...props }) => ( |
| 16 | + <h1 className="text-2xl font-bold my-4" {...props} /> |
| 17 | + ), |
| 18 | + h2: ({ node, ...props }) => ( |
| 19 | + <h2 className="text-xl font-bold mt-4 mb-3 " {...props} /> |
| 20 | + ), |
| 21 | + h3: ({ node, ...props }) => ( |
| 22 | + <h3 className="text-lg font-bold mt-4 mb-2" {...props} /> |
| 23 | + ), |
| 24 | + h4: ({ node, ...props }) => ( |
| 25 | + <h4 className="text-base font-bold mt-3 mb-2" {...props} /> |
| 26 | + ), |
| 27 | + p: ({ node, ...props }) => <p className="mx-2 my-2" {...props} />, |
| 28 | + ul: ({ node, ...props }) => ( |
| 29 | + <ul className="list-disc list-outside ml-6 my-2" {...props} /> |
| 30 | + ), |
| 31 | + ol: ({ node, ...props }) => ( |
| 32 | + <ol className="list-decimal list-outside ml-6 my-2" {...props} /> |
| 33 | + ), |
| 34 | + li: ({ node, ...props }) => <li className="my-1" {...props} />, |
| 35 | + a: ({ node, ...props }) => <a className="link link-info" {...props} />, |
| 36 | + strong: ({ node, ...props }) => ( |
| 37 | + <strong className="text-primary" {...props} /> |
| 38 | + ), |
| 39 | + code: ({ node, className, ref, style, ...props }) => { |
| 40 | + const match = /language-(\w+)/.exec(className || ""); |
| 41 | + if (match) { |
| 42 | + // block |
| 43 | + return ( |
| 44 | + <SyntaxHighlighter |
| 45 | + language={match[1]} |
| 46 | + PreTag="div" |
| 47 | + className="px-4! py-4! m-0!" |
| 48 | + // style={todo dark theme?} |
| 49 | + {...props} |
| 50 | + > |
| 51 | + {String(props.children).replace(/\n$/, "")} |
| 52 | + </SyntaxHighlighter> |
| 53 | + ); |
| 54 | + } else if (String(props.children).includes("\n")) { |
| 55 | + // 言語指定なしコードブロック |
| 56 | + return ( |
| 57 | + <SyntaxHighlighter |
| 58 | + PreTag="div" |
| 59 | + className="px-4! py-4! m-0!" |
| 60 | + // style={todo dark theme?} |
| 61 | + {...props} |
| 62 | + > |
| 63 | + {String(props.children).replace(/\n$/, "")} |
| 64 | + </SyntaxHighlighter> |
| 65 | + ); |
| 66 | + } else { |
| 67 | + // inline |
| 68 | + return ( |
| 69 | + <code |
| 70 | + className="bg-base-200 border border-base-300 p-1 rounded font-mono " |
| 71 | + {...props} |
| 72 | + /> |
| 73 | + ); |
| 74 | + } |
| 75 | + }, |
| 76 | + pre: ({ node, ...props }) => ( |
| 77 | + <pre |
| 78 | + className="bg-base-200 border border-primary mx-2 my-2 rounded-lg font-mono text-sm overflow-x-auto" |
| 79 | + {...props} |
| 80 | + /> |
| 81 | + ), |
| 82 | + hr: ({ node, ...props }) => <hr className="border-primary my-4" {...props} />, |
| 83 | +}; |
0 commit comments