wip: add give up feature (client-side UI and state)
This commit is contained in:
parent
996c973774
commit
33faccdf60
|
|
@ -23,6 +23,7 @@ interface KnowYourWorldContextValue {
|
|||
clickRegion: (regionId: string, regionName: string) => void
|
||||
nextRound: () => void
|
||||
endGame: () => void
|
||||
giveUp: () => void
|
||||
endStudy: () => void
|
||||
returnToSetup: () => void
|
||||
|
||||
|
|
@ -97,6 +98,8 @@ export function KnowYourWorldProvider({ children }: { children: React.ReactNode
|
|||
startTime: 0,
|
||||
activePlayers: [],
|
||||
playerMetadata: {},
|
||||
giveUpRegionId: null,
|
||||
giveUpTimestamp: 0,
|
||||
}
|
||||
}, [roomData])
|
||||
|
||||
|
|
@ -181,6 +184,16 @@ export function KnowYourWorldProvider({ children }: { children: React.ReactNode
|
|||
})
|
||||
}, [viewerId, sendMove, state.currentPlayer, activePlayers])
|
||||
|
||||
// Action: Give Up (show current region and advance)
|
||||
const giveUp = useCallback(() => {
|
||||
sendMove({
|
||||
type: 'GIVE_UP',
|
||||
playerId: state.currentPlayer || activePlayers[0] || '',
|
||||
userId: viewerId || '',
|
||||
data: {},
|
||||
})
|
||||
}, [viewerId, sendMove, state.currentPlayer, activePlayers])
|
||||
|
||||
// Setup Action: Set Map
|
||||
const setMap = useCallback(
|
||||
(selectedMap: 'world' | 'usa') => {
|
||||
|
|
@ -362,6 +375,7 @@ export function KnowYourWorldProvider({ children }: { children: React.ReactNode
|
|||
clickRegion,
|
||||
nextRound,
|
||||
endGame,
|
||||
giveUp,
|
||||
endStudy,
|
||||
returnToSetup,
|
||||
setMap,
|
||||
|
|
|
|||
|
|
@ -421,6 +421,8 @@ export class KnowYourWorldValidator
|
|||
startTime: 0,
|
||||
activePlayers: [],
|
||||
playerMetadata: {},
|
||||
giveUpRegionId: null,
|
||||
giveUpTimestamp: 0,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ export function GameInfoPanel({
|
|||
}: GameInfoPanelProps) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const isDark = resolvedTheme === 'dark'
|
||||
const { state, lastError, clearError } = useKnowYourWorld()
|
||||
const { state, lastError, clearError, giveUp } = useKnowYourWorld()
|
||||
|
||||
// Auto-dismiss errors after 3 seconds
|
||||
useEffect(() => {
|
||||
|
|
@ -67,6 +67,9 @@ export function GameInfoPanel({
|
|||
border: '2px solid',
|
||||
borderColor: 'blue.500',
|
||||
minWidth: 0, // Allow shrinking
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '1',
|
||||
})}
|
||||
>
|
||||
<div
|
||||
|
|
@ -90,6 +93,28 @@ export function GameInfoPanel({
|
|||
>
|
||||
{currentRegionName || '...'}
|
||||
</div>
|
||||
<button
|
||||
onClick={giveUp}
|
||||
data-action="give-up"
|
||||
className={css({
|
||||
padding: '1',
|
||||
fontSize: '2xs',
|
||||
cursor: 'pointer',
|
||||
bg: isDark ? 'yellow.800' : 'yellow.100',
|
||||
color: isDark ? 'yellow.200' : 'yellow.800',
|
||||
rounded: 'sm',
|
||||
border: '1px solid',
|
||||
borderColor: isDark ? 'yellow.600' : 'yellow.400',
|
||||
fontWeight: 'bold',
|
||||
transition: 'all 0.2s',
|
||||
_hover: {
|
||||
bg: isDark ? 'yellow.700' : 'yellow.200',
|
||||
transform: 'scale(1.02)',
|
||||
},
|
||||
})}
|
||||
>
|
||||
Give Up
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Progress - compact */}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ const Template = (args: StoryArgs) => {
|
|||
onRegionClick={(id, name) => console.log('Clicked:', id, name)}
|
||||
guessHistory={guessHistory}
|
||||
playerMetadata={mockPlayerMetadata}
|
||||
giveUpRegionId={null}
|
||||
giveUpTimestamp={0}
|
||||
forceTuning={{
|
||||
showArrows: args.showArrows,
|
||||
centeringStrength: args.centeringStrength,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,9 @@ interface MapRendererProps {
|
|||
color: string
|
||||
}
|
||||
>
|
||||
// Give up animation
|
||||
giveUpRegionId: string | null
|
||||
giveUpTimestamp: number
|
||||
// Force simulation tuning parameters
|
||||
forceTuning?: {
|
||||
showArrows?: boolean
|
||||
|
|
@ -130,6 +133,8 @@ export function MapRenderer({
|
|||
onRegionClick,
|
||||
guessHistory,
|
||||
playerMetadata,
|
||||
giveUpRegionId,
|
||||
giveUpTimestamp,
|
||||
forceTuning = {},
|
||||
showDebugBoundingBoxes = SHOW_DEBUG_BOUNDING_BOXES,
|
||||
}: MapRendererProps) {
|
||||
|
|
@ -257,6 +262,10 @@ export function MapRenderer({
|
|||
// Track whether current target region needs magnification
|
||||
const [targetNeedsMagnification, setTargetNeedsMagnification] = useState(false)
|
||||
|
||||
// Track give up animation state
|
||||
const [isGivingUpAnimation, setIsGivingUpAnimation] = useState(false)
|
||||
const [giveUpAnimationProgress, setGiveUpAnimationProgress] = useState(0) // 0-1 for flash animation
|
||||
|
||||
// Debug: Track bounding boxes for visualization
|
||||
const [debugBoundingBoxes, setDebugBoundingBoxes] = useState<DebugBoundingBox[]>([])
|
||||
// Debug: Track full zoom search result for detailed panel
|
||||
|
|
@ -461,6 +470,44 @@ export function MapRenderer({
|
|||
})
|
||||
}, [currentPrompt, svgDimensions]) // Re-check when prompt or SVG size changes
|
||||
|
||||
// Handle give up animation
|
||||
useEffect(() => {
|
||||
if (!giveUpRegionId) {
|
||||
setIsGivingUpAnimation(false)
|
||||
setGiveUpAnimationProgress(0)
|
||||
return
|
||||
}
|
||||
|
||||
console.log('[GiveUp] Starting animation for region:', giveUpRegionId)
|
||||
setIsGivingUpAnimation(true)
|
||||
setShowMagnifier(true)
|
||||
setTargetOpacity(1)
|
||||
|
||||
// Animate flash over 3 seconds (3 pulses)
|
||||
const duration = 3000 // 3 seconds total
|
||||
const startTime = Date.now()
|
||||
|
||||
const animate = () => {
|
||||
const elapsed = Date.now() - startTime
|
||||
const progress = Math.min(elapsed / duration, 1)
|
||||
|
||||
// Create pulsing effect: 0 -> 1 -> 0 -> 1 -> 0 -> 1 -> 0 (3 full pulses)
|
||||
const pulseProgress = Math.sin(progress * Math.PI * 3) ** 2
|
||||
|
||||
setGiveUpAnimationProgress(pulseProgress)
|
||||
|
||||
if (progress < 1) {
|
||||
requestAnimationFrame(animate)
|
||||
} else {
|
||||
setIsGivingUpAnimation(false)
|
||||
setGiveUpAnimationProgress(0)
|
||||
console.log('[GiveUp] Animation complete')
|
||||
}
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate)
|
||||
}, [giveUpRegionId, giveUpTimestamp])
|
||||
|
||||
const [labelPositions, setLabelPositions] = useState<RegionLabelPosition[]>([])
|
||||
const [smallRegionLabelPositions, setSmallRegionLabelPositions] = useState<
|
||||
Array<{
|
||||
|
|
|
|||
|
|
@ -112,6 +112,8 @@ export function PlayingPhase() {
|
|||
onRegionClick={clickRegion}
|
||||
guessHistory={state.guessHistory}
|
||||
playerMetadata={state.playerMetadata}
|
||||
giveUpRegionId={state.giveUpRegionId}
|
||||
giveUpTimestamp={state.giveUpTimestamp}
|
||||
/>
|
||||
</div>
|
||||
</Panel>
|
||||
|
|
|
|||
|
|
@ -70,6 +70,10 @@ export interface KnowYourWorldState extends GameState {
|
|||
// Multiplayer
|
||||
activePlayers: string[]
|
||||
playerMetadata: Record<string, any>
|
||||
|
||||
// Give up animation state
|
||||
giveUpRegionId: string | null // Region ID to show/flash when user gives up
|
||||
giveUpTimestamp: number // When the give up was triggered (for animation timing)
|
||||
}
|
||||
|
||||
// Move types
|
||||
|
|
@ -170,3 +174,10 @@ export type KnowYourWorldMove =
|
|||
selectedContinent: ContinentId | 'all'
|
||||
}
|
||||
}
|
||||
| {
|
||||
type: 'GIVE_UP'
|
||||
playerId: string
|
||||
userId: string
|
||||
timestamp: number
|
||||
data: {}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue