feat(post-form): U6 — owner-scoped delete API route + card wiring

New custom-in-repo plugin entry-actions (un-ignored in .gitignore, NOT in
plugins.txt) registers DELETE /api/v1/entry/{slug} via onApiRegisterRoutes
(KTD5). The handler requires the authenticated site OWNER (not any login/admin),
rejects unsafe slugs (400), resolves the target through the page tree, asserts it
is a direct child of the active trip's dailies container, deletes the folder and
clears the cache — sharing EntryScopeGuard with the save path so R6 can't diverge.
A lazy per-namespace autoloader loads the controller on cached-route requests
(the router dispatches from route.cache without re-firing onApiRegisterRoutes).
EntryScopeGuard gains isOwnerUser() (API user comes from the request, not
$grav['user']) and enablePages() before find() (pages are lazily disabled in the
API context).

feed-actions.js (new, built via make build-assets; loaded on the trip/home feed
only when owner_can_edit) wires the inline Delete → Cancel/Confirm swap: on
Confirm it locks both buttons (D2, no double-DELETE), fetches the route
(credentials:include), removes the card, moves focus to the next card, and
announces via a page-level aria-live region (D4); on failure it restores the
control with an inline message (D7). Adds .sr-only + .entry-action[hidden] CSS.

Verified on the 2.0.4 container — API matrix 8/8 (anon 401, non-owner 403, bad
slug 400, out-of-scope 404, owner 204 + folder removed; V3/V5) and the delete UI
in a headless browser (confirm swap, card removal, disk deletion, live announce).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H1FrCYNq6RXdGYbn5PFrhM
This commit is contained in:
2026-07-05 00:19:15 +02:00
co-authored by Claude Opus 4.8
parent 265a06a972
commit b8daea217d
12 changed files with 298 additions and 2 deletions
+16
View File
@@ -329,6 +329,9 @@ body::after {
color: var(--color-accent);
outline: none;
}
/* [hidden] must win over the inline-flex display above (used to swap
Delete <-> Cancel/Confirm from feed-actions.js). */
.entry-action[hidden] { display: none; }
.entry-action--confirm {
color: #E5786A; /* soft red — destructive confirm */
border-color: #E5786A;
@@ -350,6 +353,19 @@ body::after {
}
.entry-delete-msg:empty { display: none; }
/* Visually-hidden but screen-reader-available (feed-actions live region). */
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.journal-photo-wrap {
position: relative;
margin-bottom: var(--space-5);