Add carousel

This commit is contained in:
Jeremy Thomas 2024-06-11 02:39:35 +01:00
parent 1a6164b836
commit 6cebea9ce2
2 changed files with 174 additions and 48 deletions

View File

@ -58,6 +58,22 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
}; };
const getPreviousIndex = (list, current) => {
if (current === 0) {
return list.length - 1;
}
return current - 1;
}
const getNextIndex = (list, current) => {
if (current === list.length - 1) {
return 0;
}
return current + 1;
}
const THEME_COLOR = "success"; const THEME_COLOR = "success";
const STORAGE_CART_ID = "bulma-shop-cart-id"; const STORAGE_CART_ID = "bulma-shop-cart-id";
@ -366,10 +382,9 @@ document.addEventListener("DOMContentLoaded", () => {
}; };
const openModal = (product) => { const openModal = (product) => {
$title = $modal.querySelector(".modal-title"); const $title = $modal.querySelector(".modal-title");
$body = $modal.querySelector(".modal-body"); const $body = $modal.querySelector(".modal-body");
$buttons = $modal.querySelector(".modal .buttons"); const $buttons = $modal.querySelector(".modal .buttons");
$close = $modal.querySelector(".modal .buttons .button.is-close");
$title.replaceChildren(); $title.replaceChildren();
buildHeading($title, product); buildHeading($title, product);
@ -462,19 +477,14 @@ document.addEventListener("DOMContentLoaded", () => {
const $option = El("", "option"); const $option = El("", "option");
$option.dataset.id = id; $option.dataset.id = id;
$option.innerText = title; $option.innerText = title;
$option.value = id;
// $option.addEventListener("click", (event) => {
// event.preventDefault();
// product.selectedVariant = id;
// update();
// });
$options.appendChild($option); $options.appendChild($option);
}); });
$select.addEventListener("change", (event) => { $select.addEventListener("change", (event) => {
event.preventDefault(); event.preventDefault();
product.selectedVariant = id; product.selectedVariant = event.target.value;
update(); update();
}); });
@ -507,7 +517,7 @@ document.addEventListener("DOMContentLoaded", () => {
} }
state.products.forEach((product) => { state.products.forEach((product) => {
const { id, availableForSale, featuredImage } = product; const { id, availableForSale, images } = product;
if (!availableForSale) { if (!availableForSale) {
return; return;
@ -518,17 +528,52 @@ document.addEventListener("DOMContentLoaded", () => {
const el = El("card-content"); const el = El("card-content");
const $images = El("shop-product-images image is-square");
const $carousel = El("shop-product-carousel image is-square");
if (images) {
images.forEach(img => {
const $figure = El("shop-product-image image is-square", "figure"); const $figure = El("shop-product-image image is-square", "figure");
const $img = document.createElement("img"); const $img = document.createElement("img");
$img.src = featuredImage.url; $img.src = img.url;
$figure.appendChild($img); $figure.appendChild($img);
$card.appendChild($figure); $carousel.appendChild($figure);
$figure.addEventListener("click", async (event) => {
event.preventDefault();
openModal(product);
}); });
$images.appendChild($carousel);
if (images.length > 1) {
const $prev = El("shop-product-arrow shop-product-prev", "button");
const $prevArrow = El("icon", "button");
const $prevIcon = El("fa-solid fa-arrow-left", "i");
$prevArrow.appendChild($prevIcon);
$prev.appendChild($prevArrow);
$prev.addEventListener("click", event => {
event.preventDefault();
product.selectedImage = getPreviousIndex(images, product.selectedImage);
update();
});
const $next = El("shop-product-arrow shop-product-next", "button");
const $nextArrow = El("icon", "button");
const $nextIcon = El("fa-solid fa-arrow-right", "i");
$nextArrow.appendChild($nextIcon);
$next.appendChild($nextArrow);
$next.addEventListener("click", event => {
event.preventDefault();
product.selectedImage = getNextIndex(images, product.selectedImage);
update();
});
$images.appendChild($prev);
$images.appendChild($next);
}
}
$card.appendChild($images);
buildHeading(el, product); buildHeading(el, product);
buildDescription(el, product); buildDescription(el, product);
buildOptions(el, product); buildOptions(el, product);
@ -552,6 +597,20 @@ document.addEventListener("DOMContentLoaded", () => {
}); });
}; };
const updateImages = () => {
state.products.forEach((product) => {
const $blocs = document.querySelectorAll(
`.shop-product-${getId(product.id)}`,
);
$blocs.forEach(($bloc) => {
const $carousel = $bloc.querySelector(`.shop-product-carousel`);
const offset = product.selectedImage * 100;
$carousel.style.transform = `translateX(-${offset}%`;
});
});
}
const updateCart = () => { const updateCart = () => {
if (isEmpty(state.cart)) { if (isEmpty(state.cart)) {
return; return;
@ -577,13 +636,23 @@ document.addEventListener("DOMContentLoaded", () => {
$item.dataset.id = line.id; $item.dataset.id = line.id;
const $left = El("media-left"); const $left = El("media-left");
// const $images = El("shop-item-images");
const $image = El("shop-item-image image is-64x64"); const $image = El("shop-item-image image is-64x64");
const $img = El("", "img"); const $img = El("", "img");
if (product.featuredImage) { if (product.featuredImage) {
$img.src = product.featuredImage.url; $img.src = product.featuredImage.url;
} }
// if (product.images) {
// product.images.forEach(img => {
// const $image = El("shop-item-image image is-64x64");
// const $img = El("", "img");
// $img.src = img.url;
// $image.appendChild($img);
// $images.appendChild($image);
// });
// }
$image.appendChild($img); $image.appendChild($img);
$left.appendChild($image); $left.appendChild($image);
@ -720,17 +789,17 @@ document.addEventListener("DOMContentLoaded", () => {
`.shop-product-${getId(product.id)}`, `.shop-product-${getId(product.id)}`,
); );
// $blocs.forEach(($bloc) => { $blocs.forEach(($bloc) => {
// const $variants = $bloc.querySelectorAll(`.variants .button`); const $variants = $bloc.querySelectorAll(`.shop-product-select option`);
// $variants.forEach(($el) => { $variants.forEach(($el) => {
// if ($el.dataset.id === product.selectedVariant) { if ($el.dataset.id === product.selectedVariant) {
// $el.classList.add(`is-${THEME_COLOR}`); $el.setAttribute("selected", "");
// } else { } else {
// $el.classList.remove(`is-${THEME_COLOR}`); $el.removeAttribute("selected");
// } }
// }); });
// }); });
}); });
}; };
@ -739,6 +808,7 @@ document.addEventListener("DOMContentLoaded", () => {
updateCart(); updateCart();
updateButtons(); updateButtons();
updateVariants(); updateVariants();
updateImages();
}; };
// HTML Elements // HTML Elements
@ -855,6 +925,7 @@ document.addEventListener("DOMContentLoaded", () => {
state.products = clean.products.map((product) => { state.products = clean.products.map((product) => {
return { return {
...product, ...product,
selectedImage: 0,
selectedVariant: product.variants[0].id, selectedVariant: product.variants[0].id,
}; };
}); });

View File

@ -235,7 +235,58 @@ breadcrumb:
flex-direction: column; flex-direction: column;
} }
.shop-product-images {
position: relative;
}
.shop-product-images:hover .shop-product-arrow {
opacity: 1;
}
.shop-product-arrow {
position: absolute;
opacity: 0;
top: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: center;
padding: 1em;
}
.shop-product-arrow .icon {
background-color: rgb(0 0 0 / 10%);
border-radius: 9999px;
transition-duration: var(--shop-duration);
transition-property: background-color, color, opacity;
}
.shop-product-arrow:hover .icon {
background-color: rgb(0 0 0 / 50%);
color: white;
}
.shop-product-arrow:active .icon {
background-color: rgb(0 0 0 / 70%);
color: white;
}
.shop-product-prev {
left: 0;
}
.shop-product-next {
right: 0;
}
.shop-product-carousel {
display: flex;
transition-duration: 300ms;
transition-property: transform;
}
.shop-product-image { .shop-product-image {
flex-shrink: 0;
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
} }
@ -246,7 +297,7 @@ breadcrumb:
transform-origin: center; transform-origin: center;
} }
.shop-product-image:hover img { .shop-product-images:hover img {
transform: scale(1.1); transform: scale(1.1);
} }
@ -343,19 +394,21 @@ breadcrumb:
{% include global/header.html %} {% include global/header.html %}
{% capture shop_placeholder %} {% capture shop_placeholder %}
<div class="shop-product is-placeholder"> <div class="card shop-product is-placeholder">
<figure class="shop-product-image image is-square is-skeleton"> <figure class="shop-product-image image is-square is-skeleton">
<img <img
src="https://cdn.shopify.com/s/files/1/0837/0451/2860/files/unisex-basic-softstyle-t-shirt-white-front-6665a0551b5c8.jpg?v=1717936223" src="https://cdn.shopify.com/s/files/1/0837/0451/2860/files/unisex-basic-softstyle-t-shirt-white-front-6665a0551b5c8.jpg?v=1717936223"
/> />
</figure> </figure>
<div class="card-content">
<div class="shop-product-heading"> <div class="shop-product-heading">
<h3 class="shop-product-title is-skeleton">The Bulma T-Shirt</h3> <h3 class="shop-product-title is-skeleton">The Bulma T-Shirt</h3>
<div class="shop-product-price"> <div class="shop-product-price">
<span class="shop-price is-skeleton">$15</span> <span class="shop-price is-skeleton">$15</span>
</div> </div>
</div> </div>
<div class="shop-product-description content"> <div class="shop-product-description content">
<div class="shop-product-tagline content is-skeleton"> <div class="shop-product-tagline content is-skeleton">
Show your CSS skills and add a little extra motivation with the Show your CSS skills and add a little extra motivation with the
@ -363,11 +416,13 @@ breadcrumb:
with your favorite framework. with your favorite framework.
</div> </div>
</div> </div>
<div class="shop-product-buttons buttons"> <div class="shop-product-buttons buttons">
<button class="button is-medium is-skeleton">Add to cart</button <button class="button is-skeleton">Add to cart</button
><button class="button is-text is-skeleton">Learn more</button> ><button class="button is-text is-skeleton">Learn more</button>
</div> </div>
</div> </div>
</div>
{% endcapture %} {% endcapture %}
<div class="shop-hero"> <div class="shop-hero">