feat: make Web UI mood dropdowns Evil Mode-aware

- Disable per-server mood controls when Evil Miku is active
- Show explanatory notice for disabled server mood dropdowns
- Populate global mood dropdown with evil moods when Evil Mode is on
- Fix initialization race condition by awaiting evil mode status first
- Add CSS styles for disabled mood controls
This commit is contained in:
2026-05-18 21:43:44 +03:00
parent 27f0659cc8
commit 7cb21a372b
4 changed files with 112 additions and 28 deletions

View File

@@ -80,13 +80,16 @@ function displayServers() {
<h4 style="margin: 0 0 0.5rem 0; color: #61dafb;">Server Mood</h4>
<div><strong>Current Mood:</strong> ${server.current_mood_name || 'neutral'} ${MOOD_EMOJIS[server.current_mood_name] || ''}</div>
<div><strong>Sleeping:</strong> ${server.is_sleeping ? 'Yes' : 'No'}</div>
<div style="margin-top: 0.5rem;">
<div class="server-mood-controls" style="margin-top: 0.5rem;">
<select id="mood-select-${String(server.guild_id)}" style="margin-right: 0.5rem; padding: 0.3rem; background: #333; color: white; border: 1px solid #555; border-radius: 3px;">
<option value="">Select Mood...</option>
</select>
<button onclick="setServerMood('${String(server.guild_id)}')" style="margin-right: 0.5rem;">Change Mood</button>
<button onclick="resetServerMood('${String(server.guild_id)}')" style="background: #ff9800;">Reset Mood</button>
</div>
<div class="evil-mode-exempt-notice" id="evil-notice-${String(server.guild_id)}" style="display: none;">
⚠️ Per-server moods are unavailable while Evil Miku is active — she applies her global mood everywhere.
</div>
</div>
</div>
`).join('');
@@ -375,7 +378,7 @@ async function repairConfig() {
}
}
// Populate mood dropdowns with available moods
// Populate mood dropdowns with available moods (Evil Mode-aware)
async function populateMoodDropdowns() {
try {
console.log('🎭 Loading available moods...');
@@ -384,17 +387,28 @@ async function populateMoodDropdowns() {
if (data.moods) {
console.log(`🎭 Found ${data.moods.length} moods:`, data.moods);
const emojiMap = evilMode ? EVIL_MOOD_EMOJIS : MOOD_EMOJIS;
// Determine which mood list to use based on evil mode
let moodList = data.moods;
let emojiMap = MOOD_EMOJIS;
let defaultMood = 'neutral';
if (evilMode) {
// Evil Miku uses evil moods for the global DM dropdown
moodList = Object.keys(EVIL_MOOD_EMOJIS);
emojiMap = EVIL_MOOD_EMOJIS;
defaultMood = 'evil_neutral';
}
// Populate the DM mood dropdown (#mood on tab1)
const dmMoodSelect = document.getElementById('mood');
if (dmMoodSelect) {
dmMoodSelect.innerHTML = '';
data.moods.forEach(mood => {
moodList.forEach(mood => {
const opt = document.createElement('option');
opt.value = mood;
opt.textContent = `${emojiMap[mood] || ''} ${mood}`.trim();
if (mood === 'neutral') opt.selected = true;
if (mood === defaultMood) opt.selected = true;
dmMoodSelect.appendChild(opt);
});
}
@@ -403,32 +417,17 @@ async function populateMoodDropdowns() {
const chatMoodSelect = document.getElementById('chat-mood-select');
if (chatMoodSelect) {
chatMoodSelect.innerHTML = '';
data.moods.forEach(mood => {
moodList.forEach(mood => {
const opt = document.createElement('option');
opt.value = mood;
opt.textContent = `${emojiMap[mood] || ''} ${mood}`.trim();
if (mood === 'neutral') opt.selected = true;
if (mood === defaultMood) opt.selected = true;
chatMoodSelect.appendChild(opt);
});
}
// Populate per-server mood dropdowns (mood-select-{guildId})
document.querySelectorAll('[id^="mood-select-"]').forEach(select => {
// Keep only the first option ("Select Mood...")
while (select.children.length > 1) {
select.removeChild(select.lastChild);
}
});
data.moods.forEach(mood => {
const moodOption = document.createElement('option');
moodOption.value = mood;
moodOption.textContent = `${mood} ${emojiMap[mood] || ''}`;
document.querySelectorAll('[id^="mood-select-"]').forEach(select => {
select.appendChild(moodOption.cloneNode(true));
});
});
// Update per-server mood controls based on evil mode state
updatePerServerMoodControls(data.moods, MOOD_EMOJIS);
console.log('🎭 All mood dropdowns populated successfully');
} else {
@@ -439,6 +438,70 @@ async function populateMoodDropdowns() {
}
}
// Update per-server mood controls: enable/disable based on evil mode
function updatePerServerMoodControls(regularMoods, regularEmojiMap) {
const serverSelects = document.querySelectorAll('[id^="mood-select-"]');
if (evilMode) {
// Evil Miku is active — disable per-server mood controls
serverSelects.forEach(select => {
const guildId = select.id.replace('mood-select-', '');
const controlsDiv = select.closest('.server-mood-controls');
const noticeDiv = document.getElementById(`evil-notice-${guildId}`);
// Disable the select
select.disabled = true;
// Disable buttons in the same controls div
if (controlsDiv) {
controlsDiv.querySelectorAll('button').forEach(btn => {
btn.disabled = true;
});
}
// Show the explanation notice
if (noticeDiv) {
noticeDiv.style.display = 'block';
}
});
} else {
// Normal mode — enable per-server mood controls and populate with regular moods
serverSelects.forEach(select => {
const guildId = select.id.replace('mood-select-', '');
const controlsDiv = select.closest('.server-mood-controls');
const noticeDiv = document.getElementById(`evil-notice-${guildId}`);
// Enable the select
select.disabled = false;
// Enable buttons in the same controls div
if (controlsDiv) {
controlsDiv.querySelectorAll('button').forEach(btn => {
btn.disabled = false;
});
}
// Hide the explanation notice
if (noticeDiv) {
noticeDiv.style.display = 'none';
}
// Populate with regular moods
// Keep only the first option ("Select Mood...")
while (select.children.length > 1) {
select.removeChild(select.lastChild);
}
regularMoods.forEach(mood => {
const moodOption = document.createElement('option');
moodOption.value = mood;
moodOption.textContent = `${mood} ${regularEmojiMap[mood] || ''}`;
select.appendChild(moodOption);
});
});
}
}
// Per-Server Mood Management
async function setServerMood(guildId) {
console.log(`🎭 setServerMood called with guildId: ${guildId} (type: ${typeof guildId})`);