dcrey7's picture
Upload 9 files
e30257d verified
raw
history blame
10.9 kB
class GameUI {
constructor() {
// Initialize UI state and configurations
this.state = {
currentPage: 'landing',
isAnimating: false,
darkMode: true,
animationDuration: 300
};
// Store references to frequently accessed DOM elements
this.elements = {
pages: {},
buttons: {},
containers: {},
overlays: {}
};
// Initialize the UI
this.initialize();
}
async initialize() {
// Wait for DOM to be fully loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => this.setupUI());
} else {
this.setupUI();
}
}
setupUI() {
// Cache all important DOM elements
this.cacheElements();
// Set up event listeners
this.setupEventListeners();
// Initialize the landing page
this.showPage('landing');
}
cacheElements() {
// Cache all page elements
['landing', 'setup', 'game', 'recording', 'listening', 'voting', 'results'].forEach(pageId => {
this.elements.pages[pageId] = document.getElementById(`${pageId}-page`);
});
// Cache all button elements
this.elements.buttons = {
play: document.getElementById('play-button'),
addPlayer: document.getElementById('add-player-button'),
start: document.getElementById('start-button'),
record: document.getElementById('record-button'),
settings: document.getElementById('settings-button')
};
// Cache container elements
this.elements.containers = {
playerList: document.getElementById('player-list'),
questionDisplay: document.getElementById('question-display'),
timerDisplay: document.getElementById('timer-display'),
recordingVisualizer: document.getElementById('recording-visualizer'),
votingOptions: document.getElementById('voting-options')
};
// Cache overlay elements
this.elements.overlays = {
loading: document.getElementById('loading-overlay'),
error: document.getElementById('error-overlay'),
settings: document.getElementById('settings-overlay')
};
}
setupEventListeners() {
// Set up button click handlers
Object.entries(this.elements.buttons).forEach(([key, button]) => {
if (button) {
button.addEventListener('click', () => this.handleButtonClick(key));
}
});
// Set up keyboard shortcuts
document.addEventListener('keydown', (e) => this.handleKeyPress(e));
// Set up settings toggle
if (this.elements.buttons.settings) {
this.elements.buttons.settings.addEventListener('click', () => this.toggleSettings());
}
}
handleButtonClick(buttonType) {
switch (buttonType) {
case 'play':
this.transitionToPage('setup');
break;
case 'addPlayer':
window.game.addPlayer();
break;
case 'start':
window.game.startGame();
break;
case 'record':
this.toggleRecording();
break;
default:
console.warn(`Unhandled button type: ${buttonType}`);
}
}
async transitionToPage(pageName) {
if (this.state.isAnimating || this.state.currentPage === pageName) return;
this.state.isAnimating = true;
// Fade out current page
const currentPage = this.elements.pages[this.state.currentPage];
if (currentPage) {
await this.animateElement(currentPage, 'fadeOut');
currentPage.classList.remove('active');
}
// Update state and fade in new page
this.state.currentPage = pageName;
const newPage = this.elements.pages[pageName];
if (newPage) {
newPage.classList.add('active');
await this.animateElement(newPage, 'fadeIn');
}
this.state.isAnimating = false;
}
async animateElement(element, animation) {
return new Promise(resolve => {
element.classList.add(animation);
setTimeout(() => {
element.classList.remove(animation);
resolve();
}, this.state.animationDuration);
});
}
updatePlayerList(players) {
if (!this.elements.containers.playerList) return;
const playerList = this.elements.containers.playerList;
playerList.innerHTML = '';
players.forEach(player => {
const playerElement = document.createElement('div');
playerElement.className = 'player-avatar';
// Create avatar circle
const avatarCircle = document.createElement('div');
avatarCircle.className = 'avatar-circle';
avatarCircle.textContent = player.id;
// Create player name
const playerName = document.createElement('div');
playerName.className = 'player-name';
playerName.textContent = player.name;
playerElement.appendChild(avatarCircle);
playerElement.appendChild(playerName);
playerList.appendChild(playerElement);
});
}
updateTimer(timeLeft) {
if (!this.elements.containers.timerDisplay) return;
const minutes = Math.floor(timeLeft / 60);
const seconds = timeLeft % 60;
this.elements.containers.timerDisplay.textContent =
`${minutes}:${seconds.toString().padStart(2, '0')}`;
// Add warning class when time is running low
if (timeLeft <= 10) {
this.elements.containers.timerDisplay.classList.add('warning');
}
}
showQuestion(question) {
if (!this.elements.containers.questionDisplay) return;
const questionElement = this.elements.containers.questionDisplay;
questionElement.textContent = question;
// Animate question appearance
this.animateElement(questionElement, 'slideIn');
}
toggleRecording(isRecording) {
if (!this.elements.buttons.record) return;
const recordButton = this.elements.buttons.record;
recordButton.classList.toggle('recording', isRecording);
recordButton.textContent = isRecording ? 'Stop Recording' : 'Start Recording';
}
showLoadingOverlay(show, message = 'Loading...') {
if (!this.elements.overlays.loading) return;
const overlay = this.elements.overlays.loading;
if (show) {
overlay.querySelector('.loading-message').textContent = message;
overlay.classList.add('active');
} else {
overlay.classList.remove('active');
}
}
showError(message, duration = 3000) {
if (!this.elements.overlays.error) return;
const errorOverlay = this.elements.overlays.error;
const errorMessage = errorOverlay.querySelector('.error-message');
errorMessage.textContent = message;
errorOverlay.classList.add('active');
setTimeout(() => {
errorOverlay.classList.remove('active');
}, duration);
}
updateVotingOptions(players, currentPlayer) {
if (!this.elements.containers.votingOptions) return;
const votingContainer = this.elements.containers.votingOptions;
votingContainer.innerHTML = '';
players.forEach(player => {
if (player.id !== currentPlayer) {
const voteButton = document.createElement('button');
voteButton.className = 'vote-button';
voteButton.dataset.playerId = player.id;
const playerCircle = document.createElement('div');
playerCircle.className = 'player-circle';
playerCircle.textContent = player.id;
voteButton.appendChild(playerCircle);
votingContainer.appendChild(voteButton);
voteButton.addEventListener('click', () => {
window.game.submitVote(player.id);
});
}
});
}
showResults(results) {
const resultsPage = this.elements.pages.results;
if (!resultsPage) return;
// Clear previous results
resultsPage.innerHTML = '';
// Create results content
const content = document.createElement('div');
content.className = 'results-content';
// Add impostor reveal
const impostorReveal = document.createElement('div');
impostorReveal.className = 'impostor-reveal';
impostorReveal.textContent = `The impostor was Player ${results.impostor}!`;
// Add voting results
const votingResults = document.createElement('div');
votingResults.className = 'voting-results';
Object.entries(results.votes).forEach(([player, vote]) => {
const voteEntry = document.createElement('div');
voteEntry.className = 'vote-entry';
voteEntry.textContent = `Player ${player} voted for Player ${vote}`;
votingResults.appendChild(voteEntry);
});
content.appendChild(impostorReveal);
content.appendChild(votingResults);
resultsPage.appendChild(content);
this.transitionToPage('results');
}
handleKeyPress(event) {
// Add keyboard shortcuts
switch (event.key) {
case 'Escape':
this.closeAllOverlays();
break;
case 'r':
if (this.state.currentPage === 'recording') {
this.toggleRecording();
}
break;
}
}
closeAllOverlays() {
Object.values(this.elements.overlays).forEach(overlay => {
if (overlay) {
overlay.classList.remove('active');
}
});
}
// Method to clean up UI resources
cleanup() {
// Remove event listeners
Object.values(this.elements.buttons).forEach(button => {
if (button) {
button.replaceWith(button.cloneNode(true));
}
});
// Clear all intervals and timeouts
this.closeAllOverlays();
}
}
// Export the GameUI class
export default GameUI;