This commit is contained in:
Pavel Flegr 2026-05-07 19:10:23 +02:00
commit ff5d6ab91d
7 changed files with 388 additions and 84 deletions

View file

@ -136,6 +136,73 @@
background: rgba(255,255,255,.15);
}
.lobby-list-wrap {
margin-top: 16px;
text-align: left;
}
.lobby-list-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 8px;
}
.lobby-list-title {
font-size: .72rem;
letter-spacing: 1px;
text-transform: uppercase;
color: rgba(255,255,255,.55);
}
.btn-refresh-lobbies {
background: rgba(255,255,255,.1);
border: 1px solid rgba(255,255,255,.18);
color: rgba(255,255,255,.85);
border-radius: 8px;
padding: 5px 9px;
font-size: .72rem;
cursor: pointer;
}
.btn-refresh-lobbies:hover { background: rgba(255,255,255,.18); }
#lobby-list {
display: flex;
flex-direction: column;
gap: 8px;
max-height: 210px;
overflow-y: auto;
padding-right: 2px;
}
.lobby-item {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
background: rgba(255,255,255,.06);
border: 1px solid rgba(255,255,255,.12);
border-radius: 10px;
padding: 10px 12px;
}
.lobby-id { font-family: ui-monospace, Menlo, Consolas, monospace; color: var(--gold); font-size: .86rem; }
.lobby-meta { font-size: .72rem; color: rgba(255,255,255,.6); margin-top: 2px; }
.btn-join-lobby {
background: var(--gold);
color: #1a1a1a;
border: none;
border-radius: 8px;
padding: 7px 10px;
font-size: .78rem;
font-weight: 700;
cursor: pointer;
}
.btn-join-lobby:hover { opacity: .9; }
.lobby-empty {
font-size: .78rem;
color: rgba(255,255,255,.55);
background: rgba(255,255,255,.04);
border: 1px dashed rgba(255,255,255,.15);
border-radius: 10px;
padding: 12px;
text-align: center;
}
/* ══════════════════════════════
TABLE LAYOUT
══════════════════════════════ */
@ -957,6 +1024,14 @@
<div class="invite-id" id="invite-id-text" onclick="copyCode()" title="Klikni pro zkopírování"></div>
<div class="invite-hint">Klikni na kód pro zkopírování · Čekáme na další hráče…</div>
</div>
<div class="lobby-list-wrap">
<div class="lobby-list-head">
<div class="lobby-list-title">Veřejné lobby</div>
<button class="btn-refresh-lobbies" onclick="loadLobbies()">Obnovit</button>
</div>
<div id="lobby-list"></div>
</div>
</div>
</div>
@ -1128,6 +1203,7 @@ let restartFallbackTimer = null;
let joinPending = false;
let tableVisible = false;
let currentScriptOpen = false;
let lobbyPollTimer = null;
const SUIT_ICONS = { hearts:'♥', diamonds:'♦', spades:'♠', clubs:'♣' };
const SUIT_NAMES = { hearts:'Srdce', diamonds:'Kára', spades:'Piky', clubs:'Kříže' };
@ -1206,12 +1282,21 @@ function joinExisting() {
sendJoin();
}
function joinLobby(id) {
myName = document.getElementById('player-name').value.trim() || 'Hráč';
gameId = String(id || '').toLowerCase();
if (!gameId) return;
document.getElementById('game-id-input').value = gameId.toUpperCase();
sendJoin();
}
function sendJoin() {
joinPending = true;
ws.send(JSON.stringify({ type:'join', player_id:myId, player_name:myName, game_id:gameId }));
}
function switchToTable() {
stopLobbyPolling();
document.getElementById('lobby').style.display = 'none';
document.getElementById('table').style.display = 'flex';
document.getElementById('topbar-id').textContent = gameId.toUpperCase();
@ -1222,6 +1307,50 @@ function copyCode() {
navigator.clipboard.writeText(gameId.toUpperCase()).then(() => toast('Kód zkopírován: ' + gameId.toUpperCase()));
}
async function loadLobbies() {
const list = document.getElementById('lobby-list');
if (!list) return;
try {
const resp = await fetch('/api/lobbies');
if (!resp.ok) throw new Error(resp.statusText);
const data = await resp.json();
const lobbies = data.lobbies || [];
if (lobbies.length === 0) {
list.innerHTML = `<div class="lobby-empty">Zatím žádné čekající hry</div>`;
return;
}
list.innerHTML = lobbies.map((l) => {
const players = (l.players || []).map(escHtml).join(', ');
const rules = l.has_rules ? ' · vlastní pravidla' : '';
const safeID = escHtml(String(l.game_id || '').toUpperCase());
const onclickID = String(l.game_id || '').replace(/'/g, "\\'");
return `
<div class="lobby-item">
<div>
<div class="lobby-id">${safeID}</div>
<div class="lobby-meta">${l.player_count || 0}/4 hráči${rules}${players ? ` · ${players}` : ''}</div>
</div>
<button class="btn-join-lobby" onclick="joinLobby('${onclickID}')">Připojit</button>
</div>
`;
}).join('');
} catch (err) {
list.innerHTML = `<div class="lobby-empty">Nelze načíst lobby (${escHtml(err.message)})</div>`;
}
}
function startLobbyPolling() {
stopLobbyPolling();
loadLobbies();
lobbyPollTimer = setInterval(loadLobbies, 5000);
}
function stopLobbyPolling() {
if (!lobbyPollTimer) return;
clearInterval(lobbyPollTimer);
lobbyPollTimer = null;
}
// ── Game actions ───────────────────────────────────────────────────────
function startGame() {
ws.send(JSON.stringify({ type:'start', game_id:gameId }));
@ -1836,7 +1965,11 @@ function highlight(code) {
function checkUrlJoin() {
const params = new URLSearchParams(location.search);
const code = params.get('game');
if (code) document.getElementById('game-id-input').value = code.toLowerCase();
if (code) {
document.getElementById('game-id-input').value = code.toLowerCase();
} else {
startLobbyPolling();
}
}
connect();