diff --git a/public/index.html b/public/index.html index 079f303..4e37aae 100644 --- a/public/index.html +++ b/public/index.html @@ -88,6 +88,34 @@

No persona equipped.

+
diff --git a/public/script.js b/public/script.js index d193919..a174282 100644 --- a/public/script.js +++ b/public/script.js @@ -28,10 +28,6 @@ const personaPronounsInput = document.getElementById("personaPronouns"); const personaAppearanceInput = document.getElementById("personaAppearance"); const personaBackgroundInput = document.getElementById("personaBackground"); const personaDetailsInput = document.getElementById("personaDetails"); -const personaModal = document.getElementById("personaModal"); -const personaCloseBtn = document.getElementById("personaClose"); -const addCustomFieldBtn = document.getElementById("addCustomField"); -const customFieldsList = document.getElementById("customFieldsList"); const newPersonaBtn = document.getElementById("newPersona"); const clearPersonaBtn = document.getElementById("clearPersona"); const personaCancelBtn = document.getElementById("personaCancel"); @@ -198,7 +194,7 @@ function setActivePersonaStatus() { } function openPersonaForm(persona = null) { - personaModal.classList.remove('hidden'); + personaForm.classList.remove('hidden'); if (persona) { editingPersonaId = persona.id; personaFormTitle.textContent = 'Edit persona'; @@ -207,7 +203,6 @@ function openPersonaForm(persona = null) { personaAppearanceInput.value = persona.appearance || ''; personaBackgroundInput.value = persona.background || ''; personaDetailsInput.value = persona.details || ''; - renderCustomFields(persona.customFields || []); } else { editingPersonaId = null; personaFormTitle.textContent = 'Create persona'; @@ -216,60 +211,15 @@ function openPersonaForm(persona = null) { personaAppearanceInput.value = ''; personaBackgroundInput.value = ''; personaDetailsInput.value = ''; - renderCustomFields([]); } personaNameInput.focus(); } function closePersonaForm() { - personaModal.classList.add('hidden'); + personaForm.classList.add('hidden'); editingPersonaId = null; } -function renderCustomFields(fields) { - customFieldsList.innerHTML = ''; - fields.forEach((field, index) => { - addCustomFieldRow(field.label || '', field.value || '', index); - }); -} - -function addCustomFieldRow(label = '', value = '') { - const row = document.createElement('div'); - row.className = 'custom-field-row'; - - const labelInput = document.createElement('input'); - labelInput.type = 'text'; - labelInput.placeholder = 'Label'; - labelInput.value = label; - - const valueInput = document.createElement('input'); - valueInput.type = 'text'; - valueInput.placeholder = 'Value'; - valueInput.value = value; - - const removeBtn = document.createElement('button'); - removeBtn.type = 'button'; - removeBtn.textContent = 'Remove'; - removeBtn.className = 'secondary-action'; - removeBtn.addEventListener('click', () => row.remove()); - - row.appendChild(labelInput); - row.appendChild(valueInput); - row.appendChild(removeBtn); - customFieldsList.appendChild(row); -} - -function collectCustomFields() { - const rows = customFieldsList.querySelectorAll('.custom-field-row'); - return Array.from(rows).map(row => { - const [labelInput, valueInput] = row.querySelectorAll('input'); - return { - label: labelInput.value.trim(), - value: valueInput.value.trim() - }; - }).filter(field => field.label || field.value); -} - function renderPersonaList() { personaList.innerHTML = ''; if (!personas.length) { @@ -321,10 +271,7 @@ function renderPersonaList() { async function loadPersonas() { const res = await get('/personas'); if (res.error) return; - personas = (res.personas || []).map(persona => ({ - ...persona, - customFields: persona.customFields || [] - })); + personas = res.personas || []; activePersonaId = res.activePersonaId || null; renderPersonaList(); } @@ -349,8 +296,7 @@ async function savePersona() { pronouns: personaPronounsInput.value.trim(), appearance: personaAppearanceInput.value.trim(), background: personaBackgroundInput.value.trim(), - details: personaDetailsInput.value.trim(), - customFields: collectCustomFields() + details: personaDetailsInput.value.trim() }; if (!payload.name) return; let res; @@ -374,12 +320,6 @@ async function deletePersona(personaId) { await loadPersonas(); } -document.addEventListener('keydown', (event) => { - if (event.key === 'Escape' && !personaModal.classList.contains('hidden')) { - closePersonaForm(); - } -}); - function setLoadingState(loading) { isProcessing = loading; sendBtn.disabled = loading; @@ -650,16 +590,6 @@ newPersonaBtn.addEventListener('click', () => openPersonaForm()); personaCancelBtn.addEventListener('click', () => closePersonaForm()); -personaCloseBtn.addEventListener('click', () => closePersonaForm()); - -personaModal.addEventListener('click', (event) => { - if (event.target === personaModal) { - closePersonaForm(); - } -}); - -addCustomFieldBtn.addEventListener('click', () => addCustomFieldRow()); - clearPersonaBtn.addEventListener('click', () => clearPersona()); personaForm.addEventListener('submit', (event) => { diff --git a/public/style.css b/public/style.css index 45705bc..1083397 100644 --- a/public/style.css +++ b/public/style.css @@ -461,9 +461,14 @@ button:disabled { .persona-form { display: grid; gap: 10px; - max-height: 65vh; - overflow-y: auto; - padding-right: 6px; + background: rgba(10, 10, 20, 0.75); + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 16px; + padding: 12px; +} + +.persona-form.hidden { + display: none; } .persona-form h3 { @@ -477,83 +482,6 @@ button:disabled { flex-wrap: wrap; } -.modal-overlay { - position: fixed; - inset: 0; - background: rgba(5, 5, 20, 0.75); - display: grid; - place-items: center; - z-index: 1000; - padding: 24px; -} - -.modal-overlay.hidden { - display: none; -} - -.modal-card { - width: min(520px, 92vw); - background: rgba(19, 19, 42, 0.96); - border: 1px solid rgba(255, 255, 255, 0.08); - border-radius: 22px; - padding: 18px; - box-shadow: 0 25px 60px -12px var(--shadow); - display: grid; - gap: 14px; -} - -.modal-header { - display: flex; - align-items: center; - justify-content: space-between; - gap: 12px; -} - -.modal-header h3 { - margin: 0; - font-size: 1.2rem; -} - -.custom-fields { - display: grid; - gap: 10px; - background: rgba(10, 10, 20, 0.6); - border: 1px solid rgba(255, 255, 255, 0.06); - border-radius: 14px; - padding: 10px; -} - -.custom-fields-header { - display: flex; - align-items: center; - justify-content: space-between; - font-size: 0.9rem; - color: var(--text-secondary); -} - -.custom-fields-list { - display: grid; - gap: 8px; -} - -.custom-field-row { - display: grid; - grid-template-columns: 1fr 1fr auto; - gap: 8px; - align-items: center; -} - -.custom-field-row input { - padding: 10px 12px; - font-size: 14px; -} - -.custom-field-row button { - padding: 8px 10px; - font-size: 12px; - border-radius: 10px; -} - .chat-main { display: grid; grid-template-rows: auto 1fr auto auto; diff --git a/server.js b/server.js index e857d43..ec3493c 100644 --- a/server.js +++ b/server.js @@ -171,8 +171,6 @@ db.prepare(` TEXT, details TEXT, - custom_fields - TEXT, created_at DATETIME DEFAULT @@ -274,25 +272,25 @@ const deleteChatMessagesStmt = db.prepare( ); const listPersonasStmt = db.prepare(` - SELECT id, name, pronouns, appearance, background, details, custom_fields, created_at, updated_at + SELECT id, name, pronouns, appearance, background, details, created_at, updated_at FROM personas WHERE username = ? ORDER BY datetime(updated_at) DESC `); const getPersonaStmt = db.prepare(` - SELECT id, name, pronouns, appearance, background, details, custom_fields + SELECT id, name, pronouns, appearance, background, details FROM personas WHERE id = ? AND username = ? `); const insertPersonaStmt = db.prepare( - "INSERT INTO personas (username, name, pronouns, appearance, background, details, custom_fields) VALUES (?, ?, ?, ?, ?, ?, ?)" + "INSERT INTO personas (username, name, pronouns, appearance, background, details) VALUES (?, ?, ?, ?, ?, ?)" ); const updatePersonaStmt = db.prepare(` UPDATE personas - SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, custom_fields = ?, updated_at = CURRENT_TIMESTAMP + SET name = ?, pronouns = ?, appearance = ?, background = ?, details = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? AND username = ? `); @@ -311,7 +309,7 @@ const setActivePersonaStmt = db.prepare(` `); const getActivePersonaStmt = db.prepare(` - SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details, p.custom_fields + SELECT p.id, p.name, p.pronouns, p.appearance, p.background, p.details FROM user_settings us JOIN personas p ON p.id = us.active_persona_id WHERE us.username = ? @@ -389,27 +387,6 @@ const normalizePersonaField = (value) => { return trimmed ? trimmed : null; }; -const normalizeCustomFields = (fields) => { - if (!Array.isArray(fields)) return null; - const cleaned = fields - .map(field => ({ - label: (field?.label || "").trim(), - value: (field?.value || "").trim() - })) - .filter(field => field.label || field.value); - return cleaned.length ? JSON.stringify(cleaned) : null; -}; - -const parseCustomFields = (value) => { - if (!value) return []; - try { - const parsed = JSON.parse(value); - return Array.isArray(parsed) ? parsed : []; - } catch (error) { - return []; - } -}; - const buildPersonaPrompt = (persona) => { const lines = [ "You are roleplaying with the following persona. Stay in character, be engaging, and align with these details." @@ -419,10 +396,6 @@ const buildPersonaPrompt = (persona) => { if (persona.appearance) lines.push(`Appearance: ${persona.appearance}`); if (persona.background) lines.push(`Background: ${persona.background}`); if (persona.details) lines.push(`Details: ${persona.details}`); - const customFields = parseCustomFields(persona.custom_fields); - customFields.forEach(field => { - lines.push(`${field.label || "Custom"}: ${field.value}`); - }); return lines.join("\n"); }; @@ -511,10 +484,7 @@ app.post("/chats/:id/clear", requireLogin, (req, res) => { app.get("/personas", requireLogin, (req, res) => { const user = req.session.user; - const personas = listPersonasStmt.all(user).map(persona => ({ - ...persona, - customFields: parseCustomFields(persona.custom_fields) - })); + const personas = listPersonasStmt.all(user); const activePersonaId = getActivePersonaIdStmt.get(user)?.active_persona_id ?? null; res.json({personas, activePersonaId}); }); @@ -529,23 +499,16 @@ app.post("/personas", requireLogin, (req, res) => { const appearance = normalizePersonaField(req.body?.appearance); const background = normalizePersonaField(req.body?.background); const details = normalizePersonaField(req.body?.details); - const customFields = normalizeCustomFields(req.body?.customFields); const personaId = insertPersonaStmt.run( user, name, pronouns, appearance, background, - details, - customFields + details ).lastInsertRowid; const persona = getPersonaStmt.get(personaId, user); - res.json({ - persona: { - ...persona, - customFields: parseCustomFields(persona.custom_fields) - } - }); + res.json({persona}); }); app.put("/personas/:id", requireLogin, (req, res) => { @@ -559,14 +522,12 @@ app.put("/personas/:id", requireLogin, (req, res) => { const appearance = normalizePersonaField(req.body?.appearance); const background = normalizePersonaField(req.body?.background); const details = normalizePersonaField(req.body?.details); - const customFields = normalizeCustomFields(req.body?.customFields); const result = updatePersonaStmt.run( name, pronouns, appearance, background, details, - customFields, personaId, user ); @@ -574,12 +535,7 @@ app.put("/personas/:id", requireLogin, (req, res) => { return res.status(404).json({error: "Persona not found"}); } const persona = getPersonaStmt.get(personaId, user); - res.json({ - persona: { - ...persona, - customFields: parseCustomFields(persona.custom_fields) - } - }); + res.json({persona}); }); app.delete("/personas/:id", requireLogin, (req, res) => {