Enhance Voting and Home screens with pixel art styles; add player voting status list and update button designs for improved UI experience
This commit is contained in:
parent
38ed69bf5b
commit
fca6baa694
@ -10,7 +10,7 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/bangers": "^5.1.1",
|
"@fontsource/press-start-2p": "^5.2.5",
|
||||||
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
"@fortawesome/fontawesome-svg-core": "^6.7.2",
|
||||||
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
"@fortawesome/free-solid-svg-icons": "^6.7.2",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||||
|
12
client/pnpm-lock.yaml
generated
12
client/pnpm-lock.yaml
generated
@ -8,9 +8,9 @@ importers:
|
|||||||
|
|
||||||
.:
|
.:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@fontsource/bangers':
|
'@fontsource/press-start-2p':
|
||||||
specifier: ^5.1.1
|
specifier: ^5.2.5
|
||||||
version: 5.1.1
|
version: 5.2.5
|
||||||
'@fortawesome/fontawesome-svg-core':
|
'@fortawesome/fontawesome-svg-core':
|
||||||
specifier: ^6.7.2
|
specifier: ^6.7.2
|
||||||
version: 6.7.2
|
version: 6.7.2
|
||||||
@ -327,8 +327,8 @@ packages:
|
|||||||
resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
|
resolution: {integrity: sha512-JubJ5B2pJ4k4yGxaNLdbjrnk9d/iDz6/q8wOilpIowd6PJPgaxCuHBnBszq7Ce2TyMrywm5r4PnKm6V3iiZF+g==}
|
||||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||||
|
|
||||||
'@fontsource/bangers@5.1.1':
|
'@fontsource/press-start-2p@5.2.5':
|
||||||
resolution: {integrity: sha512-+OzMvd6OXRipNWjGtcRTz1kVn+ML2A+4OsejqroZeUju74qncQ6lhlP3cZzu6hijXR8U9rm603lufzYdVAOdsA==}
|
resolution: {integrity: sha512-MmGLqhkv0kuoyeGgGkquEMRxJP6auc6918bKd8uTWP2beXMWLZZwCfXCqmskFLf0XYbtbzxuRXLjTnQBeTwsMQ==}
|
||||||
|
|
||||||
'@fortawesome/fontawesome-common-types@6.7.2':
|
'@fortawesome/fontawesome-common-types@6.7.2':
|
||||||
resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==}
|
resolution: {integrity: sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==}
|
||||||
@ -1786,7 +1786,7 @@ snapshots:
|
|||||||
'@eslint/core': 0.12.0
|
'@eslint/core': 0.12.0
|
||||||
levn: 0.4.1
|
levn: 0.4.1
|
||||||
|
|
||||||
'@fontsource/bangers@5.1.1': {}
|
'@fontsource/press-start-2p@5.2.5': {}
|
||||||
|
|
||||||
'@fortawesome/fontawesome-common-types@6.7.2': {}
|
'@fortawesome/fontawesome-common-types@6.7.2': {}
|
||||||
|
|
||||||
|
@ -17,55 +17,67 @@
|
|||||||
min-width: 120px
|
min-width: 120px
|
||||||
background-color: $primary
|
background-color: $primary
|
||||||
color: #000
|
color: #000
|
||||||
box-shadow:
|
// Enhanced pixel art style with jagged edges
|
||||||
4px 4px 0 #000,
|
image-rendering: pixelated
|
||||||
inset -4px -4px 0 darken($primary, 30%),
|
box-shadow: 4px 4px 0 #000, inset -4px -4px 0 darken($primary, 30%), inset 4px 4px 0 lighten($primary, 10%)
|
||||||
inset 4px 4px 0 lighten($primary, 10%)
|
|
||||||
transition: all 0.1s ease
|
transition: all 0.1s ease
|
||||||
|
|
||||||
|
// Add decorative pixel corners
|
||||||
|
&:before, &:after
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
width: 4px
|
||||||
|
height: 4px
|
||||||
|
background-color: #000
|
||||||
|
z-index: 2
|
||||||
|
|
||||||
|
&:before
|
||||||
|
top: -4px
|
||||||
|
left: -4px
|
||||||
|
|
||||||
|
&:after
|
||||||
|
bottom: -4px
|
||||||
|
right: -4px
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
transform: translate(-2px, -2px)
|
transform: translate(-2px, -2px)
|
||||||
box-shadow:
|
box-shadow: 6px 6px 0 #000, inset -4px -4px 0 darken($primary, 30%), inset 4px 4px 0 lighten($primary, 10%)
|
||||||
6px 6px 0 #000,
|
|
||||||
inset -4px -4px 0 darken($primary, 30%),
|
|
||||||
inset 4px 4px 0 lighten($primary, 10%)
|
|
||||||
|
|
||||||
&:active
|
&:active
|
||||||
transform: translate(4px, 4px)
|
transform: translate(4px, 4px)
|
||||||
box-shadow:
|
box-shadow: 0 0 0 #000, inset -4px -4px 0 darken($primary, 30%), inset 4px 4px 0 lighten($primary, 10%)
|
||||||
0 0 0 #000,
|
|
||||||
inset -4px -4px 0 darken($primary, 30%),
|
|
||||||
inset 4px 4px 0 lighten($primary, 10%)
|
|
||||||
|
|
||||||
&:disabled
|
&:disabled
|
||||||
opacity: 0.5
|
opacity: 0.5
|
||||||
cursor: not-allowed
|
|
||||||
transform: none
|
// Full width modifier
|
||||||
|
&.full-width
|
||||||
|
width: 100%
|
||||||
|
margin-top: 1rem
|
||||||
|
padding: 1rem
|
||||||
|
font-size: 1rem
|
||||||
|
|
||||||
// Button types
|
// Button types
|
||||||
&.primary
|
&.primary
|
||||||
background-color: $primary
|
background-color: $primary
|
||||||
color: #000
|
color: #000
|
||||||
box-shadow:
|
box-shadow: 4px 4px 0 #000, inset -4px -4px 0 darken($primary, 30%), inset 4px 4px 0 lighten($primary, 10%)
|
||||||
4px 4px 0 #000,
|
|
||||||
inset -4px -4px 0 darken($primary, 30%),
|
|
||||||
inset 4px 4px 0 lighten($primary, 10%)
|
|
||||||
|
|
||||||
&.secondary
|
&.secondary
|
||||||
background-color: $secondary
|
background-color: $secondary
|
||||||
color: #000
|
color: #000
|
||||||
box-shadow:
|
box-shadow: 4px 4px 0 #000, inset -4px -4px 0 darken($secondary, 30%), inset 4px 4px 0 lighten($secondary, 10%)
|
||||||
4px 4px 0 #000,
|
|
||||||
inset -4px -4px 0 darken($secondary, 30%),
|
|
||||||
inset 4px 4px 0 lighten($secondary, 10%)
|
|
||||||
|
|
||||||
&.accent
|
&.accent
|
||||||
background-color: $accent
|
background-color: $accent
|
||||||
color: #000
|
color: #000
|
||||||
box-shadow:
|
box-shadow: 4px 4px 0 #000, inset -4px -4px 0 darken($accent, 30%), inset 4px 4px 0 lighten($accent, 10%)
|
||||||
4px 4px 0 #000,
|
|
||||||
inset -4px -4px 0 darken($accent, 30%),
|
@keyframes pixel-breathe
|
||||||
inset 4px 4px 0 lighten($accent, 10%)
|
0%, 100%
|
||||||
|
transform: scale(1)
|
||||||
|
50%
|
||||||
|
transform: scale(1.01)
|
||||||
|
|
||||||
// Primary button
|
// Primary button
|
||||||
.btn.primary
|
.btn.primary
|
||||||
@ -73,10 +85,10 @@
|
|||||||
color: #000
|
color: #000
|
||||||
box-shadow: 0 4px 15px rgba($primary, 0.5)
|
box-shadow: 0 4px 15px rgba($primary, 0.5)
|
||||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4)
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4)
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background: linear-gradient(45deg, $primary, lighten($primary, 10%))
|
background: linear-gradient(45deg, $primary, lighten($primary, 10%))
|
||||||
|
|
||||||
&:focus
|
&:focus
|
||||||
box-shadow: 0 0 0 2px rgba($primary, 0.5)
|
box-shadow: 0 0 0 2px rgba($primary, 0.5)
|
||||||
|
|
||||||
@ -86,10 +98,10 @@
|
|||||||
color: #000
|
color: #000
|
||||||
box-shadow: 0 4px 15px rgba($secondary, 0.5)
|
box-shadow: 0 4px 15px rgba($secondary, 0.5)
|
||||||
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4)
|
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.4)
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background: linear-gradient(45deg, $secondary, lighten($secondary, 10%))
|
background: linear-gradient(45deg, $secondary, lighten($secondary, 10%))
|
||||||
|
|
||||||
&:focus
|
&:focus
|
||||||
box-shadow: 0 0 0 2px rgba($secondary, 0.5)
|
box-shadow: 0 0 0 2px rgba($secondary, 0.5)
|
||||||
|
|
||||||
@ -98,10 +110,10 @@
|
|||||||
background: linear-gradient(45deg, darken($danger, 10%), $danger)
|
background: linear-gradient(45deg, darken($danger, 10%), $danger)
|
||||||
color: #fff
|
color: #fff
|
||||||
box-shadow: 0 4px 15px rgba($danger, 0.5)
|
box-shadow: 0 4px 15px rgba($danger, 0.5)
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
background: linear-gradient(45deg, $danger, lighten($danger, 10%))
|
background: linear-gradient(45deg, $danger, lighten($danger, 10%))
|
||||||
|
|
||||||
&:focus
|
&:focus
|
||||||
box-shadow: 0 0 0 2px rgba($danger, 0.5)
|
box-shadow: 0 0 0 2px rgba($danger, 0.5)
|
||||||
|
|
||||||
@ -113,7 +125,7 @@
|
|||||||
padding: 0.75rem 2rem
|
padding: 0.75rem 2rem
|
||||||
transform-style: preserve-3d
|
transform-style: preserve-3d
|
||||||
perspective: 1000px
|
perspective: 1000px
|
||||||
|
|
||||||
&:after
|
&:after
|
||||||
content: ''
|
content: ''
|
||||||
position: absolute
|
position: absolute
|
||||||
@ -126,9 +138,9 @@
|
|||||||
transform: translateZ(-10px)
|
transform: translateZ(-10px)
|
||||||
z-index: -1
|
z-index: -1
|
||||||
transition: transform 0.3s
|
transition: transform 0.3s
|
||||||
|
|
||||||
&:hover
|
&:hover
|
||||||
transform: translateY(-5px) rotateX(10deg)
|
transform: translateY(-5px) rotateX(10deg)
|
||||||
|
|
||||||
&:after
|
&:after
|
||||||
transform: translateZ(-5px)
|
transform: translateZ(-5px)
|
@ -274,10 +274,95 @@
|
|||||||
gap: 0.5rem
|
gap: 0.5rem
|
||||||
font-family: 'Press Start 2P', monospace
|
font-family: 'Press Start 2P', monospace
|
||||||
font-size: 0.8rem
|
font-size: 0.8rem
|
||||||
|
margin-bottom: 1rem
|
||||||
|
|
||||||
span
|
span
|
||||||
color: $primary
|
color: $primary
|
||||||
font-weight: bold
|
font-weight: bold
|
||||||
|
|
||||||
|
// Player votes list styling
|
||||||
|
.player-votes
|
||||||
|
background-color: rgba(0, 0, 0, 0.2)
|
||||||
|
border: 2px dashed rgba(255, 255, 255, 0.2)
|
||||||
|
border-radius: 0.5rem
|
||||||
|
padding: 0.75rem
|
||||||
|
margin-top: 0.5rem
|
||||||
|
|
||||||
|
h4
|
||||||
|
margin: 0 0 0.75rem 0
|
||||||
|
font-family: 'Press Start 2P', monospace
|
||||||
|
font-size: 0.8rem
|
||||||
|
color: $secondary
|
||||||
|
position: relative
|
||||||
|
display: inline-block
|
||||||
|
|
||||||
|
&:before, &:after
|
||||||
|
content: '>'
|
||||||
|
position: absolute
|
||||||
|
color: $accent
|
||||||
|
animation: pixel-blink 1s infinite
|
||||||
|
|
||||||
|
&:before
|
||||||
|
left: -1rem
|
||||||
|
|
||||||
|
&:after
|
||||||
|
right: -1rem
|
||||||
|
|
||||||
|
.players-voted-list
|
||||||
|
list-style: none
|
||||||
|
padding: 0
|
||||||
|
margin: 0
|
||||||
|
display: grid
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr))
|
||||||
|
gap: 0.5rem
|
||||||
|
|
||||||
|
li
|
||||||
|
padding: 0.5rem
|
||||||
|
border: 2px solid transparent
|
||||||
|
font-size: 0.75rem
|
||||||
|
display: flex
|
||||||
|
align-items: center
|
||||||
|
justify-content: space-between
|
||||||
|
transition: all 0.2s ease
|
||||||
|
position: relative
|
||||||
|
overflow: hidden
|
||||||
|
|
||||||
|
&.voted
|
||||||
|
background-color: rgba($success, 0.1)
|
||||||
|
border-color: rgba($success, 0.5)
|
||||||
|
|
||||||
|
.vote-icon
|
||||||
|
color: $success
|
||||||
|
margin-left: 0.5rem
|
||||||
|
filter: drop-shadow(0 0 2px rgba($success, 0.8))
|
||||||
|
animation: pixel-pulse 1.5s infinite
|
||||||
|
|
||||||
|
&:before
|
||||||
|
content: ''
|
||||||
|
position: absolute
|
||||||
|
top: 0
|
||||||
|
left: 0
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
|
background: repeating-linear-gradient(
|
||||||
|
45deg,
|
||||||
|
transparent,
|
||||||
|
transparent 5px,
|
||||||
|
rgba($success, 0.1) 5px,
|
||||||
|
rgba($success, 0.1) 10px
|
||||||
|
)
|
||||||
|
z-index: -1
|
||||||
|
|
||||||
|
&.not-voted
|
||||||
|
background-color: rgba(255, 255, 255, 0.05)
|
||||||
|
border-color: rgba(255, 255, 255, 0.1)
|
||||||
|
opacity: 0.7
|
||||||
|
|
||||||
|
@keyframes pixel-blink
|
||||||
|
0%, 100%
|
||||||
|
opacity: 1
|
||||||
|
50%
|
||||||
|
opacity: 0.3
|
||||||
|
|
||||||
// Bye container for automatic advances
|
// Bye container for automatic advances
|
||||||
.bye-container
|
.bye-container
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Main styles for the Song Battle application
|
// Main styles for the Song Battle application
|
||||||
@import './colors'
|
@import './colors'
|
||||||
@import './forms'
|
@import './forms'
|
||||||
|
@import './buttons'
|
||||||
|
|
||||||
// Component styles
|
// Component styles
|
||||||
@import './components/home-screen'
|
@import './components/home-screen'
|
||||||
|
@ -78,8 +78,12 @@ const HomeScreen = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<button type="submit" className="btn primary">
|
<button type="submit" className="btn primary pixelated full-width">
|
||||||
{isCreateMode ? 'Create New Game' : 'Join Game'}
|
{isCreateMode ? 'Create New Game' : 'Join Game'}
|
||||||
|
<span className="pixel-corner tl"></span>
|
||||||
|
<span className="pixel-corner tr"></span>
|
||||||
|
<span className="pixel-corner bl"></span>
|
||||||
|
<span className="pixel-corner br"></span>
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
// VotingScreen.jsx
|
// VotingScreen.jsx
|
||||||
import { useState, useEffect } from 'react';
|
import { useState, useEffect, useMemo } from 'react';
|
||||||
import { useGame } from '../context/GameContext';
|
import { useGame } from '../context/GameContext';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faVoteYea, faTrophy, faMusic, faCheck } from '@fortawesome/free-solid-svg-icons';
|
import { faVoteYea, faTrophy, faMusic, faCheck, faMedal, faCrown } from '@fortawesome/free-solid-svg-icons';
|
||||||
import YouTubeEmbed from './YouTubeEmbed';
|
import YouTubeEmbed from './YouTubeEmbed';
|
||||||
|
|
||||||
function VotingScreen() {
|
function VotingScreen() {
|
||||||
@ -10,10 +10,30 @@ function VotingScreen() {
|
|||||||
const [hasVoted, setHasVoted] = useState(false);
|
const [hasVoted, setHasVoted] = useState(false);
|
||||||
const [selectedSong, setSelectedSong] = useState(null);
|
const [selectedSong, setSelectedSong] = useState(null);
|
||||||
const [countdown, setCountdown] = useState(null);
|
const [countdown, setCountdown] = useState(null);
|
||||||
|
|
||||||
// Get current battle
|
// Get current battle
|
||||||
const battle = lobby?.currentBattle || null;
|
const battle = lobby?.currentBattle || null;
|
||||||
|
|
||||||
|
// Calculate the tournament phase based on the round number and total songs
|
||||||
|
const tournamentPhase = useMemo(() => {
|
||||||
|
if (!lobby || !battle) return '';
|
||||||
|
|
||||||
|
// Get total number of songs in the tournament
|
||||||
|
const totalSongs = lobby.songs?.length || 0;
|
||||||
|
|
||||||
|
if (totalSongs === 0) return 'Preliminaries';
|
||||||
|
|
||||||
|
// Calculate total rounds needed for the tournament
|
||||||
|
const totalRounds = Math.ceil(Math.log2(totalSongs));
|
||||||
|
const currentRound = battle.round + 1;
|
||||||
|
const roundsRemaining = totalRounds - currentRound;
|
||||||
|
|
||||||
|
if (roundsRemaining === 0) return 'Finals';
|
||||||
|
if (roundsRemaining === 1) return 'Semi-Finals';
|
||||||
|
if (roundsRemaining === 2) return 'Quarter-Finals';
|
||||||
|
return 'Contestant Round';
|
||||||
|
}, [lobby, battle]);
|
||||||
|
|
||||||
// Check if player has already voted
|
// Check if player has already voted
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (battle && battle.votes && currentPlayer) {
|
if (battle && battle.votes && currentPlayer) {
|
||||||
@ -35,11 +55,11 @@ function VotingScreen() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Submit final vote
|
// Submit final vote
|
||||||
const handleSubmitVote = () => {
|
const handleSubmitVote = async () => {
|
||||||
if (!selectedSong || hasVoted) return;
|
if (!selectedSong || hasVoted) return;
|
||||||
|
|
||||||
submitVote(selectedSong);
|
await submitVote(selectedSong);
|
||||||
setHasVoted(true);
|
// Setting hasVoted is now handled by the useEffect that checks votes
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get YouTube video IDs from links
|
// Get YouTube video IDs from links
|
||||||
@ -100,7 +120,13 @@ function VotingScreen() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="voting-status">
|
<div className="voting-status">
|
||||||
<button className="btn primary" onClick={() => submitVote(battle.song1.id)}>Continue to Next Battle</button>
|
<button className="btn primary pixelated full-width" onClick={() => submitVote(battle.song1.id)}>
|
||||||
|
Continue to Next Battle
|
||||||
|
<span className="pixel-corner tl"></span>
|
||||||
|
<span className="pixel-corner tr"></span>
|
||||||
|
<span className="pixel-corner bl"></span>
|
||||||
|
<span className="pixel-corner br"></span>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@ -113,7 +139,8 @@ function VotingScreen() {
|
|||||||
<div className="voting-screen">
|
<div className="voting-screen">
|
||||||
<header className="voting-header">
|
<header className="voting-header">
|
||||||
<h1>
|
<h1>
|
||||||
<FontAwesomeIcon icon={faVoteYea} /> Song Battle!
|
<FontAwesomeIcon icon={tournamentPhase === 'Finals' ? faCrown : tournamentPhase === 'Semi-Finals' ? faMedal : faVoteYea} />
|
||||||
|
{tournamentPhase}
|
||||||
</h1>
|
</h1>
|
||||||
<div className="round-info">
|
<div className="round-info">
|
||||||
<span>Round {battle.round + 1}</span>
|
<span>Round {battle.round + 1}</span>
|
||||||
@ -208,7 +235,7 @@ function VotingScreen() {
|
|||||||
disabled={!selectedSong}
|
disabled={!selectedSong}
|
||||||
>
|
>
|
||||||
Cast Vote
|
Cast Vote
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -217,6 +244,27 @@ function VotingScreen() {
|
|||||||
<div className="votes-count">
|
<div className="votes-count">
|
||||||
<span>{battle.voteCount || 0}</span> of <span>{lobby?.players?.filter(p => p.isConnected).length || 0}</span> votes
|
<span>{battle.voteCount || 0}</span> of <span>{lobby?.players?.filter(p => p.isConnected).length || 0}</span> votes
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Player voting status list */}
|
||||||
|
<div className="player-votes">
|
||||||
|
<h4>Voters</h4>
|
||||||
|
<ul className="players-voted-list">
|
||||||
|
{lobby?.players?.filter(p => p.isConnected).map(player => {
|
||||||
|
// Check if this player has voted
|
||||||
|
const hasPlayerVoted = battle.votes &&
|
||||||
|
Object.keys(battle.votes).includes(player.id);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li key={player.id} className={hasPlayerVoted ? 'voted' : 'not-voted'}>
|
||||||
|
{player.name} {player.id === currentPlayer.id && '(You)'}
|
||||||
|
{hasPlayerVoted &&
|
||||||
|
<FontAwesomeIcon icon={faCheck} className="vote-icon" />
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -539,8 +539,15 @@ class GameManager {
|
|||||||
return { error: 'Invalid song ID' };
|
return { error: 'Invalid song ID' };
|
||||||
}
|
}
|
||||||
|
|
||||||
// Record the vote
|
// Find player name for display purposes
|
||||||
lobby.currentBattle.votes.set(playerId, songId);
|
const player = lobby.players.find(p => p.id === playerId);
|
||||||
|
const playerName = player ? player.name : 'Unknown Player';
|
||||||
|
|
||||||
|
// Record the vote with player name for UI display
|
||||||
|
lobby.currentBattle.votes.set(playerId, {
|
||||||
|
songId,
|
||||||
|
playerName
|
||||||
|
});
|
||||||
|
|
||||||
// Update vote counts
|
// Update vote counts
|
||||||
if (songId === lobby.currentBattle.song1.id) {
|
if (songId === lobby.currentBattle.song1.id) {
|
||||||
@ -549,6 +556,9 @@ class GameManager {
|
|||||||
lobby.currentBattle.song2Votes++;
|
lobby.currentBattle.song2Votes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add a voteCount attribute for easier UI rendering
|
||||||
|
lobby.currentBattle.voteCount = lobby.currentBattle.votes.size;
|
||||||
|
|
||||||
// Check if all connected players have voted
|
// Check if all connected players have voted
|
||||||
const connectedPlayers = lobby.players.filter(p => p.isConnected).length;
|
const connectedPlayers = lobby.players.filter(p => p.isConnected).length;
|
||||||
const voteCount = lobby.currentBattle.votes.size;
|
const voteCount = lobby.currentBattle.votes.size;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user