diff --git a/src/main/resources/public/game.html b/src/main/resources/public/game.html index e27eafc..5bbcb54 100644 --- a/src/main/resources/public/game.html +++ b/src/main/resources/public/game.html @@ -1,162 +1,229 @@ - - + + Spotify Roulette – Spiel + + + + + + -
-

Spotify Roulette

-
Spiel-Code:
-
-
-
-
Teilnehmer
- -
-
- -
- -
-
Scoreboard
- -
-
- + + + + - + + +
+ + + - diff --git a/src/main/resources/public/js/game.js b/src/main/resources/public/js/game.js index a9e7505..077007d 100644 --- a/src/main/resources/public/js/game.js +++ b/src/main/resources/public/js/game.js @@ -6,17 +6,31 @@ import { setupStartRound } from "./start-round.js"; const gameId = getParam("gameId"); const username = getParam("username"); +// --- kleine Helper --- +function showToast(msg, ms = 2200) { + const t = document.getElementById("toast"); + if (!t) return; + t.textContent = msg; + t.classList.add("show"); + setTimeout(() => t.classList.remove("show"), ms); +} +function esc(s) { + const d = document.createElement("div"); + d.textContent = String(s ?? ""); + return d.innerHTML; +} + // 1) Parameter prüfen if (!gameId || !username) { alert("Ungültige oder fehlende URL-Parameter!"); throw new Error("Missing gameId or username"); } -// 2) Copy to clipboard (unverändert) +// 2) Copy to clipboard (unverändert, aber mit Toast) (function copyCodeToClipboard(code) { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(code) - .then(() => console.log(`GameCode ${code} copied to clipboard`)) + .then(() => showToast(`Spiel-Code ${code} kopiert`)) .catch(err => console.error("Clipboard write failed:", err)); } else { const ta = document.createElement("textarea"); @@ -28,7 +42,7 @@ if (!gameId || !username) { ta.select(); try { document.execCommand("copy"); - console.log(`GameCode ${code} copied via execCommand`); + showToast(`Spiel-Code ${code} kopiert`); } catch (err) { console.error("Fallback copy failed:", err); } @@ -36,16 +50,14 @@ if (!gameId || !username) { } })(gameId); -// 3) Visuelles Feedback (unverändert) -const notice = document.createElement("div"); -notice.textContent = `Spiel-Code ${gameId} in die Zwischenablage kopiert!`; -Object.assign(notice.style, { /* … Styles … */ }); -document.body.append(notice); -setTimeout(() => notice.remove(), 3000); - -// 4) Spiel-Code ins DOM schreiben +// 3) Spiel-Code ins DOM schreiben document.getElementById("gameId").textContent = gameId; +// 4) Drawer toggles für Songliste +const drawer = document.getElementById("songDrawer"); +document.getElementById("toggleSongList")?.addEventListener("click", () => drawer?.classList.add("open")); +document.getElementById("closeDrawer")?.addEventListener("click", () => drawer?.classList.remove("open")); + // 5) WebSocket mit Reconnect-Logik let socket; function connectWebSocket() { @@ -57,7 +69,7 @@ function connectWebSocket() { socket.addEventListener("open", () => { console.log("WebSocket connected. Requesting player list..."); socket.send(JSON.stringify({ type: "requestPlayers" })); - setupStartRound(socket); + setupStartRound(socket); // deaktiviert den Start-Button beim Klicken }); socket.addEventListener("message", async ({ data }) => { @@ -66,7 +78,6 @@ function connectWebSocket() { switch (msg.type) { case "players": - console.log("Empfangene Spieler:", msg.players); renderList("#playersList", msg.players, username); break; case "reload": @@ -106,13 +117,9 @@ const optionsDiv = document.getElementById("options"); const resultP = document.getElementById("result"); const scoreboard = document.getElementById("scoreboard"); -// 8) Funktion zum Anzeigen einer neuen Runde -//let playLock = false; - -async function handleRoundStart({ownerOptions, songUri, allTracks, trackInfos}) { +// 6) Neue Runde anzeigen +async function handleRoundStart({ ownerOptions, songUri, trackInfos }) { // UI zurücksetzen - //if (playLock) return; // Verhindert parallele Ausführung - //playLock = true; resultP.textContent = ""; optionsDiv.innerHTML = ""; songEmbed.innerHTML = ""; @@ -120,32 +127,32 @@ async function handleRoundStart({ownerOptions, songUri, allTracks, trackInfos}) // Song einbetten const trackId = songUri.split(":")[2]; songEmbed.innerHTML = ` - `; + `; + // Spotify-Playback (optional, wenn vorhanden) if (window.playOnSpotify && typeof window.playOnSpotify === "function") { - await window.playOnSpotify(songUri, username); // Warten bis fertig + await window.playOnSpotify(songUri, username); } - //if (window.playOnSpotify && typeof window.playOnSpotify === "function") { - // window.playOnSpotify(songUri, username); - //} - - // Dynamische Kreisverteilung der Buttons - // Warten, bis #options gerendert ist - setTimeout(() => { + // Buttons kreisförmig verteilen + requestAnimationFrame(() => { const optsRect = optionsDiv.getBoundingClientRect(); - const radius = Math.min(optsRect.width, optsRect.height) / 2 - 50; // 50px Abstand zum Rand - + const radius = Math.min(optsRect.width, optsRect.height) / 2 - 40; // Abstand zum Rand ownerOptions.forEach((user, i) => { const btn = document.createElement("button"); btn.textContent = user; btn.classList.add("player-option"); - const angle = 360 * i / ownerOptions.length; - btn.style.transform = `rotate(${angle}deg) translateY(-${radius}px) rotate(${-angle}deg)`; + //const angle = 360 * i / ownerOptions.length; + //btn.style.transform = `rotate(${angle}deg) translateY(-${radius}px) rotate(${-angle}deg)`; + + const angle = (360 / ownerOptions.length) * i; + // zentrieren -> dann drehen -> nach außen schieben -> Text aufrecht drehen + btn.style.transform = `translate(-50%, -50%) rotate(${angle}deg) translate(0, -${radius}px) rotate(${-angle}deg)`; + btn.addEventListener("click", () => { socket.send(JSON.stringify({ type: "guess", @@ -156,24 +163,42 @@ async function handleRoundStart({ownerOptions, songUri, allTracks, trackInfos}) }); optionsDiv.appendChild(btn); }); - }, 0); - - startBtn.hidden = true; - roundArea.hidden = false; - - const songList = document.getElementById("songList"); - songList.innerHTML = ""; - //trackinfos ist eine map bestehend aus aus Spielername und Liste von Track-Infos - const userTracks = trackInfos?.[username] ?? []; - userTracks.forEach(trackInfo => { - const li = document.createElement("li"); - li.textContent = trackInfo; - songList.appendChild(li); }); - //playLock = false; + + // Start-Button ausblenden + Rundensektion einblenden + startBtn.hidden = true; + startBtn.disabled = true; + roundArea.hidden = false; + + // Geladene Songs (beide Orte befüllen: Aside + Drawer) + const songList = document.getElementById("songList"); + const songListArea = document.getElementById("songListArea"); + const userTracks = trackInfos?.[username] ?? []; + + if (songList) { + songList.innerHTML = ""; + userTracks.forEach(t => { + const li = document.createElement("li"); + li.textContent = t; + songList.appendChild(li); + }); + } + if (songListArea) { + songListArea.innerHTML = ""; + userTracks.forEach(t => { + // Erwartetes Format "Titel - Künstler" + const [title, artists] = String(t).split(" - "); + const row = document.createElement("div"); + row.className = "track"; + row.innerHTML = ` +
+
${esc(title ?? t)}${esc(artists ?? "")}
`; + songListArea.appendChild(row); + }); + } } -// 9) Funktion zum Anzeigen des Ergebnisses +// 7) Ergebnis + Weiter-Button function renderScoreboard(scores) { scoreboard.innerHTML = ""; Object.entries(scores).forEach(([user, pts]) => { @@ -191,9 +216,8 @@ function handleRoundResult({ scores, guesses, owner }) { const correct = guess === owner; const icon = correct ? "✅" : "❌"; const delta = correct ? "+3" : "-1"; - const msg = `${icon} ${user} hat auf ${guess} getippt${correct ? " (richtig!)" : " (falsch)"} [${delta}]`; - const p = document.createElement("p"); - p.textContent = msg; + const p = document.createElement("p"); + p.textContent = `${icon} ${user} hat auf ${guess} getippt${correct ? " (richtig!)" : " (falsch)"} [${delta}]`; resultP.appendChild(p); }); @@ -205,24 +229,24 @@ function handleRoundResult({ scores, guesses, owner }) { nextBtn.hidden = true; nextBtn.disabled = true; resultP.textContent = ""; - startBtn.hidden = true; + startBtn.hidden = true; startBtn.disabled = true; - roundArea.hidden = true; + roundArea.hidden = true; }; } -function handleGameEnd({winner}) { +// 8) Spielende -> Start-Button zurück +function handleGameEnd({ winner }) { resultP.textContent = `🎉 ${winner} hat gewonnen!`; setTimeout(() => { startBtn.hidden = false; - roundArea.hidden = true; startBtn.disabled = false; + roundArea.hidden = true; scoreboard.innerHTML = ""; }, 6000); } -// Spotify-Playback Funktion -// game.js +// Spotify-Playback Funktion (unverändert) async function playOnSpotify(trackUri, username) { const deviceId = document.getElementById("deviceSelect")?.value; if (!deviceId) { @@ -244,3 +268,5 @@ async function playOnSpotify(trackUri, username) { } } window.playOnSpotify = playOnSpotify; + +