This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
<!doctype html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<title>Blind Test – Buzzer</title>
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
</head>
|
||||
<body class="buzzer-page">
|
||||
<!-- Saisie du nom -->
|
||||
<div id="joinView" class="card" hidden>
|
||||
<h2>Rejoindre la partie</h2>
|
||||
<div class="row">
|
||||
<input id="name" type="text" placeholder="Ton nom" maxlength="20" autocomplete="off">
|
||||
<button id="joinBtn" class="primary">Rejoindre</button>
|
||||
</div>
|
||||
<p id="joinError" class="error"></p>
|
||||
</div>
|
||||
|
||||
<!-- Buzzer -->
|
||||
<div id="playView" hidden style="display:none;flex-direction:column;align-items:center;gap:20px;width:100%">
|
||||
<div class="me"><span id="meName"></span><span id="meScore"></span></div>
|
||||
<button id="buzz" disabled>BUZZ</button>
|
||||
<div id="msg"></div>
|
||||
<ul id="board" class="board" style="width:100%;max-width:420px"></ul>
|
||||
</div>
|
||||
|
||||
<script src="/socket.io/socket.io.js"></script>
|
||||
<script>
|
||||
const $ = id => document.getElementById(id);
|
||||
const params = new URLSearchParams(location.search);
|
||||
const roomId = (params.get('room') || '').toUpperCase();
|
||||
const KEY = 'bt_player';
|
||||
let saved = JSON.parse(localStorage.getItem(KEY) || 'null') || {};
|
||||
if (saved.roomId !== roomId) saved = { name: saved.name || '' }; // autre room : on garde juste le nom
|
||||
let me = null;
|
||||
let state = { phase: 'lobby', players: [], buzzer: null, lockedOut: [] };
|
||||
const socket = io();
|
||||
|
||||
function showJoin(err) {
|
||||
$('joinView').hidden = false;
|
||||
$('playView').style.display = 'none';
|
||||
if (err) $('joinError').textContent = err;
|
||||
if (!$('name').value) $('name').value = saved.name || '';
|
||||
}
|
||||
function join(name, silent) {
|
||||
if (!roomId) return showJoin('Scanne le QR code affiché sur l\'écran principal.');
|
||||
socket.emit('player:join', { roomId, token: saved.token, name }, res => {
|
||||
if (res.error) {
|
||||
if (res.error === 'no_room') {
|
||||
if (silent && me) return setTimeout(() => join(name, true), 2000); // le serveur a peut-être redémarré
|
||||
return showJoin('Partie introuvable. Rescanne le QR code.');
|
||||
}
|
||||
if (res.error === 'name_taken') return showJoin('Ce nom est déjà pris.');
|
||||
return showJoin('Entre un nom.');
|
||||
}
|
||||
me = res;
|
||||
saved = { roomId, token: res.token, name: res.name };
|
||||
localStorage.setItem(KEY, JSON.stringify(saved));
|
||||
$('joinView').hidden = true;
|
||||
$('playView').style.display = 'flex';
|
||||
$('meName').textContent = res.name;
|
||||
render();
|
||||
});
|
||||
}
|
||||
socket.on('connect', () => {
|
||||
if (saved.token && saved.name) join(saved.name, true);
|
||||
else showJoin();
|
||||
});
|
||||
socket.on('state', s => { state = s; render(); });
|
||||
|
||||
function render() {
|
||||
if (!me) return;
|
||||
const mine = state.players.find(p => p.id === me.id);
|
||||
$('meScore').textContent = mine ? `${mine.score} pt${mine.score > 1 ? 's' : ''}` : '';
|
||||
const locked = state.lockedOut.includes(me.id);
|
||||
const buzz = $('buzz');
|
||||
let msg = '', enabled = false, label = 'BUZZ';
|
||||
switch (state.phase) {
|
||||
case 'lobby': msg = 'En attente du prochain morceau…'; label = '⏳'; break;
|
||||
case 'playing': if (locked) { msg = 'Bloqué pour ce morceau'; label = '🚫'; } else { enabled = true; msg = 'Buzze !'; } break;
|
||||
case 'buzzed': msg = state.buzzer && state.buzzer.id === me.id ? 'À toi de répondre !' : `${state.buzzer ? state.buzzer.name : ''} a buzzé`; label = '🔔'; break;
|
||||
case 'result': msg = state.buzzer ? `${state.buzzer.name} marque un point !` : ''; label = '✅'; break;
|
||||
case 'ended': msg = 'Partie terminée !'; label = '🏆'; break;
|
||||
}
|
||||
buzz.disabled = !enabled;
|
||||
buzz.textContent = label;
|
||||
$('msg').textContent = msg;
|
||||
|
||||
const board = $('board'); board.textContent = '';
|
||||
[...state.players].sort((a, b) => b.score - a.score || a.name.localeCompare(b.name)).forEach(p => {
|
||||
const li = document.createElement('li');
|
||||
const n = document.createElement('span'); n.className = 'name'; n.textContent = p.name;
|
||||
const s = document.createElement('span'); s.className = 'score'; s.textContent = p.score;
|
||||
li.append(n, s); board.appendChild(li);
|
||||
});
|
||||
}
|
||||
|
||||
$('buzz').addEventListener('pointerdown', e => {
|
||||
e.preventDefault();
|
||||
if ($('buzz').disabled) return;
|
||||
socket.emit('player:buzz');
|
||||
if (navigator.vibrate) navigator.vibrate(80);
|
||||
});
|
||||
$('joinBtn').addEventListener('click', () => { $('joinError').textContent = ''; join($('name').value, false); });
|
||||
$('name').addEventListener('keydown', e => { if (e.key === 'Enter') $('joinBtn').click(); });
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user