131 lines
7.3 KiB
HTML
131 lines
7.3 KiB
HTML
<!doctype html>
|
||
<html lang="fr">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||
<title>ChessNut 1 Partie</title>
|
||
<link rel="stylesheet" href="src/styles.css">
|
||
<style>
|
||
/* Minimal board CSS: keep responsive wrapper but delegate main layout to linked stylesheet */
|
||
.game-page{max-width:1000px;margin:12px auto;padding:8px}
|
||
#board-wrapper{width:100%;max-width:900px;margin:0 auto}
|
||
/* keep a wrapper that forces a square area; the actual .board/.cell layout lives in src/styles.css */
|
||
#board-wrapper .board{width:100%;aspect-ratio:1/1;box-sizing:border-box}
|
||
.cell .piece{width:100%;height:100%;object-fit:contain;display:block}
|
||
.cell.selected{outline:3px solid rgba(0,128,255,0.6);}
|
||
/* grid cells will be created dynamically via JS using grid-template */
|
||
/* checkerboard colors handled by .cell.light/.cell.dark in src/styles.css */
|
||
#meta{margin-top:8px}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
<div class="game-page">
|
||
<header><h1>Partie</h1></header>
|
||
<div id="meta">Chargement...</div>
|
||
<div id="player-color" style="margin-top:6px;font-weight:600">Couleur: —</div>
|
||
<div id="players-panel" style="margin-top:8px;font-size:14px">
|
||
<strong>Joueurs:</strong>
|
||
<ul id="players-list" style="list-style:none;padding-left:0;margin-top:6px"></ul>
|
||
</div>
|
||
<div id="server-load-indicator" style="margin-top:6px;color:#666">Chargement de l'état du serveur...</div>
|
||
<div id="board-wrapper"><div id="board-container"></div></div>
|
||
<div style="margin-top:8px">
|
||
</div>
|
||
</div>
|
||
|
||
<script src="https://cdn.socket.io/4.5.4/socket.io.min.js"></script>
|
||
<script src="src/game.js?v=4"></script>
|
||
<script>
|
||
// small bootstrap: fetch initial game state and wire socket updates
|
||
(function(){
|
||
const qs = new URLSearchParams(window.location.search);
|
||
const gid = qs.get('game');
|
||
const meta = document.getElementById('meta');
|
||
if(!gid){ meta.textContent = 'Game ID manquant'; return; }
|
||
meta.textContent = 'Affichage du plateau...';
|
||
// render an empty board immediately so user always sees a board even if backend is slow/unavailable
|
||
try { if(typeof renderBoardFromState === 'function') renderBoardFromState(null); } catch(e){ console.warn('initial empty board render failed', e); }
|
||
// fetch initial state: prefer explicit backend host then fallback to same-origin
|
||
(function(){
|
||
function handleGameObj(g){
|
||
// set globals expected by src/game.js so socket handlers attach correctly
|
||
try {
|
||
currentGameId = gid;
|
||
// prefer a session-scoped stored player id for this game (persisted at join/create)
|
||
try{
|
||
// support multiple possible sessionStorage key formats used across the app
|
||
const candidateKeys = [
|
||
'chessnut:game:' + gid + ':playerId', // older/other modules
|
||
'playerId:' + gid // newer lightweight key used elsewhere
|
||
];
|
||
let stored = null;
|
||
for (const k of candidateKeys) {
|
||
stored = sessionStorage.getItem(k);
|
||
if (stored) { myPlayerId = stored; break; }
|
||
}
|
||
// if still not found, fall back to first player from server and persist under both keys
|
||
if (!stored && g && g.players && g.players[0]) {
|
||
myPlayerId = g.players[0].id;
|
||
try{
|
||
sessionStorage.setItem('chessnut:game:' + gid + ':playerId', myPlayerId);
|
||
sessionStorage.setItem('playerId:' + gid, myPlayerId);
|
||
}catch(e){}
|
||
}
|
||
}catch(e){}
|
||
// remember the last received game object and compute this client's assigned color (if any)
|
||
window.lastGameObj = g;
|
||
if (g && g.players && myPlayerId) {
|
||
const me = g.players.find(p => p.id === myPlayerId);
|
||
window.myColor = me && me.colorAssigned ? me.colorAssigned : null;
|
||
const pc = document.getElementById('player-color'); if(pc) pc.textContent = 'Couleur: ' + (window.myColor || 'non assignée');
|
||
}
|
||
// render board from state or empty board (after computing myColor so render can honor orientation)
|
||
if(g && g.state && typeof renderBoardFromState === 'function') renderBoardFromState(g.state);
|
||
else if(typeof renderBoardFromState === 'function') renderBoardFromState(null);
|
||
const sli = document.getElementById('server-load-indicator'); if(sli) sli.style.display = 'none';
|
||
|
||
if(typeof socket === 'undefined' || !socket){
|
||
socket = io();
|
||
socket.on('connect', () => { socket.emit('join-game', gid); socket.emit('identify', { gameId: gid, playerId: myPlayerId }); });
|
||
socket.on('game-state', (s) => { if(typeof renderBoardFromState === 'function') renderBoardFromState(s); if(typeof setMeta === 'function') setMeta('game-state updated'); });
|
||
socket.on('move', (m) => { if(typeof setMeta === 'function') setMeta('remote move ' + JSON.stringify(m)); });
|
||
socket.on('player-update', (g) => {
|
||
// update local cached game object, render players list and recompute myColor when players list changes
|
||
try{
|
||
window.lastGameObj = g;
|
||
if (g) { try{ renderPlayersList(g); }catch(e){} }
|
||
if (g && g.players && myPlayerId) {
|
||
const me = g.players.find(p => p.id === myPlayerId);
|
||
window.myColor = me && me.colorAssigned ? me.colorAssigned : window.myColor;
|
||
const pc = document.getElementById('player-color'); if(pc) pc.textContent = 'Couleur: ' + (window.myColor || 'non assignée');
|
||
}
|
||
// re-render board to apply orientation change if colorAssigned arrived late
|
||
if (typeof renderBoardFromState === 'function' && g && g.state) renderBoardFromState(g.state);
|
||
}catch(e){}
|
||
if(typeof setMeta === 'function') setMeta('players updated');
|
||
});
|
||
}
|
||
// ensure players list is rendered on initial load
|
||
try{ if(window.lastGameObj) renderPlayersList(window.lastGameObj); }catch(e){}
|
||
} catch(e){ console.warn('socket init failed', e); }
|
||
}
|
||
|
||
fetch('http://localhost:4000/api/game/' + gid).then(r => r.ok ? r.json() : null).then(g => {
|
||
if(g) { handleGameObj(g); }
|
||
else {
|
||
// try same-origin
|
||
fetch('/api/game/' + gid).then(r => r.ok ? r.json() : null).then(handleGameObj).catch(()=>{ handleGameObj(null); const sli = document.getElementById('server-load-indicator'); if(sli) sli.textContent = 'Serveur injoignable'; });
|
||
}
|
||
}).catch(()=>{
|
||
fetch('/api/game/' + gid).then(r => r.ok ? r.json() : null).then(handleGameObj).catch(()=>{ handleGameObj(null); const sli = document.getElementById('server-load-indicator'); if(sli) sli.textContent = 'Serveur injoignable'; });
|
||
});
|
||
})();
|
||
|
||
const leaveBtn = document.getElementById('leave');
|
||
if (leaveBtn) {
|
||
leaveBtn.addEventListener('click', ()=>{ window.location.href = 'waiting.html?game=' + encodeURIComponent(gid); });
|
||
}
|
||
})();
|
||
</script>
|
||
</body>
|
||
</html>
|