Update WaitingRoom design

This commit is contained in:
Mathias Wagner 2025-03-01 16:21:29 +01:00
parent aa10b5b2cc
commit 251879a1e1
2 changed files with 386 additions and 117 deletions

View File

@ -160,27 +160,48 @@ export const WaitingRoom = () => {
return votes[playlistId]?.length || 0; return votes[playlistId]?.length || 0;
}; };
const renderPlaylists = () => ( const renderPlaylistSection = () => (
<div className="playlists-grid"> <div className="playlist-section">
{Object.entries(playlists).map(([genre, playlist]) => ( <div className="section-header">
<div <h2>Choose a Playlist</h2>
key={playlist.id} <p className="vote-info">Most voted playlist will be used for the game</p>
className={`playlist-card ${selectedPlaylist === playlist.id ? 'selected' : ''}`} </div>
onClick={() => handleVote(playlist.id)} <div className="playlists-grid">
> {Object.entries(playlists).map(([genre, playlist]) => (
<div className="playlist-thumbnail"> <div
<img src={playlist.thumbnail.url} alt={playlist.title} /> key={playlist.id}
<div className="vote-count"> className={`playlist-card ${selectedPlaylist === playlist.id ? 'selected' : ''}`}
<span>{getVoteCount(playlist.id)}</span> onClick={() => handleVote(playlist.id)}
<span className="vote-label">votes</span> >
<div className="playlist-thumbnail">
<img src={playlist.thumbnail.url} alt={playlist.title} />
<div className="playlist-overlay">
<div className="vote-count">
<span className="count">{getVoteCount(playlist.id)}</span>
<span className="vote-label">votes</span>
</div>
{selectedPlaylist === playlist.id && (
<div className="your-vote">Your Vote</div>
)}
</div>
</div>
<div className="playlist-info">
<h3>{genre.toUpperCase()}</h3>
<div className="playlist-details">
<span>{playlist.songCount} songs</span>
<div className="vote-percentage-bar">
<div
className="fill"
style={{
width: `${(getVoteCount(playlist.id) / Math.max(1, users.length)) * 100}%`
}}
/>
</div>
</div>
</div> </div>
</div> </div>
<div className="playlist-info"> ))}
<h3>{genre.toUpperCase()}</h3> </div>
<p>{playlist.songCount} songs</p>
</div>
</div>
))}
</div> </div>
); );
@ -208,75 +229,74 @@ export const WaitingRoom = () => {
</div> </div>
</div> </div>
<div className="waiting-room-content"> <div className="waiting-room-layout">
<div className="users-panel"> {renderPlaylistSection()}
<div className="panel-header">
<FontAwesomeIcon icon={faUsers} /> <div className="bottom-section">
<h2>Spieler ({users.length})</h2> <div className="users-panel">
</div> <div className="panel-header">
<div className="users-list"> <FontAwesomeIcon icon={faUsers} />
{users.length === 0 ? ( <h2>Spieler ({users.length})</h2>
<div className="no-users">Keine Spieler im Raum</div> </div>
) : ( <div className="users-list">
users.map((user) => ( {users.length === 0 ? (
<div key={user.id} className={`user-item ${user.creator ? 'host' : ''}`}> <div className="no-users">Keine Spieler im Raum</div>
{user.name} {user.creator && <span className="host-badge">Host</span>} ) : (
</div> users.map((user) => (
)) <div key={user.id} className={`user-item ${user.creator ? 'host' : ''}`}>
)} {user.name} {user.creator && <span className="host-badge">Host</span>}
</div> </div>
{isHost && ( ))
<div className="game-controls">
<button
className={`start-game-button ${canStartGame ? '' : 'disabled'}`}
onClick={handleStartGame}
disabled={!canStartGame}
>
<FontAwesomeIcon icon={faPlayCircle} />
Spiel starten
</button>
{!canStartGame && users.length < minPlayersToStart && (
<div className="start-hint">Mindestens {minPlayersToStart} Spieler benötigt</div>
)} )}
</div> </div>
)} {isHost && (
</div> <div className="game-controls">
<button
<div className="chat-panel"> className={`start-game-button ${canStartGame ? '' : 'disabled'}`}
<div className="panel-header"> onClick={handleStartGame}
<FontAwesomeIcon icon={faMessage} /> disabled={!canStartGame}
<h2>Chat</h2> >
</div> <FontAwesomeIcon icon={faPlayCircle} />
<div className="chat-messages"> Spiel starten
{messages.map((message, index) => ( </button>
<div key={index} className={`message ${message.system ? 'system-message' : ''}`}> {!canStartGame && users.length < minPlayersToStart && (
{message.system ? ( <div className="start-hint">Mindestens {minPlayersToStart} Spieler benötigt</div>
<span className="message-text system">{message.text}</span>
) : (
<>
<span className="message-sender">{message.sender}:</span>
<span className="message-text">{message.text}</span>
</>
)} )}
</div> </div>
))} )}
<div ref={messageEndRef}></div>
</div> </div>
<div className="chat-input">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
placeholder="Gib eine Nachricht ein..."
/>
<button onClick={handleSendMessage}>Senden</button>
</div>
</div>
<div className="playlist-section"> <div className="chat-panel">
<h2>Vote for Playlist</h2> <div className="panel-header">
{renderPlaylists()} <FontAwesomeIcon icon={faMessage} />
<h2>Chat</h2>
</div>
<div className="chat-messages">
{messages.map((message, index) => (
<div key={index} className={`message ${message.system ? 'system-message' : ''}`}>
{message.system ? (
<span className="message-text system">{message.text}</span>
) : (
<>
<span className="message-sender">{message.sender}:</span>
<span className="message-text">{message.text}</span>
</>
)}
</div>
))}
<div ref={messageEndRef}></div>
</div>
<div className="chat-input">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSendMessage()}
placeholder="Gib eine Nachricht ein..."
/>
<button onClick={handleSendMessage}>Senden</button>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -102,10 +102,11 @@
width: 100% width: 100%
max-width: 1200px max-width: 1200px
gap: 30px gap: 30px
height: calc(100vh - 180px) height: calc(100vh - 140px)
z-index: 2 z-index: 2
position: relative position: relative
animation: float-up 1.2s ease-out animation: float-up 1.2s ease-out
overflow: hidden
.users-panel, .users-panel,
.chat-panel .chat-panel
@ -130,6 +131,7 @@
flex-grow: 1 flex-grow: 1
overflow-y: auto overflow-y: auto
padding: 15px padding: 15px
min-height: 0
&::-webkit-scrollbar &::-webkit-scrollbar
width: 6px width: 6px
@ -222,6 +224,7 @@
width: 70% width: 70%
display: flex display: flex
flex-direction: column flex-direction: column
height: 100%
.chat-messages .chat-messages
flex-grow: 1 flex-grow: 1
@ -229,6 +232,7 @@
padding: 15px padding: 15px
display: flex display: flex
flex-direction: column flex-direction: column
min-height: 0
&::-webkit-scrollbar &::-webkit-scrollbar
width: 8px width: 8px
@ -331,23 +335,43 @@
margin: 0 margin: 0
.playlist-section .playlist-section
margin-bottom: 30px background: rgba(255, 255, 255, 0.08)
backdrop-filter: blur(10px)
border-radius: 20px
padding: 25px
animation: float-up 0.8s ease-out
border: 1px solid rgba(255, 255, 255, 0.2)
h2 .section-header
color: $white
text-align: center text-align: center
margin-bottom: 20px margin-bottom: 20px
font-size: 24px
text-shadow: 0 0 10px rgba(255, 255, 255, 0.5) h2
margin: 0
font-size: 32px
color: $white
background: linear-gradient(135deg, $yellow, $pink)
-webkit-background-clip: text
background-clip: text
-webkit-text-fill-color: transparent
.vote-info
color: rgba(255, 255, 255, 0.7)
font-size: 16px
.playlists-grid .playlists-grid
display: grid display: grid
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)) grid-template-columns: repeat(3, 1fr)
gap: 20px gap: 25px
padding: 20px
@media (max-width: 1200px)
grid-template-columns: repeat(2, 1fr)
@media (max-width: 768px)
grid-template-columns: 1fr
.playlist-card .playlist-card
background: rgba(255, 255, 255, 0.1) background: rgba(20, 20, 30, 0.6)
border-radius: 15px border-radius: 15px
overflow: hidden overflow: hidden
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275) transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)
@ -356,13 +380,23 @@
&:hover &:hover
transform: translateY(-5px) transform: translateY(-5px)
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3) background: rgba(30, 30, 40, 0.8)
background: rgba(255, 255, 255, 0.15)
.playlist-overlay
opacity: 1
&.selected &.selected
border-color: $yellow border-color: $yellow
box-shadow: 0 0 30px rgba($yellow, 0.3) box-shadow: 0 0 30px rgba($yellow, 0.3)
.playlist-overlay
opacity: 1
background: rgba(0, 0, 0, 0.5)
.your-vote
transform: translateY(0)
opacity: 1
.playlist-thumbnail .playlist-thumbnail
position: relative position: relative
width: 100% width: 100%
@ -376,39 +410,254 @@
height: 100% height: 100%
object-fit: cover object-fit: cover
.vote-count .playlist-overlay
position: absolute position: absolute
top: 10px inset: 0
right: 10px background: rgba(0, 0, 0, 0.3)
background: rgba(0, 0, 0, 0.8) opacity: 0
padding: 8px 12px transition: all 0.3s ease
border-radius: 20px
display: flex display: flex
flex-direction: column flex-direction: column
justify-content: center
align-items: center align-items: center
span .vote-count
color: $white background: rgba(0, 0, 0, 0.8)
padding: 12px 20px
border-radius: 25px
text-align: center
&:first-child .count
font-size: 24px font-size: 32px
font-weight: bold font-weight: bold
color: $yellow
display: block
&.vote-label .vote-label
font-size: 12px font-size: 14px
opacity: 0.8 color: rgba(255, 255, 255, 0.8)
.your-vote
position: absolute
bottom: 15px
background: $yellow
color: #000
padding: 8px 16px
border-radius: 20px
font-weight: bold
transform: translateY(20px)
opacity: 0
transition: all 0.3s ease
.playlist-info .playlist-info
padding: 15px padding: 20px
h3 h3
color: $white color: $white
margin-bottom: 5px margin-bottom: 10px
font-size: 18px font-size: 20px
p .playlist-details
color: rgba(255, 255, 255, 0.7) display: flex
font-size: 14px flex-direction: column
gap: 8px
span
color: rgba(255, 255, 255, 0.7)
font-size: 14px
.vote-percentage-bar
height: 4px
background: rgba(255, 255, 255, 0.1)
border-radius: 2px
overflow: hidden
.fill
height: 100%
background: linear-gradient(90deg, $yellow, $pink)
transition: width 0.3s ease
.bottom-section
display: flex
gap: 30px
width: 100%
min-height: 0
height: 300px
margin-top: 20px
.users-panel
height: 100%
display: flex
flex-direction: column
background: rgba(20, 20, 30, 0.6)
border-radius: 15px
border: 1px solid rgba(255, 255, 255, 0.1)
overflow: hidden
transition: all 0.3s ease
&:hover
border-color: rgba(255, 255, 255, 0.2)
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3)
.panel-header
background: rgba(30, 30, 40, 0.95)
padding: 20px
border-bottom: 1px solid rgba(255, 255, 255, 0.1)
h2
font-size: 20px
display: flex
align-items: center
gap: 10px
svg
color: $yellow
filter: drop-shadow(0 0 8px rgba($yellow, 0.4))
.users-list
padding: 15px
flex: 1
overflow-y: auto
min-height: 0
.user-item
background: rgba(255, 255, 255, 0.05)
margin-bottom: 10px
padding: 12px 15px
border-radius: 10px
transition: all 0.3s ease
border: 1px solid rgba(255, 255, 255, 0.05)
&:hover
transform: translateY(-2px)
background: rgba(255, 255, 255, 0.08)
border-color: rgba(255, 255, 255, 0.1)
&.host
background: rgba($yellow, 0.1)
border-color: rgba($yellow, 0.3)
.host-badge
background: $yellow
color: #000
font-size: 12px
padding: 4px 8px
border-radius: 20px
font-weight: bold
.game-controls
padding: 15px
background: rgba(20, 20, 30, 0.4)
border-top: 1px solid rgba(255, 255, 255, 0.05)
.start-game-button
width: 100%
padding: 12px
background: linear-gradient(135deg, $purple, $blue)
border-radius: 10px
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)
&:not(.disabled):hover
transform: translateY(-2px)
filter: brightness(1.1)
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4)
.chat-panel
flex: 1
height: 100%
background: rgba(20, 20, 30, 0.6)
border-radius: 15px
border: 1px solid rgba(255, 255, 255, 0.1)
display: flex
flex-direction: column
overflow: hidden
transition: all 0.3s ease
&:hover
border-color: rgba(255, 255, 255, 0.2)
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3)
.panel-header
background: rgba(30, 30, 40, 0.95)
padding: 20px
border-bottom: 1px solid rgba(255, 255, 255, 0.1)
h2
font-size: 20px
display: flex
align-items: center
gap: 10px
svg
color: $blue
filter: drop-shadow(0 0 8px rgba($blue, 0.4))
.chat-messages
flex: 1
padding: 20px
overflow-y: auto
display: flex
flex-direction: column
gap: 10px
min-height: 0
.message
max-width: 85%
padding: 10px 15px
border-radius: 12px
background: rgba(255, 255, 255, 0.05)
border: 1px solid rgba(255, 255, 255, 0.05)
transition: all 0.3s ease
&:hover
background: rgba(255, 255, 255, 0.08)
border-color: rgba(255, 255, 255, 0.1)
transform: translateY(-1px)
.message-sender
color: $yellow
font-weight: 600
margin-right: 8px
&.system-message
align-self: center
background: rgba(0, 0, 0, 0.2)
font-style: italic
color: rgba(255, 255, 255, 0.6)
padding: 8px 16px
border-radius: 20px
.chat-input
padding: 15px
background: rgba(20, 20, 30, 0.4)
border-top: 1px solid rgba(255, 255, 255, 0.05)
display: flex
gap: 10px
input
flex: 1
background: rgba(0, 0, 0, 0.2)
border: 1px solid rgba(255, 255, 255, 0.1)
border-radius: 8px
padding: 12px 15px
color: $white
transition: all 0.3s ease
&:focus
border-color: rgba($blue, 0.5)
box-shadow: 0 0 15px rgba($blue, 0.1)
background: rgba(0, 0, 0, 0.3)
button
padding: 12px 20px
background: linear-gradient(135deg, $purple, $blue)
border-radius: 8px
transition: all 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275)
&:hover
transform: translateY(-2px)
filter: brightness(1.1)
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.3)
@keyframes pop @keyframes pop
0% 0%