diff --git a/src/components/Map/markerManager.js b/src/components/Map/markerManager.js index fd90ea7..3b85a53 100644 --- a/src/components/Map/markerManager.js +++ b/src/components/Map/markerManager.js @@ -235,14 +235,50 @@ function applyPostDetails(modalWrap, post) { const summaryEl = modalWrap.querySelector(".sw-modal-summary"); if (summaryEl) summaryEl.textContent = summary; + const heroGallery = collectGalleryImages(post); + const heroImageSrc = heroGallery[0] || heroImageForPost(post); + const heroFullSrc = heroGallery[0] || fullImageForPost(post); + const heroHasGallery = heroGallery.length > 1; const hero = modalWrap.querySelector(".sw-modal-hero"); const clusterHero = modalWrap.querySelector(".sw-cluster-hero-media"); if (hero || clusterHero) { const target = hero || clusterHero; - target.innerHTML = img - ? `` + const heroImageHtml = heroImageSrc + ? `` : `
${escapeHtml(normCatLabel(post))}
`; + const arrowHtml = heroHasGallery + ? `` + : ""; + target.innerHTML = `${heroImageHtml}${arrowHtml}`; + let galleryRow = modalWrap.querySelector(".sw-modal-gallery-row"); + if (heroHasGallery) { + if (!galleryRow) { + galleryRow = document.createElement("div"); + galleryRow.className = "sw-modal-gallery-row"; + const heroRow = target.closest(".sw-modal-hero-row"); + const parent = heroRow?.parentNode || target.parentNode || modalWrap; + if (parent) { + parent.insertBefore(galleryRow, heroRow ? heroRow.nextSibling : target.nextSibling || null); + } else { + modalWrap.appendChild(galleryRow); + } + } + galleryRow.innerHTML = heroGallery + .map( + (url, idx) => + `` + ) + .join(""); + } else if (galleryRow) { + galleryRow.remove(); + galleryRow = null; + } bindHeroLightbox(modalWrap); + if (heroHasGallery) { + initModalGallery(modalWrap, heroGallery); + } } const badge = modalWrap.querySelector(".sw-modal-badge"); @@ -447,6 +483,44 @@ function bindHeroLightbox(modalWrap) { }); } +function initModalGallery(modalWrap, gallery) { + if (!modalWrap || !Array.isArray(gallery) || gallery.length === 0) return; + const heroImg = modalWrap.querySelector(".sw-modal-hero img, .sw-cluster-hero-media img"); + if (!heroImg) return; + let activeIndex = 0; + const thumbButtons = modalWrap.querySelectorAll(".sw-modal-gallery-thumb"); + const arrows = modalWrap.querySelectorAll(".sw-modal-hero-arrow"); + const setActive = (idx) => { + if (!Number.isFinite(idx)) return; + const normalized = (idx + gallery.length) % gallery.length; + activeIndex = normalized; + heroImg.src = gallery[normalized]; + heroImg.dataset.fullsrc = gallery[normalized]; + heroImg.dataset.galleryIndex = String(normalized); + thumbButtons.forEach((btn) => { + const btnIndex = Number(btn.dataset.index); + btn.classList.toggle("active", btnIndex === normalized); + }); + }; + arrows.forEach((btn) => { + btn.addEventListener("click", (event) => { + event.stopPropagation(); + const direction = btn.classList.contains("left") ? -1 : 1; + const nextIndex = (activeIndex + direction + gallery.length) % gallery.length; + setActive(nextIndex); + }); + }); + thumbButtons.forEach((btn) => { + btn.addEventListener("click", (event) => { + event.stopPropagation(); + const idx = Number(btn.dataset.index); + if (Number.isNaN(idx)) return; + setActive(idx); + }); + }); + setActive(0); +} + function openImageLightbox(src) { if (!src) return; const overlay = document.createElement("div"); @@ -607,6 +681,25 @@ function fullImageForPost(post) { return normalizeImageUrl(raw); } +function collectGalleryImages(post) { + const result = []; + const seen = new Set(); + const add = (value) => { + const normalized = normalizeImageUrl(value); + if (!normalized) return; + if (seen.has(normalized)) return; + seen.add(normalized); + result.push(normalized); + }; + if (Array.isArray(post?.media_urls)) { + post.media_urls.forEach(add); + } + ["image_large", "image_medium", "image_small", "image", "media_url"].forEach((key) => { + add(post?.[key]); + }); + return result; +} + function formatRelativeTime(createdAt) { try { if (!createdAt) return "now"; diff --git a/src/styles/mapMarkers.css b/src/styles/mapMarkers.css index 79f31db..de067f0 100644 --- a/src/styles/mapMarkers.css +++ b/src/styles/mapMarkers.css @@ -886,6 +886,65 @@ body[data-theme="blue"] .sw-centered-modal .post-card.sw-expanded-shell{ display:block; } +.sw-modal-hero-media{ + position:relative; +} +.sw-modal-hero-arrow{ + position:absolute; + top:50%; + transform:translateY(-50%) scale(0.95); + width:36px; + height:36px; + border-radius:50%; + border:1px solid rgba(255,255,255,0.35); + background: rgba(0,0,0,0.55); + color:#fff; + display:flex; + align-items:center; + justify-content:center; + cursor:pointer; + z-index:10; + transition:transform 0.2s ease; +} +.sw-modal-hero-arrow:hover{ + transform:translateY(-50%) scale(1); +} +.sw-modal-hero-arrow.left{ + left:10px; +} +.sw-modal-hero-arrow.right{ + right:10px; +} +.sw-modal-gallery-row{ + display:flex; + gap:0.35rem; + overflow-x:auto; + padding-top:0.5rem; + margin-top:0.5rem; +} +.sw-modal-gallery-thumb{ + border-radius:12px; + border:1px solid transparent; + width:48px; + height:48px; + flex:0 0 auto; + overflow:hidden; + padding:0; + display:inline-flex; + align-items:center; + justify-content:center; + background:rgba(15,23,42,0.65); +} +.sw-modal-gallery-thumb.active{ + border-color:rgba(56,189,248,0.95); +} +.sw-modal-gallery-thumb img{ + width:100%; + height:100%; + object-fit:cover; + display:block; +} + .sw-modal-hero-fallback{ width:100%; height:100%;