Skip to content

イベント作成ボタン仕様 ​

このドキュメントはNotionの内容を拡張したものです。TypeScriptコード例などの詳細な実装仕様が追加されています。

概要 ​

一人用と複数人用イベント作成ボタンの表示ロジックと挙動の詳細仕様です。プレイ可能性の判定、ボタンパターンと表示色の定義、revisionによるアップデート検証について定義します。

ボタンパターンと表示色 ​

Primary(青色)ボタン ​

  • 表示条件: プレイ可能
  • 色: UZU Primary Blue (#0066CC)
  • テキスト: 白色
  • 「>」マーク: あり(右端に配置)
  • 挙動: タップでイベント作成フローに進む

白色ボタン ​

  • 表示条件: プレイ可能だが推奨度が低い場合
  • 色: 白色背景、グレー枠線
  • テキスト: グレー色
  • 「>」マーク: あり(右端に配置)
  • 挙動: タップでイベント作成フローに進む

Disable(無効)ボタン ​

  • 表示条件: プレイ不可能
  • 色: グレー背景 (#F5F5F5)
  • テキスト: 薄いグレー色
  • 「>」マーク: なし
  • 挙動: タップ無効、理由をツールチップで表示

プレイ可能性の判定ロジック ​

一人用イベント ​

typescript
interface SoloEventPlayability {
  isPlayable: boolean;
  buttonType: 'primary' | 'white' | 'disabled';
  disabledReason?: string;
}

function checkSoloEventPlayability(
  scenario: Scenario,
  user: User
): SoloEventPlayability {
  // 基本的な判定
  if (!scenario.isActive) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: 'シナリオが非公開です'
    };
  }

  if (scenario.minPlayers > 1) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: '複数人専用シナリオです'
    };
  }

  // レベル制限チェック
  if (user.level < scenario.requiredLevel) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: `レベル${scenario.requiredLevel}以上が必要です`
    };
  }

  // プレイ済みチェック
  if (scenario.isPlayedByUser && !scenario.isReplayable) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: 'プレイ済みのシナリオです'
    };
  }

  // プライマリ表示条件
  if (scenario.isRecommended || scenario.isNew) {
    return {
      isPlayable: true,
      buttonType: 'primary'
    };
  }

  // 通常表示
  return {
    isPlayable: true,
    buttonType: 'white'
  };
}

複数人用イベント ​

typescript
interface MultiEventPlayability {
  isPlayable: boolean;
  buttonType: 'primary' | 'white' | 'disabled';
  disabledReason?: string;
  requiredPlayers: number;
}

function checkMultiEventPlayability(
  scenario: Scenario,
  user: User,
  availableFriends: number
): MultiEventPlayability {
  // 基本的な判定
  if (!scenario.isActive) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: 'シナリオが非公開です',
      requiredPlayers: scenario.maxPlayers
    };
  }

  if (scenario.maxPlayers <= 1) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: '一人用専用シナリオです',
      requiredPlayers: 1
    };
  }

  // フレンド数チェック
  if (availableFriends < scenario.minPlayers - 1) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: `${scenario.minPlayers}人以上必要です(フレンド不足)`,
      requiredPlayers: scenario.minPlayers
    };
  }

  // レベル制限チェック
  if (user.level < scenario.requiredLevel) {
    return {
      isPlayable: false,
      buttonType: 'disabled',
      disabledReason: `レベル${scenario.requiredLevel}以上が必要です`,
      requiredPlayers: scenario.maxPlayers
    };
  }

  // プライマリ表示条件
  if (scenario.isRecommended || scenario.isNew) {
    return {
      isPlayable: true,
      buttonType: 'primary',
      requiredPlayers: scenario.maxPlayers
    };
  }

  // 通常表示
  return {
    isPlayable: true,
    buttonType: 'white',
    requiredPlayers: scenario.maxPlayers
  };
}

revisionによるアップデート検証 ​

アップデート判定ロジック ​

typescript
interface ScenarioUpdateInfo {
  hasUpdate: boolean;
  currentRevision: number;
  latestRevision: number;
  updateBadge: boolean;
}

function checkScenarioUpdate(
  localScenario: CachedScenario,
  remoteScenario: Scenario
): ScenarioUpdateInfo {
  const hasUpdate = localScenario.revision < remoteScenario.revision;
  
  return {
    hasUpdate,
    currentRevision: localScenario.revision,
    latestRevision: remoteScenario.revision,
    updateBadge: hasUpdate && remoteScenario.isSignificantUpdate
  };
}

アップデートバッジ表示 ​

  • 表示条件: hasUpdate && isSignificantUpdate
  • 位置: ボタン右上角
  • 色: 赤色背景、白文字
  • テキスト: "NEW" または更新アイコン
  • 挙動: タップでアップデート内容を表示

ボタンレイアウト ​

標準レイアウト ​

css
.event-button {
  height: 56px;
  border-radius: 8px;
  padding: 12px 16px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.event-button-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
}

.event-button-title {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 2px;
}

.event-button-subtitle {
  font-size: 12px;
  opacity: 0.7;
}

.event-button-arrow {
  width: 24px;
  height: 24px;
  opacity: 0.6;
}

Primary(青色)スタイル ​

css
.event-button-primary {
  background-color: #0066CC;
  border: none;
  color: white;
}

.event-button-primary .event-button-arrow {
  color: white;
}

白色スタイル ​

css
.event-button-white {
  background-color: white;
  border: 1px solid #E0E0E0;
  color: #666666;
}

.event-button-white .event-button-arrow {
  color: #666666;
}

Disable(無効)スタイル ​

css
.event-button-disabled {
  background-color: #F5F5F5;
  border: 1px solid #E0E0E0;
  color: #CCCCCC;
  cursor: not-allowed;
}

.event-button-disabled .event-button-arrow {
  display: none;
}

実装注意事項 ​

  1. パフォーマンス: プレイ可能性判定の結果をキャッシュ
  2. アクセシビリティ: 無効ボタンの理由を音声読み上げで伝達
  3. UX: アップデート情報の分かりやすい表示
  4. エラーハンドリング: ネットワークエラー時の適切な表示