テーマ
UI Design: 投票券購入フロー
機能は requirements.md、技術は design.md 参照。デザイントークンは home/ui-design.md 参照。
モーダル1: PurchaseCreditsModal
レイアウト
┌─────────────────────────────────────────────┐
│ [✕] │
│ 🛒 投票券を購入 │
│ {候補者名}への投票券を選択 │
├─────────────────────────────────────────────┤
│ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ 10票 │ │ 35票 │ │ 60票 │ │ 150票 │ │
│ │¥1,000 │ │¥3,000 │ │¥5,000 │ │¥10,000│ │
│ │ │ │ 人気 │ │ │ │ │ │
│ │[購入] │ │[購入] │ │[購入] │ │[購入] │ │
│ └───────┘ └───────┘ └───────┘ └───────┘ │
└─────────────────────────────────────────────┘コンテナ
- Overlay:
fixed inset-0 bg-black/50 backdrop-blur-sm - Body:
bg-white rounded-3xl p-8 max-w-2xl w-full shadow-2xl - z-index: 90 (login modal より下、stripe modal より下)
ヘッダー
- ShoppingCart アイコン (gold) + 「投票券を購入」
- 候補者名: display フォント、
gold-dark - サブテキスト: 「{候補者名}への投票券を選択してください」
<CreditPackageCard>
- グリッド
grid-cols-2 md:grid-cols-4 gap-4 - 個別カード:
rounded-2xl p-6 border-2- 通常時: 白背景、
border-gold/30 - hover:
border-gold+shadow-lg - 「人気」バッジ付き (popular: true): 上部に
gold→rose-goldグラデバッジ
- 内容(縦並び):
- 票数(display 2.5rem、
gold-dark) - 「票」ラベル(小、opacity 0.6)
- 価格(1.25rem、weight 600)
- 「購入する」ボタン(gold背景、白文字、
rounded-full、mt-4)
- 票数(display 2.5rem、
モーダル2: StripePaymentModal
レイアウト
┌────────────────────────────────────────────┐
│ [← 戻る] [✕] │
│ │
│ 🔒 セキュア決済 (Stripe) │
│ │
│ 購入内容: 35票パッケージ │
│ 金額: ¥3,000 │
├────────────────────────────────────────────┤
│ カード番号 │
│ [0000 0000 0000 0000] │
│ │
│ 有効期限 CVC │
│ [MM/YY] [XXX] │
│ │
│ カード名義 │
│ [TARO YAMADA] │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ ¥3,000を支払う │ │
│ └────────────────────────────────────────┘ │
│ │
│ 🔒 Stripeによるセキュア決済 │
└────────────────────────────────────────────┘コンテナ
- Body:
bg-white rounded-3xl p-8 max-w-md w-full shadow-2xl - z-index: 110 (login modal より上)
ヘッダー
- 戻るボタン: 左上、ArrowLeft + 「戻る」
- 鍵アイコン (Lock) + 「セキュア決済」
- 購入内容ボックス:
- 背景:
rgba(212, 175, 55, 0.05) - 枠:
1px solid rgba(212, 175, 55, 0.2) rounded-xl p-4- 「購入内容」「金額」を縦並びで表示
- 背景:
フォームフィールド
| フィールド | プレースホルダ | 最大幅 |
|---|---|---|
| カード番号 | 0000 0000 0000 0000 | full |
| 有効期限 | MM/YY | half |
| CVC | 123 | half |
| カード名義 | TARO YAMADA | full |
各フィールド:
- ラベル: 0.85rem、weight 500、
charcoalopacity 0.7 - input:
rounded-xl border-2 border-gold/20 px-4 py-3 - focus:
border-gold+outline-none - 入力中の整形: useStripePayment が制御
「支払う」ボタン
| 状態 | スタイル |
|---|---|
| 通常 | gold背景、白文字、rounded-full py-4、weight 600 |
disabled (!isValid) | opacity 0.4、cursor not-allowed |
| processing | スピナー + 「処理中...」 |
状態別の表示
step: 'processing'
- フォーム全体を半透明の overlay で覆う
- 中央に Loader2 (回転)
- 下に「決済処理中...」テキスト
step: 'success'
- フォームを Check アイコン + 「決済完了」表示に置き換え
- 1.5秒後に自動でモーダルを閉じる
- Confetti 用に親に通知
step: 'error'
- フォーム下に赤背景のエラーボックス
- 「もう一度試す」ボタンで
step: 'payment'に戻す
フッター
- 鍵アイコン + 「Stripeによるセキュア決済」
- 0.75rem、opacity 0.6、中央揃え
アニメーション
| 要素 | プロパティ | timing |
|---|---|---|
| Modal 開閉 | scale (0.9→1), opacity | spring damping: 20 |
| パッケージカード hover | translateY(-4) + shadow | 200ms |
| 「人気」バッジ | 軽い脈動 (scale 1→1.05→1) | 2s loop |
| Loading スピナー | 360deg 回転 | 1s linear infinite |
| Success Check | scale (0→1) | spring |
レスポンシブ
モバイル
- パッケージカード: 2列グリッド
- StripePaymentModal: 横幅
max-w-sm - フォームフィールドは全て full 幅
タブレット以上
- パッケージカード: 4列グリッド
- StripePaymentModal:
max-w-md
アクセシビリティ
- フォームには
<label>を関連付け(htmlFor) - カード番号入力に
inputmode="numeric"とautocomplete="cc-number" - 有効期限に
autocomplete="cc-exp" - CVC に
autocomplete="cc-csc" - エラー時に
aria-invalid="true"+aria-describedby="error-message" - 処理中はフォーム全体を
aria-busy="true"
関連
requirements.md/design.md../home/ui-design.md— デザイントークン../social-login/ui-design.md— モーダル共通スタイル