From d65ae19f5e921451235b29e5034abedf13ac4279 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Thu, 15 Jan 2026 10:08:25 -0600 Subject: [PATCH] CLAUDE: Add lineup builder polish - search, filters, player preview, visual improvements Features: - Player search box with filter by name - Position filter tabs (All, Catchers, Infielders, Outfielders, Pitchers) - Player preview modal on click (shows positions, wara rating) - Clear lineup button with confirmation styling - Progress bar showing lineup completion - Player headshots in both roster list and lineup slots - Skeleton loading state during data fetch - Sticky navigation header with back button - Improved visual styling throughout (pills, cards, badges) TypeScript fixes: - Added pitcherPlayer computed property for proper type narrowing - Removed non-existent SbaPlayer stats (batting_average, home_runs, rbi) - Fixed unused variable warnings Co-Authored-By: Claude Opus 4.5 --- frontend-sba/pages/games/lineup/[id].vue | 610 +++++++++++++++++++---- 1 file changed, 502 insertions(+), 108 deletions(-) diff --git a/frontend-sba/pages/games/lineup/[id].vue b/frontend-sba/pages/games/lineup/[id].vue index c2722bf..97624a7 100644 --- a/frontend-sba/pages/games/lineup/[id].vue +++ b/frontend-sba/pages/games/lineup/[id].vue @@ -18,6 +18,15 @@ const season = ref(3) type TeamTab = 'home' | 'away' const activeTab = ref('away') // Away bats first +// Search and filter state +const searchQuery = ref('') +type PositionFilter = 'all' | 'catchers' | 'infielders' | 'outfielders' | 'pitchers' +const positionFilter = ref('all') + +// Player preview modal +const previewPlayer = ref(null) +const showPreview = ref(false) + // Roster data const homeRoster = ref([]) const awayRoster = ref([]) @@ -189,6 +198,77 @@ function removePlayer(slotIndex: number) { lineup[slotIndex].position = null } +// Clear entire lineup for current team +function clearLineup() { + const lineup = activeTab.value === 'home' ? homeLineup.value : awayLineup.value + lineup.forEach((slot, index) => { + slot.player = null + slot.position = null + }) +} + +// Position category helpers +const CATCHER_POSITIONS = ['C'] +const INFIELD_POSITIONS = ['1B', '2B', '3B', 'SS'] +const OUTFIELD_POSITIONS = ['LF', 'CF', 'RF'] +const PITCHER_POSITIONS = ['P'] + +function playerHasPositionInCategory(player: SbaPlayer, category: PositionFilter): boolean { + if (category === 'all') return true + + const positions = getPlayerPositions(player) + + switch (category) { + case 'catchers': + return positions.some(p => CATCHER_POSITIONS.includes(p)) + case 'infielders': + return positions.some(p => INFIELD_POSITIONS.includes(p)) + case 'outfielders': + return positions.some(p => OUTFIELD_POSITIONS.includes(p)) + case 'pitchers': + return positions.some(p => PITCHER_POSITIONS.includes(p)) + default: + return true + } +} + +// Filtered roster based on search and position filter +const filteredRoster = computed(() => { + let roster = currentRoster.value + + // Apply search filter + if (searchQuery.value.trim()) { + const query = searchQuery.value.toLowerCase().trim() + roster = roster.filter(p => p.name.toLowerCase().includes(query)) + } + + // Apply position filter + if (positionFilter.value !== 'all') { + roster = roster.filter(p => playerHasPositionInCategory(p, positionFilter.value)) + } + + return roster +}) + +// Count of players in current lineup +const currentLineupCount = computed(() => { + return currentLineup.value.filter(s => s.player).length +}) + +// Pitcher slot helper (for TypeScript narrowing) +const pitcherPlayer = computed(() => currentLineup.value[9]?.player) + +// Show player preview +function openPlayerPreview(player: SbaPlayer) { + previewPlayer.value = player + showPreview.value = true +} + +function closePlayerPreview() { + showPreview.value = false + previewPlayer.value = null +} + // Fetch game data async function fetchGameData() { try { @@ -299,92 +379,254 @@ onMounted(async () => {