add carousel to post overlay
This commit is contained in:
parent
b6c4f52df2
commit
36fc9a7dd1
|
|
@ -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
|
||||
? `<img src="${escapeHtml(img)}" data-fullsrc="${escapeHtml(fullImg)}" alt="" loading="lazy" />`
|
||||
const heroImageHtml = heroImageSrc
|
||||
? `<img src="${escapeHtml(heroImageSrc)}" data-fullsrc="${escapeHtml(heroFullSrc)}" alt="" loading="lazy" data-gallery-index="0" />`
|
||||
: `<div class="sw-modal-hero-fallback"><div class="sw-modal-hero-fallback-inner"><i class="${categoryIconClass(post)}"></i><span>${escapeHtml(normCatLabel(post))}</span></div></div>`;
|
||||
const arrowHtml = heroHasGallery
|
||||
? `<button class="sw-modal-hero-arrow left" type="button" aria-label="Previous image"><i class="fa-solid fa-chevron-left" /></button><button class="sw-modal-hero-arrow right" type="button" aria-label="Next image"><i class="fa-solid fa-chevron-right" /></button>`
|
||||
: "";
|
||||
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) =>
|
||||
`<button type="button" class="sw-modal-gallery-thumb${idx === 0 ? " active" : ""}" data-index="${idx}"><img src="${escapeHtml(
|
||||
url
|
||||
)}" alt="" loading="lazy" /></button>`
|
||||
)
|
||||
.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";
|
||||
|
|
|
|||
|
|
@ -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%;
|
||||
|
|
|
|||
Loading…
Reference in New Issue