Markdownをオシャレに！独自構文で魅力的なドキュメント作成

## はじめに

わたしは普段VSCodeのMarkdownPreviewEnhancedという拡張機能を使ってマークダウンで文章を書いたりするのですが、さすかにちょっと味気ないな・・・と感じることがあります。

CSSで見出しを調節してみたりするものの、HTML+CSS全開で作られたブログなどと比べると当たり前ですが劣ります。

そこで、Markdown本来の文章を書くことに集中する。というテーマを見失わない（＝HTMLをゴリゴリ書かない）かつ、ある程度デザインされたものを生成する方法を考えてみました。

なお、今回実装した構文は以下の2つです。

``` markdown: ちょっとおしゃれなボックス
!!!box {タイトル:コンテンツ}
```

``` markdown: いい感じのQA
!!!qa {質問:回答}
```

<details><summary>こんな感じになります。</summary>

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649608/9f32a3aa-6cff-eda7-ca42-7cb21ceec18a.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649608/97e5ef7f-b889-23d2-34e4-d0cf269beabb.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649608/3ac63792-a0e1-be27-b261-f06ddd363ea5.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649608/0ce0c4bf-33d3-cc1d-a222-6ac5a5cbd3a2.png)

</details>


## MarkdownPreviewEnhanced を拡張する
いろいろ調べてみると、MarkdownPreviewEnhancedには独自のCSS適用の他にも、マークダウンの構文解析を拡張することができるようでした。
これを使って作っていきます。

1. VSCodeでプロジェクトを開く
    ``` bash
    code プロジェクトフォルダのパス
    ```
2. 拡張用の各種ファイルの生成
F1でコマンドパレットを開き```Markdown Preview Enhanced: Extend Parser (Workspace) ```と入力して選択
3. ↓のファイルが生成されます
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/649608/561bba83-d3c5-e925-3c5c-f4e37b8b82ec.png)
4. ```parser.js```と```style.less```を編集
今回は以下のようにしています。（ChatGPTに全面的に作ってもらいました。）
    <details><summary>長いので折りたたみ</summary>

    ```javascript:parser.js
    ({
      onWillParseMarkdown: async function (markdown) {
    
        // !!!box {title:content} をカスタムHTMLに変換
        markdown = markdown.replace(/!!!box\s*\{([^:}]+):([^}]+)\}/g, function (match, title, content) {
          return `<div class="box"><span>${title}</span><p>${content}</p></div>`;
        });
    
        // !!!qa {title:content} をカスタムHTMLに変換
        markdown = markdown.replace(/!!!qa\s*\{([^:}]+):([^}]+)\}/g, function (match, title, content) {
          return `
      <details class="qa">
          <summary>${title}</summary>
          <div class="qa-content"><p>${content}</p></div>
      </details>`;
        });
    
        return markdown;
      },
      onDidParseMarkdown: async function (html) {
        return html;
      }
    })
    ```
    
    ``` css:style.less
    /* Please visit the URL below for more information: /
    / https://shd101wyy.github.io/markdown-preview-enhanced/#/customize-css */
    
    .markdown-preview.markdown-preview {
      .qa {
        max-width: none;
        margin-bottom: 5px;
        padding-left: 1em;
        border-bottom: 2px solid #d6dde3;
        background-color: #fff;
      }
    
      .qa summary {
        display: flex;
        align-items: center;
        position: relative;
        padding: 1em 2em 1em 4em;
        color: #333333;
        font-weight: 600;
        cursor: pointer;
      }
    
      .qa summary::before,
      .qa .qa-content::before {
        position: absolute;
        left: 1em;
        font-weight: 600;
        font-size: 1.3em;
      }
    
      .qa summary::before {
        color: #75bbff;
        content: "Q";
        left: 1em;
      }
    
      .qa summary::after {
        transform: translateY(-25%) rotate(45deg);
        width: 7px;
        height: 7px;
        margin-left: 0;
        border-bottom: 3px solid #333333b3;
        border-right: 3px solid #333333b3;
        content: '';
        transition: transform .5s;
        left: 0;
        position: absolute;
      }
    
      .qa[open] summary::after {
        transform: rotate(225deg);
      }
    
      .qa .qa-content {
        position: relative;
        transform: translateY(-10px);
        opacity: 0;
        margin-top: 0.3em;
        margin-bottom: 0.3em;
        padding-left: 4em;
        color: #333;
        transition: transform .5s, opacity .5s;
      }
    
      .qa .qa-content p {
        margin: 0;
      }
    
      .qa[open] .qa-content {
        transform: none;
        opacity: 1;
      }
    
      .qa .qa-content::before {
        color: #ff8d8d;
        line-height: 1;
        content: "A";
      }
    
      .box {
        max-width: none;
        margin-bottom: 1em;
        border: 2px solid #2589d0;
        border-radius: 3px;
        overflow: hidden;
      }
    
      .box span {
        padding: .4em .8em;
        background-color: #2589d0;
        color: #fff;
      }
    
      .box p {
        margin: 0.3em 0 0.1em 1em;
        padding: 0;
        color: #333;
      }
    
    }
    ```

    </details>

## 独自構文を使って書いてみる

以下の２パターンを使えるようにしているので書いてみます。

```markdown:sample.md
# 独自構文のテスト

通常のマークダウンに独自構文を混ぜてみます。

### ちょっとおしゃれなボックス

!!!box {タイトル１:一行のパターン}

!!!box {タイトル２:
複数行のパターン

複数行のパターン

複数行のパターン}


!!!box {タイトル３:

**組み合わせるパターン**

1. リスト
2. リスト
3. リスト

![alt text](image-3.png)

- [ ] チェック
- [x] チェック

| Left align | Right align | Center align |
|:-----------|------------:|:------------:|
| This       |        This |     This     |
| column     |      column |    column    |
| will       |        will |     will     |
| be         |          be |      be      |
| left       |       right |    center    |
| aligned    |     aligned |   aligned    |

}

### いい感じのQA

!!!qa {質問１:回答１}
!!!qa {質問２:
複数行で回答

複数行で回答

複数行で回答
}

!!!qa {質問３:
組み合わせて回答

1. 回答１
2. 回答２

![alt text](image-3.png)

- [ ] チェック
- [x] チェック

| Left align | Right align | Center align |
|:-----------|------------:|:------------:|
| This       |        This |     This     |
| column     |      column |    column    |
| will       |        will |     will     |
| be         |          be |      be      |
| left       |       right |    center    |
| aligned    |     aligned |   aligned    |

}


```

冒頭に載せたような感じになるハズ！


## おわりに
マークダウンはもともと好きですが、このように簡単に拡張できる可能性があることに非常に可能性を感じました。

Qiitaでも拡張できるようになるといいですね。