Feature: config UI split across Schedule and Venue panels

This commit is contained in:
Dejvino 2026-01-04 06:17:57 +00:00
parent 03474298a9
commit 066fcc26cc
2 changed files with 85 additions and 24 deletions

View File

@ -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');
}
}

View File

@ -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();