From cc7dde8520f2401972032ec1f9298bf868392e43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nu=C5=A1a=20Puk=C5=A1i=C4=8D?= Date: Fri, 10 Oct 2025 13:17:31 +0200 Subject: [PATCH] Image gallery --- assets/controllers/gallery_controller.js | 63 +++++++++ assets/styles/03-components/picture-event.css | 39 ++++++ templates/event/_kind20_picture.html.twig | 121 +++++++++++------- 3 files changed, 175 insertions(+), 48 deletions(-) create mode 100644 assets/controllers/gallery_controller.js diff --git a/assets/controllers/gallery_controller.js b/assets/controllers/gallery_controller.js new file mode 100644 index 0000000..c962503 --- /dev/null +++ b/assets/controllers/gallery_controller.js @@ -0,0 +1,63 @@ +import { Controller } from "@hotwired/stimulus"; + +// Connects to data-controller="gallery" +export default class extends Controller { + static targets = ["mainImage", "thumbnail"]; + + connect() { + this._onKeyDown = this._onKeyDown.bind(this); + this.element.addEventListener('keydown', this._onKeyDown); + // Make the gallery focusable for keyboard events + this.element.setAttribute('tabindex', '0'); + } + + disconnect() { + this.element.removeEventListener('keydown', this._onKeyDown); + } + + switch(event) { + const index = event.currentTarget.dataset.galleryIndex; + this.showImageAtIndex(Number(index)); + } + + showImageAtIndex(index) { + const thumbnails = this.thumbnailTargets; + if (!thumbnails[index]) return; + const thumbnail = thumbnails[index]; + const main = this.mainImageTarget; + main.src = thumbnail.src; + main.alt = thumbnail.alt; + if (thumbnail.dataset.dimensions) { + main.setAttribute('data-dimensions', thumbnail.dataset.dimensions); + } else { + main.removeAttribute('data-dimensions'); + } + if (thumbnail.dataset.blurhash) { + main.setAttribute('data-blurhash', thumbnail.dataset.blurhash); + } else { + main.removeAttribute('data-blurhash'); + } + thumbnails.forEach(t => t.classList.remove('selected')); + thumbnail.classList.add('selected'); + // Store current index for keyboard navigation + this.currentIndex = index; + } + + _onKeyDown(event) { + if (!this.thumbnailTargets.length) return; + // Find the currently selected index + let current = this.currentIndex; + if (typeof current !== 'number') { + current = this.thumbnailTargets.findIndex(t => t.classList.contains('selected')); + } + if (event.key === 'ArrowRight') { + event.preventDefault(); + const next = (current + 1) % this.thumbnailTargets.length; + this.showImageAtIndex(next); + } else if (event.key === 'ArrowLeft') { + event.preventDefault(); + const prev = (current - 1 + this.thumbnailTargets.length) % this.thumbnailTargets.length; + this.showImageAtIndex(prev); + } + } +} diff --git a/assets/styles/03-components/picture-event.css b/assets/styles/03-components/picture-event.css index eac3ce0..c351a37 100644 --- a/assets/styles/03-components/picture-event.css +++ b/assets/styles/03-components/picture-event.css @@ -30,3 +30,42 @@ figcaption.picture-description .credits { font-size: 1rem; line-height: 1.2; } + +.gallery-view .thumbnails { + display: flex; + gap: var(--spacing-1); + margin-top: var(--spacing-1); + justify-content: flex-start; + flex-wrap: wrap; +} +.gallery-view .thumbnail { + width: 64px; + height: 64px; + object-fit: cover; + border: 2px solid transparent; + cursor: pointer; + transition: border 0.2s; +} +.gallery-view .thumbnail.selected { + border: 2px solid var(--color-secondary); +} +.gallery-view .thumbnail:focus { + outline: none; + border: 2px solid transparent; + box-shadow: none; +} +.gallery-view .thumbnail:focus-visible { + outline: 1px solid var(--color-secondary); + border-radius: 0; + border: 2px solid transparent; + box-shadow: none; +} + +.main-image-wrapper:focus { + outline: none; +} + +.gallery-view:focus-visible { + outline: 1px solid var(--color-secondary); + border-radius: 0; +} diff --git a/templates/event/_kind20_picture.html.twig b/templates/event/_kind20_picture.html.twig index f854bb8..6012102 100644 --- a/templates/event/_kind20_picture.html.twig +++ b/templates/event/_kind20_picture.html.twig @@ -35,7 +35,8 @@