fix(extra-features): Fixed the sync product image/gallery

This commit is contained in:
2026-05-29 12:04:54 +02:00
parent d2d1dc4302
commit fc12804285
3 changed files with 161 additions and 122 deletions
@@ -1,27 +1,34 @@
@use "sass:map"; @use "sass:map";
.product-thumbs { .product-thumbs {
margin-right: -#{map.get($spacers, 1)}; margin-right: -#{map.get($spacers, 1)};
margin-left: -#{map.get($spacers, 1)}; margin-left: -#{map.get($spacers, 1)};
&__elem { &.swiper-vertical {
padding: 0 map.get($spacers, 1); max-height: 600px;
cursor: pointer; }
opacity: .3; &.swiper-horizontal {
transition: .3s ease opacity; max-height: 200px;
@include make-col(4);
&:focus,
&:hover {
opacity: 0.6;
} }
&.swiper-slide-thumb-active { &__elem {
opacity: 1; padding: 0 map.get($spacers, 1);
} cursor: pointer;
opacity: 0.3;
transition: 0.3s ease opacity;
@include make-col(4);
@include media-breakpoint-up(sm) { &:focus,
@include make-col(3); &:hover {
opacity: 0.6;
}
&.swiper-slide-thumb-active {
opacity: 1;
}
@include media-breakpoint-up(sm) {
@include make-col(3);
}
} }
}
} }
@@ -1,101 +1,148 @@
class ProductGallery { class ProductGallery {
constructor({ constructor({
thumbsSliderSelector = '.js-product-thumbs', thumbsSliderSelector = ".js-product-thumbs",
mainSliderSelector = '.js-product-main-images', mainSliderSelector = ".js-product-main-images",
modalSliderSelector = '.js-modal-gallery', modalSliderSelector = ".js-modal-gallery",
galleryModalSelector = '.js-product-images-modal', galleryModalSelector = ".js-product-images-modal",
} = {}) { } = {}) {
this.thumbsSliderSelector = thumbsSliderSelector; this.thumbsSliderSelector = thumbsSliderSelector;
this.mainSliderSelector = mainSliderSelector; this.mainSliderSelector = mainSliderSelector;
this.modalSliderSelector = modalSliderSelector; this.modalSliderSelector = modalSliderSelector;
this.galleryModalSelector = galleryModalSelector; this.galleryModalSelector = galleryModalSelector;
this.mainSliderSwiperInstance = null; this.mainSliderSwiperInstance = null;
this.modalSliderSwiperInstance = null; this.modalSliderSwiperInstance = null;
}
init() {
this.mainSliderSwiperInstance = null;
this.modalSliderSwiperInstance = null;
this.initProductImageSlider();
this.initModalGallerySlider();
}
async initProductImageSlider() {
const thumbsElem = document.querySelector(this.thumbsSliderSelector);
const galleryTopElem = document.querySelector(this.mainSliderSelector);
if (!thumbsElem && !galleryTopElem) {
return;
} }
const galleryThumbs = new prestashop.SwiperSlider(thumbsElem, { init() {
breakpoints: { this.mainSliderSwiperInstance = null;
320: { this.modalSliderSwiperInstance = null;
slidesPerView: 3, this.initProductImageSlider();
}, this.initModalGallerySlider();
576: {
slidesPerView: 4,
},
},
watchSlidesVisibility: true,
watchSlidesProgress: true,
});
const galleryThumbsInstance = await galleryThumbs.initSlider();
const mainSlider = new prestashop.SwiperSlider(galleryTopElem, {
spaceBetween: 10,
navigation: {
nextEl: galleryTopElem.querySelector('.swiper-button-next'),
prevEl: galleryTopElem.querySelector('.swiper-button-prev'),
},
thumbs: {
swiper: galleryThumbsInstance,
},
});
const mainSliderInstance = await mainSlider.initSlider();
this.mainSliderSwiperInstance = mainSliderInstance;
}
initModalGallerySlider() {
const gallerySliderElem = document.querySelector(this.modalSliderSelector);
if (!gallerySliderElem) {
return;
} }
const handleModalOpen = async () => { syncThumbsHeight() {
if (this.modalSliderSwiperInstance) { const mainImages = document.querySelector(".product-main-images");
gallerySliderElem.style.opacity = 0; const thumbs = document.querySelector(this.thumbsSliderSelector);
if (!mainImages || !thumbs) return;
// DIRTY HACK if (thumbs.classList.contains("swiper-vertical")) {
setTimeout(() => { const h = mainImages.offsetHeight;
this.modalSliderSwiperInstance.update(); if (h > 0) {
this.modalSliderSwiperInstance.slideTo(this.mainSliderSwiperInstance ? this.mainSliderSwiperInstance.activeIndex : 0, 0); thumbs.style.height = h + "px";
gallerySliderElem.style.opacity = 1; }
}, 200); } else {
} else { thumbs.style.height = "";
const modalSlider = new prestashop.SwiperSlider(gallerySliderElem, { }
slidesPerView: 1, }
spaceBetween: 10,
initialSlide: this.mainSliderSwiperInstance ? this.mainSliderSwiperInstance.activeIndex : 0, async initProductImageSlider() {
navigation: { const thumbsElem = document.querySelector(this.thumbsSliderSelector);
nextEl: gallerySliderElem.querySelector('.swiper-button-next'), const galleryTopElem = document.querySelector(this.mainSliderSelector);
prevEl: gallerySliderElem.querySelector('.swiper-button-prev'),
}, if (!thumbsElem && !galleryTopElem) {
return;
}
const galleryThumbs = new prestashop.SwiperSlider(thumbsElem, {
direction: "horizontal", // default
breakpoints: {
0: {
direction: "horizontal",
slidesPerView: 3,
},
768: {
direction: "vertical",
slidesPerView: 5,
},
992: {
direction: "horizontal",
slidesPerView: 3,
},
1200: {
direction: "vertical",
slidesPerView: 5,
},
},
watchSlidesVisibility: true,
watchSlidesProgress: true,
spaceBetween: 10,
}); });
const modalSliderInstance = await modalSlider.initSlider(); const galleryThumbsInstance = await galleryThumbs.initSlider();
this.modalSliderSwiperInstance = modalSliderInstance; galleryThumbsInstance.on("resize", () => this.syncThumbsHeight());
} galleryThumbsInstance.on("breakpoint", () => this.syncThumbsHeight());
};
// TO REFACTO LATER WITH BS5 REMOVE JQUERY! const mainSlider = new prestashop.SwiperSlider(galleryTopElem, {
$(this.galleryModalSelector).on('show.bs.modal', handleModalOpen); spaceBetween: 10,
} navigation: {
nextEl: galleryTopElem.querySelector(".swiper-button-next"),
prevEl: galleryTopElem.querySelector(".swiper-button-prev"),
},
thumbs: {
swiper: galleryThumbsInstance,
},
});
const mainSliderInstance = await mainSlider.initSlider();
this.mainSliderSwiperInstance = mainSliderInstance;
this.syncThumbsHeight();
}
initModalGallerySlider() {
const gallerySliderElem = document.querySelector(
this.modalSliderSelector,
);
if (!gallerySliderElem) {
return;
}
const handleModalOpen = async () => {
if (this.modalSliderSwiperInstance) {
gallerySliderElem.style.opacity = 0;
// DIRTY HACK
setTimeout(() => {
this.modalSliderSwiperInstance.update();
this.modalSliderSwiperInstance.slideTo(
this.mainSliderSwiperInstance
? this.mainSliderSwiperInstance.activeIndex
: 0,
0,
);
gallerySliderElem.style.opacity = 1;
}, 200);
} else {
const modalSlider = new prestashop.SwiperSlider(
gallerySliderElem,
{
slidesPerView: 1,
spaceBetween: 10,
initialSlide: this.mainSliderSwiperInstance
? this.mainSliderSwiperInstance.activeIndex
: 0,
navigation: {
nextEl: gallerySliderElem.querySelector(
".swiper-button-next",
),
prevEl: gallerySliderElem.querySelector(
".swiper-button-prev",
),
},
},
);
const modalSliderInstance = await modalSlider.initSlider();
this.modalSliderSwiperInstance = modalSliderInstance;
}
};
// TO REFACTO LATER WITH BS5 REMOVE JQUERY!
$(this.galleryModalSelector).on("show.bs.modal", handleModalOpen);
}
} }
export default ProductGallery; export default ProductGallery;
+1 -16
View File
@@ -13,6 +13,7 @@ import "@js/theme/components/quickview";
import "@js/theme/components/product"; import "@js/theme/components/product";
import "@js/theme/components/cart/cart"; import "@js/theme/components/cart/cart";
import "@js/theme/components/cart/block-cart"; import "@js/theme/components/cart/block-cart";
import "@js/theme/components/product-miniature-form.js";
import usePasswordPolicy from "@js/theme/components/usePasswordPolicy"; import usePasswordPolicy from "@js/theme/components/usePasswordPolicy";
import prestashop from "prestashop"; import prestashop from "prestashop";
@@ -66,22 +67,6 @@ function initStickyHeader() {
} }
} }
// Sync product thumbs height with main images height
function syncThumbsHeight() {
const mainImages = document.querySelector(".product-main-images");
const thumbs = document.querySelector(".product-thumbs.swiper");
// Only apply if Swiper is vertical
if (mainImages && thumbs && thumbs.classList.contains("swiper-vertical")) {
thumbs.style.maxHeight = mainImages.offsetHeight + "px";
thumbs.style.height = mainImages.offsetHeight + "px";
} else {
return;
}
}
window.addEventListener("load", syncThumbsHeight);
window.addEventListener("resize", syncThumbsHeight);
$(() => { $(() => {
initStickyHeader(); initStickyHeader();
accLinksTriggerActive(); accLinksTriggerActive();