コメント機能 インターフェイス仕様書
1. 概要
ブログ記事ページの末尾にコメントセクションを表示する。 コメント一覧の表示と、新規コメントの投稿フォームで構成される。
2. 表示条件
| 条件 | 詳細 |
|---|---|
| 対象ページ | ブログ記事の個別ページのみ |
| 除外ページ | ブログ一覧ページ、ドキュメントページ、その他ページ |
| 判定方法 | useBlogPost().isBlogPostPage が true の場合に表示 |
3. データ型
CommentData
| フィールド | 型 | 説明 |
|---|---|---|
id | number | コメントの一意識別子 |
name | string | 投稿者名(空文字の場合は匿名扱い) |
rating | number | 評価(0 = 評価なし、1〜5 = 星評価) |
body | string | コメント本文 |
date | string | 投稿日(YYYY-MM-DD 形式) |
4. コンポーネント構成
src/theme/BlogPostItem/index.tsx # Docusaurus swizzle(表示制御)
└── CommentSection # セクション全体
├── コメント一覧
│ ├── (取得中) loadingMessage
│ ├── (0件) emptyMessage
│ └── CommentItem[]
│ └── StarRating # 星評価表示(読み取り専用)
└── 投稿フォーム
├── input[name] # お名前
├── StarRating # 評価(インタラクティブ)
├── textarea[body] # コメント本文
└── button[submit] # 送信ボタン
5. postId の正規化
記事の識別子として useBlogPost().metadata.permalink を使用する。
ロケールに関わらず同じ記事のコメントを共有するため、/en/ プレフィックスを除去して正規化する。
const postId = metadata.permalink.replace(/^\/en\//, '/');
| ロケール | permalink | postId(正規化後) |
|---|---|---|
ja(デフォルト) | /blog/2026-03-20-hime | /blog/2026-03-20-hime |
en | /en/blog/2026-03-20-hime | /blog/2026-03-20-hime |
6. コメント一覧
- ページマウント時に GET API を呼び出し取得する
- フラットリスト形式で表示(スレッド・入れ子なし)
- 各コメントの表示項目:
| 項目 | 表示条件 |
|---|---|
| 投稿者名 | 常に表示 |
| 星評価 | rating >= 1 の場合のみ表示 |
| 投稿日 | 常に表示 |
| コメント本文 | 常に表示 |
一覧の状態表示
| 状態 | 表示内容 |
|---|---|
| 取得中 | 「読み込み中...」 |
| 取得完了・0件 | 「まだコメントはありません。」 |
| 取得完了・1件以上 | コメント一覧 |
| 取得失敗 | 空リスト扱い(エラー表示なし) |
7. 投稿フォーム
フォーム項目
| 項目 | 入力タイプ | 必須 | デフォルト | バリデーション |
|---|---|---|---|---|
| お名前 | <input type="text"> | 任意 | 空文字(placeholder: 匿名) | なし |
| 評価 | 星クリック(1〜5) | 任意 | 0(未選択) | なし |
| コメント | <textarea rows="4"> | ✅ | 空文字 | 空送信不可(required) |
星評価(インタラクティブ)
- 1〜5 の星をクリックして評価を選択
- ホバー時にプレビューハイライトを表示
0のまま送信した場合は「評価なし」として扱う
送信ボタンの状態
| 状態 | ラベル | disabled |
|---|---|---|
| 通常 | 送信する | false |
| 送信中 | 送信中... | true |
送信後の表示
フォームを非表示にして成功メッセージを表示する:
コメントを送信しました。ありがとうございます!
8. API 仕様
ベース URL: https://example.com/comment
8-1. コメント取得
GET https://example.com/comment?postId=<postId>
クエリパラメータ
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
postId | string | ✅ | 正規化済み記事識別子(例: /blog/2026-03-20-hime) |
レスポンスボディ
{
"comments": [
{
"id": 1,
"name": "Alice",
"rating": 5,
"body": "とても参考になりました!",
"date": "2026-03-15"
}
]
}
8-2. コメント投稿
POST https://example.com/comment
Content-Type: application/json
リクエストボディ
{
"postId": "/blog/2026-03-20-hime",
"name": "Alice",
"rating": 5,
"body": "コメント本文"
}
| フィールド | 型 | 説明 |
|---|---|---|
postId | string | 正規化済み記事識別子 |
name | string | 投稿者名(空文字の場合は匿名) |
rating | number | 評価(0〜5) |
body | string | コメント本文 |
エラーハンドリング(共通)
ネットワークエラー・HTTP エラーはいずれも無視し、処理完了扱いとする。 (現状はダミーエンドポイントのため)
9. ファイル構成
| ファイル | 役割 |
|---|---|
src/components/CommentSection/index.tsx | コメントセクション本体 |
src/components/CommentSection/styles.module.css | スタイル定義 |
src/theme/BlogPostItem/index.tsx | Docusaurus swizzle(表示条件の制御) |