Add Notes trash action
This commit is contained in:
parent
084580d3fd
commit
5349973f04
|
|
@ -50,6 +50,8 @@
|
||||||
'.notes-modal-btn.cancel:hover{background:#3a3a5e}',
|
'.notes-modal-btn.cancel:hover{background:#3a3a5e}',
|
||||||
'.notes-modal-btn.confirm{background:#4ecca3;color:#111;border-color:#4ecca3}',
|
'.notes-modal-btn.confirm{background:#4ecca3;color:#111;border-color:#4ecca3}',
|
||||||
'.notes-modal-btn.confirm:hover{background:#3dbb92}',
|
'.notes-modal-btn.confirm:hover{background:#3dbb92}',
|
||||||
|
'.notes-modal-btn.danger{background:#7a2a35;color:#fff;border-color:#b84a5a}',
|
||||||
|
'.notes-modal-btn.danger:hover{background:#963545}',
|
||||||
'.notes-status{font-size:.72rem;color:#8b8ba8;padding:.15rem .5rem;white-space:nowrap}',
|
'.notes-status{font-size:.72rem;color:#8b8ba8;padding:.15rem .5rem;white-space:nowrap}',
|
||||||
'.notes-status.success{color:#4ecca3}',
|
'.notes-status.success{color:#4ecca3}',
|
||||||
'.notes-status.error{color:#e74c3c}',
|
'.notes-status.error{color:#e74c3c}',
|
||||||
|
|
@ -88,7 +90,8 @@
|
||||||
add: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z',
|
add: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z',
|
||||||
rename: 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z',
|
rename: 'M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34a.9959.9959 0 0 0-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z',
|
||||||
open: 'M14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7zM5 5h6V3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-6h-2v6H5V5z',
|
open: 'M14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7zM5 5h6V3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-6h-2v6H5V5z',
|
||||||
search: 'M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z'
|
search: 'M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z',
|
||||||
|
trash: 'M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM8 9h8v10H8V9zm7.5-5-1-1h-5l-1 1H5v2h14V4z'
|
||||||
};
|
};
|
||||||
|
|
||||||
function iconSvg(name) {
|
function iconSvg(name) {
|
||||||
|
|
@ -336,8 +339,16 @@
|
||||||
el('button', {
|
el('button', {
|
||||||
className: 'notes-item-btn',
|
className: 'notes-item-btn',
|
||||||
title: 'Rename',
|
title: 'Rename',
|
||||||
|
'data-note-action': 'rename',
|
||||||
innerHTML: iconSvg('rename'),
|
innerHTML: iconSvg('rename'),
|
||||||
onClick: function (e) { e.stopPropagation(); beginRename(note); }
|
onClick: function (e) { e.stopPropagation(); beginRename(note); }
|
||||||
|
}),
|
||||||
|
el('button', {
|
||||||
|
className: 'notes-item-btn',
|
||||||
|
title: 'Move to Trash',
|
||||||
|
'data-note-action': 'trash',
|
||||||
|
innerHTML: iconSvg('trash'),
|
||||||
|
onClick: function (e) { e.stopPropagation(); confirmTrashNote(note); }
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|
@ -460,6 +471,24 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ─── Trash ──────────────────────────────────────────────
|
||||||
|
|
||||||
|
function confirmTrashNote(note) {
|
||||||
|
if (!note) return;
|
||||||
|
showTrashModal(note).then(function (confirmed) {
|
||||||
|
if (!confirmed || disposed) return;
|
||||||
|
setStatus('Moving note to trash...', 'loading');
|
||||||
|
api.files.trash(note.path).then(function () {
|
||||||
|
if (disposed) return;
|
||||||
|
if (selectedPath === note.path) selectedPath = '';
|
||||||
|
setStatus('Note moved to trash', 'success');
|
||||||
|
loadNotes();
|
||||||
|
}).catch(function (err) {
|
||||||
|
setStatus('Error: ' + (err.message || err), 'error');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Conflict Modal ─────────────────────────────────────
|
// ─── Conflict Modal ─────────────────────────────────────
|
||||||
|
|
||||||
function showConflictModal(title, existingPath) {
|
function showConflictModal(title, existingPath) {
|
||||||
|
|
@ -478,6 +507,28 @@
|
||||||
document.body.appendChild(overlay);
|
document.body.appendChild(overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showTrashModal(note) {
|
||||||
|
return new Promise(function (resolve) {
|
||||||
|
var overlay = el('div', { className: 'notes-modal-overlay' });
|
||||||
|
function close(value) {
|
||||||
|
overlay.remove();
|
||||||
|
resolve(value);
|
||||||
|
}
|
||||||
|
var modal = el('div', { className: 'notes-modal' }, [
|
||||||
|
el('div', { className: 'notes-modal-title' }, ['Move Note to Trash']),
|
||||||
|
el('div', { className: 'notes-modal-msg' }, [
|
||||||
|
'Move "' + (note.title || fileName(note.path)) + '" to trash?'
|
||||||
|
]),
|
||||||
|
el('div', { className: 'notes-modal-actions' }, [
|
||||||
|
el('button', { className: 'notes-modal-btn cancel', textContent: 'Cancel', onClick: function () { close(false); } }),
|
||||||
|
el('button', { className: 'notes-modal-btn danger', 'data-notes-confirm-trash': '', textContent: 'Move to Trash', onClick: function () { close(true); } })
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
overlay.appendChild(modal);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// ─── Event Wiring ───────────────────────────────────────
|
// ─── Event Wiring ───────────────────────────────────────
|
||||||
|
|
||||||
createBtn.addEventListener('click', showCreate);
|
createBtn.addEventListener('click', showCreate);
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
"name": "Notes",
|
"name": "Notes",
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"apiVersion": "0.1.0",
|
"apiVersion": "0.1.0",
|
||||||
"description": "Workspace-scoped notes manager for Markdown files in canonical Notes folders with create, rename, and Workbench integration.",
|
"description": "Workspace-scoped notes manager for Markdown files in canonical Notes folders with create, rename, trash, and Workbench integration.",
|
||||||
"source": "official",
|
"source": "official",
|
||||||
"icon": "edit",
|
"icon": "edit",
|
||||||
"provides": [
|
"provides": [
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
"permissions": [
|
"permissions": [
|
||||||
"files.read",
|
"files.read",
|
||||||
"files.write",
|
"files.write",
|
||||||
|
"files.delete",
|
||||||
"workbench.open",
|
"workbench.open",
|
||||||
"ui.register"
|
"ui.register"
|
||||||
],
|
],
|
||||||
|
|
|
||||||
|
|
@ -170,6 +170,16 @@ function makeApi(options = {}) {
|
||||||
entries.set(toRelativePath, entry);
|
entries.set(toRelativePath, entry);
|
||||||
entries.delete(fromRelativePath);
|
entries.delete(fromRelativePath);
|
||||||
},
|
},
|
||||||
|
trash: async (relativePath) => {
|
||||||
|
if (!entries.has(relativePath)) throw new Error(`not-found: ${relativePath}`);
|
||||||
|
entries.delete(relativePath);
|
||||||
|
return {
|
||||||
|
originalPath: relativePath,
|
||||||
|
trashPath: `.verstak/trash/files/mock/${path.basename(relativePath)}`,
|
||||||
|
trashId: 'mock',
|
||||||
|
deletedAt: new Date().toISOString(),
|
||||||
|
};
|
||||||
|
},
|
||||||
},
|
},
|
||||||
workbench: {
|
workbench: {
|
||||||
openResource: async (request) => {
|
openResource: async (request) => {
|
||||||
|
|
@ -229,6 +239,18 @@ async function mountNotes(api) {
|
||||||
throw new Error('create note did not open the newly created file');
|
throw new Error('create note did not open the newly created file');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const trashButton = walk(container, (node) => node.getAttribute && node.getAttribute('data-note-action') === 'trash');
|
||||||
|
if (!trashButton) throw new Error('trash note button not found');
|
||||||
|
trashButton.click();
|
||||||
|
await flush();
|
||||||
|
const trashConfirm = walk(document.body, (node) => node.getAttribute && node.getAttribute('data-notes-confirm-trash') !== undefined);
|
||||||
|
if (!trashConfirm) throw new Error('trash confirmation button not found');
|
||||||
|
trashConfirm.click();
|
||||||
|
await flush();
|
||||||
|
if (createApi.entries.has('Project/Notes/First_Note.md')) {
|
||||||
|
throw new Error('trash note did not remove the markdown file from active entries');
|
||||||
|
}
|
||||||
|
|
||||||
console.log('notes plugin smoke passed');
|
console.log('notes plugin smoke passed');
|
||||||
})().catch((err) => {
|
})().catch((err) => {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue