fix(rithmomachia): reconnect player assignment UI and fix setup layout
Restore all missing white/black player assignment functionality that was disconnected after git rebase operations. **Player Assignment UI (reconnected):** - Wire up assignWhitePlayer and assignBlackPlayer from context - Pass whitePlayerId, blackPlayerId, onAssignWhitePlayer, onAssignBlackPlayer, and gamePhase props to PageWithNav - Enable split [W][B] buttons on hover for unassigned players - Enable SWAP button on hover for assigned players - Support observer mode (players not assigned to white/black can spectate) - Permission system: only host (in rooms) or local players can assign **Duplicate Indicator Fix:** - Hide playerBadge pill when assignment UI is active to prevent showing both the fancy badge AND the assignment buttons - Keep "Your turn" / "Their turn" labels (working as intended) **Setup Layout Fix:** - Add SetupPlayerRequirement panel when tooFew players (styled for medieval theme) - Hide entire setup config UI when showing player requirement panel - Prevents squishing/scrolling issues - clean swap between the two UIs - Panel shows inactive local players, invite codes, and room history **Navigation Banner:** - Hide "Need two active players" banner during setup (panel handles this) - Show banner during playing phase only All ~10 hours of missing player management work now restored and functional. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8f226cee1b
commit
a1a0374fac
|
|
@ -6,6 +6,7 @@ import { useRouter } from 'next/navigation'
|
|||
import { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { PageWithNav } from '@/components/PageWithNav'
|
||||
import type { PlayerBadge } from '@/components/nav/types'
|
||||
import { SetupPlayerRequirement } from '@/components/nav/SetupPlayerRequirement'
|
||||
import { StandardGameLayout } from '@/components/StandardGameLayout'
|
||||
import { Z_INDEX } from '@/constants/zIndex'
|
||||
import { useGameMode } from '@/contexts/GameModeContext'
|
||||
|
|
@ -206,6 +207,12 @@ function useRosterWarning(phase: 'setup' | 'playing'): RosterWarning | undefined
|
|||
}
|
||||
|
||||
if (rosterStatus.status === 'tooFew') {
|
||||
// During setup, don't show nav banner - SetupPlayerRequirement panel handles this
|
||||
if (phase === 'setup') {
|
||||
return undefined
|
||||
}
|
||||
|
||||
// During playing phase, show nav warning banner
|
||||
const actions = []
|
||||
if (inactiveLocalPlayer) {
|
||||
actions.push({
|
||||
|
|
@ -221,10 +228,7 @@ function useRosterWarning(phase: 'setup' | 'playing'): RosterWarning | undefined
|
|||
|
||||
return {
|
||||
heading: 'Need two active players',
|
||||
description:
|
||||
phase === 'setup'
|
||||
? 'Rithmomachia needs exactly two active players before the match can begin.'
|
||||
: 'Gameplay is paused until two players are active.',
|
||||
description: 'Gameplay is paused until two players are active.',
|
||||
actions,
|
||||
}
|
||||
}
|
||||
|
|
@ -252,7 +256,8 @@ function useRosterWarning(phase: 'setup' | 'playing'): RosterWarning | undefined
|
|||
*/
|
||||
export function RithmomachiaGame() {
|
||||
const router = useRouter()
|
||||
const { state, resetGame, goToSetup, whitePlayerId, blackPlayerId } = useRithmomachia()
|
||||
const { state, resetGame, goToSetup, whitePlayerId, blackPlayerId, assignWhitePlayer, assignBlackPlayer } =
|
||||
useRithmomachia()
|
||||
const { setFullscreenElement } = useFullscreen()
|
||||
const gameRef = useRef<HTMLDivElement>(null)
|
||||
const rosterWarning = useRosterWarning(state.gamePhase === 'setup' ? 'setup' : 'playing')
|
||||
|
|
@ -312,6 +317,11 @@ export function RithmomachiaGame() {
|
|||
currentPlayerId={currentPlayerId}
|
||||
playerBadges={playerBadges}
|
||||
rosterWarning={rosterWarning}
|
||||
whitePlayerId={whitePlayerId}
|
||||
blackPlayerId={blackPlayerId}
|
||||
onAssignWhitePlayer={assignWhitePlayer}
|
||||
onAssignBlackPlayer={assignBlackPlayer}
|
||||
gamePhase={state.gamePhase}
|
||||
>
|
||||
<StandardGameLayout>
|
||||
<div
|
||||
|
|
@ -356,6 +366,7 @@ export function RithmomachiaGame() {
|
|||
*/
|
||||
function SetupPhase() {
|
||||
const { state, startGame, setConfig, lastError, clearError, rosterStatus } = useRithmomachia()
|
||||
const { players: playerMap, activePlayers: activePlayerIds, addPlayer, setActive } = useGameMode()
|
||||
const startDisabled = rosterStatus.status !== 'ok'
|
||||
|
||||
const toggleSetting = (key: keyof typeof state) => {
|
||||
|
|
@ -368,6 +379,10 @@ function SetupPhase() {
|
|||
setConfig('pointWinThreshold', Math.max(1, value))
|
||||
}
|
||||
|
||||
// Prepare data for SetupPlayerRequirement
|
||||
const activePlayers = Array.from(playerMap.values()).filter((p) => activePlayerIds.has(p.id))
|
||||
const inactivePlayers = Array.from(playerMap.values()).filter((p) => !activePlayerIds.has(p.id))
|
||||
|
||||
return (
|
||||
<div
|
||||
data-component="setup-phase-container"
|
||||
|
|
@ -458,23 +473,68 @@ function SetupPhase() {
|
|||
</div>
|
||||
)}
|
||||
|
||||
{/* Title Section - Compact medieval manuscript style */}
|
||||
<div
|
||||
data-element="title-section"
|
||||
className={css({
|
||||
textAlign: 'center',
|
||||
bg: 'rgba(255, 255, 255, 0.95)',
|
||||
borderRadius: '1.5vh',
|
||||
p: '1.5vh',
|
||||
boxShadow: '0 1vh 3vh rgba(0,0,0,0.5)',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
border: '0.3vh solid',
|
||||
borderColor: 'rgba(251, 191, 36, 0.6)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
flexShrink: 0,
|
||||
})}
|
||||
>
|
||||
{/* Player requirement panel - styled for medieval theme */}
|
||||
{rosterStatus.status === 'tooFew' && (
|
||||
<div
|
||||
className={css({
|
||||
'& > div': {
|
||||
maxWidth: '100%',
|
||||
margin: '0',
|
||||
padding: '1.5vh',
|
||||
background: 'rgba(30, 27, 75, 0.85)',
|
||||
border: '0.3vh solid rgba(251, 191, 36, 0.6)',
|
||||
borderRadius: '1.5vh',
|
||||
backdropFilter: 'blur(10px)',
|
||||
'& h2': {
|
||||
fontSize: '2vh',
|
||||
background: 'linear-gradient(135deg, #fbbf24, #f59e0b)',
|
||||
backgroundClip: 'text',
|
||||
WebkitBackgroundClip: 'text',
|
||||
},
|
||||
'& p': {
|
||||
fontSize: '1.4vh',
|
||||
color: 'rgba(255, 255, 255, 0.8)',
|
||||
},
|
||||
'& button': {
|
||||
fontSize: '1.4vh',
|
||||
padding: '0.8vh 1.5vh',
|
||||
},
|
||||
},
|
||||
})}
|
||||
>
|
||||
<SetupPlayerRequirement
|
||||
minPlayers={2}
|
||||
currentPlayers={activePlayers}
|
||||
inactivePlayers={inactivePlayers}
|
||||
onAddPlayer={(playerId) => setActive(playerId, true)}
|
||||
onConfigurePlayer={() => {
|
||||
/* TODO: Add configure player handler */
|
||||
}}
|
||||
gameTitle="Rithmomachia"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Only show setup config when we have enough players */}
|
||||
{rosterStatus.status !== 'tooFew' && (
|
||||
<>
|
||||
{/* Title Section - Compact medieval manuscript style */}
|
||||
<div
|
||||
data-element="title-section"
|
||||
className={css({
|
||||
textAlign: 'center',
|
||||
bg: 'rgba(255, 255, 255, 0.95)',
|
||||
borderRadius: '1.5vh',
|
||||
p: '1.5vh',
|
||||
boxShadow: '0 1vh 3vh rgba(0,0,0,0.5)',
|
||||
width: '100%',
|
||||
position: 'relative',
|
||||
border: '0.3vh solid',
|
||||
borderColor: 'rgba(251, 191, 36, 0.6)',
|
||||
backdropFilter: 'blur(10px)',
|
||||
flexShrink: 0,
|
||||
})}
|
||||
>
|
||||
{/* Ornamental corners - smaller */}
|
||||
<div
|
||||
className={css({
|
||||
|
|
@ -994,6 +1054,8 @@ function SetupPhase() {
|
|||
>
|
||||
⚔️ BEGIN BATTLE ⚔️
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -223,7 +223,8 @@ export function ActivePlayersList({
|
|||
</div>
|
||||
)}
|
||||
|
||||
{badge && (
|
||||
{/* Show playerBadge only if assignment UI is not present */}
|
||||
{badge && !onAssignWhitePlayer && !onAssignBlackPlayer && (
|
||||
<div
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
|
|
|
|||
|
|
@ -379,7 +379,8 @@ export function NetworkPlayerIndicator({
|
|||
/>
|
||||
</div>
|
||||
|
||||
{badge && (
|
||||
{/* Show playerBadge only if assignment UI is not present */}
|
||||
{badge && !onAssignWhitePlayer && !onAssignBlackPlayer && (
|
||||
<div
|
||||
style={{
|
||||
display: 'inline-flex',
|
||||
|
|
|
|||
Loading…
Reference in New Issue