fix(card-sorting): adjust viewport dimensions for spectator panels

Fixed issue where cards were positioned based on full window size instead
of the reduced game board area when spectator panels are visible.

The root cause:
- viewportDimensions used window.innerWidth/innerHeight (full browser size)
- Game board container was resized to account for panels
- Cards were positioned using full viewport dimensions, causing them to
  extend beyond the visible game board and go under the stats sidebar

Solution:
- Created getEffectiveViewportWidth() and getEffectiveViewportHeight()
  helper functions that calculate the actual playable area
- For spectators with sidebar open: width = window.innerWidth - 280px
- For spectators: height = window.innerHeight - 56px (banner)
- For players: full window dimensions (unchanged)
- Added useEffect to update dimensions when spectator panels toggle

Now cards are correctly positioned within the visible game board area and
won't appear underneath the spectator stats sidebar.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-10-23 21:39:20 -05:00
parent fc5cf1216f
commit 4dce16cca4

View File

@@ -897,9 +897,28 @@ export function PlayingPhaseDrag() {
const [nextZIndex, setNextZIndex] = useState(1)
// Track viewport dimensions for responsive positioning
// For spectators, reduce dimensions to account for panels
const getEffectiveViewportWidth = () => {
if (typeof window === 'undefined') return 1000
const baseWidth = window.innerWidth
if (isSpectating && !spectatorStatsCollapsed) {
return baseWidth - 280 // Subtract stats sidebar width
}
return baseWidth
}
const getEffectiveViewportHeight = () => {
if (typeof window === 'undefined') return 800
const baseHeight = window.innerHeight
if (isSpectating) {
return baseHeight - 56 // Subtract banner height
}
return baseHeight
}
const [viewportDimensions, setViewportDimensions] = useState({
width: typeof window !== 'undefined' ? window.innerWidth : 1000,
height: typeof window !== 'undefined' ? window.innerHeight : 800,
width: getEffectiveViewportWidth(),
height: getEffectiveViewportHeight(),
})
// Track if we're currently resizing to disable spring animations
@@ -997,10 +1016,10 @@ export function PlayingPhaseDrag() {
// Set resizing flag to disable spring animations
setIsResizing(true)
// Update viewport dimensions immediately
// Update viewport dimensions immediately (accounting for spectator panels)
setViewportDimensions({
width: window.innerWidth,
height: window.innerHeight,
width: getEffectiveViewportWidth(),
height: getEffectiveViewportHeight(),
})
// Clear any existing timeout
@@ -1021,8 +1040,18 @@ export function PlayingPhaseDrag() {
clearTimeout(resizeTimeoutRef.current)
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])
// Update viewport dimensions when spectator panels change
useEffect(() => {
setViewportDimensions({
width: getEffectiveViewportWidth(),
height: getEffectiveViewportHeight(),
})
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSpectating, spectatorStatsCollapsed])
// Initialize card positions when game starts or restarts
useEffect(() => {
// Reset when entering playing phase or when cards change