Redesign status bar to split Turn Info (left) and Player Identity (right)

This commit is contained in:
2025-12-21 20:15:46 +11:00
parent 91535dc8fc
commit acf32d0418
3 changed files with 111 additions and 63 deletions

View File

@@ -66,16 +66,23 @@
</div> </div>
<div class="game-info"> <div class="game-info">
<div class="status-container"> <div class="game-status-bar">
<div class="turn-indicator"> <!-- Left Side: Turn Status -->
<span class="label" id="turnLabel">Current Turn:</span> <div class="status-left">
<div class="player-display"> <div class="turn-display">
<span class="label">Current Turn:</span>
<span class="player-marker" id="currentPlayer">X</span> <span class="player-marker" id="currentPlayer">X</span>
</div> </div>
<!-- Status text integrated here -->
<span class="status-text-small" id="statusMessage">Player X starts</span>
</div> </div>
<div class="status-divider"></div>
<div class="status-text" id="statusMessage"> <!-- Right Side: Player Identity (Multiplayer only) -->
Player X starts the game <div class="status-right" id="playerIdentitySection" style="display: none;">
<span class="label">You are:</span>
<div class="player-display">
<span class="player-marker" id="playerIdentity">?</span>
</div>
</div> </div>
</div> </div>

View File

@@ -357,7 +357,7 @@ class MultiplayerClient {
document.getElementById('multiplayerPanel').style.display = 'none'; document.getElementById('multiplayerPanel').style.display = 'none';
document.getElementById('gameControls').style.display = 'grid'; document.getElementById('gameControls').style.display = 'grid';
document.querySelector('.board-wrapper').style.display = 'flex'; document.querySelector('.board-wrapper').style.display = 'flex';
// status container is part of gameControls now // Status bar is part of gameControls
// Set board size // Set board size
document.querySelectorAll('.size-btn').forEach(btn => { document.querySelectorAll('.size-btn').forEach(btn => {
@@ -370,32 +370,40 @@ class MultiplayerClient {
this.game.gameActive = true; this.game.gameActive = true;
this.game.initializeBoard(); this.game.initializeBoard();
// Update current player display to show "YOU ARE X/O" // Update player identity display (Right Side)
const currentPlayerDisplay = document.getElementById('currentPlayer'); const identitySection = document.getElementById('playerIdentitySection');
const turnLabel = document.getElementById('turnLabel'); const identityMarker = document.getElementById('playerIdentity');
currentPlayerDisplay.textContent = this.mySymbol;
turnLabel.textContent = `You are:`;
// Update player display colors based on symbol if (identitySection && identityMarker) {
const playerDisplay = document.querySelector('.player-display'); identitySection.style.display = 'flex';
if (this.mySymbol === 'O') { identityMarker.textContent = this.mySymbol;
playerDisplay.style.borderColor = 'hsl(195, 70%, 55%)';
currentPlayerDisplay.style.color = 'hsl(195, 70%, 55%)'; // Set color for identity marker
} else { if (this.mySymbol === 'O') {
playerDisplay.style.borderColor = 'hsl(270, 70%, 60%)'; identityMarker.style.color = 'hsl(195, 70%, 55%)';
currentPlayerDisplay.style.color = 'hsl(270, 70%, 60%)'; identityMarker.parentElement.style.borderColor = 'hsl(195, 70%, 55%)';
} else {
identityMarker.style.color = 'hsl(270, 70%, 60%)';
identityMarker.parentElement.style.borderColor = 'hsl(270, 70%, 60%)';
}
} }
// Update status // Ensure Turn label is correct (Left Side)
const statusText = document.getElementById('statusMessage'); // This is the status-text element const turnLabel = document.getElementById('turnLabel');
const statusContainer = statusText.parentElement; // This is the status-container element if (turnLabel) turnLabel.textContent = 'Current Turn:';
// Set initial color for Current Turn display (will be updated by game.js but good to init)
const currentPlayerDisplay = document.getElementById('currentPlayer');
// Update status text (Left Side generic message)
const statusMessage = document.getElementById('statusMessage');
if (this.myTurn) { if (this.myTurn) {
statusText.textContent = `🎮 VS ${this.opponent} | YOUR TURN - You're playing as ${this.mySymbol}`; statusMessage.textContent = `VS ${this.opponent} | YOUR TURN`;
statusContainer.className = 'status-container success'; statusMessage.className = 'status-text-small success';
} else { } else {
statusText.textContent = `🎮 VS ${this.opponent} | Waiting for ${this.opponent} to move - You're playing as ${this.mySymbol}`; statusMessage.textContent = `VS ${this.opponent} | Waiting for opponent`;
statusContainer.className = 'status-container info'; statusMessage.className = 'status-text-small info';
} }
console.log(`✅ Game started! You are ${this.mySymbol}, ${this.myTurn ? 'your turn' : 'waiting'}`); console.log(`✅ Game started! You are ${this.mySymbol}, ${this.myTurn ? 'your turn' : 'waiting'}`);
@@ -420,8 +428,11 @@ class MultiplayerClient {
this.myTurn = false; this.myTurn = false;
if (!data.gameOver) { if (!data.gameOver) {
const status = document.getElementById('statusMessage'); const statusMessage = document.getElementById('statusMessage');
status.textContent = `Playing against ${this.opponent} - Waiting for opponent...`; if (statusMessage) {
statusMessage.textContent = `Playing against ${this.opponent} - Waiting for opponent...`;
statusMessage.className = 'status-text-small info';
}
} }
} else { } else {
this.showMessage(data.error, 'error'); this.showMessage(data.error, 'error');
@@ -432,6 +443,13 @@ class MultiplayerClient {
handleOpponentMove(data) { handleOpponentMove(data) {
// Place opponent's piece on board // Place opponent's piece on board
this.game.currentPlayer = data.symbol; this.game.currentPlayer = data.symbol;
// Update turn indicator immediately to show X or O
const currentPlayerDisplay = document.getElementById('currentPlayer');
if (currentPlayerDisplay) {
currentPlayerDisplay.textContent = data.symbol;
}
const cellIndex = data.row * this.game.boardSize + data.col; const cellIndex = data.row * this.game.boardSize + data.col;
const cell = this.game.boardElement.children[cellIndex]; const cell = this.game.boardElement.children[cellIndex];
@@ -444,8 +462,11 @@ class MultiplayerClient {
this.myTurn = true; this.myTurn = true;
this.game.currentPlayer = this.mySymbol; this.game.currentPlayer = this.mySymbol;
const status = document.getElementById('statusMessage'); const statusMessage = document.getElementById('statusMessage');
status.textContent = `Playing against ${this.opponent} - Your turn (${this.mySymbol})`; if (statusMessage) {
statusMessage.textContent = `Playing against ${this.opponent} - Your turn`;
statusMessage.className = 'status-text-small success';
}
} }
// Handle game ended // Handle game ended
@@ -497,7 +518,12 @@ class MultiplayerClient {
this.isMultiplayer = false; this.isMultiplayer = false;
this.currentGameId = null; this.currentGameId = null;
document.getElementById('multiplayerPanel').style.display = 'block'; document.getElementById('multiplayerPanel').style.display = 'block';
document.getElementById('gameControls').style.display = 'block'; document.getElementById('gameControls').style.display = 'block'; // Or grid/none depending on logic, but block/grid usually toggled by logic
// Hide identity section in local play
const identitySection = document.getElementById('playerIdentitySection');
if (identitySection) identitySection.style.display = 'none';
this.socket.emit('request_active_players'); this.socket.emit('request_active_players');
} }
@@ -506,10 +532,7 @@ class MultiplayerClient {
const messageEl = document.getElementById('statusMessage'); const messageEl = document.getElementById('statusMessage');
if (messageEl) { if (messageEl) {
messageEl.textContent = text; messageEl.textContent = text;
// Apply class to the container, not the text element messageEl.className = `status-text-small ${type}`;
if (messageEl.parentElement.classList.contains('status-container')) {
messageEl.parentElement.className = `status-container ${type}`;
}
} }
} }
} }

View File

@@ -432,51 +432,69 @@ body {
} }
} }
/* Status Message */ /* Game Status Bar */
/* Merged Status Container */ .game-status-bar {
.status-container {
display: flex; display: flex;
justify-content: space-between;
align-items: center; align-items: center;
justify-content: center; padding: 0.75rem 1.5rem;
gap: 1.5rem;
padding: 1rem;
background: var(--bg-tertiary); background: var(--bg-tertiary);
border-radius: 12px; border-radius: 12px;
border: 1px solid var(--border-light); border: 1px solid var(--border-light);
width: 100%; width: 100%;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
min-height: 70px;
} }
.status-divider { /* Left Side: Turn Info + Text */
width: 1px; .status-left {
height: 24px; display: flex;
background: var(--border-light); flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 0.25rem;
} }
.status-text { .turn-display {
display: flex;
align-items: center;
gap: 1rem;
}
.status-text-small {
font-size: 0.9rem;
color: var(--text-secondary);
font-weight: 500;
margin-top: 2px;
}
/* Right Side: Identity */
.status-right {
display: flex;
align-items: center;
gap: 1rem;
padding-left: 1.5rem;
border-left: 1px solid var(--border-light);
}
.status-right .label {
color: var(--text-secondary); color: var(--text-secondary);
font-weight: 600;
font-size: 1rem; font-size: 1rem;
flex: 1; font-weight: 600;
text-align: left; white-space: nowrap;
} }
/* Status variants applied to the container */ /* Dynamic status colors applied to the text, not full bg */
.status-container.success { .status-text-small.success {
border-color: var(--success);
background: rgba(16, 185, 129, 0.05);
}
.status-container.success .status-text {
color: var(--success); color: var(--success);
} }
.status-container.info { .status-text-small.info {
border-color: var(--accent-secondary); color: var(--accent-secondary);
background: rgba(56, 189, 248, 0.05);
} }
.status-container.info .status-text { .status-text-small.error {
color: var(--accent-secondary); color: #ef4444;
} }
/* Victory Overlay */ /* Victory Overlay */