strat-gameplay-webapp/frontend-sba/components/Schedule/GameCard.vue
Cal Corum 52706bed40 CLAUDE: Mobile drag-drop lineup builder and touch-friendly UI improvements
- Add vuedraggable for mobile-friendly lineup building
- Add touch delay and threshold settings for better mobile UX
- Add drag ghost/chosen/dragging visual states
- Add replacement mode visual feedback when dragging over occupied slots
- Add getBench action to useGameActions for substitution panel
- Add BN (bench) to valid positions in LineupPlayerState
- Update lineup service to load full lineup (active + bench)
- Add touch-manipulation CSS to UI components (ActionButton, ButtonGroup, ToggleSwitch)
- Add select-none to prevent text selection during touch interactions
- Add mobile touch patterns documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 22:17:16 -06:00

88 lines
2.7 KiB
Vue

<template>
<div class="bg-white rounded-lg shadow-md hover:shadow-lg transition p-4 border border-gray-200">
<!-- Game Badge -->
<div class="flex justify-between items-start mb-3">
<span class="px-2 py-1 text-xs font-medium bg-gray-100 text-gray-600 rounded">
{{ game.season_type || 'Regular' }}
</span>
<span v-if="hasScore" class="text-xs text-green-600 font-medium">
Completed
</span>
</div>
<!-- Matchup Display -->
<div class="space-y-2 mb-4">
<!-- Away Team -->
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<span class="text-xs text-gray-400 w-10">Away</span>
<span class="font-semibold text-gray-900">
{{ game.away_team.abbrev }}
</span>
<span class="text-sm text-gray-600 hidden sm:inline">
{{ game.away_team.sname }}
</span>
</div>
<span v-if="game.away_score !== null" class="text-lg font-bold tabular-nums">
{{ game.away_score }}
</span>
</div>
<!-- Home Team -->
<div class="flex items-center justify-between">
<div class="flex items-center gap-2">
<span class="text-xs text-gray-400 w-10">Home</span>
<span class="font-semibold text-gray-900">
{{ game.home_team.abbrev }}
</span>
<span class="text-sm text-gray-600 hidden sm:inline">
{{ game.home_team.sname }}
</span>
</div>
<span v-if="game.home_score !== null" class="text-lg font-bold tabular-nums">
{{ game.home_score }}
</span>
</div>
</div>
<!-- Play This Game Button -->
<button
@click="handlePlayGame"
:disabled="isCreating"
class="w-full px-4 py-2 bg-primary hover:bg-blue-700 disabled:bg-gray-400 text-white font-medium rounded-lg transition disabled:cursor-not-allowed select-none touch-manipulation"
>
{{ isCreating ? 'Creating...' : 'Play This Game' }}
</button>
</div>
</template>
<script setup lang="ts">
import type { SbaScheduledGame } from '~/types'
interface Props {
game: SbaScheduledGame
}
const props = defineProps<Props>()
const emit = defineEmits<{
play: [homeTeamId: number, awayTeamId: number]
}>()
const isCreating = ref(false)
// Check if game has scores (completed)
const hasScore = computed(() => {
return props.game.away_score !== null && props.game.home_score !== null
})
function handlePlayGame() {
emit('play', props.game.home_team.id, props.game.away_team.id)
}
// Expose isCreating for parent to control
defineExpose({
setCreating: (value: boolean) => { isCreating.value = value }
})
</script>