Skip to content

feat(admin): editable gallery Portable Text block (TipTap node + sidebar panel)#2

Closed
Rimander wants to merge 7 commits into
mainfrom
feat/pt-gallery-editing
Closed

feat(admin): editable gallery Portable Text block (TipTap node + sidebar panel)#2
Rimander wants to merge 7 commits into
mainfrom
feat/pt-gallery-editing

Conversation

@Rimander

Copy link
Copy Markdown
Owner

What does this PR do?

Implements upstream issue emdash-cms#1436: the gallery Portable Text block was import/render-only — @emdash-cms/gutenberg-to-portable-text produces it and Gallery.astro renders it, but the admin editor had no TipTap node for it. Worse than invisible: the editor's PM→PT serializer dropped the block entirely, so opening and saving a migrated post silently destroyed its galleries. This PR makes the block first-class in the editor.

Core:

  • portable-text-to-prosemirror.ts / prosemirror-to-portable-text.ts gain a symmetric gallery mapping with a shared image sanitizer; malformed galleries (no images array) keep the visible unknown-block placeholder instead of becoming an empty grid.
  • The converter types add PortableTextGalleryBlock/PortableTextGalleryImage, preserving asset._type: "reference" — the exact shape the Gutenberg importer emits and the WP-import media pass rewrites — so imported galleries round-trip without loss. Covered by unit tests including a fixture matching the importer's output (rewritten _ref/url, per-image captions, columns).

Admin:

  • The admin's own converter pair (duplicated inside PortableTextEditor.tsx) gets the same two-way gallery mapping. Previously a loaded gallery fell into the plugin-block fallback and a gallery PM node serialized to nothing.
  • New GalleryNode (TipTap node view): WYSIWYG grid preview honoring columns, per-image captions, selection overlay with settings/delete, empty-state placeholder. Clicking an individual image opens the sidebar with that image pre-selected (transient selection — never persisted to attrs).
  • New GalleryDetailPanel (sidebar): compact 3-per-row thumbnail grid with drag-and-drop reordering (dnd-kit), multi-select "Add Images", column count, and a per-image settings card (large preview, hover Replace, original dimensions, alt text, caption). Local panel state composes sequential edits and resyncs when the panel is reopened for a different gallery node, so edits cannot leak across galleries.
  • MediaPickerModal gains an additive multi-select mode (multiple + onSelectMany, selection in click order); single-select behavior unchanged.
  • Insert entry points: toolbar button and /gallery slash command. Multiple galleries per document supported. Gallery panels are wired in the content editor, section editor, and widgets editors.

Closes #

(Upstream reference: emdash-cms#1436 — this PR is on the fork.)

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

AI-generated code disclosure

  • This PR includes AI-generated code — model/tool: Claude Code + Claude Fable 5 (orchestration/core) and Claude Sonnet 5 (parts of the admin panel/node)

Screenshots / test output

Verified end-to-end in demos/simple (Node + SQLite, core rebuilt to dist first):

  • Inserted a gallery via the toolbar, picked 3 images at once, autosave persisted a well-formed gallery PT block ({n:3, columns:3}, ordered refs) confirmed via the content API and directly in SQLite.
  • Reordered via drag-and-drop and edited captions/columns from the panel; every state change persisted and captions travel with their image through reorders.
  • Reloaded the editor: gallery still visible and editable (full converter round-trip, no [Unknown block type] placeholder).
  • Clicked individual images in the canvas: sidebar opens with that image's settings; switching images while open re-syncs; nothing transient leaks into the stored block (selectedImageKey absent from persisted PT).
  • Two galleries in one document: panel switches image sets correctly (4 ↔ 2 thumbs).
  • Published and confirmed the public page renders .emdash-gallery with 3 figures, --columns: 2, and the caption.
  • Arabic (RTL): editor node and panel mirror correctly, no crashes.

Note for reviewers: during verification we found (and deliberately did not touch here) a corrupt Arabic ICU plural in ar/messages.po for {0, plural, one {(# item)} other {(# items)}} that crashes components using that msgid in Arabic (e.g. RepeaterField). The gallery UI avoids that msgid; the one-line catalog repair belongs in a separate translation PR.

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown


Thank you for your submission, we really appreciate it. Like many open-source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution. You can sign the CLA by just posting a Pull Request Comment same as the below format.


I have read the CLA Document and I hereby sign the CLA


You can retrigger this bot by commenting recheck in this Pull Request. Posted by the CLA Assistant Lite bot.

@github-actions

Copy link
Copy Markdown

Scope check

This PR changes 1,292 lines across 13 files. Large PRs are harder to review and more likely to be closed without review.

If this scope is intentional, no action needed. A maintainer will review it. If not, please consider splitting this into smaller PRs.

See CONTRIBUTING.md for contribution guidelines.

…lery blocks

Preserves asset._type "reference" (the shape the Gutenberg importer emits
and the import media pass rewrites) through both converter pairs, with a
round-trip test against the exact imported shape. Clicking an image inside
the gallery node now opens the sidebar with that image's settings selected,
and the panel resyncs its local state when reopened for a different gallery
node so edits can't leak between galleries. Adds the release changeset.
@Rimander
Rimander force-pushed the feat/pt-gallery-editing branch from 4899a26 to 97455b9 Compare July 12, 2026 02:22
@Rimander

Copy link
Copy Markdown
Owner Author

Audit note (scope + pre-existing bug): the clipped text visible in the right sidebar's single-image panel (helper texts / Height input cut off at the panel edge) is not introduced by this branch. Git archaeology traces it to 1c150977 ("Refine admin editor settings panel actions", emdash-cms#1924, merged 2026-07-10): that commit added whitespace-normal to the default sidebar sections to counter the Kumo Sidebar's whitespace-nowrap, but missed the image-panel branch it introduced in the same change. This PR deliberately does not touch styles/layout outside the gallery components; the one-line fix (adding whitespace-normal to the image-panel wrapper in ContentSettingsPanel.tsx, and to the gallery branch that mirrors it) is verified to work and should go in a separate fix PR.

Also added since the PR description was written: clicking an individual image inside the gallery block in the canvas opens the sidebar with that image's settings pre-selected; the panel's thumbnail grid supports click-to-select (dnd-kit PointerSensor with a 6px activation distance so real clicks aren't swallowed by drag tracking); and the panel resyncs its state when reopened for a different gallery node.

@Rimander Rimander closed this Jul 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant