feat(nav): combine room info and network players in single pane

Merge room info and network players into one bordered container for
better visual cohesion. This creates a clearer hierarchy with room
info + network players on the left, and the user's own players on
the right, maintaining vertical alignment.

Also remove the confusing pulsing green "online" indicator from
network players - the gradient border frame is sufficient to
distinguish them from local players.

Changes:
- Combine RoomInfo and NetworkPlayerIndicator in shared bordered pane
- Add subtle vertical divider between room info and network players
- Remove animated pulse indicator
- Simplify network player visual design

🤖 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-11 08:39:44 -05:00
parent 2cbc5ca5f2
commit d5473ab66a
2 changed files with 89 additions and 125 deletions

View File

@@ -146,17 +146,20 @@ export function GameContextNav({
width: 'auto',
}}
>
{/* Left side: Title/room info and mode */}
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
flex: 1,
}}
>
{/* Show room info pane (with unified dropdown) if in room, otherwise show title menu + mode indicator */}
{roomInfo ? (
{/* Left side: Room info + Network players in same pane */}
{roomInfo ? (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
padding: '6px 12px',
background: 'linear-gradient(135deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.05))',
borderRadius: '12px',
border: '2px solid rgba(255, 255, 255, 0.15)',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)',
}}
>
<RoomInfo
roomName={roomInfo.roomName}
gameName={roomInfo.gameName}
@@ -188,89 +191,84 @@ export function GameContextNav({
onNewGame={onNewGame}
onQuit={onExitSession}
/>
) : (
<>
<GameTitleMenu
navTitle={navTitle}
navEmoji={navEmoji}
onSetup={onSetup}
onNewGame={onNewGame}
onQuit={onExitSession}
showMenu={!canModifyPlayers}
/>
<div style={{ marginLeft: 'auto' }}>
<GameModeIndicator gameMode={gameMode} shouldEmphasize={shouldEmphasize} showFullscreenSelection={false} />
</div>
</>
)}
</div>
{/* Right side: Players spanning full height */}
<div
style={{
display: 'flex',
alignItems: 'center',
gap: shouldEmphasize ? '16px' : '12px',
}}
>
{/* Network Players */}
{networkPlayers.length > 0 && (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '8px',
padding: '6px 12px',
background: 'linear-gradient(135deg, rgba(59, 130, 246, 0.12), rgba(147, 51, 234, 0.12))',
borderRadius: '12px',
border: '2px solid rgba(147, 51, 234, 0.25)',
boxShadow: '0 4px 12px rgba(59, 130, 246, 0.15)',
}}
>
{networkPlayers.map((player) => (
<NetworkPlayerIndicator key={player.id} player={player} shouldEmphasize={shouldEmphasize} />
))}
</div>
)}
{/* Active Players + Add Button */}
{(activePlayers.length > 0 || (shouldEmphasize && inactivePlayers.length > 0 && canModifyPlayers)) && (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: shouldEmphasize ? '12px' : '8px',
padding: shouldEmphasize ? '12px 20px' : '6px 12px',
background: shouldEmphasize
? 'linear-gradient(135deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.10))'
: 'linear-gradient(135deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.05))',
borderRadius: shouldEmphasize ? '16px' : '12px',
border: shouldEmphasize ? '3px solid rgba(255, 255, 255, 0.3)' : '2px solid rgba(255, 255, 255, 0.15)',
boxShadow: shouldEmphasize
? '0 8px 24px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255,255,255,0.3)'
: '0 4px 12px rgba(0, 0, 0, 0.1)',
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
transform: shouldEmphasize ? 'scale(1.05)' : 'scale(1)',
pointerEvents: canModifyPlayers ? 'auto' : 'none',
}}
>
<ActivePlayersList
activePlayers={activePlayers}
shouldEmphasize={shouldEmphasize}
onRemovePlayer={onRemovePlayer}
onConfigurePlayer={onConfigurePlayer}
/>
{canModifyPlayers && (
<AddPlayerButton
inactivePlayers={inactivePlayers}
shouldEmphasize={shouldEmphasize}
onAddPlayer={onAddPlayer}
{/* Network Players - inside same pane as room info */}
{networkPlayers.length > 0 && (
<>
<div
style={{
width: '1px',
height: '48px',
background: 'rgba(255, 255, 255, 0.2)',
margin: '0 4px',
}}
/>
)}
{networkPlayers.map((player) => (
<NetworkPlayerIndicator key={player.id} player={player} shouldEmphasize={shouldEmphasize} />
))}
</>
)}
</div>
) : (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: '12px',
flex: 1,
}}
>
<GameTitleMenu
navTitle={navTitle}
navEmoji={navEmoji}
onSetup={onSetup}
onNewGame={onNewGame}
onQuit={onExitSession}
showMenu={!canModifyPlayers}
/>
<div style={{ marginLeft: 'auto' }}>
<GameModeIndicator gameMode={gameMode} shouldEmphasize={shouldEmphasize} showFullscreenSelection={false} />
</div>
)}
</div>
</div>
)}
{/* Right side: Active Players + Add Button */}
{(activePlayers.length > 0 || (shouldEmphasize && inactivePlayers.length > 0 && canModifyPlayers)) && (
<div
style={{
display: 'flex',
alignItems: 'center',
gap: shouldEmphasize ? '12px' : '8px',
padding: shouldEmphasize ? '12px 20px' : '6px 12px',
background: shouldEmphasize
? 'linear-gradient(135deg, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.10))'
: 'linear-gradient(135deg, rgba(255, 255, 255, 0.10), rgba(255, 255, 255, 0.05))',
borderRadius: shouldEmphasize ? '16px' : '12px',
border: shouldEmphasize ? '3px solid rgba(255, 255, 255, 0.3)' : '2px solid rgba(255, 255, 255, 0.15)',
boxShadow: shouldEmphasize
? '0 8px 24px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255,255,255,0.3)'
: '0 4px 12px rgba(0, 0, 0, 0.1)',
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
transform: shouldEmphasize ? 'scale(1.05)' : 'scale(1)',
pointerEvents: canModifyPlayers ? 'auto' : 'none',
}}
>
<ActivePlayersList
activePlayers={activePlayers}
shouldEmphasize={shouldEmphasize}
onRemovePlayer={onRemovePlayer}
onConfigurePlayer={onConfigurePlayer}
/>
{canModifyPlayers && (
<AddPlayerButton
inactivePlayers={inactivePlayers}
shouldEmphasize={shouldEmphasize}
onAddPlayer={onAddPlayer}
/>
)}
</div>
)}
<style
dangerouslySetInnerHTML={{

View File

@@ -63,23 +63,6 @@ export function NetworkPlayerIndicator({ player, shouldEmphasize }: NetworkPlaye
}}
/>
{/* Animated network signal indicator - larger */}
<div
style={{
position: 'absolute',
top: '-10px',
right: '-10px',
width: '16px',
height: '16px',
borderRadius: '50%',
background: 'rgba(34, 197, 94, 0.95)',
border: '2px solid rgba(255, 255, 255, 0.8)',
boxShadow: '0 0 12px rgba(34, 197, 94, 0.8)',
animation: 'networkPulse 2s ease-in-out infinite',
zIndex: 1,
}}
/>
{/* Player emoji or fallback */}
<div
style={{
@@ -112,23 +95,6 @@ export function NetworkPlayerIndicator({ player, shouldEmphasize }: NetworkPlaye
>
📡
</div>
<style
dangerouslySetInnerHTML={{
__html: `
@keyframes networkPulse {
0%, 100% {
opacity: 1;
transform: scale(1);
}
50% {
opacity: 0.5;
transform: scale(1.2);
}
}
`,
}}
/>
</div>
</PlayerTooltip>
)