feat(theme): opt-in lightbox with native dialog for image and text-media grids #105
No reviewers
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle!105
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "afk/93"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
An opt-in
lightboxbool param (default false) on theimageandtext-mediaelement sidecars. When enabled, every linkless grid image is wrapped in an anchor to the full-size asset and the grid carries a baredata-lightboxmarker; a dependency-free theme script upgrades those anchors into a native<dialog>overlay. A per-imagelinkalways wins over the lightbox, and without JS the anchor simply opens the full-size image.What changed
lightboxbool (default false) appended toimage.yamlandtext-media.yaml; purely additive, existing content untouched (boolis an existing engine field type, so no Go changes and no AGENTS.md vocabulary change).ce/figure.html, mark the grid wrapper withdata-lightbox, and set aPage.Storeflag;baseof.htmlemits<script src="/js/lightbox.js" defer>only on pages whose main block rendered a lightbox grid. The figure partial wraps linkless images in<a class="ce-lightbox" href="<full asset>">; a setimg.linkkeeps its plain anchor (link wins). Image-reference resolution is factored into a newce/img-res.htmlpartial soce/img.htmland the anchor href resolve identically.assets/js/lightbox.js, a dependency-free IIFE in the consent.js mold (document-delegated, survives preview DOM swaps): one shared native<dialog>, Esc + backdrop close, prev/next buttons and ArrowLeft/ArrowRight cycling within the grid (wrapping, linked images excluded), focus returned to the trigger on close, alt text carried into the enlarged view. Modified/secondary clicks fall through to normal navigation..ce-lightbox*section intheme.cssusing the existing tokens; control focus rings kept visible.TestLightboxInProduction(internal/theme) pins the built-site contract on new kitchen-sink fixtures:data-lightboxwrappers, resolved lightbox anchors for a library ref and a bundle-local ref, link-wins inside a lightbox grid, page-scoped script emission, and a lightbox-free home page staying byte-clean of all markers.Verification
go vet,go test ./...(all packages incl. the new test),go build.Closes #93
🤖 Generated with Claude Code
Validation verdict: PASS (with a merge-conflict resolution applied — see below).
Verification signal relied on: the green Forgejo Actions run
ci / build-and-teston the resolution merge commitec23e53(run 94, success, 7m11s) — full Go + web suites. This ran on the resolved tree, not just the pre-conflict PR.Merge conflict resolved:
internal/theme/theme_test.goconflicted becausemainadvanced (cta #101, cards #99) after CI last ran. Both sides only ADDED independent test functions (TestLightboxInProductionon the PR;TestCtaRenderingInProduction+TestCardsInProductionon main) — zero deletions, no import changes. Resolved as the deterministic union (all three functions present). Re-verified locally: the three theme tests pass andgo vet ./internal/themeis clean; then confirmed by the fresh green CI above. Pushed toafk/93(11e3331..ec23e53).Substantive review:
lightboxbool (default false) onimage.yaml+text-media.yaml;boolis an existing field type, so no engine/AGENTS.md vocabulary change (AGENTS.md correctly untouched).ce/figure.html: per-imagelinkwins → elselightboxanchor → else plain img. Full-size href resolved via the newce/img-res.html(factored out ofce/img.html, behaviour-preserving), with raw-ref fallback.deckleLightboxStore flag only when a grid actually renders;baseof.htmlemitsjs/lightbox.jsonly then, outside thehugo.IsServerblock.lightbox.jsis a dependency-free, document-delegated IIFE: native<dialog>, Esc/backdrop/button close, wrap-around prev/next (buttons + arrows) scoped toa.ce-lightboxwithin[data-lightbox]so linked images are skipped, focus restored to the trigger, alt carried into the enlarged view; modified/secondary clicks fall through to native navigation (no-JS fallback preserved).lightbox=falseparam types as a genuine bool (falsy), so{{ if $lightbox }}does not spuriously activate on default images — the case the hand-authored fixtures do not cover.No outstanding blockers. Awaiting a free-text merge go-ahead before merging.