マークダウンで書いたコードをみやすくする

# はじめに

こんにちは、エンジニアのkeitaMaxです。

https://qiita.com/keitaMax/items/8d61dca52ce4276c9959

マークダウンで書いたコードをみやすくしようと思います。

# やりたいこと

![スクリーンショット 2024-12-18 19.37.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/d0d736be-ccd9-272d-7857-528525f25014.png)

現状上記のようにコードを書くとかなりみづらい状態になってしまっています。

これをVSCodeのように見やすいものを作成しようと思います。

# インストール

`react-syntax-highlighter`をインストールします。

```
npm i react-syntax-highlighter
```

また、`React Syntax Highlighter`も以下コマンドでインストールします。

```
npm install react-syntax-highlighter --save
```

# 実装

最初にどのように実装したのかコードを記載します。

```tsx:index.tsx
import React, { useState } from 'react';
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { atomDark } from 'react-syntax-highlighter/dist/esm/styles/prism';

export const AddArticle = React.memo(function AddArticle() {
    const [markdown, setMarkdown] = useState<string>('');

    // コードブロックのカスタムレンダラー
    const components = {
        code({ node, inline, className, children, ...props }: any) {
            const match = /language-(\w+)(:(.+))?/.exec(className || '');
            const language = match ? match[1] : null;
            const fileName = match && match[3] ? match[3] : null; // `:`の右側をファイル名として取得

            return !inline && language ? (
                <div>
                    {/* ファイル名がある場合は、角丸と灰色の背景を適用 */}
                    {fileName && (
                        <div className="bg-gray-500 text-white px-2 py-1 text-sm rounded-md w-fit mb-2 -mt-3 -ms-5">
                            {fileName}
                        </div>
                    )}

                    <SyntaxHighlighter
                        style={atomDark} // 好みのテーマに変更可能
                        language={match?.[1]}
                        PreTag="div"
                        {...props}
                    >
                        {children && String(children)?.replace(/\n$/, '')}
                    </SyntaxHighlighter>
                </div>
            ) : (
                <code className={className} {...props}>
                    {children}
                </code>
            );
        },
    };

    return (
        <div className="flex h-screen">
            {/* 左側のエディタ */}
            <div className="w-1/2 p-4">
                <h2 className="text-xl font-bold mb-4">Markdownエディタ</h2>
                <textarea
                    className="w-full h-full p-2 border rounded-md"
                    placeholder="ここにマークダウンを入力してください..."
                    value={markdown}
                    onChange={(e) => setMarkdown(e.target.value)}
                />
            </div>

            {/* 右側のプレビュー */}
            <div className="w-1/2 p-4 border-l overflow-y-auto">
                <h2 className="text-xl font-bold mb-4">プレビュー</h2>
                <div className="prose prose-lg max-w-none">
                    <ReactMarkdown
                        remarkPlugins={[remarkGfm]}
                        components={components} // カスタムレンダラーを指定
                    >
                        {markdown}
                    </ReactMarkdown>
                </div>
            </div>
        </div>
    );
});

export default AddArticle;

```
前回から`components`というものを追加し、
```tsx:
<ReactMarkdown
    remarkPlugins={[remarkGfm]}
    components={components} // カスタムレンダラーを指定
>
    {markdown}
</ReactMarkdown>
```
ReactMarkdownに読み込ませています。

# 解説？

```ts
const match = /language-(\w+)(:(.+))?/.exec(className || '');
const language = match ? match[1] : null;
const fileName = match && match[3] ? match[3] : null; 
```
これで`:`の右側をファイル名として、左側をファイルの型として認識させています。


```tsx
return !inline && language ? (
    <div>
        {/* ファイル名がある場合は、角丸と灰色の背景を適用 */}
        {fileName && (
            <div className="bg-gray-500 text-white px-2 py-1 text-sm rounded-md w-fit mb-2 -mt-3 -ms-5">
                {fileName}
            </div>
        )}

        <SyntaxHighlighter
            style={atomDark} // 好みのテーマに変更可能
            language={match?.[1]}
            PreTag="div"
            {...props}
        >
            {children && String(children)?.replace(/\n$/, '')}
        </SyntaxHighlighter>
    </div>
) : (
    <code className={className} {...props}>
        {children}
    </code>
);
```

ここで実際にコードに色をつけてみやすくしています。

# どんな感じの見た目か

![スクリーンショット 2024-12-18 19.47.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3715123/24e84b09-956a-02c9-5e68-2ea1fcb96398.png)

こんな感じになっています！

# おわりに

この記事での質問や、間違っている、もっといい方法があるといったご意見などありましたらご指摘していただけると幸いです。

最後まで読んでいただきありがとうございました！

# 参考

https://www.npmjs.com/package/react-syntax-highlighter

https://github.com/react-syntax-highlighter/react-syntax-highlighter