refactor: extract ActivePlayersList component from PageWithNav
Extract active player display with hover-triggered remove buttons into dedicated component. Handles emoji scaling and red × button on hover in emphasized mode. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
80
apps/web/src/components/nav/ActivePlayersList.tsx
Normal file
80
apps/web/src/components/nav/ActivePlayersList.tsx
Normal file
@@ -0,0 +1,80 @@
|
||||
import React from 'react'
|
||||
|
||||
interface Player {
|
||||
id: number
|
||||
name: string
|
||||
emoji: string
|
||||
}
|
||||
|
||||
interface ActivePlayersListProps {
|
||||
activePlayers: Player[]
|
||||
shouldEmphasize: boolean
|
||||
onRemovePlayer: (playerId: number) => void
|
||||
}
|
||||
|
||||
export function ActivePlayersList({ activePlayers, shouldEmphasize, onRemovePlayer }: ActivePlayersListProps) {
|
||||
const [hoveredPlayerId, setHoveredPlayerId] = React.useState<number | null>(null)
|
||||
|
||||
return (
|
||||
<>
|
||||
{activePlayers.map(player => (
|
||||
<div
|
||||
key={player.id}
|
||||
style={{
|
||||
position: 'relative',
|
||||
fontSize: shouldEmphasize ? '48px' : '20px',
|
||||
lineHeight: 1,
|
||||
transition: 'font-size 0.4s cubic-bezier(0.4, 0, 0.2, 1), filter 0.4s ease',
|
||||
filter: shouldEmphasize ? 'drop-shadow(0 4px 8px rgba(0,0,0,0.25))' : 'none',
|
||||
cursor: shouldEmphasize ? 'pointer' : 'default'
|
||||
}}
|
||||
title={player.name}
|
||||
onMouseEnter={() => shouldEmphasize && setHoveredPlayerId(player.id)}
|
||||
onMouseLeave={() => shouldEmphasize && setHoveredPlayerId(null)}
|
||||
>
|
||||
{player.emoji}
|
||||
{shouldEmphasize && hoveredPlayerId === player.id && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onRemovePlayer(player.id)
|
||||
}}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '-4px',
|
||||
right: '-4px',
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
borderRadius: '50%',
|
||||
border: '2px solid white',
|
||||
background: '#ef4444',
|
||||
color: 'white',
|
||||
fontSize: '12px',
|
||||
fontWeight: 'bold',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
cursor: 'pointer',
|
||||
boxShadow: '0 2px 8px rgba(0,0,0,0.3)',
|
||||
transition: 'all 0.2s ease',
|
||||
padding: 0,
|
||||
lineHeight: 1
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
e.currentTarget.style.background = '#dc2626'
|
||||
e.currentTarget.style.transform = 'scale(1.1)'
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
e.currentTarget.style.background = '#ef4444'
|
||||
e.currentTarget.style.transform = 'scale(1)'
|
||||
}}
|
||||
aria-label={`Remove ${player.name}`}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user