feat: add active features indicator badges in header
Add visual badges in header showing which roleplay features are currently active: - World Info: Shows count of enabled entries (e.g., "WI: 3") - Persona: Shows persona name when enabled - Preset: Shows active preset name - Examples: Shows when message examples are enabled - Author's Note: Shows when author's note is enabled (displays as "A/N") Badges update dynamically when features are toggled, providing at-a-glance visibility of active roleplay features without opening the Roleplay Tools panel. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
3631
CELIA 3.8.json
Normal file
3631
CELIA 3.8.json
Normal file
File diff suppressed because one or more lines are too long
@@ -26,6 +26,9 @@
|
|||||||
<div class="avatar-circle"></div>
|
<div class="avatar-circle"></div>
|
||||||
<span id="character-header-name"></span>
|
<span id="character-header-name"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="feature-badges" class="feature-badges">
|
||||||
|
<!-- Feature badges will be added here dynamically -->
|
||||||
|
</div>
|
||||||
<div class="character-controls">
|
<div class="character-controls">
|
||||||
<div class="select-wrapper">
|
<div class="select-wrapper">
|
||||||
<select id="character-select" class="character-select"></select>
|
<select id="character-select" class="character-select"></select>
|
||||||
|
|||||||
124
src/main.js
124
src/main.js
@@ -2082,11 +2082,101 @@ async function loadRoleplaySettings() {
|
|||||||
|
|
||||||
// Load Presets
|
// Load Presets
|
||||||
await loadPresets();
|
await loadPresets();
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to load roleplay settings:', error);
|
console.error('Failed to load roleplay settings:', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update feature badges in header
|
||||||
|
function updateFeatureBadges() {
|
||||||
|
const badgesContainer = document.getElementById('feature-badges');
|
||||||
|
if (!badgesContainer || !currentRoleplaySettings) {
|
||||||
|
if (badgesContainer) badgesContainer.innerHTML = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
badgesContainer.innerHTML = '';
|
||||||
|
|
||||||
|
// World Info badge - show count of enabled entries
|
||||||
|
const worldInfoEntries = (currentRoleplaySettings.world_info || []).filter(entry => entry.enabled);
|
||||||
|
if (worldInfoEntries.length > 0) {
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.className = 'feature-badge';
|
||||||
|
badge.title = `${worldInfoEntries.length} World Info ${worldInfoEntries.length === 1 ? 'entry' : 'entries'} active`;
|
||||||
|
badge.innerHTML = `
|
||||||
|
<svg class="feature-badge-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M2 4h12M2 8h12M2 12h8" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>WI: <span class="feature-badge-count">${worldInfoEntries.length}</span></span>
|
||||||
|
`;
|
||||||
|
badgesContainer.appendChild(badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Persona badge
|
||||||
|
if (currentRoleplaySettings.persona_enabled && currentRoleplaySettings.persona_name) {
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.className = 'feature-badge';
|
||||||
|
badge.title = `Persona: ${currentRoleplaySettings.persona_name}`;
|
||||||
|
badge.innerHTML = `
|
||||||
|
<svg class="feature-badge-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<circle cx="8" cy="5" r="2.5" stroke="currentColor" stroke-width="1.5"/>
|
||||||
|
<path d="M3 13c0-2.5 2-4 5-4s5 1.5 5 4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>${currentRoleplaySettings.persona_name}</span>
|
||||||
|
`;
|
||||||
|
badgesContainer.appendChild(badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preset badge
|
||||||
|
const presetSelect = document.getElementById('preset-select');
|
||||||
|
if (presetSelect && presetSelect.value) {
|
||||||
|
const presetName = presetSelect.options[presetSelect.selectedIndex]?.text || presetSelect.value;
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.className = 'feature-badge';
|
||||||
|
badge.title = `Active Preset: ${presetName}`;
|
||||||
|
badge.innerHTML = `
|
||||||
|
<svg class="feature-badge-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<rect x="3" y="3" width="10" height="10" rx="1" stroke="currentColor" stroke-width="1.5"/>
|
||||||
|
<path d="M6 7h4M6 9h4" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>${presetName}</span>
|
||||||
|
`;
|
||||||
|
badgesContainer.appendChild(badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Message Examples badge
|
||||||
|
if (currentRoleplaySettings.examples_enabled) {
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.className = 'feature-badge';
|
||||||
|
badge.title = 'Message Examples enabled';
|
||||||
|
badge.innerHTML = `
|
||||||
|
<svg class="feature-badge-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M3 6l2 2-2 2M7 10h5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>Examples</span>
|
||||||
|
`;
|
||||||
|
badgesContainer.appendChild(badge);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Author's Note badge
|
||||||
|
if (currentRoleplaySettings.authors_note_enabled && currentRoleplaySettings.authors_note) {
|
||||||
|
const badge = document.createElement('div');
|
||||||
|
badge.className = 'feature-badge';
|
||||||
|
badge.title = "Author's Note enabled";
|
||||||
|
badge.innerHTML = `
|
||||||
|
<svg class="feature-badge-icon" viewBox="0 0 16 16" fill="none">
|
||||||
|
<path d="M3 3h10v10H3z" stroke="currentColor" stroke-width="1.5" stroke-linejoin="round"/>
|
||||||
|
<path d="M6 6h4M6 9h3" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<span>A/N</span>
|
||||||
|
`;
|
||||||
|
badgesContainer.appendChild(badge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Render World Info entries
|
// Render World Info entries
|
||||||
function renderWorldInfoList(entries) {
|
function renderWorldInfoList(entries) {
|
||||||
const listContainer = document.getElementById('worldinfo-list');
|
const listContainer = document.getElementById('worldinfo-list');
|
||||||
@@ -2334,6 +2424,9 @@ async function handleToggleWorldInfoEntry(entryId, enabled) {
|
|||||||
|
|
||||||
// Update local settings
|
// Update local settings
|
||||||
entry.enabled = enabled;
|
entry.enabled = enabled;
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to toggle World Info entry:', error);
|
console.error('Failed to toggle World Info entry:', error);
|
||||||
alert(`Failed to toggle entry: ${error}`);
|
alert(`Failed to toggle entry: ${error}`);
|
||||||
@@ -2372,6 +2465,15 @@ async function handleSaveAuthorsNote() {
|
|||||||
enabled
|
enabled
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update currentRoleplaySettings
|
||||||
|
if (currentRoleplaySettings) {
|
||||||
|
currentRoleplaySettings.authors_note = content;
|
||||||
|
currentRoleplaySettings.authors_note_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
setStatus('Author\'s Note saved', 'success');
|
setStatus('Author\'s Note saved', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
@@ -2397,6 +2499,16 @@ async function handleSavePersona() {
|
|||||||
enabled
|
enabled
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update currentRoleplaySettings
|
||||||
|
if (currentRoleplaySettings) {
|
||||||
|
currentRoleplaySettings.persona_name = name;
|
||||||
|
currentRoleplaySettings.persona_description = description;
|
||||||
|
currentRoleplaySettings.persona_enabled = enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
setStatus('Persona saved', 'success');
|
setStatus('Persona saved', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
@@ -2420,6 +2532,15 @@ async function handleSaveExamples() {
|
|||||||
position
|
position
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Update currentRoleplaySettings
|
||||||
|
if (currentRoleplaySettings) {
|
||||||
|
currentRoleplaySettings.examples_enabled = enabled;
|
||||||
|
currentRoleplaySettings.examples_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
|
|
||||||
// Show success message
|
// Show success message
|
||||||
setStatus('Message Examples settings saved', 'success');
|
setStatus('Message Examples settings saved', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
@@ -2605,6 +2726,9 @@ async function handleApplyPreset() {
|
|||||||
currentRoleplaySettings.active_preset_id = presetId;
|
currentRoleplaySettings.active_preset_id = presetId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update feature badges
|
||||||
|
updateFeatureBadges();
|
||||||
|
|
||||||
setStatus(presetId ? 'Preset applied' : 'Preset removed', 'success');
|
setStatus(presetId ? 'Preset applied' : 'Preset removed', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -172,6 +172,45 @@ body {
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Feature Badges */
|
||||||
|
.feature-badges {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 6px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
padding: 3px 8px;
|
||||||
|
background: rgba(99, 102, 241, 0.1);
|
||||||
|
border: 1px solid rgba(99, 102, 241, 0.3);
|
||||||
|
border-radius: 12px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: var(--accent);
|
||||||
|
white-space: nowrap;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-badge:hover {
|
||||||
|
background: rgba(99, 102, 241, 0.15);
|
||||||
|
border-color: rgba(99, 102, 241, 0.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-badge-icon {
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-badge-count {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--accent);
|
||||||
|
}
|
||||||
|
|
||||||
.icon-btn {
|
.icon-btn {
|
||||||
width: 28px;
|
width: 28px;
|
||||||
height: 28px;
|
height: 28px;
|
||||||
|
|||||||
Reference in New Issue
Block a user