Commit ae2812a0 authored by Mahmoud Aglan's avatar Mahmoud Aglan

fix: repair game board layout, coordinates, and Arabic UX

- Remove duplicate static coord elements from game.php (board.js creates them dynamically)
- Force LTR direction on game-layout and board to prevent RTL interference
- Fix piece font-size for proper unicode rendering
- Translate all game UI text to Arabic (status, result, stats)
- Sync move list and status to both desktop and mobile panels
- Improve board colors and spacing
Co-Authored-By: 's avatarClaude Opus 4.6 <noreply@anthropic.com>
parent d5658b63
......@@ -35,19 +35,6 @@ $extraCss = '/public/css/chessboard.css';
<!-- Board -->
<div class="board-wrapper">
<div class="board" id="board"></div>
<!-- Coordinate labels -->
<div class="board-coords-file" id="coords-file">
<span>a</span><span>b</span><span>c</span><span>d</span>
<span>e</span><span>f</span><span>g</span><span>h</span>
</div>
<div class="board-coords-rank" id="coords-rank">
<span>8</span><span>7</span><span>6</span><span>5</span>
<span>4</span><span>3</span><span>2</span><span>1</span>
</div>
<!-- Arrow overlay -->
<div class="board-arrows" id="board-arrows">
<svg viewBox="0 0 800 800" preserveAspectRatio="xMidYMid meet"></svg>
</div>
</div>
</div>
......
This diff is collapsed.
......@@ -424,57 +424,61 @@ const Game = {
// --- Pro Move List ---
updateMoveList() {
const list = document.getElementById('move-list');
if (!list) return;
const lists = [document.getElementById('move-list'), document.getElementById('move-list-mobile')].filter(Boolean);
if (lists.length === 0) return;
list.innerHTML = '';
const history = this.chess.history();
for (let i = 0; i < history.length; i += 2) {
const pair = document.createElement('div');
pair.className = 'move-pair';
const num = document.createElement('span');
num.className = 'move-number';
num.textContent = (Math.floor(i / 2) + 1) + '.';
pair.appendChild(num);
const white = document.createElement('span');
white.className = 'move' + (i === this.currentMoveIndex ? ' current' : '');
white.textContent = history[i];
white.dataset.moveIndex = i;
white.onclick = () => this.jumpToMove(i);
pair.appendChild(white);
if (history[i + 1]) {
const black = document.createElement('span');
black.className = 'move' + (i + 1 === this.currentMoveIndex ? ' current' : '');
black.textContent = history[i + 1];
black.dataset.moveIndex = i + 1;
black.onclick = () => this.jumpToMove(i + 1);
pair.appendChild(black);
}
lists.forEach(list => {
list.innerHTML = '';
for (let i = 0; i < history.length; i += 2) {
const pair = document.createElement('div');
pair.className = 'move-pair';
const num = document.createElement('span');
num.className = 'move-number';
num.textContent = (Math.floor(i / 2) + 1) + '.';
pair.appendChild(num);
const moveIdx = i;
const white = document.createElement('span');
white.className = 'move' + (i === this.currentMoveIndex ? ' current' : '');
white.textContent = history[i];
white.dataset.moveIndex = i;
white.onclick = () => this.jumpToMove(moveIdx);
pair.appendChild(white);
if (history[i + 1]) {
const moveIdx2 = i + 1;
const black = document.createElement('span');
black.className = 'move' + (i + 1 === this.currentMoveIndex ? ' current' : '');
black.textContent = history[i + 1];
black.dataset.moveIndex = i + 1;
black.onclick = () => this.jumpToMove(moveIdx2);
pair.appendChild(black);
}
list.appendChild(pair);
}
list.appendChild(pair);
}
// Auto-scroll
list.scrollTop = list.scrollHeight;
list.scrollTop = list.scrollHeight;
});
// Show opening name
this.updateOpeningName(history);
},
updateOpeningName(history) {
const openingEl = document.getElementById('opening-name');
if (!openingEl) return;
const els = [
document.getElementById('opening-display'),
document.getElementById('opening-display-mobile')
].filter(Boolean);
if (history.length === 0) {
openingEl.textContent = '';
els.forEach(el => el.style.display = 'none');
return;
}
// Try progressively shorter sequences to find opening
let opening = '';
const maxCheck = Math.min(history.length, 12);
for (let len = maxCheck; len >= 1; len--) {
......@@ -485,7 +489,15 @@ const Game = {
}
}
openingEl.textContent = opening;
els.forEach(el => {
if (opening) {
el.style.display = 'flex';
const nameEl = el.querySelector('.opening-name');
if (nameEl) nameEl.textContent = opening;
} else {
el.style.display = 'none';
}
});
},
jumpToMove(index) {
......@@ -505,20 +517,25 @@ const Game = {
// --- Game Status ---
updateStatus() {
const status = document.getElementById('game-status');
if (!status) return;
const statusMobile = document.getElementById('game-status-mobile');
if (!status && !statusMobile) return;
let text = '';
if (this.chess.in_checkmate()) {
const winner = this.chess.turn() === 'w' ? 'b' : 'w';
status.textContent = winner === this.playerColor ? 'Checkmate - You win!' : 'Checkmate - You lose';
text = winner === this.playerColor ? 'كش مات - فزت!' : 'كش مات - خسرت';
} else if (this.chess.in_check()) {
status.textContent = 'Check!';
text = 'كش!';
} else if (this.chess.in_draw()) {
status.textContent = 'Draw';
text = 'تعادل';
} else if (this.chess.in_stalemate()) {
status.textContent = 'Stalemate';
text = 'جمود - تعادل';
} else {
status.textContent = this.chess.turn() === this.playerColor ? 'Your turn' : 'Opponent thinking...';
text = this.chess.turn() === this.playerColor ? 'دورك' : 'يفكر...';
}
if (status) status.textContent = text;
if (statusMobile) statusMobile.textContent = text;
},
showThinking(show) {
......@@ -536,26 +553,26 @@ const Game = {
let title, subtitle;
if (reason === 'timeout') {
title = winner === this.playerColor ? 'Win on time!' : 'Lost on time';
subtitle = 'Time ran out';
title = winner === this.playerColor ? 'فزت بالوقت!' : 'خسرت بالوقت';
subtitle = 'انتهى الوقت';
} else if (this.chess.in_checkmate()) {
const w = this.chess.turn() === 'w' ? 'b' : 'w';
title = w === this.playerColor ? 'You win!' : 'You lose';
subtitle = 'Checkmate';
title = w === this.playerColor ? 'فزت!' : 'خسرت';
subtitle = 'كش مات';
} else if (this.chess.in_stalemate()) {
title = 'Draw';
subtitle = 'Stalemate';
title = 'تعادل';
subtitle = 'جمود';
} else if (this.chess.in_draw()) {
title = 'Draw';
subtitle = 'Insufficient material';
title = 'تعادل';
subtitle = 'قطع غير كافية';
} else if (reason === 'resign') {
title = winner === this.playerColor ? 'You win!' : 'You lose';
subtitle = 'Resignation';
title = winner === this.playerColor ? 'فزت!' : 'خسرت';
subtitle = 'استسلام';
} else if (reason === 'draw') {
title = 'Draw';
subtitle = 'By agreement';
title = 'تعادل';
subtitle = 'باتفاق';
} else {
title = 'Game over';
title = 'انتهت المباراة';
subtitle = '';
}
......@@ -591,13 +608,13 @@ const Game = {
overlay.innerHTML = '<div class="game-result-title">' + title + '</div>' +
'<div class="game-result-subtitle">' + subtitle + '</div>' +
'<div class="game-result-stats">' +
'<div class="stat-row"><span>Moves</span><span>' + totalMoves + '</span></div>' +
'<div class="stat-row"><span>Avg move time</span><span>' + avgMoveTime + 's</span></div>' +
'<div class="stat-row"><span>Time used</span><span>' + totalTimeUsed + 's</span></div>' +
'<div class="stat-row"><span>النقلات</span><span>' + totalMoves + '</span></div>' +
'<div class="stat-row"><span>متوسط وقت النقلة</span><span>' + avgMoveTime + 's</span></div>' +
'<div class="stat-row"><span>اجمالي الوقت</span><span>' + totalTimeUsed + 's</span></div>' +
'</div>' +
'<div class="game-controls" style="margin-top:16px;">' +
'<button class="btn btn-cyan" id="btn-rematch-result">Rematch</button>' +
'<button class="btn btn-ghost" onclick="window.location.href=\'/play\'">Back</button>' +
'<button class="btn btn-cyan" id="btn-rematch-result">اعادة</button>' +
'<button class="btn btn-ghost" onclick="window.location.href=\'/play\'">رجوع</button>' +
'</div>';
wrapper.appendChild(overlay);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment