Merge dev into main for testing

This commit is contained in:
pewdiepie-archdaemon
2026-06-28 14:07:23 +00:00
236 changed files with 17610 additions and 9212 deletions
+93 -18
View File
@@ -10,7 +10,8 @@ import { attachColorPicker } from './colorPicker.js';
import { makeWindowDraggable } from './windowDrag.js';
import { snapModalToZone } from './tileManager.js';
import { applyEdgeDock, clearDockSide } from './modalSnap.js';
import { topToolWindowZ } from './toolWindowZOrder.js';
import { topToolWindowZ, topPortalZ } from './toolWindowZOrder.js';
import { bindMenuDismiss, dismissOrRemove } from './escMenuStack.js';
const API_BASE = window.location.origin;
let _open = false;
@@ -1834,6 +1835,9 @@ function _renderNotes() {
<button class="note-checkbox-agent${agentDoneClass}" data-note-id="${_attrEsc(note.id)}" data-idx="${i}"${agentSessionAttr} data-agent-title="${_attrEsc(agentMenuTitle)}" title="${_attrEsc(agentTitle)}">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 8V4H8"/><rect x="4" y="8" width="16" height="12" rx="2"/><path d="M2 14h2M20 14h2M15 13v2M9 13v2"/></svg>
</button>
<button class="note-checkbox-edit" data-note-id="${note.id}" data-idx="${i}" title="Edit item">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/></svg>
</button>
<button class="note-checkbox-rm" data-note-id="${note.id}" data-idx="${i}" title="Delete item">
<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>
</button>
@@ -2517,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.
@@ -3364,7 +3447,7 @@ function _buildForm(note = null) {
function _pickCustomDate() {
// Replace the dropdown menu with a small inline picker
document.querySelectorAll('.note-reminder-menu').forEach(m => m.remove());
document.querySelectorAll('.note-reminder-menu').forEach(dismissOrRemove);
const menu = document.createElement('div');
menu.className = 'note-reminder-menu';
const initial = dueInput.value || _toLocalDatetimeStr(_tomorrowDate());
@@ -3398,14 +3481,11 @@ function _buildForm(note = null) {
if (typeof dInput.showPicker === 'function') {
try { dInput.showPicker(); } catch {}
}
const close = bindMenuDismiss(menu, () => { menu.remove(); });
menu.querySelector('.note-reminder-menu-confirm').addEventListener('click', () => {
if (dInput.value) _setReminder(dInput.value);
menu.remove();
close();
});
setTimeout(() => {
const close = (e) => { if (!menu.contains(e.target)) { menu.remove(); document.removeEventListener('click', close); } };
document.addEventListener('click', close);
}, 0);
}
if (remindBtn) remindBtn.addEventListener('click', (e) => { e.stopPropagation(); _openReminderMenu(remindBtn, !!dueInput.value); });
@@ -4315,7 +4395,7 @@ function _serializeNoteForCopy(note) {
// toast. Shared by the corner-copy button click and the Ctrl/Cmd+C shortcut.
// ── ⋯ corner menu (Copy + Agent) ───────────────────────────────────
function _openNoteCornerMenu(btn) {
document.querySelectorAll('.note-corner-menu-dropdown').forEach(d => d.remove());
document.querySelectorAll('.note-corner-menu-dropdown').forEach(dismissOrRemove);
const id = btn.dataset.noteId;
const note = _notes.find(n => n.id === id);
if (!note) return;
@@ -4341,15 +4421,10 @@ function _openNoteCornerMenu(btn) {
const mh = menu.offsetHeight || 96;
const below = window.innerHeight - r.bottom;
const top = (below < mh + 8 && r.top > mh + 8) ? (r.top - mh - 4) : (r.bottom + 4);
menu.style.cssText += `position:fixed;z-index:11000;top:${Math.round(top)}px;left:${Math.round(left)}px;`;
const close = (ev) => {
if (ev && menu.contains(ev.target)) return;
menu.remove();
document.removeEventListener('click', close, true);
};
setTimeout(() => document.addEventListener('click', close, true), 0);
menu.querySelector('[data-act="copy"]').addEventListener('click', () => { menu.remove(); _copyNote(id, btn); });
menu.querySelector('[data-act="agent"]').addEventListener('click', () => { menu.remove(); _agentSolveNote(id); });
menu.style.cssText += `position:fixed;z-index:${topPortalZ()};top:${Math.round(top)}px;left:${Math.round(left)}px;`;
const close = bindMenuDismiss(menu, () => { menu.remove(); });
menu.querySelector('[data-act="copy"]').addEventListener('click', () => { close(); _copyNote(id, btn); });
menu.querySelector('[data-act="agent"]').addEventListener('click', () => { close(); _agentSolveNote(id); });
}
function _positionNoteMenu(menu, btn, width = 196) {
@@ -4360,7 +4435,7 @@ function _positionNoteMenu(menu, btn, width = 196) {
const mh = menu.offsetHeight || 112;
const below = window.innerHeight - r.bottom;
const top = (below < mh + 8 && r.top > mh + 8) ? (r.top - mh - 4) : (r.bottom + 4);
menu.style.cssText += `position:fixed;z-index:11000;top:${Math.round(top)}px;left:${Math.round(left)}px;min-width:${width}px;`;
menu.style.cssText += `position:fixed;z-index:${topPortalZ()};top:${Math.round(top)}px;left:${Math.round(left)}px;min-width:${width}px;`;
const close = (ev) => {
if (ev && menu.contains(ev.target)) return;
menu.remove();