feat: replace preset prompts with inline forms
Replace popup dialogs with themed inline forms for preset creation and duplication. Both operations now use consistent UI styling with proper theme colors, validation, and cancel/save workflows. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
120
src/main.js
120
src/main.js
@@ -2554,14 +2554,66 @@ async function handleApplyPreset() {
|
|||||||
|
|
||||||
// Create custom preset
|
// Create custom preset
|
||||||
async function handleCreatePreset() {
|
async function handleCreatePreset() {
|
||||||
const name = prompt('Enter a name for your custom preset:');
|
// Check if form already exists
|
||||||
if (!name || !name.trim()) return;
|
if (document.getElementById('preset-create-form')) return;
|
||||||
|
|
||||||
const description = prompt('Enter a description for your preset:');
|
const container = document.getElementById('presets-tab').querySelector('.roleplay-content');
|
||||||
if (!description || !description.trim()) return;
|
const createBtn = document.getElementById('create-preset-btn');
|
||||||
|
|
||||||
const systemAdditions = prompt('Enter system additions (press Cancel to skip):', '');
|
// Create inline form
|
||||||
const authorsNoteDefault = prompt('Enter default Author\'s Note (press Cancel to skip):', '');
|
const formDiv = document.createElement('div');
|
||||||
|
formDiv.id = 'preset-create-form';
|
||||||
|
formDiv.style.background = 'var(--bg-secondary)';
|
||||||
|
formDiv.style.border = '2px solid var(--accent)';
|
||||||
|
formDiv.style.borderRadius = '8px';
|
||||||
|
formDiv.style.padding = '16px';
|
||||||
|
formDiv.style.marginBottom = '16px';
|
||||||
|
|
||||||
|
formDiv.innerHTML = `
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||||
|
<div style="font-weight: 600; color: var(--text-primary); margin-bottom: 4px;">Create Custom Preset</div>
|
||||||
|
<div>
|
||||||
|
<label style="font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px;">Name *</label>
|
||||||
|
<input type="text" id="preset-create-name" placeholder="My Custom Preset" style="width: 100%;" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label style="font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px;">Description *</label>
|
||||||
|
<textarea id="preset-create-desc" placeholder="What this preset does..." rows="3" style="width: 100%;"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label style="font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px;">System Additions (optional)</label>
|
||||||
|
<textarea id="preset-create-system" placeholder="Additional text to prepend to system prompt..." rows="3" style="width: 100%;"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label style="font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px;">Default Author's Note (optional)</label>
|
||||||
|
<textarea id="preset-create-note" placeholder="Default Author's Note if user hasn't set one..." rows="3" style="width: 100%;"></textarea>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: 8px; justify-content: flex-end;">
|
||||||
|
<button type="button" class="worldinfo-btn" id="preset-create-cancel">Cancel</button>
|
||||||
|
<button type="button" class="worldinfo-btn" id="preset-create-save" style="background: var(--accent); color: white;">Create</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
container.insertBefore(formDiv, createBtn);
|
||||||
|
document.getElementById('preset-create-name').focus();
|
||||||
|
|
||||||
|
// Handle cancel
|
||||||
|
document.getElementById('preset-create-cancel').addEventListener('click', () => {
|
||||||
|
formDiv.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle save
|
||||||
|
document.getElementById('preset-create-save').addEventListener('click', async () => {
|
||||||
|
const name = document.getElementById('preset-create-name').value.trim();
|
||||||
|
const description = document.getElementById('preset-create-desc').value.trim();
|
||||||
|
const systemAdditions = document.getElementById('preset-create-system').value.trim();
|
||||||
|
const authorsNoteDefault = document.getElementById('preset-create-note').value.trim();
|
||||||
|
|
||||||
|
if (!name || !description) {
|
||||||
|
alert('Name and description are required');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Generate a simple ID from the name
|
// Generate a simple ID from the name
|
||||||
@@ -2569,8 +2621,8 @@ async function handleCreatePreset() {
|
|||||||
|
|
||||||
const preset = {
|
const preset = {
|
||||||
id: id,
|
id: id,
|
||||||
name: name.trim(),
|
name,
|
||||||
description: description.trim(),
|
description,
|
||||||
system_additions: systemAdditions || '',
|
system_additions: systemAdditions || '',
|
||||||
authors_note_default: authorsNoteDefault || '',
|
authors_note_default: authorsNoteDefault || '',
|
||||||
instructions: [],
|
instructions: [],
|
||||||
@@ -2583,6 +2635,7 @@ async function handleCreatePreset() {
|
|||||||
|
|
||||||
await invoke('save_custom_preset', { preset });
|
await invoke('save_custom_preset', { preset });
|
||||||
|
|
||||||
|
formDiv.remove();
|
||||||
setStatus('Custom preset created', 'success');
|
setStatus('Custom preset created', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
|
|
||||||
@@ -2598,6 +2651,7 @@ async function handleCreatePreset() {
|
|||||||
setStatus('Failed to create preset', 'error');
|
setStatus('Failed to create preset', 'error');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render instruction blocks list
|
// Render instruction blocks list
|
||||||
@@ -3118,18 +3172,61 @@ async function deletePreset() {
|
|||||||
async function duplicatePreset() {
|
async function duplicatePreset() {
|
||||||
if (!currentEditingPreset) return;
|
if (!currentEditingPreset) return;
|
||||||
|
|
||||||
const newName = prompt(`Enter a name for the duplicated preset:`, `${currentEditingPreset.name} (Copy)`);
|
// Check if form already exists
|
||||||
if (!newName || !newName.trim()) return;
|
if (document.getElementById('preset-duplicate-form')) return;
|
||||||
|
|
||||||
|
const presetInfo = document.getElementById('preset-info');
|
||||||
|
const formDiv = document.createElement('div');
|
||||||
|
formDiv.id = 'preset-duplicate-form';
|
||||||
|
formDiv.style.background = 'var(--bg-secondary)';
|
||||||
|
formDiv.style.border = '2px solid var(--accent)';
|
||||||
|
formDiv.style.borderRadius = '8px';
|
||||||
|
formDiv.style.padding = '16px';
|
||||||
|
formDiv.style.marginBottom = '16px';
|
||||||
|
|
||||||
|
formDiv.innerHTML = `
|
||||||
|
<div style="display: flex; flex-direction: column; gap: 12px;">
|
||||||
|
<div style="font-weight: 600; color: var(--text-primary); margin-bottom: 4px;">Duplicate Preset</div>
|
||||||
|
<div>
|
||||||
|
<label style="font-size: 12px; color: var(--text-secondary); display: block; margin-bottom: 4px;">New Preset Name *</label>
|
||||||
|
<input type="text" id="preset-duplicate-name" placeholder="My Preset (Copy)" value="${currentEditingPreset.name} (Copy)" style="width: 100%;" />
|
||||||
|
</div>
|
||||||
|
<div style="display: flex; gap: 8px; justify-content: flex-end;">
|
||||||
|
<button type="button" class="worldinfo-btn" id="preset-duplicate-cancel">Cancel</button>
|
||||||
|
<button type="button" class="worldinfo-btn" id="preset-duplicate-save" style="background: var(--accent); color: white;">Duplicate</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
presetInfo.parentNode.insertBefore(formDiv, presetInfo.nextSibling);
|
||||||
|
document.getElementById('preset-duplicate-name').focus();
|
||||||
|
document.getElementById('preset-duplicate-name').select();
|
||||||
|
|
||||||
|
// Cancel button
|
||||||
|
document.getElementById('preset-duplicate-cancel').addEventListener('click', () => {
|
||||||
|
formDiv.remove();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Duplicate button
|
||||||
|
document.getElementById('preset-duplicate-save').addEventListener('click', async () => {
|
||||||
|
const newName = document.getElementById('preset-duplicate-name').value.trim();
|
||||||
|
if (!newName) {
|
||||||
|
alert('Please enter a preset name');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const duplicatedPreset = await invoke('duplicate_preset', {
|
const duplicatedPreset = await invoke('duplicate_preset', {
|
||||||
sourcePresetId: currentEditingPreset.id,
|
sourcePresetId: currentEditingPreset.id,
|
||||||
newName: newName.trim()
|
newName: newName
|
||||||
});
|
});
|
||||||
|
|
||||||
setStatus('Preset duplicated successfully', 'success');
|
setStatus('Preset duplicated successfully', 'success');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
|
|
||||||
|
// Remove form
|
||||||
|
formDiv.remove();
|
||||||
|
|
||||||
// Reload presets
|
// Reload presets
|
||||||
await loadPresets();
|
await loadPresets();
|
||||||
|
|
||||||
@@ -3142,6 +3239,7 @@ async function duplicatePreset() {
|
|||||||
setStatus('Failed to duplicate preset', 'error');
|
setStatus('Failed to duplicate preset', 'error');
|
||||||
setTimeout(() => setStatus('Ready'), 2000);
|
setTimeout(() => setStatus('Ready'), 2000);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Restore built-in preset to default
|
// Restore built-in preset to default
|
||||||
|
|||||||
Reference in New Issue
Block a user