{% render 'product-media-custom' %}
product-media-custom.liquid
<media-gallery
class="grid__item product__media-wrapper"
style="--border-gallery-color: {{ border_color }};"
id="MediaGallery-{{ section.id }}"
data-section="{{ section.id }}"
data-enable-all-images="{{ section.settings.enable_all_images }}"
data-product-swatches="{{ settings.product_swatches | downcase }}"
>
{%- if product.media.size > 0 -%}
{%- liquid
assign featured_media_aspect_ratio = product.media[0].aspect_ratio
if product.featured_media.aspect_ratio == null
assign featured_media_aspect_ratio = 1
endif
-%}
<slider-component
class="product-single__media-group no-js-hidden{% if section.settings.media_size == 'full' %} product-single__media-group--full{% endif %}"
data-product-single-media-group
>
<a class="skip-to-content-link btn visually-hidden quick-add-hidden" href="#ProductInfo-{{ section.id }}">
{{ 'accessibility.skip_to_product_info' | t }}
</a>
<div class="product-single__media-group__wrap">
{% assign height_gallery = '100' %}
{% case media_ratio %}
{%- when 'portrait' -%}
{% assign height_gallery = '125' %}
{%- when 'adapt' -%}
{% assign height_gallery = 1 | divided_by: featured_media_aspect_ratio | times: 100 %}
{%- endcase -%}
<div class="product-single__wrapper" style="--padding: {{ height_gallery | append: '%' }};">
<ul class="product-single__gallery product-single__gallery-{{ section.id }}{% if border_gallery %} product__gallery--border{% endif %}">
{% assign productMedias = product.media %}
{% assign current_alt = '' %}
{%- for media in productMedias -%}
<li id="{{ section.id }}-{{ media.id }}"
class="product-single__gallery-item {% if forloop.first %}is-active{% endif %} "
data-alt="{{ media.alt }}"
data-media-id="{{ section.id }}-{{ media.id }}"
>
{%- liquid
assign lazy_load = true
assign gallery_media_alt = media.alt | escape | escape | camelcase
if gallery_media_alt != blank and current_alt != gallery_media_alt
assign current_alt = gallery_media_alt
assign lazy_load = false
endif
render 'media', media: media, height: height, enable_image_zoom: enable_image_zoom, autoplay_video: autoplay_video, image_zoom_size: product_image_zoom_size, image_scale: product_image_scale, lazy_load: lazy_load
-%}
</li>
{%- endfor -%}
</ul>
</div>
{% if product.media.size > 1 and product.type != 'Gift Card' %}
<div class="thumbnails-wrapper background-modal">
{% liquid
capture color_selected
if option_swatch.size > 0
for value in product_option.values
if product_option.selected_value == value
echo value | strip | camelize
endif
endfor
endif
endcapture
%}
<button type="button" class="product__thumb-arrow product__thumb-arrow--prev">
</button>
<ul class="product-single__thumbnails product-single__thumbnails-{{ section.id }}">
{% for media in product.media %}
{% assign media_alt = media.alt %}
<li data-target="{{ section.id }}-{{ media.id }}" id="{{ section.id }}-{{ media.id }}" class="product-single__thumbnails-item js{% if color_selected != blank and media_alt != color_selected %} product-single__thumbnails--hide{% endif %}">
<div
class="product-single__thumbnail-wrap text-link product-single__thumbnail product-single__thumbnail--{{ section.id }}{% if border_gallery %} product__gallery--border{% endif %}"
data-thumbnail-id="{{ section.id }}-{{ media.id }}"
>
<div
class="media media--{{ media_ratio }}"
{% if media_ratio == 'adapt' %}
style="padding-bottom: {{ 1 | divided_by: featured_media_aspect_ratio | times: 100 }}%;"
{% endif %}
>
<img
class="product-single__thumbnail-image lazyload"
srcset="
{% if media.preview_image.width >= 66 %}{{ media.preview_image | image_url: width: 66 }} 66w,{% endif %}
{% if media.preview_image.width >= 110 %}{{ media.preview_image | image_url: width: 110 }} 110w,{% endif %}
{% if media.preview_image.width >= 84 %}{{ media.preview_image | image_url: width: 84 }} 84w,{% endif %}
{% if media.preview_image.width >= 168 %}{{ media.preview_image | image_url: width: 168 }} 168w,{% endif %}
{% if media.preview_image.width >= 132 %}{{ media.preview_image | image_url: width: 132 }} 132w,{% endif %}
"
src="{{ media | image_url: width: 118 }}"
sizes="(min-width: 1000px) 110px, (min-width: 750px) 118px, 168px"
alt="{{ thumbnailAlt }}"
data-alt="{{ media_alt }}"
width="110"
height="{{ 110 | divided_by: media.preview_image.aspect_ratio | ceil }}"
>
{%- if media.media_type == 'video' or media.media_type == 'external_video' -%}
<div class="product-single__thumbnail-badge media__badge">
<i
class="icon {{ icon_style }} fa-play fa-swap-opacity"
style="color:white; filter: drop-shadow(0px 1px 1px rgb(0 0 0 / 0.7));"
></i>
</div>
{%- endif -%}
{%- if media.media_type == 'model' -%}
<div class="product-single__thumbnail-badge media__badge">
<i
class="icon icon-3d-model {{ icon_style }} fa-cube"
style="color:white; filter: drop-shadow(0px 1px 1px rgb(0 0 0 / 0.7));"
></i>
</div>
{%- endif -%}
</div>
</div>
</li>
{% endfor %}
</ul>
<button type="button" class="product__thumb-arrow product__thumb-arrow--next">
</button>
</div>
{% endif %}
</div>
</slider-component>
<noscript class="product-single__media__noscript-wrapper-{{ section.id }}">
<div class="product-single__media-group {% if section.settings.media_size == 'full' %} product-single__media-group--full{% endif %}">
<div class="product-single__media-group__wrap">
{% assign height_gallery = '100' %}
{% case media_ratio %}
{%- when 'portrait' -%}
{% assign height_gallery = '125' %}
{%- when 'adapt' -%}
{% assign height_gallery = 1 | divided_by: featured_media_aspect_ratio | times: 100 %}
{%- endcase -%}
<div class="product-single__wrapper" style="--padding: {{ height_gallery | append: '%' }};">
<ul class="product-single__gallery product-single__gallery-{{ section.id }}">
<li class="product-single__gallery-item" data-alt="{{ product.media.first | escape | camelcase }}">
<a name="picture{{ forloop.index }}"></a>
{% render 'media', media: product.media.first, height: height %}
</li>
</ul>
</div>
</div>
</div>
</noscript>
{%- else -%}
<div class="product__media-empty">
</div>
{%- endif -%}
</media-gallery>
media-gallery.js
if (!customElements.get('media-gallery')) {
customElements.define(
'media-gallery',
class MediaGallery extends HTMLElement {
constructor() {
super();
this.elements = {
liveRegion: this.querySelector('[id^="GalleryStatus"]'),
viewer: this.querySelector('.product-single__gallery'),
thumbnails: this.querySelector('.product-single__thumbnails'),
};
this.mql = window.matchMedia('(min-width: 750px)');
if (!this.elements.thumbnails) return;
this.elements.viewer.addEventListener('slideChanged', debounce(this.onSlideChanged.bind(this), 500));
this.elements.thumbnails.querySelectorAll('[data-target]').forEach((mediaToSwitch) => {
mediaToSwitch.addEventListener('click', this.setActiveMedia.bind(this, mediaToSwitch.dataset.target, false));
});
//if (this.dataset.desktopLayout.includes('thumbnail') && this.mql.matches) this.removeListSemantic();
}
onSlideChanged(event) {
const thumbnail = this.elements.thumbnails.querySelector(
`[data-target="${event.detail.currentElement.dataset.mediaId}"]`
);
this.setActiveThumbnail(thumbnail);
}
setActiveMedia(mediaId, prepend) {
console.log(mediaId);
console.log(this.elements.viewer);
const activeMedia =
this.elements.viewer.querySelector(`[data-media-id="${mediaId}"]`) ||
this.elements.viewer.querySelector('[data-media-id]');
if (!activeMedia) {
return;
}
this.elements.viewer.querySelectorAll('[data-media-id]').forEach((element) => {
element.classList.remove('is-selected');
});
activeMedia?.classList?.add('is-selected');
if(activeMedia){
const targetSlide = document.querySelector(`#${mediaId}`);
if (targetSlide) {
const flkty = $('.product-single__gallery').data('flickity');
const index = flkty.cells.findIndex(cell => cell.element.id === mediaId);
if (index !== -1) {
flkty.select(index);
}
}
}
// if (prepend) {
// activeMedia.parentElement.firstChild !== activeMedia && activeMedia.parentElement.prepend(activeMedia);
// if (this.elements.thumbnails) {
// const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`);
// activeThumbnail.parentElement.firstChild !== activeThumbnail && activeThumbnail.parentElement.prepend(activeThumbnail);
// }
// if (this.elements.viewer.slider) this.elements.viewer.resetPages();
// }
this.preventStickyHeader();
window.setTimeout(() => {
if (!this.mql.matches || this.elements.thumbnails) {
activeMedia.parentElement.scrollTo({ left: activeMedia.offsetLeft });
}
const activeMediaRect = activeMedia.getBoundingClientRect();
// Don't scroll if the image is already in view
if (activeMediaRect.top > -0.5) return;
const top = activeMediaRect.top + window.scrollY;
window.scrollTo({ top: top, behavior: 'smooth' });
});
this.playActiveMedia(activeMedia);
if (!this.elements.thumbnails) return;
const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`);
this.setActiveThumbnail(activeThumbnail);
this.announceLiveRegion(activeMedia, activeThumbnail.dataset.mediaPosition);
}
setActiveThumbnail(thumbnail) {
//console.log("22");
if (!this.elements.thumbnails || !thumbnail) return;
this.elements.thumbnails
.querySelectorAll('button')
.forEach((element) => element.removeAttribute('aria-current'));
// thumbnail.querySelector('button').setAttribute('aria-current', true);
//if (this.elements.thumbnails.isSlideVisible(thumbnail, 10)) return;
// this.elements.thumbnails.slider.scrollTo({ left: thumbnail.offsetLeft });
}
announceLiveRegion(activeItem, position) {
const image = activeItem.querySelector('.product__modal-opener--image img');
if (!image) return;
image.onload = () => {
this.elements.liveRegion.setAttribute('aria-hidden', false);
this.elements.liveRegion.innerHTML = window.accessibilityStrings.imageAvailable.replace('[index]', position);
setTimeout(() => {
this.elements.liveRegion.setAttribute('aria-hidden', true);
}, 2000);
};
image.src = image.src;
}
playActiveMedia(activeItem) {
window.pauseAllMedia();
const deferredMedia = activeItem.querySelector('.deferred-media');
if (deferredMedia) deferredMedia.loadContent(false);
}
preventStickyHeader() {
this.stickyHeader = this.stickyHeader || document.querySelector('sticky-header');
if (!this.stickyHeader) return;
this.stickyHeader.dispatchEvent(new Event('preventHeaderReveal'));
}
removeListSemantic() {
if (!this.elements.viewer.slider) return;
this.elements.viewer.slider.setAttribute('role', 'presentation');
this.elements.viewer.sliderItems.forEach((slide) => slide.setAttribute('role', 'presentation'));
}
}
);
}
js
/*** PDD SLIDER ***/
var product_custom = document.querySelectorAll('.product-slider .product-grid li');
if (product_custom.length > 4) {
product_custom.forEach(function(product_item) {
var product_slider = product_item.closest('.product-slider .product-grid');
if (product_slider) {
var flkty = new Flickity(product_slider, {
pageDots: false,
cellAlign: 'left',
groupCells: true,
wrapAround: true,
autoPlay: false,
prevNextButtons: true,
freeScroll: true,
});
}
});
}
$('.product-single__gallery').flickity({
imagesLoaded: true,
groupCells: false,
dragThreshold: 5,
cellAlign: 'center',
wrapAround: true,
prevNextButtons: true,
percentPosition: true,
pageDots: false,
rightToLeft: false,
autoPlay: false,
sync: '.product-single__thumbnails'
});
$('.product-single__gallery').on('change.flickity', function(event, index) {
var $thumbnails = $('.product-single__thumbnails li');
$thumbnails.removeClass('active'); // Remove 'active' class from all thumbnails
$thumbnails.eq(index).addClass('active'); // Add 'active' class to the current thumbnail
});
$('.product-single__thumbnails li').first().addClass('active');
// Thumbnail click event to change the gallery image
$('.product-single__thumbnails li').on('click', function() {
var index = $(this).index();
$('.product-single__gallery').flickity('select', index); // Select the corresponding image in the gallery
});
document.addEventListener("DOMContentLoaded", function() {
const thumbsScroller = document.querySelector(".product-single__thumbnails");
const btnPrev = document.querySelector("button.product__thumb-arrow.product__thumb-arrow--prev");
const btnNext = document.querySelector("button.product__thumb-arrow.product__thumb-arrow--next");
const scrollStep = 100;
const scrolledClass = "scrolled-end";
const extraItemsClass = "has-extra-items";
const minItems = 5;
const items = thumbsScroller ? thumbsScroller.children : [];
let hasScrolled = false;
function updateButtonState() {
const isAtTop = thumbsScroller.scrollTop === 0;
const isAtBottom = thumbsScroller.scrollTop + thumbsScroller.clientHeight >= thumbsScroller.scrollHeight;
btnPrev.disabled = isAtTop;
btnNext.disabled = isAtBottom;
if (hasScrolled && isAtBottom) {
thumbsScroller.classList.add(scrolledClass);
} else {
thumbsScroller.classList.remove(scrolledClass);
}
}
function addExtraItemsClass() {
if (items.length > minItems) {
thumbsScroller.classList.add(extraItemsClass);
} else {
thumbsScroller.classList.remove(extraItemsClass);
}
}
if (thumbsScroller) {
btnPrev.addEventListener("click", () => {
thumbsScroller.scrollBy({ top: -scrollStep, behavior: "smooth" });
});
btnNext.addEventListener("click", () => {
thumbsScroller.scrollBy({ top: scrollStep, behavior: "smooth" });
});
thumbsScroller.addEventListener("scroll", () => {
hasScrolled = true;
updateButtonState();
});
addExtraItemsClass();
updateButtonState();
}
});
/*** PDD SLIDER ***/