feat: added playlist option
All checks were successful
Build and Push Docker Image / docker (push) Successful in 10s
All checks were successful
Build and Push Docker Image / docker (push) Successful in 10s
This commit is contained in:
@@ -122,6 +122,21 @@
|
||||
</details>
|
||||
</div>
|
||||
|
||||
<!-- Playlist Selection (only shown in lobby for host) -->
|
||||
<div id="playlistSection"
|
||||
class="hidden rounded-lg border border-slate-200 dark:border-slate-800 bg-slate-50/60 dark:bg-slate-800/60 p-4">
|
||||
<label class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
🎵 Playlist auswählen
|
||||
</label>
|
||||
<select id="playlistSelect"
|
||||
class="w-full h-11 rounded-lg border border-slate-300 dark:border-slate-700 bg-white dark:bg-slate-800 px-3 outline-none focus:ring-2 focus:ring-indigo-500">
|
||||
<option value="default">Lade Playlists...</option>
|
||||
</select>
|
||||
<p class="mt-2 text-xs text-slate-500 dark:text-slate-400">
|
||||
Als Host kannst du die Playlist für dieses Spiel wählen.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 items-start">
|
||||
<div class="space-y-1">
|
||||
<div class="text-slate-700 dark:text-slate-300">
|
||||
@@ -130,6 +145,9 @@
|
||||
<div class="text-slate-700 dark:text-slate-300">
|
||||
Am Zug: <span id="guesser" class="font-medium"></span>
|
||||
</div>
|
||||
<div id="playlistInfo" class="text-slate-700 dark:text-slate-300">
|
||||
Playlist: <span id="currentPlaylist" class="font-medium">default</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-3 justify-start md:justify-end">
|
||||
<label class="inline-flex items-center gap-3 text-slate-700 dark:text-slate-300 select-none">
|
||||
|
||||
@@ -41,6 +41,11 @@ export const $answerForm = el('answerForm');
|
||||
export const $guessTitle = el('guessTitle');
|
||||
export const $guessArtist = el('guessArtist');
|
||||
export const $answerResult = el('answerResult');
|
||||
// Playlist elements
|
||||
export const $playlistSection = el('playlistSection');
|
||||
export const $playlistSelect = el('playlistSelect');
|
||||
export const $currentPlaylist = el('currentPlaylist');
|
||||
export const $playlistInfo = el('playlistInfo');
|
||||
|
||||
export function showLobby() {
|
||||
$lobby.classList.remove('hidden');
|
||||
|
||||
@@ -145,8 +145,9 @@ export function handleReveal(msg) {
|
||||
const $placeArea = document.getElementById('placeArea');
|
||||
if ($placeArea) $placeArea.classList.add('hidden');
|
||||
const rd = document.getElementById('recordDisc');
|
||||
if (rd && track?.id) {
|
||||
const coverUrl = `/cover/${encodeURIComponent(track.id)}`;
|
||||
if (rd && track?.file) {
|
||||
// Use track.file instead of track.id to include playlist folder prefix
|
||||
const coverUrl = `/cover/${encodeURIComponent(track.file)}`;
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
rd.src = coverUrl;
|
||||
|
||||
@@ -4,10 +4,28 @@ import { onMessage } from './handlers.js';
|
||||
import { wireUi } from './ui.js';
|
||||
import { $nameLobby } from './dom.js';
|
||||
|
||||
// Fetch and store available playlists
|
||||
async function loadPlaylists() {
|
||||
try {
|
||||
const response = await fetch('/api/playlists');
|
||||
const data = await response.json();
|
||||
if (data.ok && data.playlists) {
|
||||
state.playlists = data.playlists;
|
||||
return data.playlists;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Failed to load playlists:', error);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Initialize UI and open WebSocket connection
|
||||
wireUi();
|
||||
connectWS(onMessage);
|
||||
|
||||
// Load playlists on startup
|
||||
loadPlaylists();
|
||||
|
||||
// Restore name/id immediately for initial render smoothness
|
||||
(() => {
|
||||
try {
|
||||
|
||||
@@ -112,6 +112,35 @@ export function renderRoom(room) {
|
||||
|
||||
if ($startGame) $startGame.classList.toggle('hidden', !canStart);
|
||||
|
||||
// Update playlist display
|
||||
const $playlistSection = document.getElementById('playlistSection');
|
||||
const $playlistSelect = document.getElementById('playlistSelect');
|
||||
const $currentPlaylist = document.getElementById('currentPlaylist');
|
||||
const $playlistInfo = document.getElementById('playlistInfo');
|
||||
if ($playlistSection) {
|
||||
$playlistSection.classList.toggle('hidden', room.state.status !== 'lobby' || !isHost);
|
||||
}
|
||||
if ($playlistSelect && state.playlists && state.playlists.length > 0) {
|
||||
// Populate playlist dropdown if not already populated
|
||||
if ($playlistSelect.options.length === 1 && $playlistSelect.options[0].value === 'default') {
|
||||
$playlistSelect.innerHTML = '';
|
||||
state.playlists.forEach((playlist) => {
|
||||
const option = document.createElement('option');
|
||||
option.value = playlist.id;
|
||||
option.textContent = `${playlist.name} (${playlist.trackCount} Tracks)`;
|
||||
$playlistSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
// Set selected playlist
|
||||
$playlistSelect.value = room.state.playlist || 'default';
|
||||
}
|
||||
if ($currentPlaylist) {
|
||||
$currentPlaylist.textContent = room.state.playlist || 'default';
|
||||
}
|
||||
if ($playlistInfo) {
|
||||
$playlistInfo.classList.toggle('hidden', room.state.status === 'lobby');
|
||||
}
|
||||
|
||||
const isMyTurn =
|
||||
room.state.status === 'playing' &&
|
||||
room.state.phase === 'guess' &&
|
||||
|
||||
@@ -11,4 +11,5 @@ export const state = {
|
||||
revealed: false,
|
||||
pendingReady: null,
|
||||
isBuffering: false,
|
||||
playlists: [], // Available playlists
|
||||
};
|
||||
|
||||
@@ -129,6 +129,15 @@ export function wireUi() {
|
||||
sendMsg({ type: 'set_ready', ready: val });
|
||||
});
|
||||
|
||||
// Playlist selection
|
||||
const $playlistSelect = document.getElementById('playlistSelect');
|
||||
if ($playlistSelect) {
|
||||
wire($playlistSelect, 'change', (e) => {
|
||||
const playlistId = e.target.value;
|
||||
sendMsg({ type: 'set_playlist', playlist: playlistId });
|
||||
});
|
||||
}
|
||||
|
||||
wire($placeBtn, 'click', () => {
|
||||
const slot = parseInt($slotSelect.value, 10);
|
||||
sendMsg({ type: 'place_guess', slot });
|
||||
|
||||
Reference in New Issue
Block a user