Files
Claude a9fb5b3e85 Admin: write blog posts and manage images
A Posts page lists every post with Write a post: title, topic, kind,
date, summary, a cover picked from the vault or uploaded, the pages it is
about, the Markdown body with a rendered preview, and Save draft or
Publish. An Images page uploads several images into an _attachments
folder, shows which notes use each one, copies its embed line, and
deletes unused ones. The content service gains the attachment list,
upload and delete endpoints behind the editor and admin tokens.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
2026-10-12 03:40:59 +00:00

26 lines
968 B
JavaScript

// The admin page's only script, and it is optional: every page works without
// it. It adds Copy buttons for embed lines and asks before a delete.
for (const b of document.querySelectorAll("button.copy[data-copy]")) {
b.addEventListener("click", async () => {
const text = b.getAttribute("data-copy") || "";
try {
await navigator.clipboard.writeText(text);
} catch {
const input = b.previousElementSibling;
if (input && "select" in input) {
input.select();
document.execCommand("copy");
}
}
const was = b.textContent;
b.textContent = "Copied";
setTimeout(() => (b.textContent = was), 1500);
});
}
for (const f of document.querySelectorAll("form[action='/images/delete']")) {
f.addEventListener("submit", (e) => {
const name = f.querySelector("input[name=name]")?.value ?? "this image";
if (!confirm(`Delete ${name} from the vault? This cannot be undone.`)) e.preventDefault();
});
}