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'; ...@@ -35,19 +35,6 @@ $extraCss = '/public/css/chessboard.css';
<!-- Board --> <!-- Board -->
<div class="board-wrapper"> <div class="board-wrapper">
<div class="board" id="board"></div> <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>
</div> </div>
......
/* Chess Board Styles */ /* Chess Board Styles - EL3AB Pro */
.game-container { /* ============================================
GAME LAYOUT
============================================ */
.game-layout {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 12px; gap: 0;
max-width: 100%; max-width: 100%;
direction: ltr;
}
.game-board-column {
display: flex;
flex-direction: column;
gap: 0;
align-items: center;
} }
/* Player info + clock rows */
.game-header { .game-header {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding: 12px 16px; padding: 10px 14px;
background: var(--bg-2); background: var(--bg-2);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
width: 100%;
max-width: 560px;
direction: rtl;
} }
.game-player { .game-player {
...@@ -36,13 +52,14 @@ ...@@ -36,13 +52,14 @@
.game-clock { .game-clock {
font-family: var(--font-en); font-family: var(--font-en);
font-size: 18px; font-size: 20px;
font-weight: 700; font-weight: 700;
padding: 6px 12px; padding: 8px 14px;
background: var(--bg-3); background: var(--bg-3);
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
min-width: 70px; min-width: 80px;
text-align: center; text-align: center;
direction: ltr;
} }
.game-clock.active { .game-clock.active {
...@@ -60,13 +77,25 @@ ...@@ -60,13 +77,25 @@
50% { opacity: 0.7; } 50% { opacity: 0.7; }
} }
/* Board */ /* ============================================
BOARD
============================================ */
.game-board-section {
display: flex;
gap: 6px;
align-items: stretch;
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.board-wrapper { .board-wrapper {
position: relative; position: relative;
width: 100%; width: 100%;
max-width: 560px;
margin: 0 auto;
aspect-ratio: 1; aspect-ratio: 1;
direction: ltr;
margin: 4px 0;
} }
.board { .board {
...@@ -80,6 +109,7 @@ ...@@ -80,6 +109,7 @@
overflow: hidden; overflow: hidden;
user-select: none; user-select: none;
touch-action: none; touch-action: none;
direction: ltr;
} }
.square { .square {
...@@ -91,17 +121,17 @@ ...@@ -91,17 +121,17 @@
transition: background 0.1s; transition: background 0.1s;
} }
.square-light { background: #B7C0D8; } .square-light { background: #E8EDF9; }
.square-dark { background: #5A7BAE; } .square-dark { background: #7195D1; }
.square.selected { background: rgba(21, 215, 255, 0.4) !important; } .square.selected { background: rgba(21, 215, 255, 0.45) !important; }
.square.legal-move::after { .square.legal-move::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 28%; width: 30%;
height: 28%; height: 30%;
border-radius: 50%; border-radius: 50%;
background: rgba(0, 0, 0, 0.2); background: rgba(0, 0, 0, 0.18);
} }
.square.legal-capture::after { .square.legal-capture::after {
content: ''; content: '';
...@@ -109,30 +139,30 @@ ...@@ -109,30 +139,30 @@
width: 85%; width: 85%;
height: 85%; height: 85%;
border-radius: 50%; border-radius: 50%;
border: 3px solid rgba(0, 0, 0, 0.2); border: 3.5px solid rgba(0, 0, 0, 0.18);
background: transparent; background: transparent;
} }
.square.last-move { background: rgba(231, 168, 50, 0.3) !important; } .square.last-move { background: rgba(255, 199, 40, 0.35) !important; }
.square.in-check { background: rgba(239, 68, 68, 0.5) !important; } .square.in-check { background: rgba(239, 68, 68, 0.55) !important; box-shadow: inset 0 0 8px rgba(239,68,68,0.6); }
.square.premove-from { background: rgba(21, 180, 240, 0.35) !important; } .square.premove-from { background: rgba(21, 180, 240, 0.3) !important; }
.square.premove-to { background: rgba(21, 180, 240, 0.35) !important; } .square.premove-to { background: rgba(21, 180, 240, 0.3) !important; }
.square.highlight-green { background: rgba(21, 180, 90, 0.45) !important; } .square.highlight-green { background: rgba(21, 180, 90, 0.4) !important; }
.square.highlight-red { background: rgba(220, 50, 50, 0.45) !important; } .square.highlight-red { background: rgba(220, 50, 50, 0.4) !important; }
.square.highlight-yellow { background: rgba(220, 180, 30, 0.45) !important; } .square.highlight-yellow { background: rgba(220, 180, 30, 0.4) !important; }
/* Pieces */ /* Pieces */
.piece { .piece {
width: 85%; width: 100%;
height: 85%; height: 100%;
font-size: calc(min(10vw, 56px)); font-size: min(11vw, 58px);
line-height: 1; line-height: 1;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
cursor: grab; cursor: grab;
z-index: 1; z-index: 1;
transition: transform 0.15s ease;
user-select: none; user-select: none;
text-shadow: 0 1px 3px rgba(0,0,0,0.3);
} }
.piece:active { cursor: grabbing; } .piece:active { cursor: grabbing; }
...@@ -140,7 +170,8 @@ ...@@ -140,7 +170,8 @@
position: fixed; position: fixed;
z-index: 100; z-index: 100;
pointer-events: none; pointer-events: none;
transform: scale(1.1); transform: scale(1.15);
filter: drop-shadow(0 4px 8px rgba(0,0,0,0.4));
} }
/* Coordinate labels */ /* Coordinate labels */
...@@ -149,75 +180,271 @@ ...@@ -149,75 +180,271 @@
display: flex; display: flex;
font-family: var(--font-en); font-family: var(--font-en);
font-size: 10px; font-size: 10px;
font-weight: 600; font-weight: 700;
color: var(--text-3); color: var(--text-3);
pointer-events: none; pointer-events: none;
opacity: 0.7;
} }
.board-coords-file { .board-coords-file {
bottom: -20px; bottom: 2px;
left: 0; left: 0;
right: 0; right: 0;
justify-content: space-around; justify-content: space-around;
padding: 0 4%; padding: 0 2%;
}
.board-coords-file span {
width: 12.5%;
text-align: center;
} }
.board-coords-rank { .board-coords-rank {
top: 0; top: 0;
bottom: 0; bottom: 0;
right: -20px; left: 2px;
flex-direction: column; flex-direction: column;
justify-content: space-around; justify-content: space-around;
align-items: flex-start;
padding: 1% 0;
}
.board-coords-rank span {
height: 12.5%;
display: flex;
align-items: center; align-items: center;
padding: 2% 0;
} }
/* Move list */ /* Arrow Canvas */
.move-list { .arrow-canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
pointer-events: none;
z-index: 5;
}
/* Eval Bar */
.eval-bar {
width: 22px;
min-width: 22px;
background: #333;
border-radius: var(--radius-sm);
overflow: hidden;
position: relative;
border: 1px solid var(--border);
flex-shrink: 0;
}
.eval-bar-fill {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #fff;
transition: height 0.5s ease;
height: 50%;
}
.eval-bar-label {
position: absolute;
left: 0;
right: 0;
text-align: center;
font-family: var(--font-en);
font-size: 8px;
font-weight: 700;
pointer-events: none;
z-index: 1;
}
.eval-bar-label-top { top: 3px; color: #fff; }
.eval-bar-label-bottom { bottom: 3px; color: #333; }
/* ============================================
SIDE PANEL
============================================ */
.game-side-panel {
display: none;
flex-direction: column;
width: 260px;
min-width: 240px;
}
.analysis-panel {
background: var(--bg-2); background: var(--bg-2);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
padding: 12px; display: flex;
max-height: 200px; flex-direction: column;
overflow: hidden;
height: 100%;
}
/* Opening Display */
.opening-display {
padding: 8px 12px;
border-bottom: 1px solid var(--border);
font-size: 12px;
color: var(--text-2);
display: flex;
align-items: center;
gap: 6px;
direction: ltr;
}
.opening-eco {
font-family: var(--font-en);
font-weight: 700;
color: var(--cyan);
font-size: 11px;
}
.opening-name {
font-weight: 500;
font-family: var(--font-en);
}
/* Pro Move List */
.move-list-pro {
flex: 1;
overflow-y: auto; overflow-y: auto;
font-family: var(--font-en); font-family: var(--font-en);
font-size: 13px; font-size: 13px;
direction: ltr; direction: ltr;
text-align: left;
padding: 6px 0;
min-height: 80px;
max-height: 300px;
} }
.move-pair { .move-list-pro .move-pair {
display: flex; display: flex;
align-items: center;
padding: 4px 12px;
gap: 4px; gap: 4px;
padding: 2px 0;
} }
.move-number { .move-list-pro .move-pair:nth-child(odd) {
background: rgba(255,255,255,0.03);
}
.move-list-pro .move-number {
color: var(--text-3); color: var(--text-3);
min-width: 28px; min-width: 28px;
font-size: 12px;
} }
.move { .move-list-pro .move {
padding: 2px 6px; padding: 3px 8px;
border-radius: 4px; border-radius: 4px;
cursor: pointer; cursor: pointer;
min-width: 50px;
text-align: center;
font-weight: 500;
}
.move-list-pro .move:hover {
background: rgba(255,255,255,0.08);
}
.move-list-pro .move.current {
background: var(--cyan);
color: var(--text-inverse);
} }
.move:hover { background: var(--bg-3); } /* Game Status */
.move.current { background: var(--cyan); color: var(--text-inverse); } .panel-status {
padding: 10px 14px;
border-top: 1px solid var(--border);
font-size: 13px;
text-align: center;
color: var(--text-2);
direction: rtl;
}
/* Game controls */ /* Panel Controls Row */
.game-controls { .panel-controls {
display: flex; display: flex;
gap: 8px; gap: 6px;
justify-content: center; padding: 10px 12px;
border-top: 1px solid var(--border);
direction: rtl;
}
.panel-controls .btn {
flex: 1;
font-size: 12px;
padding: 8px 6px;
min-width: 0;
}
/* Post-game Controls */
.postgame-controls {
display: flex;
gap: 6px;
padding: 10px 12px;
border-top: 1px solid var(--border);
flex-wrap: wrap;
} }
.game-controls .btn { .postgame-controls .btn {
flex: 1; flex: 1;
max-width: 160px; min-width: 0;
font-size: 12px;
padding: 8px 6px;
}
/* ============================================
THINKING INDICATOR
============================================ */
.thinking {
display: flex;
align-items: center;
gap: 8px;
padding: 6px 14px;
font-size: 12px;
color: var(--text-2);
direction: rtl;
max-width: 560px;
width: 100%;
}
.thinking-dots span {
display: inline-block;
width: 5px;
height: 5px;
border-radius: 50%;
background: var(--cyan);
animation: thinking-bounce 1.4s infinite;
margin: 0 2px;
}
.thinking-dots span:nth-child(2) { animation-delay: 0.2s; }
.thinking-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes thinking-bounce {
0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
40% { transform: translateY(-5px); opacity: 1; }
}
/* Pre-move indicator */
.premove-indicator {
font-size: 11px;
color: var(--cyan);
padding: 4px 14px;
max-width: 560px;
width: 100%;
direction: rtl;
} }
/* Game result overlay */ /* ============================================
GAME RESULT OVERLAY
============================================ */
.game-result { .game-result {
position: absolute; position: absolute;
inset: 0; inset: 0;
...@@ -225,19 +452,21 @@ ...@@ -225,19 +452,21 @@
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: rgba(5, 13, 23, 0.9); background: rgba(5, 13, 23, 0.92);
z-index: 10; z-index: 10;
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
gap: 12px; gap: 12px;
direction: ltr;
} }
.game-result-title { .game-result-title {
font-size: 24px; font-size: 22px;
font-weight: 700; font-weight: 700;
color: #fff;
} }
.game-result-subtitle { .game-result-subtitle {
font-size: 14px; font-size: 13px;
color: var(--text-2); color: var(--text-2);
} }
...@@ -260,41 +489,13 @@ ...@@ -260,41 +489,13 @@
.game-result-stats .stat-row span:last-child { .game-result-stats .stat-row span:last-child {
font-weight: 600; font-weight: 600;
color: var(--text-1, #fff); color: #fff;
}
/* Thinking indicator */
.thinking {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: var(--bg-2);
border: 1px solid var(--border);
border-radius: var(--radius-md);
font-size: 13px;
color: var(--text-2);
}
.thinking-dots span {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--cyan);
animation: thinking-bounce 1.4s infinite;
margin: 0 2px;
} }
.thinking-dots span:nth-child(2) { animation-delay: 0.2s; } /* ============================================
.thinking-dots span:nth-child(3) { animation-delay: 0.4s; } PROMOTION MODAL
============================================ */
@keyframes thinking-bounce {
0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
40% { transform: translateY(-6px); opacity: 1; }
}
/* Promotion modal */
.promotion-modal { .promotion-modal {
position: absolute; position: absolute;
top: 50%; top: 50%;
...@@ -327,94 +528,9 @@ ...@@ -327,94 +528,9 @@
.promotion-piece:hover { background: var(--cyan); } .promotion-piece:hover { background: var(--cyan); }
/* ============================================ /* ============================================
PRO FEATURES MOVE BADGES (Analysis)
============================================ */ ============================================ */
/* Eval Bar */
.eval-bar {
width: 24px;
min-width: 24px;
height: 100%;
background: #333;
border-radius: var(--radius-sm);
overflow: hidden;
position: relative;
border: 1px solid var(--border);
}
.eval-bar-fill {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: #fff;
transition: height 0.5s ease;
height: 50%;
}
.eval-bar-label {
position: absolute;
left: 0;
right: 0;
text-align: center;
font-family: var(--font-en);
font-size: 9px;
font-weight: 700;
pointer-events: none;
z-index: 1;
}
.eval-bar-label-top {
top: 4px;
color: #fff;
}
.eval-bar-label-bottom {
bottom: 4px;
color: #333;
}
/* Arrow Overlay */
.board-arrows {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 5;
}
.board-arrows svg {
width: 100%;
height: 100%;
position: absolute;
inset: 0;
}
.board-arrows svg line,
.board-arrows svg polygon {
opacity: 0.7;
}
/* Square Highlights */
.square-highlight-green {
background: rgba(21, 215, 100, 0.4) !important;
}
.square-highlight-red {
background: rgba(239, 68, 68, 0.45) !important;
}
.square-highlight-yellow {
background: rgba(255, 200, 0, 0.4) !important;
}
/* Pre-move Ghost Piece */
.piece-ghost {
opacity: 0.45;
pointer-events: none;
filter: grayscale(0.3);
}
/* Move Classification Badges */
.move-badge { .move-badge {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
...@@ -430,46 +546,16 @@ ...@@ -430,46 +546,16 @@
flex-shrink: 0; flex-shrink: 0;
} }
.move-brilliant { .move-brilliant { background: #26c6da; color: #fff; }
background: #26c6da; .move-great { background: #66bb6a; color: #fff; }
color: #fff; .move-good { background: #81c784; color: #fff; }
} .move-inaccuracy { background: #fdd835; color: #333; }
.move-mistake { background: #ef6c00; color: #fff; }
.move-great { .move-blunder { background: #e53935; color: #fff; }
background: #66bb6a;
color: #fff;
}
.move-good {
background: #81c784;
color: #fff;
}
.move-inaccuracy {
background: #fdd835;
color: #333;
}
.move-mistake {
background: #ef6c00;
color: #fff;
}
.move-blunder { /* ============================================
background: #e53935; ANALYSIS PAGE
color: #fff; ============================================ */
}
/* Analysis Panel */
.analysis-panel {
background: var(--bg-2);
border: 1px solid var(--border);
border-radius: var(--radius-md);
display: flex;
flex-direction: column;
overflow: hidden;
min-height: 0;
}
.analysis-panel-header { .analysis-panel-header {
padding: 10px 14px; padding: 10px 14px;
...@@ -496,7 +582,24 @@ ...@@ -496,7 +582,24 @@
display: block; display: block;
} }
/* Puzzle UI */ .eval-graph-container {
position: relative;
width: 100%;
height: 80px;
background: var(--bg-3);
}
.eval-graph-container canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
}
/* ============================================
PUZZLE UI
============================================ */
.puzzle-header { .puzzle-header {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -505,6 +608,7 @@ ...@@ -505,6 +608,7 @@
background: var(--bg-2); background: var(--bg-2);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
direction: rtl;
} }
.puzzle-streak { .puzzle-streak {
...@@ -527,164 +631,15 @@ ...@@ -527,164 +631,15 @@
border-radius: var(--radius-sm); border-radius: var(--radius-sm);
} }
/* Pro Move List */ /* Pre-move Ghost Piece */
.move-list-pro { .piece-ghost {
flex: 1; opacity: 0.4;
overflow-y: auto; pointer-events: none;
font-family: var(--font-en); filter: grayscale(0.3);
font-size: 13px;
direction: ltr;
text-align: left;
padding: 8px 0;
min-height: 0;
max-height: 320px;
}
.move-list-pro .move-pair {
display: flex;
align-items: center;
padding: 3px 12px;
gap: 2px;
}
.move-list-pro .move-pair:nth-child(odd) {
background: var(--bg-3);
}
.move-list-pro .move-number {
color: var(--text-3);
min-width: 30px;
font-size: 12px;
}
.move-list-pro .move {
padding: 3px 8px;
border-radius: 4px;
cursor: pointer;
min-width: 54px;
text-align: center;
}
.move-list-pro .move:hover {
background: var(--bg-hover, rgba(255,255,255,0.08));
}
.move-list-pro .move.current {
background: var(--cyan);
color: var(--text-inverse);
}
/* Opening Display */
.opening-display {
padding: 8px 14px;
border-bottom: 1px solid var(--border);
font-size: 12px;
color: var(--text-2);
display: flex;
align-items: center;
gap: 6px;
}
.opening-eco {
font-family: var(--font-en);
font-weight: 700;
color: var(--cyan);
font-size: 11px;
}
.opening-name {
font-weight: 500;
}
/* Game Status in Panel */
.panel-status {
padding: 10px 14px;
border-top: 1px solid var(--border);
font-size: 13px;
text-align: center;
color: var(--text-2);
}
/* Post-game Controls */
.postgame-controls {
display: flex;
gap: 6px;
padding: 10px 14px;
border-top: 1px solid var(--border);
flex-wrap: wrap;
}
.postgame-controls .btn {
flex: 1;
min-width: 0;
font-size: 12px;
padding: 6px 8px;
}
/* Panel Controls Row */
.panel-controls {
display: flex;
gap: 6px;
padding: 10px 14px;
border-top: 1px solid var(--border);
}
.panel-controls .btn {
flex: 1;
font-size: 12px;
padding: 6px 8px;
}
/* Pre-move indicator */
.premove-indicator {
font-size: 11px;
color: var(--cyan);
padding: 4px 14px;
border-top: 1px solid var(--border);
}
/* ============================================
PRO GAME LAYOUT (Desktop + Mobile)
============================================ */
.game-layout {
display: flex;
flex-direction: column;
gap: 12px;
max-width: 100%;
}
.game-board-section {
display: flex;
gap: 8px;
align-items: stretch;
}
.game-side-panel {
display: none;
flex-direction: column;
width: 280px;
min-width: 260px;
max-height: calc(100vw - 60px);
}
/* Eval graph canvas container */
.eval-graph-container {
position: relative;
width: 100%;
height: 80px;
background: var(--bg-3);
}
.eval-graph-container canvas {
position: absolute;
inset: 0;
width: 100%;
height: 100%;
} }
/* ============================================ /* ============================================
RESPONSIVE RESPONSIVE - Desktop
============================================ */ ============================================ */
@media (min-width: 768px) { @media (min-width: 768px) {
...@@ -692,16 +647,22 @@ ...@@ -692,16 +647,22 @@
flex-direction: row; flex-direction: row;
align-items: flex-start; align-items: flex-start;
gap: 16px; gap: 16px;
justify-content: center;
padding: 8px 0;
} }
.game-board-column { .game-board-column {
flex: 0 0 auto; flex: 0 0 auto;
max-width: 560px;
}
.game-board-section {
max-width: 590px;
} }
.game-side-panel { .game-side-panel {
display: flex; display: flex;
flex: 1; flex: 0 1 280px;
max-width: 320px;
max-height: 560px; max-height: 560px;
} }
...@@ -709,14 +670,24 @@ ...@@ -709,14 +670,24 @@
display: none; display: none;
} }
.board-wrapper { .game-header {
max-width: 560px; max-width: 560px;
} }
} }
/* ============================================
RESPONSIVE - Mobile
============================================ */
@media (max-width: 767px) { @media (max-width: 767px) {
.game-layout { .game-layout {
flex-direction: column; flex-direction: column;
align-items: center;
padding: 0;
}
.game-board-column {
width: 100%;
} }
.game-side-panel { .game-side-panel {
...@@ -726,18 +697,33 @@ ...@@ -726,18 +697,33 @@
.game-mobile-panel { .game-mobile-panel {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
width: 100%;
} }
.game-mobile-panel .analysis-panel { .game-mobile-panel .analysis-panel {
max-height: 260px; max-height: 240px;
border-radius: 0 0 var(--radius-md) var(--radius-md);
} }
.game-mobile-panel .move-list-pro { .game-mobile-panel .move-list-pro {
max-height: 160px; max-height: 140px;
}
.game-board-section {
max-width: 100%;
}
.board-wrapper {
max-width: 100vw;
}
.game-header {
border-radius: var(--radius-sm);
max-width: 100%;
} }
.eval-bar { .eval-bar {
width: 18px; width: 16px;
min-width: 18px; min-width: 16px;
} }
} }
...@@ -424,12 +424,14 @@ const Game = { ...@@ -424,12 +424,14 @@ const Game = {
// --- Pro Move List --- // --- Pro Move List ---
updateMoveList() { updateMoveList() {
const list = document.getElementById('move-list'); const lists = [document.getElementById('move-list'), document.getElementById('move-list-mobile')].filter(Boolean);
if (!list) return; if (lists.length === 0) return;
list.innerHTML = '';
const history = this.chess.history(); const history = this.chess.history();
lists.forEach(list => {
list.innerHTML = '';
for (let i = 0; i < history.length; i += 2) { for (let i = 0; i < history.length; i += 2) {
const pair = document.createElement('div'); const pair = document.createElement('div');
pair.className = 'move-pair'; pair.className = 'move-pair';
...@@ -439,42 +441,44 @@ const Game = { ...@@ -439,42 +441,44 @@ const Game = {
num.textContent = (Math.floor(i / 2) + 1) + '.'; num.textContent = (Math.floor(i / 2) + 1) + '.';
pair.appendChild(num); pair.appendChild(num);
const moveIdx = i;
const white = document.createElement('span'); const white = document.createElement('span');
white.className = 'move' + (i === this.currentMoveIndex ? ' current' : ''); white.className = 'move' + (i === this.currentMoveIndex ? ' current' : '');
white.textContent = history[i]; white.textContent = history[i];
white.dataset.moveIndex = i; white.dataset.moveIndex = i;
white.onclick = () => this.jumpToMove(i); white.onclick = () => this.jumpToMove(moveIdx);
pair.appendChild(white); pair.appendChild(white);
if (history[i + 1]) { if (history[i + 1]) {
const moveIdx2 = i + 1;
const black = document.createElement('span'); const black = document.createElement('span');
black.className = 'move' + (i + 1 === this.currentMoveIndex ? ' current' : ''); black.className = 'move' + (i + 1 === this.currentMoveIndex ? ' current' : '');
black.textContent = history[i + 1]; black.textContent = history[i + 1];
black.dataset.moveIndex = i + 1; black.dataset.moveIndex = i + 1;
black.onclick = () => this.jumpToMove(i + 1); black.onclick = () => this.jumpToMove(moveIdx2);
pair.appendChild(black); 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); this.updateOpeningName(history);
}, },
updateOpeningName(history) { updateOpeningName(history) {
const openingEl = document.getElementById('opening-name'); const els = [
if (!openingEl) return; document.getElementById('opening-display'),
document.getElementById('opening-display-mobile')
].filter(Boolean);
if (history.length === 0) { if (history.length === 0) {
openingEl.textContent = ''; els.forEach(el => el.style.display = 'none');
return; return;
} }
// Try progressively shorter sequences to find opening
let opening = ''; let opening = '';
const maxCheck = Math.min(history.length, 12); const maxCheck = Math.min(history.length, 12);
for (let len = maxCheck; len >= 1; len--) { for (let len = maxCheck; len >= 1; len--) {
...@@ -485,7 +489,15 @@ const Game = { ...@@ -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) { jumpToMove(index) {
...@@ -505,20 +517,25 @@ const Game = { ...@@ -505,20 +517,25 @@ const Game = {
// --- Game Status --- // --- Game Status ---
updateStatus() { updateStatus() {
const status = document.getElementById('game-status'); 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()) { if (this.chess.in_checkmate()) {
const winner = this.chess.turn() === 'w' ? 'b' : 'w'; 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()) { } else if (this.chess.in_check()) {
status.textContent = 'Check!'; text = 'كش!';
} else if (this.chess.in_draw()) { } else if (this.chess.in_draw()) {
status.textContent = 'Draw'; text = 'تعادل';
} else if (this.chess.in_stalemate()) { } else if (this.chess.in_stalemate()) {
status.textContent = 'Stalemate'; text = 'جمود - تعادل';
} else { } 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) { showThinking(show) {
...@@ -536,26 +553,26 @@ const Game = { ...@@ -536,26 +553,26 @@ const Game = {
let title, subtitle; let title, subtitle;
if (reason === 'timeout') { if (reason === 'timeout') {
title = winner === this.playerColor ? 'Win on time!' : 'Lost on time'; title = winner === this.playerColor ? 'فزت بالوقت!' : 'خسرت بالوقت';
subtitle = 'Time ran out'; subtitle = 'انتهى الوقت';
} else if (this.chess.in_checkmate()) { } else if (this.chess.in_checkmate()) {
const w = this.chess.turn() === 'w' ? 'b' : 'w'; const w = this.chess.turn() === 'w' ? 'b' : 'w';
title = w === this.playerColor ? 'You win!' : 'You lose'; title = w === this.playerColor ? 'فزت!' : 'خسرت';
subtitle = 'Checkmate'; subtitle = 'كش مات';
} else if (this.chess.in_stalemate()) { } else if (this.chess.in_stalemate()) {
title = 'Draw'; title = 'تعادل';
subtitle = 'Stalemate'; subtitle = 'جمود';
} else if (this.chess.in_draw()) { } else if (this.chess.in_draw()) {
title = 'Draw'; title = 'تعادل';
subtitle = 'Insufficient material'; subtitle = 'قطع غير كافية';
} else if (reason === 'resign') { } else if (reason === 'resign') {
title = winner === this.playerColor ? 'You win!' : 'You lose'; title = winner === this.playerColor ? 'فزت!' : 'خسرت';
subtitle = 'Resignation'; subtitle = 'استسلام';
} else if (reason === 'draw') { } else if (reason === 'draw') {
title = 'Draw'; title = 'تعادل';
subtitle = 'By agreement'; subtitle = 'باتفاق';
} else { } else {
title = 'Game over'; title = 'انتهت المباراة';
subtitle = ''; subtitle = '';
} }
...@@ -591,13 +608,13 @@ const Game = { ...@@ -591,13 +608,13 @@ const Game = {
overlay.innerHTML = '<div class="game-result-title">' + title + '</div>' + overlay.innerHTML = '<div class="game-result-title">' + title + '</div>' +
'<div class="game-result-subtitle">' + subtitle + '</div>' + '<div class="game-result-subtitle">' + subtitle + '</div>' +
'<div class="game-result-stats">' + '<div class="game-result-stats">' +
'<div class="stat-row"><span>Moves</span><span>' + totalMoves + '</span></div>' + '<div class="stat-row"><span>النقلات</span><span>' + totalMoves + '</span></div>' +
'<div class="stat-row"><span>Avg move time</span><span>' + avgMoveTime + 's</span></div>' + '<div class="stat-row"><span>متوسط وقت النقلة</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>' + totalTimeUsed + 's</span></div>' +
'</div>' + '</div>' +
'<div class="game-controls" style="margin-top:16px;">' + '<div class="game-controls" style="margin-top:16px;">' +
'<button class="btn btn-cyan" id="btn-rematch-result">Rematch</button>' + '<button class="btn btn-cyan" id="btn-rematch-result">اعادة</button>' +
'<button class="btn btn-ghost" onclick="window.location.href=\'/play\'">Back</button>' + '<button class="btn btn-ghost" onclick="window.location.href=\'/play\'">رجوع</button>' +
'</div>'; '</div>';
wrapper.appendChild(overlay); 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