feat(post-form): dark-theme the photo widget + drag-to-reorder that sticks

Styling: repaint FilePond's default light drop zone/thumbnails/actions with
the Field Notes dark tokens so the picker matches the site palette.

Reordering: enable FilePond drag-reorder (allowReorder, itemInsertLocation
'after'). FilePond does NOT re-sequence its submitted data[photos][] inputs on
reorder, so post-form.js sends the visual order as a top-level `photo_order`
POST key on submit. cache-on-save reads it from $_POST (after add-page-by-form
copies the files, priority -100) and renames them photo-1..N in that order —
which the entry honours since it lists media by filename and treats the first
as hero. The order key is top-level (not data[...]), so it never lands in the
entry frontmatter. Best-effort + self-idempotent: locates the new entry folder
by the uploaded filenames and no-ops if they're already renamed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-04 20:25:56 +02:00
co-authored by Claude Opus 4.8
parent 87da3e4b5b
commit d17d1256ba
5 changed files with 237 additions and 48 deletions
+28 -1
View File
@@ -137,6 +137,28 @@ function initPhotoConversion() {
var converting = 0; // HEIC conversions in flight (before FilePond) — gates Submit
var collapse = buildPhotoCollapse();
var orderPond = null; // set when the managed FilePond instance is found
// FilePond does NOT re-sequence its submitted data[photos][] inputs when the
// list is reordered — those stay in upload order — so the drag order never
// reaches the server on its own. Send it explicitly: on submit, write the
// current visual order into a hidden input. Its name is a TOP-LEVEL POST key
// ("photo_order", not "data[...]") so Grav's form never captures it into the
// page data — the server reads it straight from $_POST and renames the
// copied files photo-1..N to match, with nothing leaking into frontmatter.
form.addEventListener('submit', function () {
if (!orderPond) return;
var files = orderPond.getFiles();
if (!files.length) return; // text-only post — send nothing
var hidden = form.querySelector('input[name="photo_order"]');
if (!hidden) {
hidden = document.createElement('input');
hidden.type = 'hidden';
hidden.name = 'photo_order';
form.appendChild(hidden);
}
hidden.value = JSON.stringify(files.map(function (f) { return f.filename; }));
}, true);
function setStatus(msg, kind) {
var el = photoStatusEl();
@@ -244,7 +266,12 @@ function initPhotoConversion() {
ponds.forEach(function (pond) {
if (pond && !pond._heicHooked) {
pond._heicHooked = true;
pond.setOptions({ beforeAddFile: makeBeforeAddFile(pond) });
// allowReorder: drag thumbnails to set the order. The server
// (cache-on-save) renames the copied files photo-1..N in the
// submitted order so the published entry honours it (entry media
// is filename-ordered; hero = first).
pond.setOptions({ beforeAddFile: makeBeforeAddFile(pond), allowReorder: true, itemInsertLocation: 'after' });
orderPond = pond;
// Update the collapse summary as files are added/uploaded/removed.
['addfile', 'processfile', 'processfiles', 'removefile', 'error'].forEach(function (ev) {
try { pond.on(ev, scheduleRefresh); } catch (e) { /* older FilePond API */ }