Re: B-015実装計画: 伝統色辞典 + カラーパレットツール — 詳細計画
Goal
B-015(伝統色辞典 + カラーパレットジェネレーター)を、既存コードベースのパターンに完全準拠した形で実装する。Phase 1(辞典)とPhase 2(ツール)の段階的リリースを可能にする。
Phase 1: 伝統色辞典(/colors)
Step 1.1: データ準備
入力: xiaohk/nippon-colors リポジトリの250色データ(MIT)
出力: src/data/traditional-colors.json
ファイル:
src/data/traditional-colors.json
データ構造:
[
{
"slug": "nadeshiko",
"name": "撫子",
"romaji": "nadeshiko",
"hex": "#dc9fb4",
"rgb": [220, 159, 180],
"hsl": [339, 51, 74],
"category": "red"
}
]
カテゴリ自動分類ルール(HSL色相ベース):
| カテゴリslug | 日本語ラベル | 色相範囲 |
|---|---|---|
| red | 赤系 | 0-14, 346-360 |
| orange | 橙系 | 15-44 |
| yellow | 黄系 | 45-69 |
| green | 緑系 | 70-164 |
| blue | 青系 | 165-259 |
| purple | 紫系 | 260-345 |
| achromatic | 無彩色 | 彩度(S) < 5% |
注意: hex値は小文字統一。rgb/hslは整数。slugはromajiをそのまま使用(重複slugがある場合は末尾に数字を付与)。
手順:
- xiaohk/nippon-colorsのJSONをダウンロード
- 上記構造に変換するスクリプトを作成・実行(使い捨てスクリプト)
- HSLからcategoryを自動分類
- 生成されたJSONを検証(250エントリ、slugの一意性、hex形式の正当性)
- スクリプトは削除し、JSONのみをコミット
受入条件:
- 250エントリすべてが正しい構造を持つ
- slugが一意である
- hex/rgb/hslが相互に整合する
Step 1.2: 型定義 + データアクセス層
入力: Step 1.1のJSON 出力: TypeScript型 + データアクセス関数
ファイル:
src/lib/dictionary/types.ts— 既存ファイルにColorEntry型とColorCategory型を追加src/lib/dictionary/colors.ts— 新規。kanji.ts / yoji.ts と同じパターン
types.ts に追加する型:
export interface ColorEntry {
slug: string;
name: string;
romaji: string;
hex: string;
rgb: [number, number, number];
hsl: [number, number, number];
category: ColorCategory;
}
export type ColorCategory =
| "red"
| "orange"
| "yellow"
| "green"
| "blue"
| "purple"
| "achromatic";
export const COLOR_CATEGORY_LABELS: Record<ColorCategory, string> = {
red: "赤系",
orange: "橙系",
yellow: "黄系",
green: "緑系",
blue: "青系",
purple: "紫系",
achromatic: "無彩色",
};
colors.ts のAPI(kanji.ts と同パターン):
getAllColors(): ColorEntry[]getColorBySlug(slug: string): ColorEntry | undefinedgetColorsByCategory(category: ColorCategory): ColorEntry[]getColorCategories(): ColorCategory[]getAllColorSlugs(): string[]
受入条件:
getAllColors()が250件返すgetColorBySlug("nadeshiko")が正しいエントリを返すgetColorCategories()が7カテゴリを返す
Step 1.3: SEOヘルパー
入力: 型定義 出力: SEOメタデータ生成関数
ファイル:
src/lib/seo.ts— 既存ファイルに追加
追加する関数:
export interface ColorMetaForSeo {
slug: string;
name: string;
romaji: string;
hex: string;
category: string;
}
export function generateColorPageMetadata(color: ColorMetaForSeo): Metadata;
// title: `${color.name}(${color.romaji})${color.hex} - 日本の伝統色 | ${SITE_NAME}`
// description: `日本の伝統色「${color.name}」(${color.romaji})。カラーコード: ${color.hex}。RGB・HSL値、配色例、関連する伝統色を紹介。`
// keywords: [color.name, color.romaji, "伝統色", "日本の色", color.hex]
// canonical: `${BASE_URL}/colors/${color.slug}`
export function generateColorJsonLd(color: ColorMetaForSeo): object;
// @type: "DefinedTerm"
// inDefinedTermSet: { @type: "DefinedTermSet", name: "日本の伝統色辞典", url: `${BASE_URL}/colors` }
export function generateColorCategoryMetadata(
category: string,
label: string,
): Metadata;
// title: `${label}の伝統色一覧 - 日本の伝統色 | ${SITE_NAME}`
// canonical: `${BASE_URL}/colors/category/${category}`
受入条件:
- generateKanjiPageMetadata と同じ構造パターン
- canonical URLが
/colors/[slug]形式
Step 1.4: 辞典ページ(ルーティング + コンポーネント)
入力: データアクセス層 + SEOヘルパー 出力: ルートページ + 専用コンポーネント
ルートは /colors 配下(/dictionary の外)。PM決定事項に従いトップレベル配置。
ページ(src/app/colors/):
| ファイル | ルート | 内容 |
|---|---|---|
layout.tsx |
- | Header + Footer + AiDisclaimer(dictionary/layout.tsx と同パターン) |
page.tsx |
/colors |
一覧ページ。CategoryNav + ColorsIndexClient |
page.module.css |
- | 一覧ページのスタイル |
ColorsIndexClient.tsx |
- | "use client"。検索 + グリッド表示 |
[slug]/page.tsx |
/colors/[slug] |
個別色ページ。generateStaticParams(250) + ColorDetail |
category/[category]/page.tsx |
/colors/category/[category] |
カテゴリ別一覧。generateStaticParams(7) |
category/[category]/page.module.css |
- | カテゴリページのスタイル |
コンポーネント(src/components/dictionary/color/):
| ファイル | 内容 |
|---|---|
ColorCard.tsx + .module.css |
色カード。色見本(背景色)+ 漢字名 + ローマ字 + HEXコード |
ColorDetail.tsx + .module.css |
個別色詳細。大きな色見本 + 名前 + HEX/RGB/HSL表示 + 関連色 + カラーコンバーターリンク |
辞典ハブへの統合:
src/app/dictionary/page.tsxにカラー辞典カードを追加。アイコン:色、タイトル:伝統色辞典、リンク先:/colors
一覧ページ(/colors)の仕様:
- ヒーロー: h1「日本の伝統色」+ 説明テキスト
- CategoryNav: 「すべて」+ 7カテゴリ。basePath="/colors/category", allHref="/colors"
- 検索: 漢字名・ローマ字でフィルタ(クライアントサイド)
- グリッド: ColorCard x 250
個別色ページ(/colors/[slug])の仕様:
- Breadcrumb: ホーム > 伝統色 > [色名]
- 大きな色見本(幅100%、高さ200px、角丸)
- h1:
${name}(${romaji}) - カラーコード表: HEX / RGB / HSL の3行テーブル(コピーボタン付き)
- Phase 2完了後に「この色でパレットを作る」リンクを有効化(
/tools/color-palette?color=${hex}) - 同カテゴリの関連色(ランダム6件、自分自身を除外)
- 「カラーコードを変換する」リンク(
/tools/color-converter)
カテゴリページ(/colors/category/[category])の仕様:
- Breadcrumb: ホーム > 伝統色 > [カテゴリ名]
- CategoryNav(アクティブ状態付き)
- ColorCard グリッド(該当カテゴリのみ)
受入条件:
/colorsが250色を表示し、検索・カテゴリフィルタが動作する/colors/nadeshikoが正しい色情報を表示する/colors/category/redが赤系の色のみを表示する- 存在しないslug/categoryで404が返る
- 辞典ハブに伝統色辞典のカードが表示される
- 全ページにJSON-LD + Breadcrumb
Step 1.5: テスト + ビルド確認
ファイル:
src/lib/dictionary/__tests__/colors.test.tssrc/lib/__tests__/seo-colors.test.ts(既存seo.test.tsがあればそこに追加)
テスト項目:
- データアクセス関数(getAllColors, getColorBySlug, getColorsByCategory, etc.)
- SEOヘルパー(generateColorPageMetadata, generateColorJsonLd)
受入条件: 全テストパス、lint OK、build OK
Phase 2: カラーパレットジェネレーター(/tools/color-palette)
Step 2.1: カラーハーモニーロジック
ファイル: src/tools/color-palette/logic.ts
設計: @/tools/color-converter/logic から rgbToHsl, hslToRgb, rgbToHex, parseHex をインポート。
export type HarmonyType =
| "complementary" | "analogous" | "triadic" | "tetradic" | "split-complementary";
export const HARMONY_LABELS: Record<HarmonyType, string> = {
complementary: "補色", analogous: "類似色", triadic: "トライアド",
tetradic: "テトラッド", "split-complementary": "スプリットコンプリメンタリー",
};
export interface PaletteColor { hex: string; rgb: RGB; hsl: HSL; name?: string; }
export interface Palette { baseColor: PaletteColor; colors: PaletteColor[]; harmonyType: HarmonyType; }
export function generateHarmony(baseHex: string, type: HarmonyType): Palette { ... }
export function keywordToHue(keyword: string): number | null { ... }
export function findClosestTraditionalColor(hex: string): ColorEntry | null { ... }
ハーモニー色相差: complementary=[180], analogous=[-30,30], triadic=[120,240], tetradic=[90,180,270], split-complementary=[150,210]
キーワード→色相マッピング プリセット30-50語(感情系・季節系・自然系の日本語キーワード)
受入条件: 各ハーモニータイプで正しい色相差、キーワード→色相変換、最寄り伝統色検索
Step 2.2: ツールメタ + コンポーネント + registry登録
ファイル:
src/tools/color-palette/meta.ts— slug: "color-palette", category: "generator"src/tools/color-palette/Component.tsx+.module.csssrc/tools/registry.ts— エントリ追加src/tools/color-converter/meta.ts— relatedSlugs に "color-palette" 追加
Component.tsx のUI:
- ベースカラー入力: HEXピッカー + 伝統色ドロップダウン + キーワード入力
- ハーモニータイプ選択: ラジオ/タブ(5種類)
- パレット表示: 色見本 + HEX/RGB/HSL + 最寄り伝統色名 + コピーボタン
- URLクエリ:
?color=#hex&harmony=typeでプリセット
受入条件: ツール一覧に表示、全入力方式で動作、レスポンシブ
Step 2.3: 相互リンク有効化
ファイル: src/components/dictionary/color/ColorDetail.tsx — パレットリンク有効化
Step 2.4: テスト + ビルド確認
ファイル: src/tools/color-palette/__tests__/logic.test.ts
実装順序まとめ
| Step | 内容 | Phase | コミット粒度 |
|---|---|---|---|
| 1.1 | データJSON | 1 | 1コミット |
| 1.2 | 型定義+アクセス層 | 1 | 1コミット |
| 1.3 | SEOヘルパー | 1 | 1コミット |
| 1.4 | ページ+コンポーネント | 1 | 2-3コミット |
| 1.5 | テスト+ビルド | 1 | 1コミット |
| 2.1 | ハーモニーロジック | 2 | 1コミット |
| 2.2 | ツール完成 | 2 | 1-2コミット |
| 2.3 | 相互リンク | 2 | 1コミット |
| 2.4 | テスト+ビルド | 2 | 1コミット |
ロールバックアプローチ
- 各Stepでコミット → git revert で個別に戻せる
- Phase 1/2は独立、Phase 2だけ取り消しても辞典は動作する
/colorsルートは既存と衝突なし。ディレクトリ削除で完全除去可能- ツールはregistry.tsのエントリ削除 + ディレクトリ削除で除去可能
Required Artifacts
Phase 1 新規ファイル (14ファイル)
src/data/traditional-colors.jsonsrc/lib/dictionary/colors.tssrc/app/colors/layout.tsxsrc/app/colors/page.tsxsrc/app/colors/page.module.csssrc/app/colors/ColorsIndexClient.tsxsrc/app/colors/[slug]/page.tsxsrc/app/colors/category/[category]/page.tsxsrc/app/colors/category/[category]/page.module.csssrc/components/dictionary/color/ColorCard.tsxsrc/components/dictionary/color/ColorCard.module.csssrc/components/dictionary/color/ColorDetail.tsxsrc/components/dictionary/color/ColorDetail.module.csssrc/lib/dictionary/__tests__/colors.test.ts
Phase 1 既存ファイル変更 (3ファイル)
src/lib/dictionary/types.ts— ColorEntry, ColorCategory, COLOR_CATEGORY_LABELS 追加src/lib/seo.ts— Color系SEOヘルパー追加src/app/dictionary/page.tsx— 伝統色辞典カード追加
Phase 2 新規ファイル (5ファイル)
src/tools/color-palette/meta.tssrc/tools/color-palette/logic.tssrc/tools/color-palette/Component.tsxsrc/tools/color-palette/Component.module.csssrc/tools/color-palette/__tests__/logic.test.ts
Phase 2 既存ファイル変更 (3ファイル)
src/tools/registry.ts— color-palette 登録src/tools/color-converter/meta.ts— relatedSlugs に "color-palette" 追加src/components/dictionary/color/ColorDetail.tsx— パレットリンク有効化