mcpField
M
markdown-content

markdown-content

github.com/joyco-studio開発1246 回インストール8 週間前に更新
リポジトリ

markdown-content について

markdown-contentは、Next.js App RouterでMDXコンテンツページを構築するためのスキルです。MDXとReactコンポーネントのコード表示を共通の処理とスタイルで揃えます。

主な機能

  1. 01MDXコレクションとスキーマの定義
  2. 02コンテンツページの読み込みと解決
  3. 03ビルド時と実行時のコードハイライト
  4. 04タブ付きコードブロックとコピー機能
  5. 05本文とコードブロックのスタイル設定

活用シーン

  1. 01ブログや変更履歴の構築
  2. 02法務ページやナレッジベースの作成
  3. 03シンタックスハイライトの表示統一
  4. 04コード例へのコピー機能の追加

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/joyco-studio/skills --skill markdown-content

インストール後、Claude Code で/markdown-contentを入力して読み込まれたか確認します。

詳細

Markdown コンテンツページ — Next.js

このスキルでは、MDX を使用して、Next.js App Router プロジェクトでコンテンツ主体のページ(ブログ記事、変更履歴、法的ページ、ナレッジベース)を構築する方法を定義します。

目標は、次の間で視覚的および動作上の一貫性を保つことです。

  • .mdx ファイルに記述された Markdown コードブロック(ビルド時に処理)
  • ページ上にレンダリングされるカスタム React コードコンポーネント(実行時にハイライト)

スタックの概要

レイヤーライブラリ目的
コンテンツフレームワークfumadocs-mdxMDX コレクション定義、フロントマターのスキーマ、ビルド時の処理
コンテンツランタイムfumadocs-coreソースローダー、ページツリー、スラッグの解決
シンタックスハイライトshiki + rehype-pretty-codeビルド時(MDX)と実行時(コンポーネント)のデュアルテーマコードハイライト
スキーマ検証zodデフォルト値とオプションフィールドを備えた、型付きフロントマター
スタイリングTailwind CSS v4ユーティリティファーストのスタイル、カスタム prose CSS、コードブロックのスタイル
フレームワークNext.js(App Router)コンテンツページ用のキャッチオール [[...slug]] を使ったファイルベースのルーティング
npm install fumadocs-mdx fumadocs-core shiki rehype-pretty-code zod

プロジェクト構成

├── app/
│   ├── layout.tsx                       # Root layout
│   ├── styles/
│   │   ├── globals.css                  # Tailwind + stylesheet imports (order matters)
│   │   ├── prose.css                    # Self-contained typography for .prose class
│   │   ├── shiki.css                    # Code block styling (themes, line numbers, highlights)
│   │   └── theming.css                  # Color variables (light/dark) — imported first
│   └── (content)/                       # Route group for content pages
│       ├── layout.tsx                   # Content layout wrapper
│       └── [[...slug]]/
│           └── page.tsx                 # Catch-all page rendering MDX content
├── content/
│   ├── meta.json                        # Top-level page ordering
│   ├── index.mdx                        # Landing page
│   └── <category>/                      # e.g. blog/, legal/, changelog/
│       ├── meta.json                    # Category page ordering
│       └── <page>.mdx                   # Individual content pages
├── components/                          # Code block components (see Code Block Components)
├── lib/
│   ├── source.ts                        # fumadocs-core source loader
│   ├── shiki.ts                         # Shared shiki config, transformers, highlightCode()
│   └── cn.ts                            # clsx + tailwind-merge utility
├── mdx-components.tsx                   # MDX element → React component mappings
└── source.config.ts                     # fumadocs-mdx collection + rehype pipeline

コンテンツコレクション

source.config.ts

次の 2 つを定義します。

  1. コンテンツコレクション — content/ ディレクトリを参照する defineDocs() と、Zod で拡張したフロントマターのスキーマです。
  2. MDX パイプライン — デフォルトの fumadocs ハイライターを置き換える rehype-pretty-code を指定した defineConfig() です。

主なパターン:

  • rehypePlugins 内で plugins.shift() を呼び出して組み込みの fumadocs シンタックスハイライターを削除し、その後 plugins.push() で rehype-pretty-code を追加します。
  • Shiki のデュアルテーマ(ライトとダークを 1 つずつ)を設定して、両方の配色をマークアップに埋め込みます。どちらを表示するかは CSS で切り替えます。
  • カスタムの Shiki トランスフォーマーを渡して、コンポーネントがレンダリング時に読み取れるメタデータ(ソーステキスト)を AST に追加します。
  • onVisitTitle を使ってコードブロックのタイトル要素に not-prose を追加し、prose のタイポグラフィが適用されないようにします。
next.config.ts

fumadocs-mdx/next の createMDX() で Next.js の設定をラップします。

lib/source.ts

fumadocs-core/source から loader() を作成し、baseUrl とコレクションの .toFumadocsSource() を指定します。ソースと、InferPageType を使用した Page 型をエクスポートします。


コンテンツファイル

MDX フロントマター

すべての .mdx ファイルは、source.config.ts の Zod スキーマで検証される YAML フロントマターから始まります。インポートは、閉じる --- の後に記述します。標準の Markdown に加えて、React コンポーネントをインラインで使用できます。コードブロックには言語タグ付きのフェンス構文を使用し、title="filename.tsx" というメタ文字列を追加するとタイトルバーが表示されます。

meta.json

ディレクトリ内のページの順序を制御します — スラッグ文字列の配列です。

{
  "pages": ["index", "terms-of-service", "privacy-policy"]
}

キャッチオールコンテンツページ

[[...slug]]/page.tsx ルートは source.getPage(params.slug) でスラッグを解決し、見つからない場合は notFound() を返して、次をレンダリングします。

<article className="prose">
  <h1>{page.data.title}</h1>
  <p className="text-muted-foreground">{page.data.description}</p>
  <MDX components={getMDXComponents()} />
</article>

静的生成には、source.generateParams() を使用して generateStaticParams をエクスポートします。


Shiki の設定

lib/shiki.ts

シンタックスハイライトの設定を一元管理します。MDX パイプライン(ビルド時)とカスタムコードコンポーネント(実行時)の両方で使用します。

このモジュールでは、次をエクスポートします。

  1. 言語マップ — ファイル拡張子(ts、tsx、sh など)を Shiki の言語識別子に対応付ける Record<string, BuiltinLanguage> です。さらに、getLanguageFromExtension() ヘルパーも用意します。

  2. Shiki トランスフォーマー — MDX のコンパイル時に実行され、コンポーネントがレンダリング時に読み取るカスタムプロパティを AST ノードに追加します。コンポーネントのマッピングが使用できるよう、コピー用ボタンのための元のソース文字列を追加します。

  3. highlightCode(code, language) — MDX パイプラインと同じデュアルテーマを使用し、codeToHtml() でハイライトする非同期関数です。これは一貫性を保つための仕組みです。ビルド時と実行時のどちらのハイライトにも同じ Shiki 設定を使用し、同じデータ属性(data-line-numbers、data-line)を生成することで、どこでも視覚的な出力が一致します。


MDX コンポーネントのマッピング

mdx-components.tsx

MDX コンパイラーが出力する HTML 要素を React コンポーネントにマッピングします。生の Markdown とコンポーネントシステムをつなぐ役割を担います。

主なマッピング:

  • code — スタイル付きのインライン <code> 要素をレンダリングします。

  • pre — props からトランスフォーマーのメタデータを読み取ります。生のソーステキストを使って、CopyButton を重ねた <pre> をレンダリングします。

  • img — 最適化のために、必要に応じて Next.js の Image でラップします。

処理の流れ:作成者がフェンス付きコードブロックを書く → rehype-pretty-code と shiki が構文トークン付きの <pre><code> を生成する → shiki のトランスフォーマーがメタデータを付与する → MDX がこれらのマッピングを呼び出す → コンポーネントがメタデータを読み取り、それに応じてレンダリングする。


コードブロックコンポーネント

コード表示システム用に、以下のクライアントコンポーネントを作成します。

CodeBlock

単一のコード表示です。highlightedCode(HTML 文字列)、language、任意の title、コピー用の rawCode、maxHeight、wrap を受け取ります。任意の <figcaption> タイトルバー、dangerouslySetInnerHTML によるハイライト済み HTML、CopyButton を含む <figure data-rehype-pretty-code-figure> をレンダリングします。

CodeBlockTabs

複数ファイルのタブ付きコード表示です。{ filename, highlightedCode, rawCode } の配列をタブとして受け取ります。制御されたタブ状態を使用します。<figcaption> 内にタブと、アクティブなタブ用の CopyButton をレンダリングします。

CopyButton

視覚的なフィードバックを備えたクリップボードボタンです。navigator.clipboard.writeText() を呼び出す useCopyToClipboard フックを使用し、約 2 秒間チェックマークを表示します。右上に絶対位置で配置し、グループにホバーしたときに不透明度が切り替わります。


スタイリングのアーキテクチャ

globals.css — インポート順序
@import 'tailwindcss';
@import './theming.css';
@import './prose.css';
@import './shiki.css';

theming.css は最初に読み込む必要があります。prose と shiki が使用するカラー変数を定義するためです。

theming.css — カラー変数

shiki.css とコンポーネントのクラスで使用するライトモードおよびダークモードの変数を定義します。

  • --color-code — コードブロックの背景色
  • --color-code-foreground — コードブロックのテキスト色
  • --color-code-highlight — ハイライトされた行の背景色
prose.css — 自己完結型のタイポグラフィ

@tailwindcss/typography や UI フレームワークに依存しない、独自に作成した .prose クラスです。:where() セレクターを使い、詳細度をゼロに保ちます。埋め込みコンポーネントを除外するための手段として .not-prose を使用します。

最低限、本文の色と行の高さ、見出し(h1–h6)、段落、リンク、strong、リスト(ul/ol/li)、引用、水平線、表、コードの figure(figure[data-rehype-pretty-code-figure])を対象にします。

デザイン上の決定事項:

  • 読みやすさを柔らかくするため、本文の不透明度を下げます(例:color-mix を使って --foreground の 70% にする)
  • 見出しには --foreground をそのまま使い、行の高さを詰めます
  • コードの figure には上下のマージンを設定し、最初と最後の子要素にはリセットを適用します
shiki.css — コードブロックのスタイル

すべてのコードブロックに統一したスタイルを適用します。MDX がレンダリングしたコードブロックとコンポーネントがレンダリングしたコードブロックのどちらにも、同じデータ属性を使用します。

主なルール:

  • デュアルテーマの切り替え — .dark 内では、[data-rehype-pretty-code-figure] span の color を var(--shiki-dark) に切り替えます。ライトテーマがデフォルトです。shiki は両方のカラーセットを CSS 変数として埋め込みます。
  • コンテナー — [data-rehype-pretty-code-figure] の背景色に --color-code を使い、角を丸くして、はみ出した部分を隠します。
  • 行番号 — [data-line-numbers] [data-line]::before に CSS カウンターを使います。横スクロール時にも表示されるよう、左側にスティッキー配置します。
  • 行のハイライト — [data-highlighted-line] に控えめな背景色と左ボーダーを設定します。
  • タイトルバー — [data-rehype-pretty-code-title] に等幅フォント、控えめな色、下ボーダーを設定します。
  • テキストの折り返し — [data-wrap='true'] code で white-space: pre-wrap を有効にします。

一貫性モデル

フェンス付き Markdown コードブロックと <CodeBlock> React コンポーネントが、同一の視覚的出力を生成することを保証します。これは次の方法で実現しています。

  1. 同じ Shiki テーマ — MDX パイプラインと highlightCode() で、同じデュアルテーマの組み合わせを使用します。
  2. 同じ CSS ターゲット — どちらも shiki.css でスタイル設定された [data-rehype-pretty-code-figure] 要素を生成します。
  3. 同じデータ属性 — どちらの経路でも data-line、data-line-numbers、data-highlighted-line、data-wrap を使用します。
  4. 同じカラー変数 — theming.css の --color-code ファミリーが全体に適用されます。
  5. 共通のコピー用ボタン — すべてのコード表示で同じ CopyButton コンポーネントを使用します。

実装チェックリスト

  1. 依存関係をインストールします:fumadocs-mdx、fumadocs-core、shiki、rehype-pretty-code、zod
  2. frontmatter スキーマと rehype-pretty-code パイプラインを含む source.config.ts を作成します
  3. createMDX() で next.config.ts をラップします
  4. ソースローダーを含む lib/source.ts を作成します
  5. 言語マップ、トランスフォーマー、highlightCode() を含む lib/shiki.ts を作成します
  6. pre と code をカスタムコンポーネントにマッピングする mdx-components.tsx を作成します
  7. コードブロックコンポーネント(CodeBlock、CodeBlockTabs、CopyButton)を作成します
  8. prose.css(自己完結型のタイポグラフィ)と shiki.css(コードブロックのスタイリング)を設定します
  9. --color-code ファミリーを含むテーマ変数を theming.css で定義します
  10. meta.json ファイルを含むコンテンツディレクトリを作成します
  11. キャッチオールの [[...slug]]/page.tsx ルートを作成します
  12. globals.css でスタイルシートを正しい順序(theming → prose → shiki)でインポートします

コメント