almost all ready
This commit is contained in:
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
+45
-6
@@ -32,7 +32,7 @@
|
||||
|
||||
@layer components {
|
||||
.site-container {
|
||||
@apply mx-auto w-full max-w-7xl px-4 sm:px-5 lg:px-8;
|
||||
@apply mx-auto w-full max-w-[104rem] px-4 sm:px-5 lg:px-8;
|
||||
}
|
||||
|
||||
.site-header {
|
||||
@@ -96,7 +96,7 @@
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
@apply flex flex-wrap items-center gap-4 py-4 sm:gap-5 sm:py-5 lg:flex-nowrap;
|
||||
@apply flex flex-wrap items-center gap-3 py-3 sm:gap-5 sm:py-5 lg:flex-nowrap;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
@@ -108,11 +108,11 @@
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
@apply inline-flex h-11 items-center justify-center rounded-full border border-stone-300/70 bg-white/80 px-5 text-xs font-semibold uppercase tracking-[0.28em] text-stone-900 transition hover:border-amber-500 hover:text-amber-600;
|
||||
@apply inline-flex h-11 items-center justify-center rounded-full border border-stone-300/70 bg-white/90 px-5 text-[0.68rem] font-semibold uppercase tracking-[0.28em] text-stone-900 shadow-[0_10px_24px_rgba(20,33,61,0.08)] transition hover:border-amber-500 hover:text-amber-600;
|
||||
}
|
||||
|
||||
.menu-panel {
|
||||
@apply order-last w-full rounded-3xl border border-white/70 bg-white/95 p-4 shadow-[0_16px_34px_rgba(20,33,61,0.12)] backdrop-blur lg:order-none lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0 lg:shadow-none;
|
||||
@apply order-last mt-2 w-full rounded-[1.75rem] border border-white/70 bg-white/95 p-4 shadow-[0_16px_34px_rgba(20,33,61,0.12)] backdrop-blur lg:order-none lg:mt-0 lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0 lg:shadow-none;
|
||||
}
|
||||
|
||||
.desktop-nav {
|
||||
@@ -158,11 +158,11 @@
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
@apply ml-0 flex items-center gap-4 text-2xl text-stone-900 lg:ml-auto;
|
||||
@apply order-2 ml-auto flex items-center gap-2 text-2xl text-stone-900 lg:ml-auto lg:gap-4;
|
||||
}
|
||||
|
||||
.nav-icon {
|
||||
@apply flex h-11 w-11 items-center justify-center rounded-full bg-white/70 text-[1.35rem] shadow-[0_10px_24px_rgba(20,33,61,0.08)] transition hover:-translate-y-0.5 hover:text-amber-600;
|
||||
@apply flex h-11 w-11 items-center justify-center rounded-full bg-white/80 text-[1.2rem] shadow-[0_10px_24px_rgba(20,33,61,0.08)] transition hover:-translate-y-0.5 hover:text-amber-600 sm:text-[1.35rem];
|
||||
}
|
||||
|
||||
@media (max-width: 1023px) {
|
||||
@@ -170,6 +170,45 @@
|
||||
.mega-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.utility-bar .site-container {
|
||||
@apply gap-2 py-2.5;
|
||||
}
|
||||
|
||||
.utility-bar a[href^="mailto:"] {
|
||||
@apply hidden;
|
||||
}
|
||||
|
||||
.header-locale {
|
||||
@apply grid w-full grid-cols-2 gap-2;
|
||||
}
|
||||
|
||||
.locale-picker,
|
||||
.locale-picker__summary {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.brand-mark {
|
||||
@apply text-[2.2rem];
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
@apply gap-y-3;
|
||||
}
|
||||
|
||||
.menu-panel {
|
||||
@apply max-h-[70vh] overflow-y-auto p-3;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 639px) {
|
||||
.header-actions .nav-icon:first-child {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
@apply px-4;
|
||||
}
|
||||
}
|
||||
|
||||
button[type='submit'] {
|
||||
|
||||
+556
@@ -106,3 +106,559 @@ if (cartButton) {
|
||||
root.style.setProperty("--cta-glow", "0 0 0 0 rgba(0,0,0,0)");
|
||||
});
|
||||
}
|
||||
|
||||
const productMainImage = document.querySelector("[data-product-main-image]");
|
||||
const defaultProductImage = productMainImage?.dataset.defaultImage || productMainImage?.getAttribute("src") || "";
|
||||
const productThumbCarousel = document.querySelector("[data-product-thumb-carousel]");
|
||||
const productThumbViewport = productThumbCarousel?.querySelector("[data-product-thumb-viewport]");
|
||||
const productThumbTrack = productThumbCarousel?.querySelector("[data-product-thumb-track]");
|
||||
const productThumbPrev = productThumbCarousel?.querySelector("[data-product-thumb-prev]");
|
||||
const productThumbNext = productThumbCarousel?.querySelector("[data-product-thumb-next]");
|
||||
const productThumbs = [...document.querySelectorAll("[data-product-thumb-index]")];
|
||||
|
||||
if (productMainImage && productThumbCarousel && productThumbViewport && productThumbTrack && productThumbs.length > 0) {
|
||||
let activeProductThumbIndex = 0;
|
||||
|
||||
const updateProductThumbState = () => {
|
||||
productThumbs.forEach((thumb, index) => {
|
||||
if (index === activeProductThumbIndex) {
|
||||
thumb.classList.remove("border-stone-800");
|
||||
thumb.classList.add("border-amber-400/60", "ring-1", "ring-amber-300/40");
|
||||
thumb.setAttribute("aria-current", "true");
|
||||
return;
|
||||
}
|
||||
thumb.classList.remove("border-amber-400/60", "ring-1", "ring-amber-300/40");
|
||||
thumb.classList.add("border-stone-800");
|
||||
thumb.removeAttribute("aria-current");
|
||||
});
|
||||
};
|
||||
|
||||
const scrollProductThumbIntoView = (index) => {
|
||||
const thumb = productThumbs[index];
|
||||
thumb?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
||||
};
|
||||
|
||||
const showProductThumb = (index) => {
|
||||
const normalizedIndex = (index + productThumbs.length) % productThumbs.length;
|
||||
const thumb = productThumbs[normalizedIndex];
|
||||
const nextSrc = thumb?.dataset.productThumbLarge || thumb?.dataset.productThumbLargeFallback || "";
|
||||
if (!thumb || !nextSrc) {
|
||||
return;
|
||||
}
|
||||
activeProductThumbIndex = normalizedIndex;
|
||||
productMainImage.setAttribute("src", nextSrc);
|
||||
if (thumb.dataset.productThumbAlt) {
|
||||
productMainImage.setAttribute("alt", thumb.dataset.productThumbAlt);
|
||||
}
|
||||
updateProductThumbState();
|
||||
scrollProductThumbIntoView(normalizedIndex);
|
||||
};
|
||||
|
||||
const stepProductThumbs = (direction) => {
|
||||
showProductThumb(activeProductThumbIndex + direction);
|
||||
};
|
||||
|
||||
productThumbPrev?.addEventListener("click", () => {
|
||||
stepProductThumbs(-1);
|
||||
});
|
||||
|
||||
productThumbNext?.addEventListener("click", () => {
|
||||
stepProductThumbs(1);
|
||||
});
|
||||
|
||||
productThumbs.forEach((thumb, index) => {
|
||||
thumb.addEventListener("click", () => {
|
||||
showProductThumb(index);
|
||||
});
|
||||
});
|
||||
|
||||
const initialIndex = productThumbs.findIndex((thumb) => thumb.dataset.productThumbLarge === productMainImage.getAttribute("src"));
|
||||
showProductThumb(initialIndex >= 0 ? initialIndex : 0);
|
||||
|
||||
productThumbViewport.addEventListener(
|
||||
"wheel",
|
||||
(event) => {
|
||||
if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
productThumbViewport.scrollBy({ left: event.deltaY, behavior: "smooth" });
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
}
|
||||
|
||||
const variantPicker = document.querySelector("[data-variant-picker]");
|
||||
const variantCombinationInput = document.querySelector("[data-variant-combination]");
|
||||
|
||||
if (variantPicker && variantCombinationInput) {
|
||||
const interactiveGroups = [...variantPicker.querySelectorAll("[data-variant-group]")];
|
||||
const variantSummary = document.querySelector("[data-variant-selection-summary]");
|
||||
const productPriceGross = document.querySelector("[data-product-price-gross]");
|
||||
const productPriceNet = document.querySelector("[data-product-price-net]");
|
||||
const defaultPriceGross = productPriceGross?.dataset.defaultPriceGross || productPriceGross?.textContent || "";
|
||||
const defaultPriceNet = productPriceNet?.dataset.defaultPriceNet || productPriceNet?.textContent || "";
|
||||
const combinationImageNodes = [...document.querySelectorAll("[data-variant-combination-image]")];
|
||||
const combinationImageByID = new Map(
|
||||
combinationImageNodes.map((node) => [
|
||||
node.dataset.variantCombinationImage,
|
||||
{
|
||||
imageLarge: node.dataset.imageLarge || "",
|
||||
priceGross: node.dataset.priceGross || "",
|
||||
priceNet: node.dataset.priceNet || "",
|
||||
},
|
||||
]),
|
||||
);
|
||||
|
||||
const parseCombinationIDs = (value) =>
|
||||
(value || "")
|
||||
.split(",")
|
||||
.map((item) => Number.parseInt(item, 10))
|
||||
.filter((item) => Number.isInteger(item) && item > 0);
|
||||
|
||||
const optionClassName = (presentation, selected, disabled) => {
|
||||
if (presentation === "radio") {
|
||||
if (disabled) {
|
||||
return "rounded-full border border-stone-200 bg-stone-100 px-4 py-2 text-sm font-medium text-stone-400 opacity-50 transition";
|
||||
}
|
||||
if (selected) {
|
||||
return "rounded-full border border-stone-900 bg-stone-900 px-4 py-2 text-sm font-medium text-stone-50 transition";
|
||||
}
|
||||
return "rounded-full border border-stone-300 bg-white px-4 py-2 text-sm font-medium text-stone-900 transition hover:border-stone-700";
|
||||
}
|
||||
if (presentation === "select") {
|
||||
if (disabled) {
|
||||
return "w-full rounded-2xl px-4 py-3 text-left text-sm font-medium text-stone-400 opacity-50 transition";
|
||||
}
|
||||
if (selected) {
|
||||
return "w-full rounded-2xl bg-stone-900 px-4 py-3 text-left text-sm font-medium text-stone-50 transition";
|
||||
}
|
||||
return "w-full rounded-2xl px-4 py-3 text-left text-sm font-medium text-stone-700 transition hover:bg-stone-100 hover:text-stone-950";
|
||||
}
|
||||
if (disabled) {
|
||||
return "inline-flex min-h-10 min-w-10 items-center justify-center border border-stone-200 p-0.5 opacity-40 transition";
|
||||
}
|
||||
if (selected) {
|
||||
return "inline-flex min-h-10 min-w-10 items-center justify-center border border-stone-900 p-0.5 ring-1 ring-stone-900 transition";
|
||||
}
|
||||
return "inline-flex min-h-10 min-w-10 items-center justify-center border border-stone-300 p-0.5 transition hover:border-stone-700";
|
||||
};
|
||||
|
||||
const intersectIDs = (left, right) => left.filter((id) => right.includes(id));
|
||||
|
||||
const availableCombinationIDsForGroup = (targetGroup) => {
|
||||
let matched = null;
|
||||
|
||||
interactiveGroups.forEach((group) => {
|
||||
if (group === targetGroup) {
|
||||
return;
|
||||
}
|
||||
const activeButton = group.querySelector("[data-variant-option][data-selected='true']");
|
||||
const ids = parseCombinationIDs(activeButton?.dataset.combinationIds);
|
||||
if (ids.length === 0) {
|
||||
return;
|
||||
}
|
||||
if (matched === null) {
|
||||
matched = ids;
|
||||
return;
|
||||
}
|
||||
matched = intersectIDs(matched, ids);
|
||||
});
|
||||
|
||||
return matched;
|
||||
};
|
||||
|
||||
const selectedValueForGroup = (group) => {
|
||||
if (group.dataset.variantSelect !== undefined) {
|
||||
const triggerValue = group.querySelector("[data-variant-select-value]");
|
||||
return triggerValue?.textContent?.trim() || "";
|
||||
}
|
||||
|
||||
const activeButton = group.querySelector("[data-variant-option][data-selected='true']");
|
||||
return activeButton?.getAttribute("aria-label")?.trim() || activeButton?.textContent?.trim() || "";
|
||||
};
|
||||
|
||||
const updateSelectionSummary = () => {
|
||||
const parts = [];
|
||||
|
||||
interactiveGroups.forEach((group) => {
|
||||
const key = group.dataset.variantGroup;
|
||||
const value = selectedValueForGroup(group);
|
||||
const labelNode = key
|
||||
? document.querySelector(`[data-variant-current="${key}"]`)
|
||||
: null;
|
||||
|
||||
if (labelNode) {
|
||||
labelNode.textContent = value;
|
||||
}
|
||||
|
||||
const wrapper = group.closest(".space-y-3");
|
||||
const label = wrapper?.querySelector("p")?.textContent?.trim() || "";
|
||||
if (label && value) {
|
||||
parts.push(`${label}: ${value}`);
|
||||
}
|
||||
});
|
||||
|
||||
if (variantSummary) {
|
||||
variantSummary.textContent = parts.length > 0 ? parts.join(" • ") : "Choose product options";
|
||||
}
|
||||
};
|
||||
|
||||
const updateButtonSelection = (group, activeButton) => {
|
||||
group.querySelectorAll("[data-variant-option]").forEach((button) => {
|
||||
const isActive = button === activeButton;
|
||||
button.dataset.selected = isActive ? "true" : "false";
|
||||
const disabled = button.dataset.disabled === "true";
|
||||
button.className = optionClassName(button.dataset.variantPresentation, isActive, disabled);
|
||||
});
|
||||
};
|
||||
|
||||
const syncSelectTriggerValue = (group) => {
|
||||
if (group.dataset.variantSelect === undefined) {
|
||||
return;
|
||||
}
|
||||
const valueNode = group.querySelector("[data-variant-select-value]");
|
||||
const activeButton = group.querySelector("[data-variant-option][data-selected='true']");
|
||||
if (valueNode && activeButton) {
|
||||
valueNode.textContent = activeButton.textContent?.trim() || "";
|
||||
}
|
||||
};
|
||||
|
||||
const refreshGroupAvailability = (group) => {
|
||||
const availableIDs = availableCombinationIDsForGroup(group);
|
||||
const options = [...group.querySelectorAll("[data-variant-option]")];
|
||||
|
||||
options.forEach((button) => {
|
||||
const optionIDs = parseCombinationIDs(button.dataset.combinationIds);
|
||||
const enabled = availableIDs === null || intersectIDs(optionIDs, availableIDs).length > 0;
|
||||
button.dataset.disabled = enabled ? "false" : "true";
|
||||
button.disabled = !enabled;
|
||||
button.setAttribute("aria-disabled", enabled ? "false" : "true");
|
||||
});
|
||||
|
||||
const selectedButton = group.querySelector("[data-variant-option][data-selected='true']");
|
||||
if (selectedButton?.dataset.disabled === "true") {
|
||||
selectedButton.dataset.selected = "false";
|
||||
}
|
||||
|
||||
let nextSelected = group.querySelector("[data-variant-option][data-selected='true'][data-disabled='false']");
|
||||
if (!nextSelected) {
|
||||
nextSelected = group.querySelector("[data-variant-option][data-disabled='false']");
|
||||
}
|
||||
if (nextSelected) {
|
||||
updateButtonSelection(group, nextSelected);
|
||||
syncSelectTriggerValue(group);
|
||||
} else {
|
||||
options.forEach((button) => {
|
||||
button.dataset.selected = "false";
|
||||
button.className = optionClassName(button.dataset.variantPresentation, false, true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const normalizeVariantSelections = () => {
|
||||
for (let pass = 0; pass < 2; pass += 1) {
|
||||
interactiveGroups.forEach((group) => {
|
||||
refreshGroupAvailability(group);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const resolveCombination = () => {
|
||||
normalizeVariantSelections();
|
||||
|
||||
let matched = null;
|
||||
|
||||
interactiveGroups.forEach((group) => {
|
||||
const activeButton = group.querySelector("[data-variant-option][data-selected='true']");
|
||||
const ids = parseCombinationIDs(activeButton?.dataset.combinationIds);
|
||||
|
||||
if (ids.length === 0) {
|
||||
matched = [];
|
||||
return;
|
||||
}
|
||||
|
||||
if (matched === null) {
|
||||
matched = ids;
|
||||
return;
|
||||
}
|
||||
|
||||
matched = matched.filter((id) => ids.includes(id));
|
||||
});
|
||||
|
||||
if (matched && matched.length > 0) {
|
||||
const combinationID = String(matched[0]);
|
||||
variantCombinationInput.value = combinationID;
|
||||
const combinationData = combinationImageByID.get(combinationID);
|
||||
if (productMainImage) {
|
||||
const nextImage = combinationData?.imageLarge || defaultProductImage;
|
||||
if (nextImage) {
|
||||
productMainImage.setAttribute("src", nextImage);
|
||||
const matchingThumbIndex = productThumbs.findIndex((thumb) => thumb.dataset.productThumbLarge === nextImage);
|
||||
if (matchingThumbIndex >= 0) {
|
||||
productThumbs.forEach((thumb, index) => {
|
||||
if (index === matchingThumbIndex) {
|
||||
thumb.classList.remove("border-stone-800");
|
||||
thumb.classList.add("border-amber-400/60", "ring-1", "ring-amber-300/40");
|
||||
thumb.setAttribute("aria-current", "true");
|
||||
} else {
|
||||
thumb.classList.remove("border-amber-400/60", "ring-1", "ring-amber-300/40");
|
||||
thumb.classList.add("border-stone-800");
|
||||
thumb.removeAttribute("aria-current");
|
||||
}
|
||||
});
|
||||
productThumbs[matchingThumbIndex]?.scrollIntoView({ behavior: "smooth", block: "nearest", inline: "center" });
|
||||
}
|
||||
}
|
||||
}
|
||||
if (productPriceGross) {
|
||||
productPriceGross.textContent = combinationData?.priceGross || defaultPriceGross;
|
||||
}
|
||||
if (productPriceNet) {
|
||||
productPriceNet.textContent = combinationData?.priceNet || defaultPriceNet;
|
||||
}
|
||||
} else {
|
||||
variantCombinationInput.value = "";
|
||||
if (productPriceGross) {
|
||||
productPriceGross.textContent = defaultPriceGross;
|
||||
}
|
||||
if (productPriceNet) {
|
||||
productPriceNet.textContent = defaultPriceNet;
|
||||
}
|
||||
}
|
||||
|
||||
updateSelectionSummary();
|
||||
};
|
||||
|
||||
const closeVariantSelects = () => {
|
||||
interactiveGroups.forEach((group) => {
|
||||
if (group.dataset.variantSelect === undefined) return;
|
||||
group.querySelector("[data-variant-select-menu]")?.classList.add("hidden");
|
||||
group.querySelector("[data-variant-select-trigger]")?.setAttribute("aria-expanded", "false");
|
||||
});
|
||||
};
|
||||
|
||||
interactiveGroups.forEach((group) => {
|
||||
if (group.dataset.variantSelect !== undefined) {
|
||||
const trigger = group.querySelector("[data-variant-select-trigger]");
|
||||
const menu = group.querySelector("[data-variant-select-menu]");
|
||||
const valueNode = group.querySelector("[data-variant-select-value]");
|
||||
|
||||
trigger?.addEventListener("click", () => {
|
||||
const isOpen = trigger.getAttribute("aria-expanded") === "true";
|
||||
closeVariantSelects();
|
||||
if (isOpen) {
|
||||
return;
|
||||
}
|
||||
menu?.classList.remove("hidden");
|
||||
trigger.setAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
group.querySelectorAll("[data-variant-option]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
if (button.dataset.disabled === "true") {
|
||||
return;
|
||||
}
|
||||
updateButtonSelection(group, button);
|
||||
if (valueNode) {
|
||||
valueNode.textContent = button.textContent?.trim() || "";
|
||||
}
|
||||
closeVariantSelects();
|
||||
resolveCombination();
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
group.querySelectorAll("[data-variant-option]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
if (button.dataset.disabled === "true") {
|
||||
return;
|
||||
}
|
||||
updateButtonSelection(group, button);
|
||||
resolveCombination();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
resolveCombination();
|
||||
|
||||
document.addEventListener("click", (event) => {
|
||||
const target = event.target;
|
||||
if (!(target instanceof Node)) return;
|
||||
const insidePicker = variantPicker.contains(target);
|
||||
if (!insidePicker) {
|
||||
closeVariantSelects();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
closeVariantSelects();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const galleryModal = document.querySelector("[data-gallery-modal]");
|
||||
const galleryMain = galleryModal?.querySelector("[data-gallery-main]");
|
||||
const galleryOpeners = [...document.querySelectorAll("[data-gallery-open]")];
|
||||
const galleryClosers = [...document.querySelectorAll("[data-gallery-close]")];
|
||||
const galleryThumbs = [...document.querySelectorAll("[data-gallery-thumb]")];
|
||||
const galleryPrev = galleryModal?.querySelector("[data-gallery-prev]");
|
||||
const galleryNext = galleryModal?.querySelector("[data-gallery-next]");
|
||||
const galleryThumbViewport = galleryModal?.querySelector("[data-gallery-thumb-viewport]");
|
||||
const galleryThumbPrev = galleryModal?.querySelector("[data-gallery-thumb-prev]");
|
||||
const galleryThumbNext = galleryModal?.querySelector("[data-gallery-thumb-next]");
|
||||
|
||||
if (galleryModal && galleryMain && galleryOpeners.length > 0) {
|
||||
let activeIndex = 0;
|
||||
let wheelLocked = false;
|
||||
|
||||
const openGallery = () => {
|
||||
const productMainImage = document.querySelector("[data-product-main-image]");
|
||||
const currentMainSrc = productMainImage?.getAttribute("src") || "";
|
||||
if (currentMainSrc) {
|
||||
const matchingIndex = galleryThumbs.findIndex((thumb) => thumb.dataset.galleryThumb === currentMainSrc);
|
||||
if (matchingIndex >= 0) {
|
||||
showGalleryImage(matchingIndex);
|
||||
}
|
||||
}
|
||||
galleryModal.classList.remove("hidden");
|
||||
galleryModal.setAttribute("aria-hidden", "false");
|
||||
document.body.style.overflow = "hidden";
|
||||
};
|
||||
|
||||
const closeGallery = () => {
|
||||
galleryModal.classList.add("hidden");
|
||||
galleryModal.setAttribute("aria-hidden", "true");
|
||||
document.body.style.overflow = "";
|
||||
};
|
||||
|
||||
const setActiveThumb = (activeThumb) => {
|
||||
galleryThumbs.forEach((thumb) => {
|
||||
thumb.classList.remove("border-amber-400/60");
|
||||
thumb.classList.add("border-stone-800");
|
||||
});
|
||||
if (activeThumb) {
|
||||
activeThumb.classList.remove("border-stone-800");
|
||||
activeThumb.classList.add("border-amber-400/60");
|
||||
activeThumb.scrollIntoView({ block: "nearest", inline: "nearest" });
|
||||
}
|
||||
};
|
||||
|
||||
const showGalleryImage = (index) => {
|
||||
if (galleryThumbs.length === 0) return;
|
||||
const normalizedIndex = (index + galleryThumbs.length) % galleryThumbs.length;
|
||||
const thumb = galleryThumbs[normalizedIndex];
|
||||
const nextSrc = thumb.dataset.galleryThumb;
|
||||
const nextAlt = thumb.dataset.galleryAlt || galleryMain.getAttribute("alt") || "";
|
||||
if (!nextSrc) return;
|
||||
activeIndex = normalizedIndex;
|
||||
galleryMain.setAttribute("src", nextSrc);
|
||||
galleryMain.setAttribute("alt", nextAlt);
|
||||
setActiveThumb(thumb);
|
||||
};
|
||||
|
||||
const stepGallery = (direction) => {
|
||||
if (galleryThumbs.length <= 1) return;
|
||||
showGalleryImage(activeIndex + direction);
|
||||
};
|
||||
|
||||
galleryThumbPrev?.addEventListener("click", () => {
|
||||
stepGallery(-1);
|
||||
});
|
||||
|
||||
galleryThumbNext?.addEventListener("click", () => {
|
||||
stepGallery(1);
|
||||
});
|
||||
|
||||
galleryOpeners.forEach((trigger) => {
|
||||
trigger.addEventListener("click", openGallery);
|
||||
});
|
||||
|
||||
galleryClosers.forEach((trigger) => {
|
||||
trigger.addEventListener("click", closeGallery);
|
||||
});
|
||||
|
||||
galleryThumbs.forEach((thumb, index) => {
|
||||
if (index === 0) {
|
||||
showGalleryImage(0);
|
||||
}
|
||||
thumb.addEventListener("click", () => {
|
||||
showGalleryImage(index);
|
||||
});
|
||||
});
|
||||
|
||||
galleryPrev?.addEventListener("click", () => {
|
||||
stepGallery(-1);
|
||||
});
|
||||
|
||||
galleryNext?.addEventListener("click", () => {
|
||||
stepGallery(1);
|
||||
});
|
||||
|
||||
galleryThumbViewport?.addEventListener(
|
||||
"wheel",
|
||||
(event) => {
|
||||
if (window.innerWidth >= 1024) {
|
||||
event.preventDefault();
|
||||
galleryThumbViewport.scrollBy({ top: event.deltaY, behavior: "smooth" });
|
||||
return;
|
||||
}
|
||||
if (Math.abs(event.deltaY) <= Math.abs(event.deltaX)) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
galleryThumbViewport.scrollBy({ left: event.deltaY, behavior: "smooth" });
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
|
||||
galleryModal.addEventListener("click", (event) => {
|
||||
if (event.target === galleryModal) {
|
||||
closeGallery();
|
||||
}
|
||||
});
|
||||
|
||||
galleryModal.addEventListener(
|
||||
"wheel",
|
||||
(event) => {
|
||||
if (galleryModal.getAttribute("aria-hidden") !== "false" || galleryThumbs.length <= 1) {
|
||||
return;
|
||||
}
|
||||
if (Math.abs(event.deltaY) < 10) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (wheelLocked) {
|
||||
return;
|
||||
}
|
||||
wheelLocked = true;
|
||||
stepGallery(event.deltaY > 0 ? 1 : -1);
|
||||
window.setTimeout(() => {
|
||||
wheelLocked = false;
|
||||
}, 180);
|
||||
},
|
||||
{ passive: false },
|
||||
);
|
||||
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (galleryModal.getAttribute("aria-hidden") !== "false") {
|
||||
return;
|
||||
}
|
||||
if (event.key === "Escape") {
|
||||
closeGallery();
|
||||
return;
|
||||
}
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault();
|
||||
stepGallery(-1);
|
||||
return;
|
||||
}
|
||||
if (event.key === "ArrowRight") {
|
||||
event.preventDefault();
|
||||
stepGallery(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user