Skip to content

feat: #91 ランク画像を実装#92

Merged
Neon-straySheep merged 2 commits intodevelopfrom
feature/issue-91-rank-images
Feb 21, 2026
Merged

feat: #91 ランク画像を実装#92
Neon-straySheep merged 2 commits intodevelopfrom
feature/issue-91-rank-images

Conversation

@Neon-straySheep
Copy link
Contributor

実装の概要

エンジニアランク(Rank 0~9)の表示を、従来の色分け表示から画像表示に変更しました。各ランクに対応する木のイラスト画像を使用し、種子から世界樹へと成長していく視覚的な表現を実現しています。

主な変更内容

  1. RankBadgeコンポーネントの拡張

    • displayMode prop追加("image" / "color"
    • Next.jsのnext/imageを使用した画像表示機能
    • 画像読み込み失敗時の自動フォールバック機能
  2. ランクラベルの統一

    • 木の成長をテーマにした一貫したネーミング
    • 種子 → 苗木 → 若木 → 巨木 → 母樹 → 林 → 森 → 霊樹 → 古樹 → 世界樹
  3. 画像ファイルの配置

    • frontend/public/images/ranks/配下に10枚の画像を配置
    • PNG形式、RGBA、透過背景対応

🔧 技術的な意思決定とトレードオフ (最重要)

採用したアプローチ

  • 手法: Next.jsのImageコンポーネントを使用した画像表示
  • メリット:
    • 自動的な画像最適化(WebP変換、サイズ最適化)
    • Lazy loading による初期表示パフォーマンスの向上
    • レスポンシブ対応が容易
  • デメリット/リスク:
    • 初回表示時に画像ダウンロードが発生(ただしNext.jsのキャッシュで軽減)
    • 画像ファイルがない場合のフォールバック処理が必要

却下したアプローチ(代替案)

  • 手法: SVGをReactコンポーネントとしてインライン化
  • 却下理由:
    • 画像が複雑なイラストのため、SVG化するとファイルサイズが大きくなる
    • デザイナーがPNGで提供している画像をそのまま活用できる方が運用しやすい
    • 将来的なデザイン変更時の柔軟性を確保

🧪 テスト戦略と範囲

実施したテスト

  • TypeScript型チェック: エラーなし
  • ESLint: エラーなし
  • Next.jsビルド: 正常完了
  • 画像ファイル検証: 全10ファイル配置確認(PNG形式、RGBA)
  • ブラウザ表示確認: 全ランク(0~9)の画像表示を確認
  • レスポンシブ対応: サイズ(sm/md/lg)が適切に表示
  • エッジケーステスト: 異常値(-1, 10, 999, NaN)がRank 0にフォールバック
  • 後方互換性: displayMode="color"で従来の色分け表示が動作

追加したテストケース

  • 正常系: Rank 0~9の全画像が正しく表示される
  • 正常系: 画像のアスペクト比が維持される
  • 異常系: ランク番号の範囲外(-1, 10, 999)はRank 0にフォールバック
  • 異常系: NaN値の場合もRank 0にフォールバック
  • 異常系: 画像が見つからない場合、色分け表示にフォールバック(console.warn出力)
  • テストしていないこと:
    • 画像の実際のロード時間によるパフォーマンステスト(本番環境での計測が必要)
    • 極端に遅いネットワーク環境での挙動

セキュリティに関する自己評価

  • 機密情報のハードコードはないか: なし
  • 入力値の検証(バリデーション)は行っているか:
    • ランク番号を厳格に検証(typeof rank === 'number' && rank >= 0 && rank <= 9
    • 範囲外の値は強制的にRank 0にフォールバック
  • 既知の脆弱性パターンへの対策は考慮したか:
    • XSS対策: ランク番号の検証により、不正な値がパス生成に使用されることを防止
    • パストラバーサル対策: 画像パスはランク番号からのみ生成され、ユーザー入力に依存しない
    • アクセシビリティ: altテキスト、sr-only、aria-labelで適切な情報提供

アクセシビリティ対応

  • 画像に適切なaltテキスト設定
  • スクリーンリーダー用にsr-onlyクラスで追加情報提供
  • 色分けモードにもaria-labelを設定
  • キーボード操作に影響なし

レビュワー(人間)への申し送り事項

確認してほしいポイント

  1. 画像表示の確認

    • ダッシュボード画面でランクバッジが画像で表示されているか
    • 各ランクの画像が適切に表示されているか
  2. フォールバック動作

    • 実装上は画像読み込み失敗時に色分け表示にフォールバックしますが、現状全画像が配置済みなので通常は発生しません
    • テストしたい場合は、DevToolsのNetworkタブで画像をブロックしてください
  3. ランクラベルの統一

    • 木のテーマに統一したラベル(種子→世界樹)が適切か
    • 必要に応じて別途議論・調整可能

実装上の注意点

  • displayModeのデフォルトは"image": 既存のRankBadge使用箇所は自動的に画像表示になります
  • 後方互換性: displayMode="color"を指定することで従来の色分け表示も可能
  • RANK_COLORS定数は削除せず保持: フォールバック用として必要

今後の拡張性

  • ランク画像のアニメーション化(CSSアニメーション or Lottie)の追加が容易
  • 画像ファイルの差し替えのみでデザイン変更が可能
  • 将来的にランク数が増えた場合も、画像追加とRANK_COLORS更新のみで対応可

スクリーンショット

※ ブラウザで http://localhost:3000/test-rank を開いて確認済み

  • Rank 0~9の全画像表示
  • サイズバリエーション(sm/md/lg)
  • エッジケースのフォールバック動作

チェックリスト

  • コードに機密情報が含まれていないか確認
  • TypeScript型チェック通過
  • ESLintエラーなし
  • ビルド成功
  • ブラウザでの動作確認完了
  • コミットメッセージがConventional Commits形式
  • Issue番号をコミットメッセージに含めた
  • セキュリティ対策を実装(XSS、入力検証)
  • アクセシビリティ対応済み

補足情報

ファイル変更サマリー

  • 変更: frontend/src/features/dashboard/components/RankBadge.tsx (機能拡張)
  • 変更: frontend/src/features/dashboard/components/StatusCard.tsx (displayMode指定)
  • 変更: frontend/src/features/dashboard/constants/rankColors.ts (ラベル統一)
  • 新規: frontend/public/images/ranks/ (ディレクトリ + 画像10枚 + README)

コミット履歴

  1. feat: #91 ランク表示画像実装用のコンポーネント更新

    • RankBadge、StatusCardの更新
    • 画像ディレクトリ作成
  2. feat: #91 ランクラベルを木のテーマに統一

    • RANK_COLORSのラベル更新

RankBadgeコンポーネントに画像表示モードを追加。
displayMode="image"で画像表示、"color"で従来の色分け表示が可能。
画像読み込み失敗時は自動的に色分け表示にフォールバック。

変更内容:
- RankBadge: displayMode prop追加、Next.js Image使用、エラーハンドリング実装
- StatusCard: RankBadgeにdisplayMode="image"を明示的に指定
- frontend/public/images/ranks/: 画像配置用ディレクトリ作成、README追加

セキュリティ対策:
- ランク番号の検証(0-9の範囲チェック)でXSS対策
- 画像パスはユーザー入力に依存しない固定パス使用

アクセシビリティ対応:
- altテキスト設定
- スクリーンリーダー用のsr-onlyテキスト追加
- 画像表示時もaria-labelで情報提供
ランクラベルを以下のように変更:
- Rank 0: 初心者 → 種子
- Rank 1: 見習い → 苗木
- Rank 2: 駆け出し → 若木
- Rank 3: 中級者 → 巨木
- Rank 4: 実践者 → 母樹
- Rank 5: 熟練者 → 林
- Rank 6: エキスパート → 森
- Rank 7: マスター → 霊樹
- Rank 8: レジェンド → 古樹
- Rank 9: グランドマスター → 世界樹

種子から世界樹へと成長していく一貫したテーマを設定し、
ユーザーの成長過程を視覚的に表現。
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

このPRは、エンジニアランク(Rank 0~9)の表示を、従来の色分け表示から画像表示に変更する機能を実装しています。各ランクに対応する木のイラスト画像を使用し、種子から世界樹へと成長していく視覚的な表現を実現しています。

Changes:

  • RankBadgeコンポーネントに画像表示モード(displayMode="image")を追加し、Next.jsのImageコンポーネントを使用した画像表示機能を実装
  • ランクラベルを木の成長をテーマにした統一ネーミングに変更(種子→苗木→若木→巨木→母樹→林→森→霊樹→古樹→世界樹)
  • frontend/public/images/ranks/ディレクトリに10枚のランク画像(PNG形式)を配置し、README.mdで仕様を文書化

Reviewed changes

Copilot reviewed 4 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
frontend/src/features/dashboard/components/RankBadge.tsx 画像表示モードの追加、入力検証の実装、フォールバック機能の実装
frontend/src/features/dashboard/components/StatusCard.tsx RankBadgeコンポーネントにdisplayMode="image"を指定
frontend/src/features/dashboard/constants/rankColors.ts ランクラベルを木のテーマに統一
frontend/public/images/ranks/rank_tree_*.png Rank 0~9に対応する10枚の画像ファイルを追加
frontend/public/images/ranks/README.md 画像ディレクトリの仕様と使用方法を文書化
Comments suppressed due to low confidence (2)

frontend/src/features/dashboard/components/RankBadge.tsx:67

  • 画像表示時のsr-onlyテキストは、既にImageコンポーネントのalt属性で同じ情報を提供しているため、冗長です。スクリーンリーダーはalt属性を読み上げるため、追加のsr-only要素は不要です。この行を削除することを推奨します。
        {/* スクリーンリーダー用のテキスト */}
        <span className="sr-only">{altText}</span>

frontend/src/features/dashboard/components/StatusCard.tsx:63

  • displayModeプロパティは明示的に"image"として指定されていますが、デフォルト値も"image"(行20)であるため、この指定は冗長です。コードの簡潔性のため、デフォルト値に依存する場合はこのプロパティを省略できます。
          <RankBadge 
            rank={rank.rank} 
            label={rank.rank_name} 
            size="lg" 
            displayMode="image"

Comment on lines +54 to +64
<Image
src={imagePath}
alt={altText}
width={80}
height={80}
className="h-full w-auto object-contain"
onError={() => {
console.warn(`Failed to load rank image: ${imagePath}. Falling back to color mode.`);
setImageError(true);
}}
priority={size === "lg"}
Copy link

Copilot AI Feb 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Next.jsのImageコンポーネントはonErrorプロパティをサポートしていません。画像の読み込み失敗時のフォールバック処理が動作しない可能性があります。

代替案として、以下のいずれかの方法を推奨します:

  1. 通常の<img>タグを使用してonErrorを処理する(frontend/src/features/exercise/components/ExerciseMenu.tsxの81行目の実装パターンを参照)
  2. 画像の存在を事前に検証するサーバーサイドロジックを追加する
  3. エラーバウンダリーコンポーネントを使用する

Copilot uses AI. Check for mistakes.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot 君のフィードバックによると読み込み失敗の対策が足りないそう 詳細はこちら

Copy link

Copilot AI commented Feb 21, 2026

@Neon-straySheep I've opened a new pull request, #94, to work on those changes. Once the pull request is ready, I'll request review from you.

@Neon-straySheep
Copy link
Contributor Author

スクリーンショット 2026-02-22 0 43 05 スクリーンショット 2026-02-22 0 43 12 スクリーンショット 2026-02-22 0 43 18

@Neon-straySheep
Copy link
Contributor Author

ほんまに申し訳ないんですけどマイグレーション周りの解像度とランクの変更周りがちょっとアレだったのでそれ用のページを用意してもらってテストしました。一応コードざっと見た感じ大丈夫のはずです

@Neon-straySheep Neon-straySheep merged commit 9c913b8 into develop Feb 21, 2026
8 checks passed
Neon-straySheep added a commit that referenced this pull request Feb 21, 2026
スキルツリー左側のRankBarコンポーネントで、ランク番号(数字)の代わりに
ランク画像(rank_tree_0.png~rank_tree_9.png)を表示するように変更。

【変更理由】
- 既存の画像アセットが未使用だった
- ユーザー体験向上のため視覚的な表現を強化

【技術的な実装】
- Next.js Image コンポーネントを使用して最適化
- tierIndex(0-9)を基に画像パスを動的生成
- レトロピクセル感を維持するため imageRendering を設定
Neon-straySheep added a commit that referenced this pull request Feb 21, 2026
feat: #92 RankBarコンポーネントにランク画像表示を実装
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants