Add show theme feature for themed episodes

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-17 23:46:48 -06:00
parent 7e2ef1fa2b
commit d33a022676
4 changed files with 167 additions and 1 deletions
+63
View File
@@ -113,6 +113,69 @@ header button:hover {
border-color: rgba(232, 121, 29, 0.3);
}
.theme-bar {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 12px;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
}
.theme-label {
font-size: 0.8rem;
color: #aaa;
white-space: nowrap;
}
.theme-input {
background: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.15);
border-radius: 4px;
color: #fff;
padding: 4px 8px;
font-size: 0.85rem;
width: 200px;
}
.theme-input:focus {
outline: none;
border-color: #f5a623;
}
.theme-input.active {
border-color: #f5a623;
background: rgba(245, 166, 35, 0.1);
}
.theme-btn {
padding: 4px 10px;
border-radius: 4px;
border: none;
cursor: pointer;
font-size: 0.8rem;
}
.theme-btn.set {
background: #f5a623;
color: #000;
}
.theme-btn.set:hover {
background: #e6991a;
}
.theme-btn.clear {
background: rgba(255, 255, 255, 0.1);
color: #aaa;
padding: 4px 6px;
}
.theme-btn.clear:hover {
background: rgba(255, 80, 80, 0.3);
color: #ff5050;
}
.on-air-btn {
font-weight: 700;
text-transform: uppercase;
+6
View File
@@ -17,6 +17,12 @@
<button id="export-session-btn">Export</button>
<button id="settings-btn">Settings</button>
</div>
<div class="theme-bar">
<label for="show-theme-input" class="theme-label">Theme:</label>
<input type="text" id="show-theme-input" class="theme-input" placeholder="e.g. St. Patrick's Day" maxlength="100">
<button id="set-theme-btn" class="theme-btn set" title="Set show theme">Set</button>
<button id="clear-theme-btn" class="theme-btn clear hidden" title="Clear theme">&#x2715;</button>
</div>
<div id="show-clock" class="show-clock">
<span class="clock-time" id="clock-time"></span>
<span id="show-timers" class="show-timers hidden">
+72
View File
@@ -130,6 +130,7 @@ document.addEventListener('DOMContentLoaded', async () => {
await loadSettings();
initEventListeners();
initClock();
loadShowTheme();
loadVoicemails();
setInterval(loadVoicemails, 30000);
loadEmails();
@@ -345,6 +346,13 @@ function initEventListeners() {
document.getElementById('devon-play-btn')?.addEventListener('click', playDevonSuggestion);
document.getElementById('devon-dismiss-btn')?.addEventListener('click', dismissDevonSuggestion);
// Show Theme
document.getElementById('set-theme-btn')?.addEventListener('click', setShowTheme);
document.getElementById('clear-theme-btn')?.addEventListener('click', clearShowTheme);
document.getElementById('show-theme-input')?.addEventListener('keydown', (e) => {
if (e.key === 'Enter') setShowTheme();
});
// Settings
document.getElementById('settings-btn')?.addEventListener('click', async () => {
document.getElementById('settings-modal')?.classList.remove('hidden');
@@ -692,6 +700,7 @@ async function newSession() {
// Reload callers to get new session ID
await loadCallers();
await loadShowTheme();
log('New session started - all callers have fresh backgrounds');
}
@@ -1159,6 +1168,69 @@ async function playSFX(soundFile) {
}
// --- Show Theme ---
async function loadShowTheme() {
try {
const res = await fetch('/api/show-theme');
const data = await res.json();
const input = document.getElementById('show-theme-input');
const setBtn = document.getElementById('set-theme-btn');
const clearBtn = document.getElementById('clear-theme-btn');
if (data.theme) {
input.value = data.theme;
input.classList.add('active');
setBtn.classList.add('hidden');
clearBtn.classList.remove('hidden');
} else {
input.value = '';
input.classList.remove('active');
setBtn.classList.remove('hidden');
clearBtn.classList.add('hidden');
}
} catch (e) {
console.error('Failed to load show theme:', e);
}
}
async function setShowTheme() {
const input = document.getElementById('show-theme-input');
const theme = input.value.trim();
if (!theme) return;
try {
const res = await fetch('/api/show-theme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme })
});
const data = await res.json();
if (data.theme) {
input.classList.add('active');
document.getElementById('set-theme-btn').classList.add('hidden');
document.getElementById('clear-theme-btn').classList.remove('hidden');
}
} catch (e) {
console.error('Failed to set show theme:', e);
}
}
async function clearShowTheme() {
try {
await fetch('/api/show-theme', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ theme: '' })
});
const input = document.getElementById('show-theme-input');
input.value = '';
input.classList.remove('active');
document.getElementById('set-theme-btn').classList.remove('hidden');
document.getElementById('clear-theme-btn').classList.add('hidden');
} catch (e) {
console.error('Failed to clear show theme:', e);
}
}
// --- Settings ---
async function loadSettings() {
try {