fix: batch tag queries, inline edit, delete response, SPA catch-all, link glyph
- Fix N+1 tag query in List() with batched IN clause
- Add inline body editing in web detail pane (dblclick or e key)
- Delete API returns {result: "soft"|"hard"} with 200 instead of 204
- SPA handler serves index.html for all extensionless paths
- Link glyph changed from emoji 🔗 to unicode ↗ for terminal alignment
- Capture bar contrast and hover glow increased
- Comment on load-bearing "--" in root.go
This commit is contained in:
+46
-4
@@ -4,7 +4,7 @@
|
||||
const GLYPHS = {
|
||||
note: '◦', todo: '▸', event: '◇',
|
||||
snippet: '◆', template: '◈', checklist: '☐',
|
||||
decision: '⚖', link: '🔗',
|
||||
decision: '⚖', link: '↗',
|
||||
};
|
||||
|
||||
const GLYPH_CLASSES = {
|
||||
@@ -278,11 +278,14 @@
|
||||
<span class="detail-id">${shortId}</span>
|
||||
${e.time_anchor ? `<span class="entity-time">@${e.time_anchor}</span>` : ''}
|
||||
</div>
|
||||
<div class="detail-body">${escHtml(e.body)}</div>
|
||||
<div class="detail-body" data-id="${e.id}">${escHtml(e.body)}</div>
|
||||
${tags ? `<div class="detail-tags">${tags}</div>` : ''}
|
||||
${cardContent}
|
||||
<div class="detail-actions">${actions}</div>
|
||||
`;
|
||||
|
||||
const bodyEl = pane.querySelector('.detail-body');
|
||||
if (bodyEl) bodyEl.addEventListener('dblclick', startEditBody);
|
||||
}
|
||||
|
||||
function renderCardContent(e) {
|
||||
@@ -334,6 +337,40 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ========== Inline edit ==========
|
||||
|
||||
function startEditBody() {
|
||||
const e = state.entities[state.selectedIndex];
|
||||
if (!e) return;
|
||||
const el = $(`.detail-body[data-id="${e.id}"]`);
|
||||
if (!el || el.tagName === 'TEXTAREA') return;
|
||||
|
||||
const ta = document.createElement('textarea');
|
||||
ta.className = 'detail-body-edit';
|
||||
ta.value = e.body;
|
||||
el.replaceWith(ta);
|
||||
ta.focus();
|
||||
ta.setSelectionRange(ta.value.length, ta.value.length);
|
||||
|
||||
async function save() {
|
||||
const newBody = ta.value.trim();
|
||||
if (newBody && newBody !== e.body) {
|
||||
await api.updateEntity(e.id, { body: newBody });
|
||||
await loadEntities();
|
||||
const idx = state.entities.findIndex(x => x.id === e.id);
|
||||
if (idx >= 0) selectEntity(idx);
|
||||
} else {
|
||||
renderDetailPane();
|
||||
}
|
||||
}
|
||||
|
||||
ta.addEventListener('blur', save);
|
||||
ta.addEventListener('keydown', (ev) => {
|
||||
if (ev.key === 'Enter' && ev.ctrlKey) { ev.preventDefault(); ta.removeEventListener('blur', save); save(); }
|
||||
if (ev.key === 'Escape') { ev.preventDefault(); ta.removeEventListener('blur', save); renderDetailPane(); }
|
||||
});
|
||||
}
|
||||
|
||||
// ========== Actions ==========
|
||||
|
||||
function selectEntity(idx) {
|
||||
@@ -498,8 +535,9 @@
|
||||
const captureInput = $('#capture-input');
|
||||
|
||||
document.addEventListener('keydown', (ev) => {
|
||||
if (document.activeElement === captureInput) {
|
||||
if (ev.key === 'Escape') captureInput.blur();
|
||||
if (document.activeElement === captureInput ||
|
||||
document.activeElement.classList.contains('detail-body-edit')) {
|
||||
if (ev.key === 'Escape') document.activeElement.blur();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -544,6 +582,10 @@
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
startEditBody();
|
||||
break;
|
||||
}
|
||||
case '1': switchView('stream'); break;
|
||||
case '2': switchView('cards'); break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user