feat: add Setup button to exit arcade sessions
- Add onExitSession prop to PageWithNav and GameContextNav - Display Setup button (⚙️) in nav bar during games - Call exitSession() and reload page to return to setup - Provides consistent exit UI across all arcade games 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { useArcadeMemoryPairs } from '../context/ArcadeMemoryPairsContext'
|
||||
import { useFullscreen } from '../../../../contexts/FullscreenContext'
|
||||
import { SetupPhase } from './SetupPhase'
|
||||
import { GamePhase } from './GamePhase'
|
||||
import { ResultsPhase } from './ResultsPhase'
|
||||
import { StandardGameLayout } from '../../../../components/StandardGameLayout'
|
||||
import { PageWithNav } from '@/components/PageWithNav'
|
||||
import { css } from '../../../../../styled-system/css'
|
||||
|
||||
export function MemoryPairsGame() {
|
||||
const { state, exitSession } = useArcadeMemoryPairs()
|
||||
const { setFullscreenElement } = useFullscreen()
|
||||
const gameRef = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
// Register this component's main div as the fullscreen element
|
||||
if (gameRef.current) {
|
||||
console.log('🎯 MemoryPairsGame: Registering fullscreen element:', gameRef.current)
|
||||
setFullscreenElement(gameRef.current)
|
||||
}
|
||||
}, [setFullscreenElement])
|
||||
|
||||
return (
|
||||
<PageWithNav
|
||||
navTitle="Memory Pairs"
|
||||
navEmoji="🧩"
|
||||
emphasizeGameContext={state.gamePhase === 'setup'}
|
||||
onExitSession={() => {
|
||||
exitSession()
|
||||
window.location.reload()
|
||||
}}
|
||||
>
|
||||
<StandardGameLayout>
|
||||
<div
|
||||
ref={gameRef}
|
||||
className={css({
|
||||
flex: 1,
|
||||
padding: { base: '12px', sm: '16px', md: '20px' },
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'center',
|
||||
position: 'relative',
|
||||
overflow: 'auto'
|
||||
})}>
|
||||
{/* Note: Fullscreen restore prompt removed - client-side navigation preserves fullscreen */}
|
||||
|
||||
<main className={css({
|
||||
width: '100%',
|
||||
maxWidth: '1200px',
|
||||
background: 'rgba(255,255,255,0.95)',
|
||||
borderRadius: { base: '12px', md: '20px' },
|
||||
padding: { base: '12px', sm: '16px', md: '24px', lg: '32px' },
|
||||
boxShadow: '0 10px 30px rgba(0,0,0,0.2)',
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden'
|
||||
})}>
|
||||
{state.gamePhase === 'setup' && <SetupPhase />}
|
||||
{state.gamePhase === 'playing' && <GamePhase />}
|
||||
{state.gamePhase === 'results' && <ResultsPhase />}
|
||||
</main>
|
||||
</div>
|
||||
</StandardGameLayout>
|
||||
</PageWithNav>
|
||||
)
|
||||
}
|
||||
@@ -10,10 +10,11 @@ interface PageWithNavProps {
|
||||
navTitle?: string
|
||||
navEmoji?: string
|
||||
emphasizeGameContext?: boolean
|
||||
onExitSession?: () => void
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
export function PageWithNav({ navTitle, navEmoji, emphasizeGameContext = false, children }: PageWithNavProps) {
|
||||
export function PageWithNav({ navTitle, navEmoji, emphasizeGameContext = false, onExitSession, children }: PageWithNavProps) {
|
||||
const { players, activePlayers, setActive, activePlayerCount } = useGameMode()
|
||||
const [mounted, setMounted] = React.useState(false)
|
||||
const [configurePlayerId, setConfigurePlayerId] = React.useState<string | null>(null)
|
||||
@@ -68,6 +69,7 @@ export function PageWithNav({ navTitle, navEmoji, emphasizeGameContext = false,
|
||||
onAddPlayer={handleAddPlayer}
|
||||
onRemovePlayer={handleRemovePlayer}
|
||||
onConfigurePlayer={handleConfigurePlayer}
|
||||
onExitSession={onExitSession}
|
||||
/>
|
||||
) : null
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ interface GameContextNavProps {
|
||||
onAddPlayer: (playerId: string) => void
|
||||
onRemovePlayer: (playerId: string) => void
|
||||
onConfigurePlayer: (playerId: string) => void
|
||||
onExitSession?: () => void
|
||||
}
|
||||
|
||||
export function GameContextNav({
|
||||
@@ -35,7 +36,8 @@ export function GameContextNav({
|
||||
showFullscreenSelection,
|
||||
onAddPlayer,
|
||||
onRemovePlayer,
|
||||
onConfigurePlayer
|
||||
onConfigurePlayer,
|
||||
onExitSession
|
||||
}: GameContextNavProps) {
|
||||
const [isTransitioning, setIsTransitioning] = React.useState(false)
|
||||
const [layoutMode, setLayoutMode] = React.useState<'column' | 'row'>(showFullscreenSelection ? 'column' : 'row')
|
||||
@@ -93,6 +95,41 @@ export function GameContextNav({
|
||||
showFullscreenSelection={showFullscreenSelection}
|
||||
/>
|
||||
|
||||
{/* Exit Session Button */}
|
||||
{onExitSession && !showFullscreenSelection && (
|
||||
<button
|
||||
onClick={onExitSession}
|
||||
style={{
|
||||
background: 'linear-gradient(135deg, #dfe6e9, #b2bec3)',
|
||||
border: 'none',
|
||||
borderRadius: '8px',
|
||||
padding: '6px 12px',
|
||||
fontSize: '13px',
|
||||
fontWeight: 'bold',
|
||||
color: 'rgb(51, 51, 51)',
|
||||
cursor: 'pointer',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
gap: '4px',
|
||||
transition: 'all 0.2s ease',
|
||||
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.1)'
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = 'linear-gradient(135deg, #b2bec3, #636e72)'
|
||||
e.currentTarget.style.transform = 'translateY(-1px)'
|
||||
e.currentTarget.style.boxShadow = '0 3px 6px rgba(0, 0, 0, 0.15)'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = 'linear-gradient(135deg, #dfe6e9, #b2bec3)'
|
||||
e.currentTarget.style.transform = 'translateY(0)'
|
||||
e.currentTarget.style.boxShadow = '0 2px 4px rgba(0, 0, 0, 0.1)'
|
||||
}}
|
||||
>
|
||||
<span>⚙️</span>
|
||||
<span>Setup</span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* Active Players + Add Button */}
|
||||
{(activePlayers.length > 0 || (shouldEmphasize && inactivePlayers.length > 0)) && (
|
||||
<div style={{
|
||||
|
||||
Reference in New Issue
Block a user