diff --git a/static/js/notes.js b/static/js/notes.js index cf9886439..aa854078c 100644 --- a/static/js/notes.js +++ b/static/js/notes.js @@ -1835,6 +1835,9 @@ function _renderNotes() { + @@ -2518,6 +2521,85 @@ function _bindCardEvents(body) { }); }); + function _startChecklistItemEdit(noteId, idx, span) { + if (span.isContentEditable) return; + const note = _notes.find(n => n.id === noteId); + if (!note || !Array.isArray(note.items) || !note.items[idx]) return; + + span.textContent = note.items[idx].text || ''; + span.contentEditable = "true"; + span.spellcheck = false; + span.focus(); + + const selection = window.getSelection(); + const range = document.createRange(); + range.selectNodeContents(span); + selection.removeAllRanges(); + selection.addRange(range); + + const save = () => { + if (!span.isContentEditable) return; + span.contentEditable = "false"; + const newText = span.textContent.trim(); + const oldText = (note.items[idx].text || '').trim(); + + if (newText === oldText) { + _renderNotes(); + return; + } + + const oldItem = note.items[idx]; + if (!newText) { + note.items.splice(idx, 1); + } else { + note.items[idx].text = newText; + } + + _patchNote(noteId, { items: note.items }).catch(() => { + if (!newText) note.items.splice(idx, 0, oldItem); + else note.items[idx].text = oldText; + _renderNotes(); + uiModule.showError('Failed to update item'); + }); + _renderNotes(); + }; + + const onKeydown = (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + save(); + } else if (e.key === 'Escape') { + e.preventDefault(); + span.contentEditable = "false"; + _renderNotes(); + } + }; + + span.addEventListener('blur', save, { once: true }); + span.addEventListener('keydown', onKeydown); + } + + // Edit a single checklist item (hover Edit button) + body.querySelectorAll('.note-checkbox-edit').forEach(btn => { + btn.addEventListener('click', (e) => { + e.stopPropagation(); + if (_selectMode) return; + const noteId = btn.dataset.noteId; + const idx = parseInt(btn.dataset.idx); + const span = btn.parentElement.querySelector('.note-check-text'); + if (span) _startChecklistItemEdit(noteId, idx, span); + }); + }); + + // Prevent clicks from toggling the row while actively editing inline + body.querySelectorAll('.note-check-text').forEach(span => { + span.addEventListener('click', (e) => { + if (span.isContentEditable) { + e.stopPropagation(); + } + }); + }); + // Per-item agent solve (hover button next to the X). Scoped to one todo // item — uses the note title as context if present, but only the single // item's text as the work. Mirrors the per-note _agentSolveNote pattern. diff --git a/static/style.css b/static/style.css index 3af43307e..99bedacf9 100644 --- a/static/style.css +++ b/static/style.css @@ -34117,7 +34117,7 @@ body.notes-mobile-mode.notes-drag-mode .note-card-pin.active { word-break: break-all; } .note-link:hover { opacity: 0.8; } -.note-checkbox-rm { +.note-checkbox-edit, .note-checkbox-rm { flex: 0 0 auto; background: transparent; border: none; @@ -34129,13 +34129,25 @@ body.notes-mobile-mode.notes-drag-mode .note-card-pin.active { display: flex; align-items: center; justify-content: center; - margin-left: auto; - margin-right: 0; + margin-left: 2px; transition: opacity 0.12s, background 0.12s, color 0.12s; } +.note-checkbox-rm { margin-left: auto; } +.note-checkbox-edit { margin-left: auto; } +.note-checkbox:hover .note-checkbox-edit, .note-checkbox:hover .note-checkbox-rm { opacity: 0.55; } .note-checkbox-rm:hover { opacity: 1 !important; color: var(--red); background: color-mix(in srgb, var(--red) 12%, transparent); } +.note-checkbox-edit:hover { opacity: 1 !important; color: var(--accent, var(--blue)); background: color-mix(in srgb, var(--accent, var(--blue)) 12%, transparent); } +.note-card-selectmode .note-checkbox-edit, .note-card-selectmode .note-checkbox-rm { display: none; } +.note-check-text[contenteditable="true"] { + background: color-mix(in srgb, var(--fg) 8%, transparent); + outline: 1px solid var(--accent, var(--blue)); + border-radius: 2px; + cursor: text; + padding: 0 2px; + margin: 0 -2px; +} .note-check-dot { width: 16px; height: 16px;