Product image carousel in shop categories

The individual product pages have nifty arrows on the side of the image preview to scroll through the images of a product, these are called “carousel”. I wanted that functionality extended to the category view - to be able to quickly scroll product images without entering the individual product page.

HTML:

JAVASCRIPT:

<script>
document.addEventListener('DOMContentLoaded', function() {
const subString = 'shop';
const subStringTwo = 'shop/p/';
const getURL = window.location.href;
if (getURL.includes(subString) && !getURL.includes(subStringTwo)) {
const headerActions = document.querySelector('.header-actions');
let isTouch = false;
function checkHeader() {
const styles = window.getComputedStyle(headerActions);
isTouch = styles.getPropertyValue('display') !== 'flex';
}
checkHeader();
function cloneImageArrows() {
const products = document.querySelectorAll('.product-lists-item');
products.forEach((product, index) => {
const allImages = product.querySelectorAll('.grid-item-image');
if (allImages.length >= 2) {
const clonedElement = document.createElement('div');
const productImage = product.querySelector('.grid-image');
productImage.prepend(clonedElement);
clonedElement.id = `carousel${index + 1}`;
clonedElement.classList.add('carousel', 'categoryArrows', 'ProductItem-gallery-carousel-controls');
const leftArrow = document.createElement('div');
const rightArrow = document.createElement('div');
clonedElement.appendChild(leftArrow);
clonedElement.appendChild(rightArrow);
leftArrow.classList.add('arrowButton', 'arrowPrev', 'ProductItem-gallery-prev', 'product-item-gallery-carousel-control');
rightArrow.classList.add('arrowButton', 'arrowNext', 'ProductItem-gallery-next', 'product-item-gallery-carousel-control');
function adjustImageArrows() {
if (!isTouch) {
leftArrow.style.position = 'absolute';
leftArrow.style.left = '-14%';
leftArrow.style.transform = 'scale(0.33)';
rightArrow.style.position = 'absolute';
rightArrow.style.right = '-14%';
rightArrow.style.transform = 'scale(0.33)';
} else {
leftArrow.style.position = 'absolute';
leftArrow.style.left = '0%';
leftArrow.style.transform = 'scale(1.2)';
rightArrow.style.position = 'absolute';
rightArrow.style.right = '0%';
rightArrow.style.transform = 'scale(1.2)';
}
}
adjustImageArrows();
allImages.forEach((image, i) => {
if (i !== 0) image.style.display = 'none';
});
productImage.addEventListener('click', function(event) {
const clickedArrow = event.target.closest('.arrowButton');
if (!clickedArrow) return;
event.preventDefault();
const direction = clickedArrow.classList.contains('arrowPrev') ? 'left' : 'right';
handleArrowClick(direction, allImages);
});
function handleArrowClick(direction, images) {
const imagesArray = Array.from(images);
const activeImage = imagesArray.find(image => image.style.display === 'block');
const currentIndex = imagesArray.indexOf(activeImage);
let newIndex;
if (direction === 'left') {
newIndex = currentIndex > 0 ? currentIndex - 1 : imagesArray.length - 1;
} else {
newIndex = currentIndex < imagesArray.length - 1 ? currentIndex + 1 : 0;
}
activeImage.style.display = 'none';
activeImage.classList.remove('active'); 
imagesArray[newIndex].classList.add('active'); 
imagesArray[newIndex].style.display = 'block';
imagesArray[newIndex].classList.remove('grid-image-hover');
}
window.addEventListener('resize', function() {
const prevIsTouch = isTouch;
checkHeader();
if (isTouch !== prevIsTouch) {
adjustImageArrows();
}
});
}
});
}
cloneImageArrows();
}
});
</script>
CSS:

//PRODUCT CATEGORY CAROUSEL//
.product-item-gallery-carousel-control::after {
  font-weight: bold;
  border-right: 3px solid black !important;
  border-top: 3px solid black !important;
  border-image: linear-gradient(45deg, rgba(0,0,0,0) 50%, rgba(0,0,0,1) 100%);
  border-image-slice: 1;
  background-size: contain;
  background-position: center;
  background-repeat: no-repeat;
  transition: all 1s ease;
}
.product-item-gallery-carousel-control:hover::after {
   background: linear-gradient(45deg, rgba(0,0,0,0) 50%, rgba(255,199,0,0.8) 100%,);
}
.carousel {
    z-index: 9999;
    position: absolute;
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
}
.grid-item-image {
  color: transparent;
  opacity: 0% !important;
  transition: all 1s ease-in-out !important;
}
.grid-item-image.active {
  opacity: 100% !important;
  display: block;
}
Previous
Previous

Variant Select Animated Gear Icon

Next
Next

Resume And Continue Shopping Buttons