From 066fcc26cccc65996e57722ac4e2ac9cd825b73b Mon Sep 17 00:00:00 2001 From: Dejvino Date: Sun, 4 Jan 2026 06:17:57 +0000 Subject: [PATCH] Feature: config UI split across Schedule and Venue panels --- party-stage/src/scene/config-ui.js | 103 ++++++++++++++++++++------ party-stage/src/scene/music-player.js | 6 +- 2 files changed, 85 insertions(+), 24 deletions(-) diff --git a/party-stage/src/scene/config-ui.js b/party-stage/src/scene/config-ui.js index 8a7b20e..613e043 100644 --- a/party-stage/src/scene/config-ui.js +++ b/party-stage/src/scene/config-ui.js @@ -9,12 +9,14 @@ export class ConfigUI extends SceneFeature { super(); sceneFeatureManager.register(this); this.toggles = {}; + this.containers = []; } init() { - const container = document.createElement('div'); - container.id = 'config-ui'; - Object.assign(container.style, { + // --- Left Panel: Party Schedule --- + const leftContainer = document.createElement('div'); + leftContainer.id = 'config-ui-left'; + Object.assign(leftContainer.style, { position: 'absolute', top: '70px', left: '20px', @@ -29,6 +31,47 @@ export class ConfigUI extends SceneFeature { gap: '10px', minWidth: '200px' }); + this.containers.push(leftContainer); + + const heading = document.createElement('h3'); + heading.innerText = 'Party schedule'; + Object.assign(heading.style, { + margin: '0 0 15px 0', + textAlign: 'center', + borderBottom: '1px solid #555', + paddingBottom: '10px' + }); + leftContainer.appendChild(heading); + + // --- Right Panel: Party Venue --- + const rightContainer = document.createElement('div'); + rightContainer.id = 'config-ui-right'; + Object.assign(rightContainer.style, { + position: 'absolute', + top: '70px', + right: '20px', + zIndex: '1000', + backgroundColor: 'rgba(0, 0, 0, 0.8)', + padding: '15px', + borderRadius: '8px', + color: 'white', + fontFamily: 'sans-serif', + display: 'flex', + flexDirection: 'column', + gap: '10px', + minWidth: '200px' + }); + this.containers.push(rightContainer); + + const venueHeading = document.createElement('h3'); + venueHeading.innerText = 'Party venue'; + Object.assign(venueHeading.style, { + margin: '0 0 15px 0', + textAlign: 'center', + borderBottom: '1px solid #555', + paddingBottom: '10px' + }); + rightContainer.appendChild(venueHeading); const saveConfig = () => { localStorage.setItem('partyConfig', JSON.stringify(state.config)); @@ -56,7 +99,7 @@ export class ConfigUI extends SceneFeature { this.toggles[configKey] = { checkbox: chk, callback: onChange }; row.appendChild(lbl); row.appendChild(chk); - container.appendChild(row); + rightContainer.appendChild(row); }; // Torches Toggle @@ -99,14 +142,11 @@ export class ConfigUI extends SceneFeature { hatRow.appendChild(hatLabel); hatRow.appendChild(hatSelect); - container.appendChild(hatRow); + rightContainer.appendChild(hatRow); // --- Status & Control Section --- const statusContainer = document.createElement('div'); Object.assign(statusContainer.style, { - marginTop: '15px', - paddingTop: '10px', - borderTop: '1px solid #555', display: 'flex', flexDirection: 'column', gap: '8px' @@ -143,7 +183,7 @@ export class ConfigUI extends SceneFeature { marginTop: '10px', padding: '8px', cursor: 'pointer', - backgroundColor: '#555', + backgroundColor: '#ff9800', // Default orange color: 'white', border: 'none', borderRadius: '4px', @@ -168,6 +208,7 @@ export class ConfigUI extends SceneFeature { loadPosterBtn.onclick = () => { posterInput.click(); }; + this.loadPosterBtn = loadPosterBtn; statusContainer.appendChild(loadPosterBtn); // Load Tapes Button @@ -178,7 +219,7 @@ export class ConfigUI extends SceneFeature { marginTop: '10px', padding: '8px', cursor: 'pointer', - backgroundColor: '#555', + backgroundColor: '#ff9800', // Default orange color: 'white', border: 'none', borderRadius: '4px', @@ -194,7 +235,7 @@ export class ConfigUI extends SceneFeature { marginTop: '10px', padding: '8px', cursor: 'pointer', - backgroundColor: '#555', + backgroundColor: '#ff9800', // Default orange color: 'white', border: 'none', borderRadius: '4px', @@ -204,6 +245,7 @@ export class ConfigUI extends SceneFeature { const fileInput = document.getElementById('musicFileInput'); if (fileInput) fileInput.click(); }; + this.chooseSongBtn = chooseSongBtn; statusContainer.appendChild(chooseSongBtn); // Start Party Button @@ -214,8 +256,8 @@ export class ConfigUI extends SceneFeature { marginTop: '10px', padding: '10px', cursor: 'not-allowed', - backgroundColor: '#333', - color: '#777', + backgroundColor: '#dc3545', // Default red + color: 'white', border: 'none', borderRadius: '4px', fontSize: '16px', @@ -227,7 +269,7 @@ export class ConfigUI extends SceneFeature { if (musicPlayer) musicPlayer.startSequence(); }; statusContainer.appendChild(this.startButton); - container.appendChild(statusContainer); + leftContainer.appendChild(statusContainer); // Reset Button const resetBtn = document.createElement('button'); @@ -293,10 +335,10 @@ export class ConfigUI extends SceneFeature { if (this.hatSelect) this.hatSelect.value = defaults.djHat; this.updateStatus(); }; - container.appendChild(resetBtn); + leftContainer.appendChild(resetBtn); - document.body.appendChild(container); - this.container = container; + document.body.appendChild(leftContainer); + document.body.appendChild(rightContainer); this.updateStatus(); // Restore poster @@ -311,23 +353,40 @@ export class ConfigUI extends SceneFeature { updateStatus() { if (!this.songLabel) return; + const orange = '#ff9800'; + const green = '#28a745'; + const red = '#dc3545'; + // Update Song Info if (state.music && state.music.songTitle) { this.songLabel.innerText = `Song: ${state.music.songTitle}`; this.songLabel.style.color = '#fff'; this.startButton.disabled = false; - this.startButton.style.backgroundColor = '#28a745'; + this.startButton.style.backgroundColor = green; this.startButton.style.color = 'white'; this.startButton.style.cursor = 'pointer'; + this.startButton.style.opacity = '1'; + + if (this.chooseSongBtn) this.chooseSongBtn.style.backgroundColor = green; } else { this.songLabel.innerText = 'Song: (None)'; this.songLabel.style.color = '#aaa'; this.startButton.disabled = true; - this.startButton.style.backgroundColor = '#333'; - this.startButton.style.color = '#777'; + this.startButton.style.backgroundColor = red; + this.startButton.style.color = 'white'; + this.startButton.style.opacity = '0.6'; this.startButton.style.cursor = 'not-allowed'; + + if (this.chooseSongBtn) this.chooseSongBtn.style.backgroundColor = orange; + } + + if (this.loadPosterBtn) { + this.loadPosterBtn.style.backgroundColor = state.posterImage ? green : orange; + } + if (state.loadTapeButton) { + state.loadTapeButton.style.backgroundColor = (state.videoUrls && state.videoUrls.length > 0) ? green : orange; } // Update Tape List @@ -356,10 +415,10 @@ export class ConfigUI extends SceneFeature { } onPartyStart() { - if (this.container) this.container.style.display = 'none'; + this.containers.forEach(c => c.style.display = 'none'); } onPartyEnd() { - if (this.container) this.container.style.display = 'flex'; + this.containers.forEach(c => c.style.display = 'flex'); } } \ No newline at end of file diff --git a/party-stage/src/scene/music-player.js b/party-stage/src/scene/music-player.js index 0286d13..e19a92a 100644 --- a/party-stage/src/scene/music-player.js +++ b/party-stage/src/scene/music-player.js @@ -77,10 +77,12 @@ export class MusicPlayer extends SceneFeature { startSequence() { const uiContainer = document.getElementById('ui-container'); - const configUI = document.getElementById('config-ui'); + const configUILeft = document.getElementById('config-ui-left'); + const configUIRight = document.getElementById('config-ui-right'); if (uiContainer) uiContainer.style.display = 'none'; - if (configUI) configUI.style.display = 'none'; + if (configUILeft) configUILeft.style.display = 'none'; + if (configUIRight) configUIRight.style.display = 'none'; if (state.loadTapeButton) state.loadTapeButton.classList.add('hidden'); showStandbyScreen();