diff --git a/src/main.js b/src/main.js index df17aa5..2176932 100644 --- a/src/main.js +++ b/src/main.js @@ -2098,63 +2098,158 @@ function renderWorldInfoList(entries) { // Add new World Info entry async function handleAddWorldInfoEntry() { - const keys = prompt('Enter keywords (comma-separated):\nExample: John, John Smith'); - if (!keys) return; + const listContainer = document.getElementById('worldinfo-list'); - const content = prompt('Enter the content to inject when keywords are found:'); - if (!content) return; + // Check if form already exists + if (document.getElementById('worldinfo-add-form')) return; - const priorityStr = prompt('Enter priority (higher = injected first, default 0):', '0'); - const priority = parseInt(priorityStr) || 0; + // Create inline form + const formDiv = document.createElement('div'); + formDiv.id = 'worldinfo-add-form'; + formDiv.className = 'worldinfo-entry worldinfo-edit-form'; - try { - const keysArray = keys.split(',').map(k => k.trim()).filter(k => k); - await invoke('add_world_info_entry', { - characterId: currentCharacter.id, - keys: keysArray, - content: content.trim(), - priority, - caseSensitive: false - }); + formDiv.innerHTML = ` +
+
Add World Info Entry
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ `; - // Reload settings - await loadRoleplaySettings(); - } catch (error) { - console.error('Failed to add World Info entry:', error); - alert(`Failed to add entry: ${error}`); - } + listContainer.prepend(formDiv); + + // Focus first input + document.getElementById('wi-add-keys').focus(); + + // Handle cancel + document.getElementById('wi-add-cancel').addEventListener('click', () => { + formDiv.remove(); + }); + + // Handle save + document.getElementById('wi-add-save').addEventListener('click', async () => { + const keys = document.getElementById('wi-add-keys').value.trim(); + const content = document.getElementById('wi-add-content').value.trim(); + const priority = parseInt(document.getElementById('wi-add-priority').value) || 0; + + if (!keys || !content) { + alert('Keywords and content are required'); + return; + } + + try { + const keysArray = keys.split(',').map(k => k.trim()).filter(k => k); + await invoke('add_world_info_entry', { + characterId: currentCharacter.id, + keys: keysArray, + content: content, + priority, + caseSensitive: false + }); + + formDiv.remove(); + await loadRoleplaySettings(); + } catch (error) { + console.error('Failed to add World Info entry:', error); + alert(`Failed to add entry: ${error}`); + } + }); } // Edit World Info entry async function handleEditWorldInfoEntry(entry) { - const keys = prompt('Edit keywords (comma-separated):', entry.keys.join(', ')); - if (keys === null) return; + const entryDiv = document.querySelector(`.worldinfo-entry[data-entry-id="${entry.id}"]`); + if (!entryDiv) return; - const content = prompt('Edit content:', entry.content); - if (content === null) return; + // Check if already editing + if (entryDiv.querySelector('.worldinfo-inline-edit')) return; - const priorityStr = prompt('Edit priority:', entry.priority.toString()); - if (priorityStr === null) return; - const priority = parseInt(priorityStr) || 0; + // Hide normal content + const header = entryDiv.querySelector('.worldinfo-entry-header'); + const content = entryDiv.querySelector('.worldinfo-entry-content'); + header.style.display = 'none'; + content.style.display = 'none'; - try { - const keysArray = keys.split(',').map(k => k.trim()).filter(k => k); - await invoke('update_world_info_entry', { - characterId: currentCharacter.id, - entryId: entry.id, - keys: keysArray, - content: content.trim(), - enabled: entry.enabled, - priority, - caseSensitive: entry.case_sensitive - }); + // Create inline edit form + const editForm = document.createElement('div'); + editForm.className = 'worldinfo-inline-edit'; + editForm.innerHTML = ` +
+
Edit Entry
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ `; - // Reload settings - await loadRoleplaySettings(); - } catch (error) { - console.error('Failed to update World Info entry:', error); - alert(`Failed to update entry: ${error}`); - } + entryDiv.appendChild(editForm); + + // Focus first input + editForm.querySelector('.wi-edit-keys').focus(); + + // Handle cancel + editForm.querySelector('.wi-edit-cancel').addEventListener('click', () => { + header.style.display = ''; + content.style.display = ''; + editForm.remove(); + }); + + // Handle save + editForm.querySelector('.wi-edit-save').addEventListener('click', async () => { + const keys = editForm.querySelector('.wi-edit-keys').value.trim(); + const contentText = editForm.querySelector('.wi-edit-content').value.trim(); + const priority = parseInt(editForm.querySelector('.wi-edit-priority').value) || 0; + + if (!keys || !contentText) { + alert('Keywords and content are required'); + return; + } + + try { + const keysArray = keys.split(',').map(k => k.trim()).filter(k => k); + await invoke('update_world_info_entry', { + characterId: currentCharacter.id, + entryId: entry.id, + keys: keysArray, + content: contentText, + enabled: entry.enabled, + priority, + caseSensitive: entry.case_sensitive + }); + + await loadRoleplaySettings(); + } catch (error) { + console.error('Failed to update World Info entry:', error); + alert(`Failed to update entry: ${error}`); + } + }); } // Toggle World Info entry enabled state @@ -2781,45 +2876,147 @@ function renderInstructionBlocks(instructions, isReadOnly) { function addInstructionBlock() { if (!currentEditingPreset) return; - const name = prompt('Enter instruction block name:'); - if (!name || !name.trim()) return; + const listContainer = document.getElementById('preset-instructions-list'); - const content = prompt('Enter instruction block content:'); - if (!content || !content.trim()) return; + // Check if form already exists + if (document.getElementById('instruction-add-form')) return; - // Generate ID and determine order - const id = `inst_${Date.now()}`; - const maxOrder = currentEditingPreset.instructions.length > 0 - ? Math.max(...currentEditingPreset.instructions.map(i => i.order)) - : 0; + // Create inline form + const formDiv = document.createElement('div'); + formDiv.id = 'instruction-add-form'; + formDiv.style.background = 'var(--bg-secondary)'; + formDiv.style.border = '2px solid var(--accent)'; + formDiv.style.borderRadius = '6px'; + formDiv.style.padding = '12px'; + formDiv.style.marginBottom = '8px'; - const newInstruction = { - id, - name: name.trim(), - content: content.trim(), - enabled: true, - order: maxOrder + 1 - }; + formDiv.innerHTML = ` +
+
Add Instruction Block
+
+ + +
+
+ + +
+
+ + +
+
+ `; - currentEditingPreset.instructions.push(newInstruction); + listContainer.prepend(formDiv); + document.getElementById('inst-add-name').focus(); - // Re-render - renderInstructionBlocks(currentEditingPreset.instructions, false); + // Handle cancel + document.getElementById('inst-add-cancel').addEventListener('click', () => { + formDiv.remove(); + }); + + // Handle save + document.getElementById('inst-add-save').addEventListener('click', () => { + const name = document.getElementById('inst-add-name').value.trim(); + const content = document.getElementById('inst-add-content').value.trim(); + + if (!name || !content) { + alert('Name and content are required'); + return; + } + + // Generate ID and determine order + const id = `inst_${Date.now()}`; + const maxOrder = currentEditingPreset.instructions.length > 0 + ? Math.max(...currentEditingPreset.instructions.map(i => i.order)) + : 0; + + const newInstruction = { + id, + name, + content, + enabled: true, + order: maxOrder + 1 + }; + + currentEditingPreset.instructions.push(newInstruction); + formDiv.remove(); + + // Re-render + renderInstructionBlocks(currentEditingPreset.instructions, false); + }); } // Edit instruction block function editInstruction(instruction) { - const newName = prompt('Edit instruction block name:', instruction.name); - if (newName === null) return; + // Find the instruction block div + const listContainer = document.getElementById('preset-instructions-list'); + const blocks = Array.from(listContainer.children); + const blockDiv = blocks.find(el => { + const header = el.querySelector('[style*="cursor: pointer"]'); + return header && header.textContent.includes(instruction.name); + }); - const newContent = prompt('Edit instruction block content:', instruction.content); - if (newContent === null) return; + if (!blockDiv) return; - instruction.name = newName.trim(); - instruction.content = newContent.trim(); + // Check if already editing + if (blockDiv.querySelector('.instruction-edit-form')) return; - // Re-render - renderInstructionBlocks(currentEditingPreset.instructions, false); + // Hide original content + const header = blockDiv.querySelector('[style*="cursor: pointer"]'); + const content = blockDiv.querySelector('.instruction-content'); + header.style.display = 'none'; + content.style.display = 'none'; + + // Create edit form + const editForm = document.createElement('div'); + editForm.className = 'instruction-edit-form'; + editForm.style.padding = '8px'; + editForm.innerHTML = ` +
+
Edit Instruction Block
+
+ + +
+
+ + +
+
+ + +
+
+ `; + + blockDiv.appendChild(editForm); + editForm.querySelector('.inst-edit-name').focus(); + + // Handle cancel + editForm.querySelector('.inst-edit-cancel').addEventListener('click', () => { + header.style.display = ''; + content.style.display = ''; + editForm.remove(); + }); + + // Handle save + editForm.querySelector('.inst-edit-save').addEventListener('click', () => { + const newName = editForm.querySelector('.inst-edit-name').value.trim(); + const newContent = editForm.querySelector('.inst-edit-content').value.trim(); + + if (!newName || !newContent) { + alert('Name and content are required'); + return; + } + + instruction.name = newName; + instruction.content = newContent; + + // Re-render + renderInstructionBlocks(currentEditingPreset.instructions, false); + }); } // Delete instruction block diff --git a/src/styles.css b/src/styles.css index 6632844..8813ad3 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1855,6 +1855,41 @@ body.view-comfortable .message-content pre { word-wrap: break-word; } +.worldinfo-edit-form, +.worldinfo-inline-edit { + background: var(--bg-secondary); + border: 2px solid var(--accent); + border-radius: 8px; + padding: 16px; +} + +.worldinfo-edit-form input, +.worldinfo-edit-form textarea, +.worldinfo-inline-edit input, +.worldinfo-inline-edit textarea { + background: var(--bg-tertiary); + border: 1px solid var(--border); + border-radius: 6px; + padding: 8px; + color: var(--text-primary); + font-size: 13px; + font-family: inherit; +} + +.worldinfo-edit-form input:focus, +.worldinfo-edit-form textarea:focus, +.worldinfo-inline-edit input:focus, +.worldinfo-inline-edit textarea:focus { + outline: none; + border-color: var(--accent); +} + +.worldinfo-edit-form textarea, +.worldinfo-inline-edit textarea { + resize: vertical; + min-height: 80px; +} + .header-left-controls { display: flex; gap: 8px;