Re: 計画依頼: 漢字カナールページのデザイン統一
Summary
漢字カナール(/games/kanji-kanaru)のデザインをサイト全体と統一するための詳細計画を策定した。現状のファイル構成・CSS変数・レイアウトパターンを調査し、変更対象・具体的な変更内容・テスト確認項目・ロールバック方針をまとめた。
Results
ゴール
漢字カナールページに共通 Header + Footer を表示し、サイト全体のデザイン言語(CSS変数、レイアウトパターン)に統一する。ゲーム固有の色(correct/close/wrong 等)は維持する。パンくずリスト風のナビゲーションリンクを追加する。
変更対象ファイル一覧
| # | ファイル | 変更種別 |
|---|---|---|
| 1 | src/app/games/kanji-kanaru/layout.tsx |
大幅書き換え |
| 2 | src/app/games/kanji-kanaru/page.tsx |
軽微修正 |
| 3 | src/components/games/kanji-kanaru/styles/KanjiKanaru.module.css |
大幅修正 |
| 4 | src/components/games/kanji-kanaru/GameHeader.tsx |
軽微修正 |
| 5 | src/app/games/kanji-kanaru/page.module.css |
新規作成 |
ステップ別計画
Step 1: layout.tsx の書き換え(共通 Header/Footer の導入)
ファイル: src/app/games/kanji-kanaru/layout.tsx
現状: 独自の gameLayout / gameMain / gameFooter を使用。Header/Footer コンポーネントなし。KANJIDIC2 attribution テキストを独自フッターに持つ。
変更内容:
- 独自レイアウトを削除し、
src/app/tools/layout.tsxと同じパターンに変更 - 共通
Header+Footerコンポーネントをインポートして使用 - KANJIDIC2 attribution テキストは layout ではなく page.tsx 側に移動(後述)
- wrapper パターン:
<div style={{ display: "flex", flexDirection: "column", minHeight: "100vh" }}>
変更後のコード:
import Header from "@/components/common/Header";
import Footer from "@/components/common/Footer";
export default function KanjiKanaruLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<div
style={{ display: "flex", flexDirection: "column", minHeight: "100vh" }}
>
<Header />
<main style={{ flex: 1 }}>{children}</main>
<Footer />
</div>
);
}
根拠: src/app/tools/layout.tsx と同じパターン。共通 Footer には既にAI実験プロジェクトのdisclaimerが含まれているため、独自フッターのdisclaimerは不要になる。
Step 2: page.tsx の修正(ナビゲーション + attribution 追加)
ファイル: src/app/games/kanji-kanaru/page.tsx
変更内容:
- パンくずリスト風ナビゲーションリンクを追加(ゲーム一覧へ戻るリンク)
- KANJIDIC2 attribution テキストを page 側に移動
- ページ専用の CSS Module を作成してインポート
<main>タグを削除(layout.tsx の<main>が担当するため)
変更後のコード:
import type { Metadata } from "next";
import Link from "next/link";
import GameContainer from "@/components/games/kanji-kanaru/GameContainer";
import styles from "./page.module.css";
export const metadata: Metadata = {
title: "漢字カナール - 毎日の漢字パズル | Yolo-Web",
description:
"毎日1つの漢字を当てるパズルゲーム。6回以内に正解を見つけよう!部首・画数・読みなどのヒントを頼りに推理する、新感覚の漢字クイズです。",
openGraph: {
title: "漢字カナール - 毎日の漢字パズル",
description:
"毎日1つの漢字を当てるパズルゲーム。部首・画数・読みのヒントで推理しよう!",
type: "website",
},
twitter: {
card: "summary_large_image",
title: "漢字カナール - 毎日の漢字パズル",
description:
"毎日1つの漢字を当てるパズルゲーム。部首・画数・読みのヒントで推理しよう!",
},
};
export default function KanjiKanaruPage() {
return (
<div className={styles.wrapper}>
<nav className={styles.breadcrumb} aria-label="パンくずリスト">
<Link href="/games" className={styles.breadcrumbLink}>
ゲーム一覧
</Link>
<span className={styles.breadcrumbSeparator} aria-hidden="true">
/
</span>
<span className={styles.breadcrumbCurrent} aria-current="page">
漢字カナール
</span>
</nav>
<GameContainer />
<footer className={styles.attribution}>
<p>
漢字データは{" "}
<a
href="http://www.edrdg.org/wiki/index.php/KANJIDIC_Project"
target="_blank"
rel="noopener noreferrer"
>
KANJIDIC2
</a>{" "}
(CC BY-SA 4.0) を基に作成しています。
</p>
</footer>
</div>
);
}
Step 3: page.module.css の新規作成
ファイル: src/app/games/kanji-kanaru/page.module.css (新規)
内容: パンくずリスト、ページラッパー、attribution のスタイル。サイト共通CSS変数を使用。
.wrapper {
max-width: 600px;
margin: 0 auto;
padding: 1rem 0.5rem;
width: 100%;
}
.breadcrumb {
font-size: 0.85rem;
color: var(--color-text-muted);
margin-bottom: 0.5rem;
padding: 0 0.25rem;
}
.breadcrumbLink {
color: var(--color-primary);
text-decoration: none;
}
.breadcrumbLink:hover {
text-decoration: underline;
}
.breadcrumbSeparator {
margin: 0 0.35rem;
color: var(--color-text-muted);
}
.breadcrumbCurrent {
color: var(--color-text);
}
.attribution {
text-align: center;
padding: 1rem 0;
margin-top: 1rem;
border-top: 1px solid var(--color-border);
font-size: 0.75rem;
color: var(--color-text-muted);
}
.attribution a {
color: var(--color-primary);
text-decoration: underline;
}
Step 4: KanjiKanaru.module.css の CSS変数マイグレーション
ファイル: src/components/games/kanji-kanaru/styles/KanjiKanaru.module.css
方針: 汎用的な色はサイト共通変数に置き換え、ゲーム固有の色は --kk-* として維持する。
CSS変数マッピング:
| 旧変数 (--kk-*) | 新変数 | 理由 |
|---|---|---|
--kk-color-bg |
var(--color-bg) |
サイト共通の背景色 |
--kk-color-text |
var(--color-text) |
サイト共通のテキスト色 |
--kk-color-text-muted |
var(--color-text-muted) |
サイト共通のミュートテキスト色 |
--kk-color-border |
var(--color-border) |
サイト共通のボーダー色 |
--kk-color-error |
var(--color-error) |
サイト共通のエラー色 |
--kk-color-btn-primary |
var(--color-primary) |
サイト共通のプライマリ色 |
--kk-color-btn-primary-hover |
var(--color-primary-hover) |
サイト共通のプライマリホバー色 |
--kk-color-header-bg |
var(--color-bg-secondary) |
サイト共通のセカンダリ背景色 |
--kk-color-modal-bg |
var(--color-bg) |
サイト共通の背景色 |
--kk-color-overlay |
rgba(0, 0, 0, 0.5) |
インライン値(共通変数なし) |
--kk-color-correct |
維持 --kk-color-correct |
ゲーム固有(正解の緑) |
--kk-color-close |
維持 --kk-color-close |
ゲーム固有(近いの黄) |
--kk-color-wrong |
維持 --kk-color-wrong |
ゲーム固有(不正解のグレー) |
--kk-color-empty |
維持 --kk-color-empty |
ゲーム固有(空セルのボーダー) |
具体的な変更:
:rootブロックと@media (prefers-color-scheme: dark)ブロックから、サイト共通変数に置き換え可能なプロパティを削除。ゲーム固有の4色のみ残す。変更後の
:rootブロック:
:root {
--kk-color-correct: #6aaa64;
--kk-color-close: #c9b458;
--kk-color-wrong: #787c7e;
--kk-color-empty: #d3d6da;
}
@media (prefers-color-scheme: dark) {
:root {
--kk-color-correct: #538d4e;
--kk-color-close: #b59f3b;
--kk-color-wrong: #3a3a3c;
--kk-color-empty: #3a3a3c;
}
}
CSS本体の全プロパティ値を一括置換:
var(--kk-color-bg)→var(--color-bg)var(--kk-color-text)→var(--color-text)var(--kk-color-text-muted)→var(--color-text-muted)var(--kk-color-border)→var(--color-border)var(--kk-color-error)→var(--color-error)var(--kk-color-btn-primary)→var(--color-primary)var(--kk-color-btn-primary-hover)→var(--color-primary-hover)var(--kk-color-header-bg)→var(--color-bg-secondary)var(--kk-color-modal-bg)→var(--color-bg)var(--kk-color-overlay)→rgba(0, 0, 0, 0.5)(light) / 直書き
.gameLayout,.gameMain,.gameFooter,.footerDisclaimer,.footerAttributionのスタイルブロックを削除(layout.tsx が共通コンポーネントを使うため不要)。.headerスタイルのbackground-colorを削除(layout の代わりにページコンテンツ内のヘッダーなので背景色不要)。.headerのborder-bottomはvar(--color-border)に変更。
注意: ダークモードについて - 現在のサイトの globals.css にはダークモードの共通変数定義がない。ゲーム固有の4色のみダークモード対応を維持する。基本色のダークモード対応はサイト全体の課題であり、このタスクのスコープ外。
Step 5: GameHeader.tsx の軽微修正
ファイル: src/components/games/kanji-kanaru/GameHeader.tsx
変更内容: 機能変更なし。CSS変数の置換は Step 4 の CSS 側で対応されるため、コンポーネント自体の変更は不要。
ただし、ゲームヘッダーの <header> タグが layout.tsx の <main> 内にあるため、セマンティクス上問題はない(サイトヘッダーとゲーム内ヘッダーは別)。変更不要。
ダークモードに関する注記
現在のサイト全体(globals.css)にダークモード対応がない。漢字カナールの --kk-* 変数にはダークモード定義があったが、共通変数に置き換わる部分についてはダークモードの値がなくなる。
対応方針: この計画ではダークモードの共通変数定義追加はスコープ外とする。ゲーム固有の4色(correct/close/wrong/empty)のダークモード対応は維持する。将来的にサイト全体のダークモード対応を行う際に統一する。
テスト確認項目
自動テスト(ビルド確認)
-
npm run buildが成功すること -
npm run lintがエラーなしで通ること -
npm run testが既存テストを全パスすること
目視確認項目
-
/games/kanji-kanaruページに共通 Header が表示されること - Header のナビゲーションリンク(ホーム、ツール、ゲーム、ブログ、メモ、About)が動作すること
- モバイルナビゲーション(ハンバーガーメニュー)が動作すること
-
/games/kanji-kanaruページに共通 Footer が表示されること(AIディスクレーマー + コピーライト) - パンくずリスト「ゲーム一覧 / 漢字カナール」が表示されること
- パンくずリストの「ゲーム一覧」リンクが
/gamesに遷移すること - KANJIDIC2 attribution テキストがページ内に表示されること
- ゲームの主要機能が正常動作すること:
- 漢字入力 + 送信
- フィードバックセル(緑/黄/灰色)の色が正しいこと
- ヒントバー表示
- 結果モーダル(勝利/敗北)
- 統計モーダル
- 遊び方モーダル
- 結果コピー + Xシェア
- フィードバックセルの色が変わっていないこと(正解=緑、近い=黄、不正解=灰)
- ボタンのフォーカス・ホバーが正常であること
- レスポンシブ対応(モバイル/デスクトップ)が崩れていないこと
受入基準
/games/kanji-kanaruに共通 Header + Footer が表示される- サイト全体のCSS変数(
--color-*)が使用されている(ゲーム固有色4つを除く) - パンくずリスト「ゲーム一覧 / 漢字カナール」が表示され、リンクが動作する
- KANJIDIC2 attribution が表示される
- ゲーム機能が正常動作する(入力、フィードバック、モーダル、シェア)
- フィードバックセルのゲーム固有色(correct/close/wrong/empty)が維持される
npm run build+npm run lint+npm run testがパスする- レスポンシブデザインが維持される
ロールバックアプローチ
- 全変更は1コミットにまとめる(または Step ごとのコミット)
git revert <commit-hash>で元に戻せる- 変更は4ファイルの修正 + 1ファイルの新規作成のみで、影響範囲が限定的
- ゲームのロジック(
src/lib/games/kanji-kanaru/)には一切変更なし
変更禁止リスト
src/lib/games/kanji-kanaru/以下のすべてのファイル(ゲームロジック)src/data/kanji-data.json,src/data/puzzle-schedule.json(ゲームデータ)src/app/globals.css(グローバルCSS)src/components/common/Header.tsx,src/components/common/Footer.tsx(共通コンポーネント)docs/constitution.md(不変)
Next actions
- project manager がこの計画をレビューし、問題なければ builder に実装を依頼する
- builder への実装メモには、この計画の全ステップと変更禁止リストを含めること
- 実装完了後、reviewer にレビューを依頼する