import { state } from './state.js'; import { badgeColorForYear } from '../utils/colors.js'; import { $answerForm, $answerResult, $dashboardList, $guesser, $lobby, $mediaControls, $nameDisplay, $nextArea, $np, $placeArea, $readyChk, $revealBanner, $room, $roomId, $slotSelect, $startGame, $status, $timeline, $tokens } from './dom.js'; export function renderRoom(room) { state.room = room; if (!room) { $lobby.classList.remove('hidden'); $room.classList.add('hidden'); return; } try { localStorage.setItem('lastRoomId', room.id); } catch {} $lobby.classList.add('hidden'); $room.classList.remove('hidden'); $roomId.textContent = room.id; $status.textContent = room.state.status; $guesser.textContent = shortName(room.state.currentGuesser); const me = room.players.find(p=>p.id===state.playerId); if ($nameDisplay) $nameDisplay.textContent = (me?.name || localStorage.getItem('playerName') || '-'); if ($dashboardList) { $dashboardList.innerHTML = room.players.map(p => { const connected = p.connected ? 'online' : 'offline'; const ready = p.ready ? 'bereit' : '-'; const score = (room.state.timeline?.[p.id]?.length) ?? 0; const isMe = p.id === state.playerId; return `
${escapeHtml(p.name)}${p.spectator ? ' 👻' : ''} ${p.id===room.hostId ? '\u2B50' : ''} ${isMe ? '(du)' : ''}
${connected} ${ready} ${score} `; }).join(''); } const myTl = room.state.timeline?.[state.playerId] || []; $timeline.innerHTML = myTl.map(t => { const title = escapeHtml(t.title || t.trackId || 'Unbekannt'); const artist = t.artist ? escapeHtml(t.artist) : ''; const year = (t.year ?? '?'); const badgeStyle = badgeColorForYear(year); return `
${year}
${title}
${artist}
`; }).join(''); $tokens.textContent = room.state.tokens?.[state.playerId] ?? 0; if ($readyChk) { const serverReady = !!me?.ready; if (state.pendingReady === null || state.pendingReady === undefined) { $readyChk.checked = serverReady; } else { $readyChk.checked = !!state.pendingReady; if (serverReady === state.pendingReady) state.pendingReady = null; } $readyChk.parentElement.classList.toggle('hidden', room.state.status !== 'lobby'); } const isHost = state.playerId === room.hostId; const allReady = room.players.length>0 && room.players.every(p=>p.ready); if ($startGame) $startGame.classList.toggle('hidden', !(isHost && room.state.status==='lobby' && allReady)); const isMyTurn = room.state.status==='playing' && room.state.phase==='guess' && room.state.currentGuesser===state.playerId && room.state.currentTrack; const canGuess = isMyTurn; // Media controls (play/pause) only for current guesser while guessing and a track is active if ($mediaControls) $mediaControls.classList.toggle('hidden', !isMyTurn); // Build slot options for insertion positions when it's my turn if ($placeArea && $slotSelect) { if (canGuess) { const tl = room.state.timeline?.[state.playerId] || []; $slotSelect.innerHTML = ''; for (let i = 0; i <= tl.length; i++) { const left = i > 0 ? (tl[i - 1]?.year ?? '?') : null; const right = i < tl.length ? (tl[i]?.year ?? '?') : null; let label = ''; if (tl.length === 0) label = 'Einsetzen'; else if (i === 0) label = `Vor (${right})`; else if (i === tl.length) label = `Nach (${left})`; else label = `Zwischen (${left} / ${right})`; const opt = document.createElement('option'); opt.value = String(i); opt.textContent = label; $slotSelect.appendChild(opt); } } else { // Clear options when not guessing $slotSelect.innerHTML = ''; } $placeArea.classList.toggle('hidden', !canGuess); } $np.classList.toggle('hidden', !room.state.currentTrack); if ($revealBanner) { const inReveal = room.state.phase === 'reveal'; if (!inReveal) { $revealBanner.className = 'hidden'; $revealBanner.textContent=''; } } const canNext = room.state.status==='playing' && room.state.phase==='reveal' && (isHost || room.state.currentGuesser===state.playerId); if ($nextArea) $nextArea.classList.toggle('hidden', !canNext); // Answer form visible during guess phase while a track is active const showAnswer = room.state.status==='playing' && room.state.phase==='guess' && !!room.state.currentTrack; if ($answerForm) $answerForm.classList.toggle('hidden', !showAnswer); if ($answerResult && !showAnswer) { $answerResult.textContent=''; $answerResult.className='mt-1 text-sm'; } } export function shortName(id) { if (!id) return '-'; const p = state.room?.players.find(x=>x.id===id); return p ? p.name : id.slice(0,4); } export function escapeHtml(s) { return String(s).replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])); }