Skip to content

Feature/diagnosi UI#39

Merged
Koseeee-27 merged 22 commits intodevelopfrom
feature/diagnosi-ui
Feb 22, 2026
Merged

Feature/diagnosi UI#39
Koseeee-27 merged 22 commits intodevelopfrom
feature/diagnosi-ui

Conversation

@Koseeee-27
Copy link
Copy Markdown
Contributor

診断UIの改善 (feature/diagnosi-ui)

概要

診断フロー(MBTI選択・簡易性格診断)のUIを整備し、バックエンド仕様に合わせた型定義とスタイルの共通化を行いました。

変更内容

背景の共通化

  • globals.css に Tailwind v4 の @utility で共通背景を定義
    • bg-page-pattern: 黄色ベース + 白の水玉模様(診断ページなど)
    • bg-top-pattern: SVG背景 + 白の水玉オーバーレイ(トップページ)
  • 診断ページ・トップページで共通クラスを利用

MBTI選択画面(MbtiSelect)

  • 4ジャンル(分析家・外交官・番人・探検家)のタブ切り替えUI
  • キャラクターカードのカルーセル表示(左右矢印で遷移)
  • 決定確認ポップアップの追加
  • レイアウト調整: 中央寄せ、縦方向の拡張(min-h-[70vh])、余白の削減
  • キャラ画像サイズの拡大(max-h-36 → max-h-44)

簡易性格診断(BaselineSurvey)

  • バックエンド仕様に合わせた型定義の修正
    • QuestionOption: { value: 'A'|'B'|'C'|'D', label: string } を追加
    • 表示用ラベルと送信用の値(A/B/C/D)を分離
  • 型エラーの解消と baseline_answers 形式での送信に対応

その他

  • <img> を Next.js の <Image> に置き換え(LCP・帯域の最適化)
  • ESLint の警告対応(未使用変数など)

Copy link
Copy Markdown

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

This PR improves the diagnosis flow UI (MBTI selection and baseline survey) by:

Changes:

  • Implemented common background patterns in Tailwind v4 utilities (yellow + white dots for diagnostic pages, SVG + white dots for top page)
  • Enhanced MBTI selection screen with tabbed interface, carousel navigation, confirmation popup, and larger character images
  • Updated BaselineSurvey to align with backend specification using new QuestionOption type structure
  • Migrated <img> to Next.js <Image> components for performance optimization

Reviewed changes

Copilot reviewed 6 out of 26 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
frontend/src/features/diagnosis/types/index.ts Added QuestionOption type and finalized quiz questions with Japanese content
frontend/src/features/diagnosis/components/MbtiSelect.tsx Complete UI overhaul with tabs, carousel, animations, and confirmation dialog
frontend/src/features/diagnosis/components/BaselineSurvey.tsx Updated to use new QuestionOption type structure
frontend/src/app/page.tsx Migrated to Next.js Image component and applied background pattern
frontend/src/app/globals.css Added Tailwind v4 utilities for common background patterns
frontend/src/app/diagnosis/page.tsx Applied background pattern utility
frontend/public/images/StartButton.png New start button image asset

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +184 to +213
<motion.button
key={type.code}
type="button"
onClick={() => setSelected(type.code)}
className="relative flex flex-1 basis-0 flex-col cursor-pointer items-center justify-center overflow-hidden rounded-4xl bg-transparent outline-none ring-0"
whileHover={{
scale: 1.2,
y: -16,
transition: { duration: 0.2 },
}}
whileTap={{ scale: 1.02 }}
style={{ boxShadow: 'none' }}
>
<div className="relative flex min-h-0 flex-1 items-center justify-center w-full">
<Image
src={`/images/mbti/${type.code}.png`}
alt={type.name}
width={176}
height={176}
className="max-h-44 w-auto border-0 object-contain outline-none"
/>
<div
className={`absolute bottom-0 left-0 right-0 ${GROUP_OVERLAY_COLORS[groupIndex]} py-1.5 px-2 text-center`}
>
<p className="text-sm font-bold text-white">
{type.code} / {type.name}
</p>
</div>
</div>
</motion.button>
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.

The motion.button elements for MBTI type selection should have accessible labels. Each button should include an aria-label describing what it does, such as aria-label={${type.code} ${type.name}を選択}. This helps screen reader users understand what each button represents.

Copilot uses AI. Check for mistakes.
Comment on lines +119 to +136
<motion.button
key={group}
type="button"
onClick={() => handleTabClick(index)}
className={`relative z-10 cursor-pointer rounded-t-lg border-4 border-b-0 border-gray-800 px-4 py-2 text-base font-semibold text-gray-800 ${
GROUP_COLORS[index]
} ${groupIndex === index ? 'mb-[-4px]' : ''}`}
animate={{
y: groupIndex === index ? 2 : 0,
boxShadow:
groupIndex === index
? 'inset 0 3px 6px rgba(0,0,0,0.12)'
: 'none',
}}
transition={{ duration: 0.2 }}
>
{group}
</motion.button>
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.

The tab buttons should have aria-selected attributes to indicate which tab is currently active. Add aria-selected={groupIndex === index} to improve accessibility for screen reader users navigating the tabs.

Copilot uses AI. Check for mistakes.
Comment on lines +231 to +284
{selectedType && (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/50"
role="dialog"
aria-modal="true"
aria-labelledby="mbti-confirm-title"
>
スキップ
</button>
</div>
<div
className={`mx-4 w-full max-w-md rounded-2xl border-4 border-gray-800 p-6 shadow-xl ${
GROUP_COLORS[
Math.max(
0,
MBTI_GROUPS.findIndex((g) => g === selectedType.group)
)
]
}`}
>
<p
id="mbti-confirm-title"
className="text-center text-lg font-bold text-gray-900"
>
あなたのMBTIは
</p>
<div className="my-4 flex justify-center">
<Image
src={`/images/mbti/${selectedType.code}.png`}
alt={selectedType.name}
width={128}
height={128}
className="h-32 w-auto border-0 object-contain outline-none"
/>
</div>
<p className="text-center text-xl font-bold text-gray-900">
{selectedType.code} / {selectedType.name}
</p>
<div className="mt-6 flex gap-4">
<button
type="button"
onClick={handleReselect}
className="flex-1 cursor-pointer rounded-lg border-4 border-gray-800 bg-white px-4 py-3 font-semibold text-gray-800 transition-all duration-200 hover:scale-105 hover:bg-gray-100 hover:shadow-md active:scale-95"
>
選び直す
</button>
<button
type="button"
onClick={handleConfirm}
className="flex-1 cursor-pointer rounded-lg border-4 border-gray-800 bg-white px-4 py-3 font-semibold text-gray-800 transition-all duration-200 hover:scale-105 hover:bg-gray-100 hover:shadow-md active:scale-95"
>
決定
</button>
</div>
</div>
</div>
)}
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.

The confirmation dialog should implement keyboard trap (focus management) and allow closing with the ESC key for better accessibility. Consider using a focus trap library or implementing custom keyboard event handlers to prevent focus from leaving the modal when open, and add an onKeyDown handler to close the modal when ESC is pressed.

Copilot uses AI. Check for mistakes.
Comment on lines +158 to +225
<button
type="button"
onClick={handleArrowPrev}
aria-label="前のジャンル"
className="h-0 w-0 shrink-0 cursor-pointer border-y-18 border-r-24 border-l-0 border-y-transparent border-r-white transition hover:border-r-gray-200 hover:scale-110"
/>

<div className="relative min-h-52 overflow-visible">
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={groupIndex}
initial="enter"
animate="center"
exit="exit"
variants={contentVariants}
transition={{ duration: 0.25 }}
className="absolute inset-0 flex items-center justify-center gap-1"
>
{type.code}
<span className="ml-1 font-normal text-gray-500">
{type.name}
</span>
</button>
))}
<div
className="flex h-full w-full items-stretch justify-center gap-2 rounded-lg bg-white px-1 py-1"
style={{
backgroundImage: `radial-gradient(circle, ${GROUP_COLOR_HEX[groupIndex]} 2px, transparent 2px)`,
backgroundSize: '20px 20px',
}}
>
{currentTypes.map((type) => (
<motion.button
key={type.code}
type="button"
onClick={() => setSelected(type.code)}
className="relative flex flex-1 basis-0 flex-col cursor-pointer items-center justify-center overflow-hidden rounded-4xl bg-transparent outline-none ring-0"
whileHover={{
scale: 1.2,
y: -16,
transition: { duration: 0.2 },
}}
whileTap={{ scale: 1.02 }}
style={{ boxShadow: 'none' }}
>
<div className="relative flex min-h-0 flex-1 items-center justify-center w-full">
<Image
src={`/images/mbti/${type.code}.png`}
alt={type.name}
width={176}
height={176}
className="max-h-44 w-auto border-0 object-contain outline-none"
/>
<div
className={`absolute bottom-0 left-0 right-0 ${GROUP_OVERLAY_COLORS[groupIndex]} py-1.5 px-2 text-center`}
>
<p className="text-sm font-bold text-white">
{type.code} / {type.name}
</p>
</div>
</div>
</motion.button>
))}
</div>
</motion.div>
</AnimatePresence>
</div>

<button
type="button"
onClick={handleArrowNext}
aria-label="次のジャンル"
className="h-0 w-0 shrink-0 cursor-pointer border-y-18 border-l-24 border-r-0 border-y-transparent border-l-white transition hover:border-l-gray-200 hover:scale-110"
/>
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.

The arrow navigation buttons (triangles created with CSS borders) may not be accessible via keyboard navigation alone. While they have proper aria-label attributes, users navigating with keyboard should also be able to use left/right arrow keys to navigate between groups. Consider adding keyboard event handlers to support arrow key navigation.

Copilot uses AI. Check for mistakes.
Comment on lines +240 to +245
GROUP_COLORS[
Math.max(
0,
MBTI_GROUPS.findIndex((g) => g === selectedType.group)
)
]
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.

The use of Math.max(0, MBTI_GROUPS.findIndex(...)) is defensive but may hide a potential bug. If selectedType.group doesn't match any MBTI_GROUPS entry, findIndex returns -1, and this code falls back to index 0. Since selectedType should always have a valid group matching one of MBTI_GROUPS, consider adding a runtime check or assertion to catch this case during development instead of silently defaulting to index 0.

Copilot uses AI. Check for mistakes.
@Koseeee-27 Koseeee-27 requested review from ru-se and tamtya February 22, 2026 00:10
@Koseeee-27 Koseeee-27 merged commit f1f441f into develop Feb 22, 2026
1 check passed
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