UI immer aus Laras Perspektive: Lara unten, Brett-Orientierung dynamisch, Züge in Gold

This commit is contained in:
2026-05-24 14:41:08 +02:00
parent 84973c002c
commit 15b6f31f62
2 changed files with 136 additions and 66 deletions

185
app.js
View File

@@ -14,6 +14,8 @@ let allLaraGames = [];
let refreshTimer = null; let refreshTimer = null;
let countdown = 0; let countdown = 0;
let serverLastFetch = null; let serverLastFetch = null;
let laraColor = null;
let currentMoveIndex = -1;
/** /**
* Lädt die PGN-Datei und aktualisiert die Anzeige * Lädt die PGN-Datei und aktualisiert die Anzeige
@@ -75,19 +77,23 @@ function updateBoard() {
// Spiegele das Brett, wenn Lara Schwarz hat // Spiegele das Brett, wenn Lara Schwarz hat
const laraIsBlack = currentGame.black.toLowerCase().includes('kiesewetter'); const laraIsBlack = currentGame.black.toLowerCase().includes('kiesewetter');
const orientation = laraIsBlack ? 'black' : 'white'; const orientation = laraIsBlack ? 'black' : 'white';
laraColor = laraIsBlack ? 'b' : 'w';
// Führe alle Züge aus // Führe alle Züge aus
for (const move of currentGame.moves) { const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
if (move.isResult) break; for (const move of nonResultMoves) {
try { try {
chess.move(move.san); chess.move(move.san);
} catch (e) { } catch (e) {
// Ignoriere ungültige Züge // Ignoriere ungültige Züge
} }
} }
currentMoveIndex = nonResultMoves.length - 1;
if (board) board.position(chess.fen(), true); if (board) {
else { board.position(chess.fen(), true);
board.orientation(orientation);
} else {
board = Chessboard('board', { board = Chessboard('board', {
position: chess.fen(), position: chess.fen(),
orientation: orientation, orientation: orientation,
@@ -104,6 +110,38 @@ function updateBoard() {
highlightActivePlayer(); highlightActivePlayer();
} }
/**
* Gehe zu einem bestimmten Zug (Index)
*/
function goToMove(index) {
if (!currentGame) return;
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
if (index < -1) index = -1;
if (index >= nonResultMoves.length) index = nonResultMoves.length - 1;
currentMoveIndex = index;
chess = new Chess();
for (let i = 0; i <= index; i++) {
try {
chess.move(nonResultMoves[i].san);
} catch (err) {
break;
}
}
board.position(chess.fen(), true);
highlightActivePlayer();
document.querySelectorAll('#moves-list .move').forEach(el => el.classList.remove('current'));
if (index >= 0) {
const moveEl = document.querySelector(`#moves-list [data-index="${index}"]`);
if (moveEl) moveEl.classList.add('current');
}
}
/** /**
* Aktualisiert die Spielerinformationen * Aktualisiert die Spielerinformationen
*/ */
@@ -112,23 +150,27 @@ function updatePlayerInfo() {
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter'); const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
if (laraIsWhite) { const laraPlayer = laraIsWhite ? currentGame.white : currentGame.black;
document.getElementById('white-name').textContent = currentGame.white; const laraElo = laraIsWhite ? currentGame.whiteElo : currentGame.blackElo;
document.getElementById('white-elo').textContent = currentGame.whiteElo ? `(ELO: ${currentGame.whiteElo})` : ''; const laraClock = laraIsWhite ? currentGame.whiteClock : currentGame.blackClock;
document.getElementById('white-clock').textContent = formatClock(currentGame.whiteClock); const laraEmoji = laraIsWhite ? '⬜' : '⬛';
document.getElementById('black-name').textContent = currentGame.black; const oppPlayer = laraIsWhite ? currentGame.black : currentGame.white;
document.getElementById('black-elo').textContent = currentGame.blackElo ? `(ELO: ${currentGame.blackElo})` : ''; const oppElo = laraIsWhite ? currentGame.blackElo : currentGame.whiteElo;
document.getElementById('black-clock').textContent = formatClock(currentGame.blackClock); const oppClock = laraIsWhite ? currentGame.blackClock : currentGame.whiteClock;
} else { const oppEmoji = laraIsWhite ? '⬛' : '⬜';
document.getElementById('white-name').textContent = currentGame.white;
document.getElementById('white-elo').textContent = currentGame.whiteElo ? `(ELO: ${currentGame.whiteElo})` : '';
document.getElementById('white-clock').textContent = formatClock(currentGame.whiteClock);
document.getElementById('black-name').textContent = currentGame.black; // Top-Panel (player-black) = Gegner
document.getElementById('black-elo').textContent = currentGame.blackElo ? `(ELO: ${currentGame.blackElo})` : ''; document.getElementById('black-name').textContent = oppPlayer;
document.getElementById('black-clock').textContent = formatClock(currentGame.blackClock); document.getElementById('black-elo').textContent = oppElo ? `(ELO: ${oppElo})` : '';
} document.getElementById('black-clock').textContent = formatClock(oppClock);
document.querySelector('#player-black .player-avatar').textContent = oppEmoji;
// Bottom-Panel (player-white) = Lara
document.getElementById('white-name').textContent = laraPlayer;
document.getElementById('white-elo').textContent = laraElo ? `(ELO: ${laraElo})` : '';
document.getElementById('white-clock').textContent = formatClock(laraClock);
document.querySelector('#player-white .player-avatar').textContent = laraEmoji;
// Round info // Round info
const roundInfo = `Runde ${currentGame.round} ${currentGame.event || 'Turnier'}`; const roundInfo = `Runde ${currentGame.round} ${currentGame.event || 'Turnier'}`;
@@ -147,18 +189,21 @@ function updatePlayerInfo() {
* Highlight den Spieler, der gerade am Zug ist * Highlight den Spieler, der gerade am Zug ist
*/ */
function highlightActivePlayer() { function highlightActivePlayer() {
if (!chess) return; if (!chess || !currentGame) return;
const whiteEl = document.getElementById('player-white'); const laraPanel = document.getElementById('player-white');
const blackEl = document.getElementById('player-black'); const oppPanel = document.getElementById('player-black');
whiteEl.classList.remove('active'); laraPanel.classList.remove('active');
blackEl.classList.remove('active'); oppPanel.classList.remove('active');
if (chess.turn() === 'w') { const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
whiteEl.classList.add('active'); const isLaraTurn = (chess.turn() === 'w' && laraIsWhite) || (chess.turn() === 'b' && !laraIsWhite);
if (isLaraTurn) {
laraPanel.classList.add('active');
} else { } else {
blackEl.classList.add('active'); oppPanel.classList.add('active');
} }
} }
@@ -172,37 +217,53 @@ function updateMovesList() {
movesList.innerHTML = ''; movesList.innerHTML = '';
const nonResultMoves = currentGame.moves.filter(m => !m.isResult); const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
const laraIsWhite = currentGame.white.toLowerCase().includes('kiesewetter');
for (let i = 0; i < nonResultMoves.length; i += 2) { for (let i = 0; i < nonResultMoves.length; i += 2) {
const moveNumber = Math.floor(i / 2) + 1; const moveNumber = Math.floor(i / 2) + 1;
// Move number
const numSpan = document.createElement('span'); const numSpan = document.createElement('span');
numSpan.className = 'move-number'; numSpan.className = 'move-number';
numSpan.textContent = `${moveNumber}.`; numSpan.textContent = `${moveNumber}.`;
movesList.appendChild(numSpan); movesList.appendChild(numSpan);
// White move if (laraIsWhite) {
const whiteMove = document.createElement('span'); // Lara (Weiß) zuerst
whiteMove.className = 'move'; const laraMove = document.createElement('span');
whiteMove.textContent = nonResultMoves[i].san; laraMove.className = 'move lara-move';
whiteMove.dataset.index = i; laraMove.textContent = nonResultMoves[i].san;
movesList.appendChild(whiteMove); laraMove.dataset.index = i;
movesList.appendChild(laraMove);
// Black move
if (i + 1 < nonResultMoves.length) { if (i + 1 < nonResultMoves.length) {
const blackMove = document.createElement('span'); const oppMove = document.createElement('span');
blackMove.className = 'move'; oppMove.className = 'move opp-move';
blackMove.textContent = nonResultMoves[i + 1].san; oppMove.textContent = nonResultMoves[i + 1].san;
blackMove.dataset.index = i + 1; oppMove.dataset.index = i + 1;
movesList.appendChild(blackMove); movesList.appendChild(oppMove);
}
} else {
// Lara (Schwarz) Gegner zuerst, dann Lara
const oppMove = document.createElement('span');
oppMove.className = 'move opp-move';
oppMove.textContent = nonResultMoves[i].san;
oppMove.dataset.index = i;
movesList.appendChild(oppMove);
if (i + 1 < nonResultMoves.length) {
const laraMove = document.createElement('span');
laraMove.className = 'move lara-move';
laraMove.textContent = nonResultMoves[i + 1].san;
laraMove.dataset.index = i + 1;
movesList.appendChild(laraMove);
}
} }
} }
// Mark last move // Mark current move
if (nonResultMoves.length > 0) { if (currentMoveIndex >= 0) {
const lastMove = movesList.querySelector(`[data-index="${nonResultMoves.length - 1}"]`); const curMove = movesList.querySelector(`[data-index="${currentMoveIndex}"]`);
if (lastMove) lastMove.classList.add('current'); if (curMove) curMove.classList.add('current');
} }
// Scroll to bottom // Scroll to bottom
@@ -214,24 +275,7 @@ function updateMovesList() {
*/ */
function handleMoveClick(e) { function handleMoveClick(e) {
if (!e.target.classList.contains('move') || !currentGame) return; if (!e.target.classList.contains('move') || !currentGame) return;
goToMove(parseInt(e.target.dataset.index));
const index = parseInt(e.target.dataset.index);
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
chess = new Chess();
for (let i = 0; i <= index; i++) {
try {
chess.move(nonResultMoves[i].san);
} catch (err) {
break;
}
}
board.position(chess.fen(), true);
// Update current highlight
document.querySelectorAll('#moves-list .move').forEach(el => el.classList.remove('current'));
e.target.classList.add('current');
} }
/** /**
@@ -337,6 +381,23 @@ document.getElementById('refresh-btn').addEventListener('click', () => {
loadPGN(); loadPGN();
}); });
/**
* Pfeiltasten-Navigation
*/
document.addEventListener('keydown', (e) => {
if (!currentGame) return;
const nonResultMoves = currentGame.moves.filter(m => !m.isResult);
if (e.key === 'ArrowLeft') {
e.preventDefault();
goToMove(currentMoveIndex - 1);
} else if (e.key === 'ArrowRight') {
e.preventDefault();
goToMove(currentMoveIndex + 1);
}
});
/** /**
* Init * Init
*/ */

View File

@@ -213,6 +213,15 @@ header h1 {
color: #fff; color: #fff;
} }
#moves-list .lara-move {
color: #ffd700;
font-weight: bold;
}
#moves-list .opp-move {
color: #aaa;
}
#all-games-list { #all-games-list {
display: flex; display: flex;
flex-direction: column; flex-direction: column;