Add vote progress bar and related styles to enhance voting feedback
All checks were successful
Publish Docker image / Push Docker image to Docker Hub (push) Successful in 3m21s
All checks were successful
Publish Docker image / Push Docker image to Docker Hub (push) Successful in 3m21s
This commit is contained in:
parent
8f91e27ca1
commit
f3c87878ce
@ -447,3 +447,230 @@
|
||||
justify-content: center
|
||||
margin: 2rem 0
|
||||
animation: pixel-float 3s infinite ease-in-out
|
||||
|
||||
// Vote Progress Bar
|
||||
.vote-progress-container
|
||||
width: 100%
|
||||
margin-top: 1.5rem
|
||||
margin-bottom: 2rem
|
||||
padding: 0 0.5rem
|
||||
animation: fade-in-up 0.5s ease forwards
|
||||
position: relative
|
||||
|
||||
@keyframes fade-in-up
|
||||
from
|
||||
opacity: 0
|
||||
transform: translateY(10px)
|
||||
to
|
||||
opacity: 1
|
||||
transform: translateY(0)
|
||||
|
||||
.vote-progress-labels
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
margin-bottom: 0.5rem
|
||||
font-size: 0.8rem
|
||||
font-family: 'Press Start 2P', monospace
|
||||
|
||||
.vote-label
|
||||
padding: 0.5rem 0.75rem
|
||||
background-color: rgba(0, 0, 0, 0.7)
|
||||
border: 2px solid #000
|
||||
transform: translateY(0)
|
||||
transition: transform 0.3s ease
|
||||
position: relative
|
||||
z-index: 2
|
||||
|
||||
&.left
|
||||
color: $primary
|
||||
border-left-color: $primary
|
||||
border-top-color: $primary
|
||||
border-bottom-color: $primary
|
||||
box-shadow: -3px 3px 0 rgba($primary, 0.3)
|
||||
&:hover
|
||||
transform: translateY(-3px)
|
||||
box-shadow: -5px 5px 0 rgba($primary, 0.5)
|
||||
|
||||
&.right
|
||||
color: $accent
|
||||
border-right-color: $accent
|
||||
border-top-color: $accent
|
||||
border-bottom-color: $accent
|
||||
box-shadow: 3px 3px 0 rgba($accent, 0.3)
|
||||
&:hover
|
||||
transform: translateY(-3px)
|
||||
box-shadow: 5px 5px 0 rgba($accent, 0.5)
|
||||
|
||||
&.winning
|
||||
background-color: rgba(#000, 0.8)
|
||||
border-width: 3px
|
||||
transform: translateY(-3px)
|
||||
position: relative
|
||||
z-index: 3
|
||||
animation: winner-pulse 1.5s infinite alternate
|
||||
|
||||
&.left
|
||||
box-shadow: -5px 5px 0 rgba($primary, 0.7), 0 0 15px rgba($primary, 0.7)
|
||||
|
||||
&.right
|
||||
box-shadow: 5px 5px 0 rgba($accent, 0.7), 0 0 15px rgba($accent, 0.7)
|
||||
|
||||
&.landslide
|
||||
transform: translateY(-5px)
|
||||
font-weight: bold
|
||||
animation: winner-landslide-pulse 1s infinite alternate
|
||||
|
||||
&.left
|
||||
box-shadow: -6px 6px 0 rgba($primary, 0.7), 0 0 25px rgba($primary, 0.9)
|
||||
|
||||
&.right
|
||||
box-shadow: 6px 6px 0 rgba($accent, 0.7), 0 0 25px rgba($accent, 0.9)
|
||||
|
||||
@keyframes winner-landslide-pulse
|
||||
from
|
||||
box-shadow: -6px 6px 0 rgba($primary, 0.7), 0 0 25px rgba($primary, 0.9)
|
||||
to
|
||||
box-shadow: -6px 6px 0 rgba($primary, 0.7), 0 0 40px rgba($primary, 1)
|
||||
|
||||
.vote-progress-bar
|
||||
height: 36px
|
||||
background-color: #222
|
||||
border: 4px solid #000
|
||||
position: relative
|
||||
overflow: hidden
|
||||
display: flex
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3)
|
||||
|
||||
.vote-progress-fill
|
||||
height: 100%
|
||||
transition: width 1.2s cubic-bezier(0.34, 1.56, 0.64, 1)
|
||||
position: relative
|
||||
min-width: 0
|
||||
|
||||
&.song1
|
||||
background: linear-gradient(to right, darken($primary, 20%), $primary)
|
||||
box-shadow: 0 8px 24px rgba($primary, 0.3), 0 0 10px rgba($primary, 0.2)
|
||||
animation: pulse-song1 2s infinite alternate
|
||||
|
||||
&.song2
|
||||
background: linear-gradient(to left, darken($accent, 20%), $accent)
|
||||
box-shadow: 0 8px 24px rgba($accent, 0.3), 0 0 10px rgba($accent, 0.2)
|
||||
animation: pulse-song2 2s infinite alternate
|
||||
|
||||
.vote-progress-decoration
|
||||
position: absolute
|
||||
top: 0
|
||||
bottom: 0
|
||||
width: 20px
|
||||
background-size: 4px 4px
|
||||
opacity: 0.6
|
||||
|
||||
&.left
|
||||
right: 10px
|
||||
background-image: linear-gradient(45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent)
|
||||
animation: move-stripes-left 20s linear infinite
|
||||
|
||||
&.right
|
||||
left: 10px
|
||||
background-image: linear-gradient(-45deg, rgba(255,255,255,0.4) 25%, transparent 25%, transparent 50%, rgba(255,255,255,0.4) 50%, rgba(255,255,255,0.4) 75%, transparent 75%, transparent)
|
||||
animation: move-stripes-right 20s linear infinite
|
||||
|
||||
&.landslide
|
||||
border-width: 5px
|
||||
animation: landslide-border-pulse 1.5s infinite alternate
|
||||
|
||||
&.song1
|
||||
border-color: lighten($primary, 20%)
|
||||
|
||||
&.song2
|
||||
border-color: lighten($accent, 20%)
|
||||
|
||||
.vote-progress-divider
|
||||
position: absolute
|
||||
top: -8px
|
||||
bottom: -8px
|
||||
width: 6px
|
||||
background-color: #fff
|
||||
transform: translateX(-50%)
|
||||
z-index: 10
|
||||
box-shadow: 0 0 15px rgba(255, 255, 255, 0.7), 0 0 5px rgba(0, 0, 0, 0.5)
|
||||
transition: left 1.2s cubic-bezier(0.34, 1.56, 0.64, 1)
|
||||
&:before, &:after
|
||||
content: ''
|
||||
position: absolute
|
||||
left: 50%
|
||||
width: 12px
|
||||
height: 12px
|
||||
background-color: #fff
|
||||
transform: translateX(-50%) rotate(45deg)
|
||||
box-shadow: 0 0 10px rgba(255, 255, 255, 0.7), 0 0 3px rgba(0, 0, 0, 0.5)
|
||||
|
||||
&:before
|
||||
top: 0
|
||||
|
||||
&:after
|
||||
bottom: 0
|
||||
|
||||
.vote-progress-percentages
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
margin-top: 0.75rem
|
||||
font-family: 'Press Start 2P', monospace
|
||||
font-size: 1rem
|
||||
|
||||
.vote-percent
|
||||
font-weight: bold
|
||||
text-shadow: 2px 2px 0 #000
|
||||
padding: 0.4rem 0.75rem
|
||||
background-color: rgba(0, 0, 0, 0.7)
|
||||
border: 2px solid #000
|
||||
letter-spacing: 1px
|
||||
position: relative
|
||||
|
||||
&.left
|
||||
color: $primary
|
||||
border-left-color: $primary
|
||||
border-bottom-color: $primary
|
||||
transform: skew(-10deg)
|
||||
box-shadow: -3px 3px 0 rgba($primary, 0.4)
|
||||
|
||||
&.right
|
||||
color: $accent
|
||||
border-right-color: $accent
|
||||
border-bottom-color: $accent
|
||||
transform: skew(10deg)
|
||||
box-shadow: 3px 3px 0 rgba($accent, 0.4)
|
||||
|
||||
&.winning
|
||||
font-size: 1.2rem
|
||||
font-weight: bolder
|
||||
animation: winner-text-pulse 2s infinite alternate
|
||||
|
||||
&.left
|
||||
box-shadow: -5px 5px 0 rgba($primary, 0.5), 0 0 10px rgba($primary, 0.5)
|
||||
|
||||
&.right
|
||||
box-shadow: 5px 5px 0 rgba($accent, 0.5), 0 0 10px rgba($accent, 0.5)
|
||||
|
||||
&.landslide
|
||||
font-size: 1.3rem
|
||||
animation: landslide-text-pulse 1s infinite alternate
|
||||
|
||||
&.left
|
||||
box-shadow: -6px 6px 0 rgba($primary, 0.6), 0 0 15px rgba($primary, 0.6)
|
||||
|
||||
&.right
|
||||
box-shadow: 6px 6px 0 rgba($accent, 0.6), 0 0 15px rgba($accent, 0.6)
|
||||
|
||||
@keyframes landslide-text-pulse
|
||||
from
|
||||
text-shadow: 2px 2px 0 #000, 0 0 10px currentColor
|
||||
to
|
||||
text-shadow: 2px 2px 0 #000, 0 0 25px currentColor, 0 0 5px #fff
|
||||
|
||||
// Bye container for automatic advances
|
||||
.bye-container
|
||||
display: flex
|
||||
justify-content: center
|
||||
margin: 2rem 0
|
||||
animation: pixel-float 3s infinite ease-in-out
|
||||
|
@ -37,6 +37,27 @@ function VotingScreen() {
|
||||
return 'Vorrunde';
|
||||
}, [lobby, battle]);
|
||||
|
||||
// Berechne das Verhältnis der Stimmen für den Fortschrittsbalken
|
||||
const voteRatio = useMemo(() => {
|
||||
if (!battle || !hasVoted) return { song1Percent: 50, song2Percent: 50 };
|
||||
|
||||
const totalVotes = (battle.song1Votes || 0) + (battle.song2Votes || 0);
|
||||
|
||||
if (totalVotes === 0) return { song1Percent: 50, song2Percent: 50 };
|
||||
|
||||
const song1Percent = Math.round((battle.song1Votes / totalVotes) * 100);
|
||||
const song2Percent = 100 - song1Percent;
|
||||
|
||||
// Determine winner (for styling purposes)
|
||||
const winner = song1Percent > song2Percent ? 'song1' : song1Percent < song2Percent ? 'song2' : 'tie';
|
||||
|
||||
// Calculate margin of victory for animation intensity
|
||||
const margin = Math.abs(song1Percent - song2Percent);
|
||||
const isLandslide = margin >= 30;
|
||||
|
||||
return { song1Percent, song2Percent, winner, totalVotes, isLandslide, margin };
|
||||
}, [battle, hasVoted]);
|
||||
|
||||
// Prüfe, ob der Spieler bereits abgestimmt hat
|
||||
useEffect(() => {
|
||||
if (battle && battle.votes && currentPlayer) {
|
||||
@ -296,6 +317,56 @@ function VotingScreen() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Vote Progress Bar - Only show after voting */}
|
||||
{hasVoted && (
|
||||
<div className="vote-progress-container">
|
||||
<div className="vote-progress-labels">
|
||||
<span className={`vote-label left ${voteRatio.winner === 'song1' ? 'winning' : ''} ${voteRatio.winner === 'song1' && voteRatio.isLandslide ? 'landslide' : ''}`}>
|
||||
{battle.song1Votes || 0} Stimmen
|
||||
{voteRatio.winner === 'song1' && voteRatio.totalVotes > 1 &&
|
||||
<span className="winner-crown"><FontAwesomeIcon icon={faCrown} /></span>
|
||||
}
|
||||
</span>
|
||||
<span className={`vote-label right ${voteRatio.winner === 'song2' ? 'winning' : ''} ${voteRatio.winner === 'song2' && voteRatio.isLandslide ? 'landslide' : ''}`}>
|
||||
{battle.song2Votes || 0} Stimmen
|
||||
{voteRatio.winner === 'song2' && voteRatio.totalVotes > 1 &&
|
||||
<span className="winner-crown"><FontAwesomeIcon icon={faCrown} /></span>
|
||||
}
|
||||
</span>
|
||||
</div>
|
||||
<div className={`vote-progress-bar ${voteRatio.winner !== 'tie' ? voteRatio.winner : ''} ${voteRatio.isLandslide ? 'landslide' : ''}`}>
|
||||
<div
|
||||
className={`vote-progress-fill song1 ${voteRatio.winner === 'song1' ? 'winning' : ''}`}
|
||||
style={{ width: `${voteRatio.song1Percent}%` }}
|
||||
>
|
||||
{voteRatio.song1Percent > 5 && (
|
||||
<div className="vote-progress-decoration left"></div>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className={`vote-progress-divider ${voteRatio.margin <= 10 ? 'close-race' : ''}`}
|
||||
style={{ left: `${voteRatio.song1Percent}%` }}
|
||||
></div>
|
||||
<div
|
||||
className={`vote-progress-fill song2 ${voteRatio.winner === 'song2' ? 'winning' : ''}`}
|
||||
style={{ width: `${voteRatio.song2Percent}%` }}
|
||||
>
|
||||
{voteRatio.song2Percent > 5 && (
|
||||
<div className="vote-progress-decoration right"></div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="vote-progress-percentages">
|
||||
<span className={`vote-percent left ${voteRatio.winner === 'song1' ? 'winning' : ''} ${voteRatio.winner === 'song1' && voteRatio.isLandslide ? 'landslide' : ''}`}>
|
||||
{voteRatio.song1Percent}%
|
||||
</span>
|
||||
<span className={`vote-percent right ${voteRatio.winner === 'song2' ? 'winning' : ''} ${voteRatio.winner === 'song2' && voteRatio.isLandslide ? 'landslide' : ''}`}>
|
||||
{voteRatio.song2Percent}%
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!hasVoted && (
|
||||
<div className="voting-actions">
|
||||
<button
|
||||
|
Loading…
x
Reference in New Issue
Block a user