mirror of
https://git.kh3group.com/georgebiri/khy_website.git
synced 2026-07-02 07:03:33 +00:00
- Replaced static quantity controls with a modal for image enlargement on product detail and catalog pages. - Added event listeners for image clicks to trigger modal display with enlarged images. - Updated product detail page to dynamically load images and descriptions, improving user experience. - Refactored JavaScript to streamline image handling and modal interactions. - Enhanced CSS for modal styling and transitions, ensuring a smooth user experience.
1433 lines
47 KiB
JavaScript
1433 lines
47 KiB
JavaScript
// Global script initialization test
|
|
console.log("=== MAIN.JS LOADED ===");
|
|
console.log("Current pathname:", window.location.pathname);
|
|
console.log(
|
|
"Is comparison page:",
|
|
window.location.pathname.includes("product-comparison.html")
|
|
);
|
|
|
|
// Update year in footer and handle smooth scrolling
|
|
function initSite() {
|
|
// Update footer year
|
|
const footer = document.querySelector("footer p");
|
|
if (footer) {
|
|
const currentYear = new Date().getFullYear();
|
|
footer.innerHTML = footer.innerHTML.replace("2024", currentYear);
|
|
}
|
|
|
|
// Smooth scrolling for navigation links
|
|
const navLinks = document.querySelectorAll('.nav-link[href^="#"]');
|
|
navLinks.forEach((link) => {
|
|
link.addEventListener("click", function (e) {
|
|
e.preventDefault();
|
|
const targetId = this.getAttribute("href").substring(1);
|
|
const targetElement = document.getElementById(targetId);
|
|
if (targetElement) {
|
|
const headerHeight = 112;
|
|
const targetPosition = targetElement.offsetTop - headerHeight;
|
|
window.scrollTo({ top: targetPosition, behavior: "smooth" });
|
|
}
|
|
});
|
|
});
|
|
|
|
// Handle cross-page navigation links (links that point to other pages with anchors)
|
|
const crossPageLinks = document.querySelectorAll('.nav-link[href*=".html#"]');
|
|
crossPageLinks.forEach((link) => {
|
|
link.addEventListener("click", function () {
|
|
// allow default navigation
|
|
});
|
|
});
|
|
|
|
// Remove any lingering .active classes and avoid adding new ones
|
|
const allNavLinks = document.querySelectorAll(".nav-link");
|
|
allNavLinks.forEach((a) => a.classList.remove("active"));
|
|
|
|
// Do not add page-specific active state anymore
|
|
// const currentPage = window.location.pathname.split("/").pop() || "index.html";
|
|
// const currentPageLink = document.querySelector(`.nav-link[href="${currentPage}"]`);
|
|
// if (currentPageLink) currentPageLink.classList.add("active");
|
|
|
|
// Disable scroll-based active highlighting
|
|
// (Keeping function for potential future use, but it does nothing now.)
|
|
function updateActiveLink() {
|
|
// no-op: active highlighting disabled globally
|
|
}
|
|
window.addEventListener("scroll", updateActiveLink);
|
|
updateActiveLink();
|
|
|
|
// Related products (dynamic)
|
|
(async function initRelated() {
|
|
const grid = document.getElementById("related-grid");
|
|
if (!grid) return;
|
|
|
|
// Don't run this function on product detail pages - let the product detail function handle it
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const productId = urlParams.get("id");
|
|
if (productId) return;
|
|
|
|
try {
|
|
const res = await fetch("data/products.json", { cache: "no-store" });
|
|
const data = await res.json();
|
|
const products = Array.isArray(data.products) ? data.products : [];
|
|
|
|
// Determine current product's category from the title text (fallback seating)
|
|
const title = document.querySelector("h1");
|
|
const currentName = (title?.textContent || "").trim();
|
|
const current = products.find(
|
|
(p) => (p.name || "").trim() === currentName
|
|
);
|
|
const category = current?.category || "seating";
|
|
|
|
// Filter related: same category but not the current product
|
|
const related = products.filter(
|
|
(p) => p.category === category && p.name !== currentName
|
|
);
|
|
|
|
let page = 1;
|
|
const pageSize = 4;
|
|
|
|
function render() {
|
|
grid.innerHTML = "";
|
|
const start = 0;
|
|
const end = page * pageSize; // cumulative show-more
|
|
related.slice(start, end).forEach((p) => {
|
|
const card = document.createElement("article");
|
|
card.className = "rounded-lg overflow-hidden bg-white shadow-sm";
|
|
|
|
// Distinct image background for Asgaard sofa to match others
|
|
const imageBgClass =
|
|
(p.name || "").toLowerCase() === "asgaard sofa"
|
|
? "bg-linen"
|
|
: "bg-white";
|
|
const panelBgClass = "bg-light-bg";
|
|
|
|
card.innerHTML = `
|
|
<div class=\"h-72 ${imageBgClass} flex items-center justify-center\">
|
|
<img src=\"${p.image}\" alt=\"${
|
|
p.alt || p.name
|
|
}\" class=\"w-full h-full object-cover\" />
|
|
</div>
|
|
<div class=\"${panelBgClass} p-6\">
|
|
<h3 class=\"font-poppins font-semibold text-2xl text-[#3A3A3A] mb-0\">${
|
|
p.name
|
|
}</h3>
|
|
</div>`;
|
|
grid.appendChild(card);
|
|
});
|
|
|
|
// Toggle show-more visibility
|
|
const btn = document.getElementById("related-show-more");
|
|
if (btn) {
|
|
const hasMore = related.length > page * pageSize;
|
|
btn.style.display = hasMore ? "inline-flex" : "none";
|
|
// Ensure centered label
|
|
btn.classList.add("inline-flex", "items-center", "justify-center");
|
|
}
|
|
}
|
|
|
|
const btn = document.getElementById("related-show-more");
|
|
if (btn) {
|
|
btn.addEventListener("click", () => {
|
|
page += 1;
|
|
render();
|
|
});
|
|
}
|
|
|
|
render();
|
|
} catch (e) {
|
|
console.error("Failed to load related products:", e);
|
|
}
|
|
})();
|
|
|
|
// Footer newsletter subscribe validation and feedback (works on all pages)
|
|
const siteFooter = document.querySelector("footer");
|
|
if (siteFooter) {
|
|
const emailInputs = siteFooter.querySelectorAll('input[type="email"]');
|
|
emailInputs.forEach((emailInput) => {
|
|
const inputRow = emailInput.closest(".flex") || emailInput.parentElement;
|
|
let subscribeButton = inputRow ? inputRow.querySelector("button") : null;
|
|
if (!subscribeButton) {
|
|
subscribeButton = emailInput.parentElement?.querySelector("button");
|
|
}
|
|
if (!subscribeButton) return;
|
|
subscribeButton.type = "button";
|
|
let feedback = inputRow ? inputRow.nextElementSibling : null;
|
|
if (!(feedback instanceof HTMLElement) || !feedback.dataset.feedback) {
|
|
feedback = document.createElement("div");
|
|
feedback.dataset.feedback = "newsletter";
|
|
if (inputRow && inputRow.parentElement) {
|
|
inputRow.parentElement.insertBefore(feedback, inputRow.nextSibling);
|
|
}
|
|
}
|
|
feedback.className =
|
|
"hidden mt-3 rounded-lg px-4 py-3 font-playfair text-base";
|
|
function showMessage(text, type) {
|
|
feedback.textContent = text;
|
|
feedback.className =
|
|
"mt-3 rounded-lg px-4 py-3 font-playfair text-base";
|
|
if (type === "success") {
|
|
feedback.classList.add(
|
|
"bg-green-50",
|
|
"border",
|
|
"border-green-200",
|
|
"text-green-800"
|
|
);
|
|
} else {
|
|
feedback.classList.add(
|
|
"bg-red-50",
|
|
"border",
|
|
"border-red-200",
|
|
"text-red-800"
|
|
);
|
|
}
|
|
feedback.classList.remove("hidden");
|
|
setTimeout(() => feedback.classList.add("hidden"), 3000);
|
|
}
|
|
subscribeButton.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
const value = (emailInput.value || "").trim();
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
emailInput.classList.remove("border-red-500");
|
|
if (!emailRegex.test(value)) {
|
|
emailInput.classList.add("border-red-500");
|
|
showMessage("Please enter a valid email address.", "error");
|
|
emailInput.focus();
|
|
return;
|
|
}
|
|
showMessage("Thank you for subscribing!", "success");
|
|
emailInput.value = "";
|
|
subscribeButton.disabled = true;
|
|
setTimeout(() => (subscribeButton.disabled = false), 1200);
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
// Image enlargement modal functionality (global)
|
|
function addImageEnlargementListeners() {
|
|
// Target both main product image AND gallery carousel images
|
|
const mainProductImage = document.querySelector(
|
|
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\] img[data-enlarge-src]"
|
|
);
|
|
const galleryImages = document.querySelectorAll(
|
|
"#product-gallery-images img[data-enlarge-src]"
|
|
);
|
|
const modal = document.getElementById("image-modal");
|
|
const modalImage = document.getElementById("modal-image");
|
|
const modalCloseBtn = document.getElementById("modal-close-btn");
|
|
|
|
console.log("Adding image enlargement listeners...");
|
|
console.log("Found main product image:", !!mainProductImage);
|
|
console.log("Found gallery images:", galleryImages.length);
|
|
console.log("Modal elements:", {
|
|
modal: !!modal,
|
|
modalImage: !!modalImage,
|
|
modalCloseBtn: !!modalCloseBtn,
|
|
});
|
|
|
|
if (!modal || !modalImage || !modalCloseBtn) {
|
|
console.log("Modal elements not found, skipping image enlargement setup");
|
|
return;
|
|
}
|
|
|
|
// Add click listener to main product image
|
|
if (mainProductImage) {
|
|
console.log(
|
|
`Adding click listener to main product image:`,
|
|
mainProductImage.src
|
|
);
|
|
mainProductImage.removeEventListener("click", handleImageClick);
|
|
mainProductImage.addEventListener("click", handleImageClick);
|
|
} else {
|
|
console.log("Main product image not found");
|
|
}
|
|
|
|
// Add click listeners to gallery carousel images
|
|
galleryImages.forEach((img, index) => {
|
|
console.log(
|
|
`Adding click listener to gallery image ${index + 1}:`,
|
|
img.src
|
|
);
|
|
img.removeEventListener("click", handleImageClick);
|
|
img.addEventListener("click", handleImageClick);
|
|
});
|
|
|
|
function handleImageClick(e) {
|
|
console.log("Image clicked!", this.src);
|
|
const imageSrc = this.getAttribute("data-enlarge-src");
|
|
const imageAlt = this.getAttribute("alt");
|
|
|
|
console.log("Opening modal with image:", imageSrc);
|
|
modalImage.src = imageSrc;
|
|
modalImage.alt = imageAlt;
|
|
|
|
// Show modal with animation
|
|
modal.classList.remove("hidden");
|
|
document.body.style.overflow = "hidden"; // Prevent background scrolling
|
|
|
|
// Trigger animation after a brief delay
|
|
setTimeout(() => {
|
|
modalImage.classList.remove("scale-95");
|
|
modalImage.classList.add("scale-100");
|
|
}, 10);
|
|
}
|
|
|
|
// Close modal functionality
|
|
function closeModal() {
|
|
// Animate out
|
|
modalImage.classList.remove("scale-100");
|
|
modalImage.classList.add("scale-95");
|
|
|
|
// Hide modal after animation
|
|
setTimeout(() => {
|
|
modal.classList.add("hidden");
|
|
document.body.style.overflow = ""; // Restore scrolling
|
|
}, 300);
|
|
}
|
|
|
|
modalCloseBtn.addEventListener("click", closeModal);
|
|
|
|
// Close modal when clicking outside the image
|
|
modal.addEventListener("click", function (e) {
|
|
if (e.target === modal) {
|
|
closeModal();
|
|
}
|
|
});
|
|
|
|
// Close modal with Escape key
|
|
document.addEventListener("keydown", function (e) {
|
|
if (e.key === "Escape" && !modal.classList.contains("hidden")) {
|
|
closeModal();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Thumbnail click functionality (global)
|
|
function addThumbnailClickListeners() {
|
|
const thumbnails = document.querySelectorAll("[data-thumbnail-src]");
|
|
const mainImageContainer = document.querySelector(
|
|
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\]"
|
|
);
|
|
|
|
console.log("Adding thumbnail click listeners...");
|
|
console.log("Found thumbnails:", thumbnails.length);
|
|
console.log("Main image container:", !!mainImageContainer);
|
|
|
|
if (!mainImageContainer) {
|
|
console.log("Main image container not found");
|
|
return;
|
|
}
|
|
|
|
thumbnails.forEach((thumbnail, index) => {
|
|
thumbnail.addEventListener("click", function () {
|
|
const imageSrc = this.getAttribute("data-thumbnail-src");
|
|
console.log(`Thumbnail ${index + 1} clicked, switching to:`, imageSrc);
|
|
|
|
// Update the main product image
|
|
const mainImg = mainImageContainer.querySelector("img");
|
|
if (mainImg) {
|
|
mainImg.src = imageSrc;
|
|
mainImg.setAttribute("data-enlarge-src", imageSrc);
|
|
console.log("Main image updated to:", imageSrc);
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
// Product detail page functionality
|
|
async function initProductDetail() {
|
|
console.log("Product detail script running...");
|
|
console.log("Current URL:", window.location.href);
|
|
|
|
// Check if we're on the product detail page
|
|
const productTitle = document.querySelector("h1");
|
|
if (!productTitle) {
|
|
console.log("No h1 found, not on product detail page");
|
|
return;
|
|
}
|
|
console.log("Found h1 element:", productTitle);
|
|
|
|
// Get product ID from URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const productId = parseInt(urlParams.get("id"));
|
|
console.log("Product ID from URL:", productId);
|
|
|
|
if (!productId) {
|
|
console.log("No product ID found in URL");
|
|
return;
|
|
}
|
|
|
|
try {
|
|
// Load product data
|
|
const response = await fetch("data/products.json");
|
|
const data = await response.json();
|
|
const product = data.products.find((p) => p.id === productId);
|
|
|
|
if (!product) {
|
|
console.error("Product not found:", productId);
|
|
return;
|
|
}
|
|
|
|
console.log("Loading product:", product);
|
|
|
|
// Update page title
|
|
document.title = `${product.name} - KHY`;
|
|
|
|
// Update the "Product Details" title with the actual product name
|
|
const productDetailsTitle = document.getElementById(
|
|
"product-details-title"
|
|
);
|
|
if (productDetailsTitle) {
|
|
productDetailsTitle.textContent = product.name;
|
|
}
|
|
|
|
// Update product title (the main product title, not the breadcrumb)
|
|
const productTitle = document.getElementById("product-title");
|
|
console.log("Product title element:", productTitle);
|
|
if (productTitle) {
|
|
productTitle.textContent = product.name;
|
|
console.log("Updated product title to:", product.name);
|
|
}
|
|
|
|
// Update product description
|
|
const productDescription = document.getElementById("product-description");
|
|
console.log("Product description element:", productDescription);
|
|
if (productDescription) {
|
|
productDescription.textContent = product.description;
|
|
console.log("Updated product description to:", product.description);
|
|
}
|
|
|
|
// Update main product image
|
|
const mainImageContainer = document.querySelector(
|
|
".w-full.h-80.md\\:w-\\[500px\\].md\\:h-\\[500px\\]"
|
|
);
|
|
console.log("Main image container:", mainImageContainer);
|
|
if (mainImageContainer) {
|
|
mainImageContainer.innerHTML = `
|
|
<img
|
|
src="${product.image}"
|
|
alt="${product.alt || product.name}"
|
|
class="w-full h-full object-cover cursor-pointer hover:opacity-90 transition-opacity"
|
|
data-enlarge-src="${product.image}"
|
|
/>
|
|
`;
|
|
console.log("Updated main image to:", product.image);
|
|
|
|
// Add image enlargement functionality to the main product image
|
|
setTimeout(() => {
|
|
addImageEnlargementListeners();
|
|
}, 100);
|
|
}
|
|
|
|
// Update thumbnail images
|
|
const thumbnailContainer = document.querySelector(
|
|
".flex.flex-row.md\\:flex-col.gap-3.md\\:gap-4"
|
|
);
|
|
console.log("Thumbnail container:", thumbnailContainer);
|
|
if (thumbnailContainer && product.images) {
|
|
thumbnailContainer.innerHTML = product.images
|
|
.slice(0, 4)
|
|
.map(
|
|
(img, index) => `
|
|
<div class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer hover:opacity-80 transition-opacity" data-thumbnail-src="${img}">
|
|
<img
|
|
src="${img}"
|
|
alt="${product.name} ${index + 1}"
|
|
class="w-full h-full object-cover"
|
|
/>
|
|
</div>
|
|
`
|
|
)
|
|
.join("");
|
|
console.log("Updated thumbnails with", product.images.length, "images");
|
|
|
|
// Add click event listeners to thumbnails
|
|
addThumbnailClickListeners();
|
|
}
|
|
|
|
// Update size options
|
|
const sizeContainer = document.getElementById("size-buttons-container");
|
|
console.log("Size container:", sizeContainer);
|
|
if (sizeContainer && product.sizes) {
|
|
sizeContainer.innerHTML = product.sizes
|
|
.map(
|
|
(size, index) => `
|
|
<button
|
|
class="w-8 h-8 ${
|
|
index === 0
|
|
? "bg-uc-gold text-white"
|
|
: "bg-floral-white text-black"
|
|
} font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
|
|
>
|
|
${size}
|
|
</button>
|
|
`
|
|
)
|
|
.join("");
|
|
console.log("Updated size options with", product.sizes.length, "sizes");
|
|
}
|
|
|
|
// Update color options
|
|
const colorContainer = document.getElementById("color-buttons-container");
|
|
console.log("Color container:", colorContainer);
|
|
if (colorContainer && product.colors) {
|
|
colorContainer.innerHTML = product.colors
|
|
.map(
|
|
(color, index) => `
|
|
<button
|
|
class="w-8 h-8 rounded-full ${
|
|
index === 0 ? "border-2 border-black" : ""
|
|
}"
|
|
style="background-color: ${color}"
|
|
></button>
|
|
`
|
|
)
|
|
.join("");
|
|
console.log(
|
|
"Updated color options with",
|
|
product.colors.length,
|
|
"colors"
|
|
);
|
|
}
|
|
|
|
// Update product metadata - find by text content
|
|
const allSpans = document.querySelectorAll("span");
|
|
|
|
// Find and update Model No.
|
|
const modelNoLabel = Array.from(allSpans).find(
|
|
(span) => span.textContent === "Model No."
|
|
);
|
|
if (modelNoLabel && product.modelNo) {
|
|
const modelNoValue =
|
|
modelNoLabel.parentElement.querySelector("span:last-child");
|
|
if (modelNoValue) {
|
|
modelNoValue.textContent = product.modelNo;
|
|
}
|
|
}
|
|
|
|
// Find and update Category
|
|
const categoryLabel = Array.from(allSpans).find(
|
|
(span) => span.textContent === "Category"
|
|
);
|
|
if (categoryLabel && product.category) {
|
|
const categoryValue =
|
|
categoryLabel.parentElement.querySelector("span:last-child");
|
|
if (categoryValue) {
|
|
categoryValue.textContent =
|
|
product.category.charAt(0).toUpperCase() + product.category.slice(1);
|
|
}
|
|
}
|
|
|
|
|
|
// Find and update Dimensions
|
|
const dimensionsLabel = Array.from(allSpans).find(
|
|
(span) => span.textContent === "Dimension"
|
|
);
|
|
console.log("Dimensions label found:", dimensionsLabel);
|
|
console.log("Product dimensions:", product.dimensions);
|
|
|
|
if (dimensionsLabel && product.dimensions) {
|
|
const dimensionsValue =
|
|
dimensionsLabel.parentElement.querySelector("span:last-child");
|
|
console.log("Dimensions value element:", dimensionsValue);
|
|
if (dimensionsValue) {
|
|
dimensionsValue.textContent = product.dimensions;
|
|
console.log("Updated dimensions to:", product.dimensions);
|
|
}
|
|
}
|
|
|
|
// Update description content
|
|
const descriptionContainer = document.getElementById(
|
|
"product-description-content"
|
|
);
|
|
console.log("Description content container:", descriptionContainer);
|
|
if (descriptionContainer && product.descriptionLong) {
|
|
descriptionContainer.innerHTML = product.descriptionLong
|
|
.map(
|
|
(paragraph) => `
|
|
<p class="font-playfair text-base leading-6 text-[#333333] text-justify">
|
|
${paragraph}
|
|
</p>
|
|
`
|
|
)
|
|
.join("");
|
|
console.log(
|
|
"Updated description content with",
|
|
product.descriptionLong.length,
|
|
"paragraphs"
|
|
);
|
|
}
|
|
|
|
// Update gallery images with carousel
|
|
const galleryContainer = document.getElementById("product-gallery-images");
|
|
const galleryBackBtn = document.getElementById("gallery-back-btn");
|
|
const galleryNextBtn = document.getElementById("gallery-next-btn");
|
|
console.log("Gallery container:", galleryContainer);
|
|
console.log("Product galleryPairs:", product.galleryPairs);
|
|
|
|
if (galleryContainer && product.galleryPairs) {
|
|
// galleryPairs is now a simple array of image paths
|
|
const allGalleryImages = product.galleryPairs;
|
|
console.log("All gallery images:", allGalleryImages);
|
|
|
|
// Store gallery images for carousel
|
|
window.currentGalleryImages = allGalleryImages;
|
|
window.currentGalleryIndex = 0;
|
|
|
|
console.log("About to call renderGalleryCarousel...");
|
|
// Render initial gallery view
|
|
renderGalleryCarousel();
|
|
|
|
// Show navigation arrows for looped carousel (always show if more than 2 images)
|
|
if (allGalleryImages.length > 2) {
|
|
galleryBackBtn.style.display = "block";
|
|
galleryNextBtn.style.display = "block";
|
|
} else {
|
|
galleryBackBtn.style.display = "none";
|
|
galleryNextBtn.style.display = "none";
|
|
}
|
|
|
|
console.log(
|
|
"Gallery carousel:",
|
|
allGalleryImages.length,
|
|
"gallery images total (sliding)"
|
|
);
|
|
}
|
|
|
|
function renderGalleryCarousel() {
|
|
console.log("renderGalleryCarousel called");
|
|
console.log("window.currentGalleryImages:", window.currentGalleryImages);
|
|
console.log("galleryContainer:", galleryContainer);
|
|
|
|
if (!window.currentGalleryImages || !galleryContainer) {
|
|
console.log(
|
|
"Early return: missing currentGalleryImages or galleryContainer"
|
|
);
|
|
return;
|
|
}
|
|
|
|
console.log(
|
|
"Rendering gallery carousel with",
|
|
window.currentGalleryImages.length,
|
|
"images"
|
|
);
|
|
|
|
// Handle single image vs multiple images
|
|
if (window.currentGalleryImages.length === 1) {
|
|
// Single image - show only one image, hide arrows
|
|
const image1 = window.currentGalleryImages[0];
|
|
console.log("Rendering single image:", image1);
|
|
galleryContainer.innerHTML = `
|
|
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-1">
|
|
<img
|
|
src="${image1}"
|
|
alt="${product.name} gallery"
|
|
class="w-full h-80 object-contain mx-auto"
|
|
data-enlarge-src="${image1}"
|
|
/>
|
|
</div>
|
|
`;
|
|
|
|
// Hide arrows for single image
|
|
galleryBackBtn.style.display = "none";
|
|
galleryNextBtn.style.display = "none";
|
|
} else {
|
|
// Multiple images - show 2 images with carousel
|
|
const image1 = window.currentGalleryImages[window.currentGalleryIndex];
|
|
const image2Index =
|
|
(window.currentGalleryIndex + 1) % window.currentGalleryImages.length;
|
|
const image2 = window.currentGalleryImages[image2Index];
|
|
|
|
console.log("Rendering multiple images:", image1, image2);
|
|
|
|
galleryContainer.innerHTML = `
|
|
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-1">
|
|
<img
|
|
src="${image1}"
|
|
alt="${product.name} gallery"
|
|
class="w-full h-80 object-contain mx-auto"
|
|
data-enlarge-src="${image1}"
|
|
/>
|
|
</div>
|
|
<div class="rounded-[10px] bg-floral-white p-6 transition-all duration-1500 ease-out cursor-pointer hover:opacity-90" id="gallery-image-2">
|
|
<img
|
|
src="${image2}"
|
|
alt="${product.name} gallery"
|
|
class="w-full h-80 object-contain mx-auto"
|
|
data-enlarge-src="${image2}"
|
|
/>
|
|
</div>
|
|
`;
|
|
|
|
// Show arrows for multiple images
|
|
galleryBackBtn.style.display = "block";
|
|
galleryBackBtn.style.opacity = "1";
|
|
galleryBackBtn.style.pointerEvents = "auto";
|
|
|
|
galleryNextBtn.style.display = "block";
|
|
galleryNextBtn.style.opacity = "1";
|
|
galleryNextBtn.style.pointerEvents = "auto";
|
|
}
|
|
|
|
// Add click event listeners to gallery images for enlargement
|
|
console.log("About to call addImageEnlargementListeners for gallery...");
|
|
addImageEnlargementListeners();
|
|
}
|
|
|
|
// Add click handlers for looped gallery carousel navigation
|
|
if (galleryBackBtn) {
|
|
galleryBackBtn.addEventListener("click", function () {
|
|
// Left arrow moves forward: if at last position, go to 0
|
|
window.currentGalleryIndex =
|
|
(window.currentGalleryIndex + 1) % window.currentGalleryImages.length;
|
|
renderGalleryCarousel();
|
|
});
|
|
}
|
|
|
|
if (galleryNextBtn) {
|
|
galleryNextBtn.addEventListener("click", function () {
|
|
// Right arrow moves backward: if at 0, go to last position
|
|
window.currentGalleryIndex =
|
|
window.currentGalleryIndex === 0
|
|
? window.currentGalleryImages.length - 1
|
|
: window.currentGalleryIndex - 1;
|
|
renderGalleryCarousel();
|
|
});
|
|
}
|
|
|
|
// Update related products section
|
|
const relatedGrid = document.getElementById("related-grid");
|
|
if (relatedGrid && product.category) {
|
|
console.log("Current product category:", product.category);
|
|
console.log(
|
|
"All products:",
|
|
data.products.map((p) => ({
|
|
id: p.id,
|
|
name: p.name,
|
|
category: p.category,
|
|
}))
|
|
);
|
|
|
|
// Filter related products by category (excluding current product)
|
|
const allRelatedProducts = data.products.filter(
|
|
(p) => p.category === product.category && p.id !== product.id
|
|
);
|
|
|
|
console.log("All related products found:", allRelatedProducts);
|
|
|
|
let currentPage = 1;
|
|
const pageSize = 4;
|
|
|
|
function renderRelatedProducts() {
|
|
const start = 0;
|
|
const end = currentPage * pageSize;
|
|
const productsToShow = allRelatedProducts.slice(start, end);
|
|
|
|
relatedGrid.innerHTML = productsToShow
|
|
.map(
|
|
(p) => `
|
|
<a href="product-detail.html?id=${p.id}" class="block">
|
|
<div class="rounded-lg overflow-hidden bg-white shadow-sm hover:shadow-lg transition-shadow">
|
|
<div class="h-72 ${
|
|
p.name.toLowerCase().includes("asgaard")
|
|
? "bg-linen"
|
|
: "bg-white"
|
|
} flex items-center justify-center">
|
|
<img src="${p.image}" alt="${
|
|
p.alt || p.name
|
|
}" class="w-full h-full object-cover" />
|
|
</div>
|
|
<div class="bg-light-bg p-6">
|
|
<h3 class="font-poppins font-semibold text-2xl text-[#3A3A3A] mb-0">${
|
|
p.name
|
|
}</h3>
|
|
</div>
|
|
</div>
|
|
</a>
|
|
`
|
|
)
|
|
.join("");
|
|
|
|
// Handle "Show More" button visibility
|
|
const showMoreBtn = document.getElementById("related-show-more");
|
|
if (showMoreBtn) {
|
|
const hasMore = allRelatedProducts.length > end;
|
|
showMoreBtn.style.display = hasMore ? "inline-flex" : "none";
|
|
showMoreBtn.classList.add(
|
|
"inline-flex",
|
|
"items-center",
|
|
"justify-center"
|
|
);
|
|
}
|
|
}
|
|
|
|
// Add event listener for "Show More" button
|
|
const showMoreBtn = document.getElementById("related-show-more");
|
|
if (showMoreBtn) {
|
|
showMoreBtn.addEventListener("click", () => {
|
|
currentPage += 1;
|
|
renderRelatedProducts();
|
|
});
|
|
}
|
|
|
|
// Initial render
|
|
renderRelatedProducts();
|
|
}
|
|
} catch (error) {
|
|
console.error("Error loading product data:", error);
|
|
}
|
|
}
|
|
|
|
// Product Comparison Page Functionality
|
|
function initProductComparison() {
|
|
console.log("=== INITIALIZING PRODUCT COMPARISON ===");
|
|
|
|
// Prevent running twice (it's invoked in multiple places)
|
|
if (window.__cmpInitialized) {
|
|
console.log("[Comparison] Already initialized, skipping");
|
|
return;
|
|
}
|
|
window.__cmpInitialized = true;
|
|
|
|
// Get product IDs from URL parameters
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const product1Id = urlParams.get("product1");
|
|
const product2Id = urlParams.get("product2");
|
|
|
|
console.log("URL Parameters:", { product1Id, product2Id });
|
|
|
|
// Keep references to the two products for event handlers
|
|
let cmpProduct1 = null;
|
|
let cmpProduct2 = null;
|
|
|
|
// Fetch product data
|
|
fetch("data/products.json")
|
|
.then((response) => {
|
|
console.log("Fetch response status:", response.status);
|
|
return response.json();
|
|
})
|
|
.then((data) => {
|
|
console.log("Products data loaded:", data);
|
|
console.log("Total products:", data.products.length);
|
|
|
|
// Find products by ID
|
|
const product1 = data.products.find((p) => p.id == product1Id);
|
|
const product2 = data.products.find((p) => p.id == product2Id);
|
|
|
|
console.log("Found products:", { product1, product2 });
|
|
|
|
// Update product cards
|
|
if (product1) {
|
|
console.log("Updating product card 1 with:", product1.name);
|
|
cmpProduct1 = product1;
|
|
updateProductCard(1, product1);
|
|
updateComparisonTable(product1, 1);
|
|
}
|
|
|
|
if (product2) {
|
|
console.log("Updating product card 2 with:", product2.name);
|
|
cmpProduct2 = product2;
|
|
updateProductCard(2, product2);
|
|
updateComparisonTable(product2, 2);
|
|
}
|
|
|
|
// Populate dropdown
|
|
populateProductDropdown(data.products);
|
|
|
|
// Update View More link with current comparison state
|
|
updateViewMoreLink(product1Id, product2Id);
|
|
})
|
|
.catch((error) => {
|
|
console.error("Error loading products:", error);
|
|
});
|
|
}
|
|
|
|
function updateProductCard(slotNumber, product) {
|
|
console.log(`=== UPDATING PRODUCT CARD ${slotNumber} ===`);
|
|
console.log("Product data:", product);
|
|
|
|
const cardContainer = document.querySelector(`.product-card-${slotNumber}`);
|
|
console.log("Card container found:", cardContainer);
|
|
|
|
if (cardContainer) {
|
|
const imageContainer = cardContainer.querySelector("div");
|
|
const title = cardContainer.querySelector("p");
|
|
|
|
console.log("Image container found:", imageContainer);
|
|
console.log("Title element found:", title);
|
|
|
|
if (imageContainer) {
|
|
console.log("Replacing image container with:", product.image);
|
|
// Replace the placeholder div with an image
|
|
imageContainer.innerHTML = `<img src="${product.image}" alt="${product.name}" class="w-full h-full object-cover rounded-lg">`;
|
|
}
|
|
if (title) {
|
|
console.log("Updating title to:", product.name);
|
|
title.textContent = product.name;
|
|
}
|
|
} else {
|
|
console.log(`Product card container .product-card-${slotNumber} not found`);
|
|
}
|
|
}
|
|
|
|
function updateComparisonTable(product, slotNumber) {
|
|
console.log(`=== UPDATING COMPARISON TABLE FOR SLOT ${slotNumber} ===`);
|
|
console.log("Product:", product);
|
|
|
|
// Update all sections
|
|
const sections = ["general", "product", "dimensions", "warranty"];
|
|
|
|
sections.forEach((section) => {
|
|
console.log(`Updating ${section} section...`);
|
|
updateTableSection(section, product, slotNumber);
|
|
});
|
|
}
|
|
|
|
function updateTableSection(sectionName, product, slotNumber) {
|
|
console.log(
|
|
`=== UPDATING TABLE SECTION: ${sectionName} (SLOT ${slotNumber}) ===`
|
|
);
|
|
const sectionData = getProductSectionData(product, sectionName);
|
|
|
|
// Find the section header
|
|
const section = document.querySelector(
|
|
`.comparison-table .${sectionName}-section`
|
|
);
|
|
if (!section) {
|
|
console.log(`Section ${sectionName}-section not found`);
|
|
return;
|
|
}
|
|
|
|
// Find the table that comes after this section header
|
|
const sectionTable = section.nextElementSibling;
|
|
if (!sectionTable) {
|
|
console.log(`Table after ${sectionName}-section not found`);
|
|
return;
|
|
}
|
|
|
|
// Find all flex rows and filter to only those with data columns
|
|
const allRows = sectionTable.querySelectorAll(".flex.items-center");
|
|
const rows = Array.from(allRows).filter((row) =>
|
|
row.querySelector(".column-1")
|
|
);
|
|
console.log(
|
|
`Found ${rows.length} data rows in ${sectionName} section (out of ${allRows.length} total rows)`
|
|
);
|
|
|
|
if (rows.length > 0 && sectionData) {
|
|
console.log("Updating rows with data:", sectionData);
|
|
|
|
// Update each row with the corresponding data
|
|
rows.forEach((row, index) => {
|
|
if (index < sectionData.length) {
|
|
const column = row.querySelector(`.column-${slotNumber}`);
|
|
if (column) {
|
|
console.log(
|
|
`Updating row ${index + 1} with data: ${sectionData[index]}`
|
|
);
|
|
console.log(`Row element:`, row);
|
|
console.log(`Column element:`, column);
|
|
console.log(`Column text before update: "${column.textContent}"`);
|
|
column.textContent = sectionData[index];
|
|
console.log(`Column text after update: "${column.textContent}"`);
|
|
} else {
|
|
console.log(`Column ${slotNumber} not found in row ${index + 1}`);
|
|
}
|
|
}
|
|
});
|
|
|
|
console.log("Table section updated successfully.");
|
|
} else {
|
|
console.log("No rows found or section data is empty, skipping update.");
|
|
console.log("Rows found:", rows.length);
|
|
console.log("Section data:", sectionData);
|
|
}
|
|
}
|
|
|
|
function getProductSectionData(product, sectionName) {
|
|
console.log(`=== GETTING PRODUCT SECTION DATA: ${sectionName} ===`);
|
|
console.log("Product:", product);
|
|
|
|
let sectionData;
|
|
switch (sectionName) {
|
|
case "general":
|
|
sectionData = [
|
|
product.salesPackage || "N/A", // Sales Package
|
|
product.modelNo || "N/A", // Model Number
|
|
product.additionalInformation?.Material || "N/A", // Secondary Material
|
|
product.configuration || "N/A", // Configuration
|
|
product.additionalInformation?.Upholstery || "N/A", // Upholstery Material
|
|
product.colors?.[0]?.name || "N/A", // Upholstery Color
|
|
];
|
|
break;
|
|
case "product":
|
|
sectionData = [
|
|
product.fillingMaterial || "N/A", // Filling Material
|
|
product.finishType || "N/A", // Finish Type
|
|
product.adjustableHeadrest || "N/A", // Adjustable Headrest
|
|
product.maxLoadCapacity || "N/A", // Maximum Load Capacity
|
|
product.originOfManufacture || "N/A", // Origin of Manufacture
|
|
];
|
|
break;
|
|
case "dimensions":
|
|
const dims = product.dimensions?.split(" x ") || [];
|
|
sectionData = [
|
|
dims[0] || "N/A", // Width
|
|
dims[1] || "N/A", // Height
|
|
dims[2] || "N/A", // Depth
|
|
product.weight || "N/A", // Weight
|
|
product.seatHeight || "N/A", // Seat Height
|
|
product.legHeight || "N/A", // Leg Height
|
|
];
|
|
break;
|
|
case "warranty":
|
|
sectionData = [
|
|
product.additionalInformation?.Warranty || "N/A", // Warranty Summary
|
|
product.warrantyServiceType || "N/A", // Warranty Service Type
|
|
product.coveredInWarranty || "N/A", // Covered in Warranty
|
|
product.notCoveredInWarranty || "N/A", // Not Covered in Warranty
|
|
product.additionalInformation?.Warranty || "N/A", // Domestic Warranty
|
|
];
|
|
break;
|
|
default:
|
|
sectionData = [];
|
|
}
|
|
|
|
console.log(`Section data for ${sectionName}:`, sectionData);
|
|
console.log(`Detailed breakdown for ${sectionName}:`);
|
|
sectionData.forEach((item, index) => {
|
|
console.log(` Item ${index + 1}: "${item}"`);
|
|
});
|
|
|
|
return sectionData;
|
|
}
|
|
|
|
function populateProductDropdown(products) {
|
|
const dropdown = document.getElementById("product-dropdown");
|
|
if (dropdown) {
|
|
// Clear existing options except the first one
|
|
while (dropdown.children.length > 1) {
|
|
dropdown.removeChild(dropdown.lastChild);
|
|
}
|
|
|
|
// Add all products
|
|
products.forEach((product) => {
|
|
const option = document.createElement("option");
|
|
option.value = product.id;
|
|
option.textContent = product.name;
|
|
dropdown.appendChild(option);
|
|
});
|
|
|
|
// Add event listener for product selection
|
|
dropdown.addEventListener("change", function () {
|
|
const selectedProductId = this.value;
|
|
console.log("Product selected from dropdown:", selectedProductId);
|
|
|
|
if (selectedProductId && selectedProductId !== "Choose a Product") {
|
|
// Find the selected product
|
|
const selectedProduct = products.find((p) => p.id == selectedProductId);
|
|
|
|
if (selectedProduct) {
|
|
console.log("Selected product found:", selectedProduct);
|
|
|
|
// Update the second product slot
|
|
updateProductCard(2, selectedProduct);
|
|
updateComparisonTable(selectedProduct, 2);
|
|
|
|
// Update URL to include the second product
|
|
updateURLParameter("product2", selectedProductId);
|
|
|
|
// Reset dropdown to default option
|
|
this.value = "Choose a Product";
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function updateURLParameter(param, value) {
|
|
const url = new URL(window.location);
|
|
url.searchParams.set(param, value);
|
|
window.history.replaceState({}, "", url);
|
|
}
|
|
|
|
function updateViewMoreLink(product1Id, product2Id) {
|
|
const viewMoreLink = document.querySelector(
|
|
'a[href*="product-catalog.html"]'
|
|
);
|
|
if (viewMoreLink) {
|
|
// Determine which slot is available (1 or 2)
|
|
let availableSlot = 1;
|
|
if (!product1Id) {
|
|
availableSlot = 1;
|
|
} else if (!product2Id) {
|
|
availableSlot = 2;
|
|
} else {
|
|
// Both slots are filled, default to slot 2 for replacement
|
|
availableSlot = 2;
|
|
}
|
|
|
|
let newHref = `product-catalog.html?returnTo=comparison&slot=${availableSlot}`;
|
|
if (product1Id) newHref += `&product1=${product1Id}`;
|
|
if (product2Id) newHref += `&product2=${product2Id}`;
|
|
|
|
viewMoreLink.href = newHref;
|
|
console.log("Updated View More link:", newHref);
|
|
}
|
|
}
|
|
|
|
// Initialize product comparison if on comparison page
|
|
console.log("=== CHECKING IF COMPARISON PAGE INITIALIZATION SHOULD RUN ===");
|
|
console.log(
|
|
"Pathname includes product-comparison.html:",
|
|
window.location.pathname.includes("product-comparison.html")
|
|
);
|
|
|
|
if (window.location.pathname.includes("product-comparison.html")) {
|
|
console.log("Product comparison page detected, initializing immediately");
|
|
initProductComparison();
|
|
|
|
// Also try on DOMContentLoaded as backup
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
console.log("Product comparison page DOMContentLoaded backup");
|
|
initProductComparison();
|
|
});
|
|
}
|
|
|
|
// Product Detail Page - Compare Products functionality
|
|
function initProductDetailCompare() {
|
|
console.log("=== INITIALIZING PRODUCT DETAIL COMPARE ===");
|
|
console.log("Current URL:", window.location.href);
|
|
console.log("Pathname:", window.location.pathname);
|
|
|
|
// Try to find the button immediately
|
|
let compareButton = document.getElementById("compare-products-btn");
|
|
console.log("Button found by ID:", compareButton);
|
|
|
|
if (!compareButton) {
|
|
console.log("Button not found by ID, trying text search...");
|
|
const buttons = document.querySelectorAll("button");
|
|
console.log("Total buttons found:", buttons.length);
|
|
|
|
buttons.forEach((button, index) => {
|
|
console.log(`Button ${index}: "${button.textContent.trim()}"`);
|
|
});
|
|
|
|
compareButton = Array.from(buttons).find(
|
|
(button) => button.textContent.trim() === "Compare Products"
|
|
);
|
|
console.log("Button found by text search:", compareButton);
|
|
}
|
|
|
|
if (compareButton) {
|
|
console.log("=== ADDING CLICK LISTENER ===");
|
|
|
|
// Remove any existing listeners first
|
|
compareButton.removeEventListener("click", handleCompareClick);
|
|
compareButton.addEventListener("click", handleCompareClick);
|
|
|
|
// Also add a direct onclick handler as backup
|
|
compareButton.onclick = handleCompareClick;
|
|
|
|
console.log("Click listener added successfully");
|
|
console.log("Button element:", compareButton);
|
|
console.log("Button text content:", compareButton.textContent);
|
|
} else {
|
|
console.log("=== BUTTON NOT FOUND ===");
|
|
console.log("Compare Products button not found");
|
|
}
|
|
}
|
|
|
|
// Separate function for the click handler
|
|
function handleCompareClick(event) {
|
|
console.log("Compare Products button clicked");
|
|
event.preventDefault();
|
|
event.stopPropagation();
|
|
|
|
// Get current product ID from URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const productId = urlParams.get("id");
|
|
|
|
console.log("Product ID from URL:", productId);
|
|
|
|
if (productId) {
|
|
// Navigate to comparison page with current product as product1
|
|
const comparisonUrl = `product-comparison.html?product1=${productId}`;
|
|
console.log("Navigating to:", comparisonUrl);
|
|
window.location.href = comparisonUrl;
|
|
} else {
|
|
// If no product ID, just go to comparison page
|
|
console.log("No product ID found, navigating to comparison page");
|
|
window.location.href = "product-comparison.html";
|
|
}
|
|
}
|
|
|
|
// Initialize immediately if we're on the product detail page
|
|
if (window.location.pathname.includes("product-detail.html")) {
|
|
console.log(
|
|
"Product detail page detected, initializing compare functionality immediately"
|
|
);
|
|
initProductDetailCompare();
|
|
// Also initialize product detail loading
|
|
initProductDetail();
|
|
}
|
|
|
|
// Also try to initialize on DOMContentLoaded
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
console.log("DOMContentLoaded event fired");
|
|
if (window.location.pathname.includes("product-detail.html")) {
|
|
console.log("Product detail page detected in DOMContentLoaded");
|
|
initProductDetailCompare();
|
|
// Also initialize product detail loading
|
|
initProductDetail();
|
|
}
|
|
});
|
|
|
|
// Initialize product comparison if on comparison page
|
|
if (window.location.pathname.includes("product-comparison.html")) {
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
initProductComparison();
|
|
});
|
|
}
|
|
|
|
// Initialize comparison functionality if on product catalog page
|
|
if (window.location.pathname.includes("product-catalog.html")) {
|
|
console.log("=== PRODUCT CATALOG PAGE DETECTED ===");
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
console.log(
|
|
"=== DOM CONTENT LOADED - INITIALIZING PRODUCT CATALOG COMPARISON ==="
|
|
);
|
|
initProductCatalogComparison();
|
|
});
|
|
}
|
|
|
|
// Product Catalog - Handle comparison page returns
|
|
function initProductCatalogComparison() {
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const returnTo = urlParams.get("returnTo");
|
|
const slot = urlParams.get("slot");
|
|
const product1Id = urlParams.get("product1");
|
|
const product2Id = urlParams.get("product2");
|
|
|
|
console.log("Product catalog comparison params:", {
|
|
returnTo,
|
|
slot,
|
|
product1Id,
|
|
product2Id,
|
|
});
|
|
|
|
if (returnTo === "comparison" && slot) {
|
|
console.log("Setting up comparison return functionality for slot:", slot);
|
|
|
|
// Note: Product card click handling is now done in products.js viewProduct method
|
|
console.log(
|
|
"Comparison mode activated - View buttons will navigate to comparison page"
|
|
);
|
|
}
|
|
}
|
|
|
|
// Replace Poppins with Playfair in all font references
|
|
function updateFontClasses() {
|
|
// Find all elements with font-poppins class and replace with font-playfair
|
|
const poppinsElements = document.querySelectorAll(".font-poppins");
|
|
poppinsElements.forEach((element) => {
|
|
element.classList.remove("font-poppins");
|
|
element.classList.add("font-playfair");
|
|
});
|
|
}
|
|
|
|
// Run font update on page load
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
updateFontClasses();
|
|
});
|
|
|
|
if (document.readyState === "loading") {
|
|
document.addEventListener("DOMContentLoaded", initSite);
|
|
} else {
|
|
initSite();
|
|
}
|
|
|
|
// Initialize page functionality
|
|
document.addEventListener("DOMContentLoaded", function () {
|
|
initHeroCarousel();
|
|
initMobileMenu();
|
|
initCuratedCardsTap();
|
|
});
|
|
|
|
// Hero Carousel Functionality
|
|
function initHeroCarousel() {
|
|
const arrowButton = document.getElementById("story-arrow-button");
|
|
const heroImage = document.querySelector("#hero-image img");
|
|
|
|
if (!arrowButton || !heroImage) return;
|
|
|
|
// Carousel images array
|
|
const carouselImages = [
|
|
"assets/images/our_story/chair.jpg",
|
|
"assets/images/our_story/booth.png",
|
|
"assets/images/our_story/screen.jpg",
|
|
"assets/images/our_story/table.jpg",
|
|
"assets/images/our_story/chair2.jpg",
|
|
"assets/images/our_story/storage.jpg",
|
|
];
|
|
|
|
let currentImageIndex = 0;
|
|
|
|
// Function to update image with fade transition
|
|
function updateImage(newIndex) {
|
|
const newImage = new Image();
|
|
newImage.onload = function () {
|
|
// Fade out current image
|
|
heroImage.style.opacity = "0";
|
|
|
|
setTimeout(() => {
|
|
// Change image source
|
|
heroImage.src = carouselImages[newIndex];
|
|
heroImage.alt = `Carousel image ${newIndex + 1}`;
|
|
|
|
// Ensure image always fits its container uniformly
|
|
heroImage.style.height = "100%";
|
|
heroImage.style.objectFit = "cover";
|
|
|
|
// Fade in new image
|
|
heroImage.style.opacity = "1";
|
|
|
|
// Update indicators
|
|
updateIndicators(newIndex);
|
|
}, 300);
|
|
};
|
|
newImage.src = carouselImages[newIndex];
|
|
}
|
|
|
|
// Function to update carousel indicators
|
|
function updateIndicators(activeIndex) {
|
|
for (let i = 0; i < 6; i++) {
|
|
const indicator = document.getElementById(`carousel-indicator-${i}`);
|
|
if (indicator) {
|
|
indicator.style.opacity = i === activeIndex ? "1" : "0.5";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Arrow button click handler
|
|
arrowButton.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
currentImageIndex = (currentImageIndex + 1) % carouselImages.length;
|
|
updateImage(currentImageIndex);
|
|
});
|
|
|
|
// Indicator click handlers
|
|
for (let i = 0; i < 6; i++) {
|
|
const indicator = document.getElementById(`carousel-indicator-${i}`);
|
|
if (indicator) {
|
|
indicator.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
currentImageIndex = i;
|
|
updateImage(currentImageIndex);
|
|
});
|
|
}
|
|
}
|
|
|
|
// No dynamic height capture needed; CSS handles sizing
|
|
|
|
// Auto-advance carousel every 5 seconds
|
|
setInterval(() => {
|
|
currentImageIndex = (currentImageIndex + 1) % carouselImages.length;
|
|
updateImage(currentImageIndex);
|
|
}, 5000);
|
|
}
|
|
|
|
// Tap-to-toggle for curated cards on touch devices
|
|
function initCuratedCardsTap() {
|
|
try {
|
|
const cards = document.querySelectorAll(".curated-card");
|
|
if (!cards || cards.length === 0) return;
|
|
|
|
// Only enable on coarse pointers (touch)
|
|
const isTouchLike = window.matchMedia(
|
|
"(hover: none), (pointer: coarse)"
|
|
).matches;
|
|
if (!isTouchLike) return;
|
|
|
|
cards.forEach((card) => {
|
|
card.addEventListener("click", (e) => {
|
|
// Toggle active state; second tap removes it
|
|
card.classList.toggle("is-active");
|
|
});
|
|
|
|
// Optional: remove active when tapping outside the card
|
|
document.addEventListener("click", (evt) => {
|
|
if (!card.contains(evt.target)) {
|
|
card.classList.remove("is-active");
|
|
}
|
|
});
|
|
});
|
|
} catch (err) {
|
|
console.warn("Failed to init curated card tap behavior:", err);
|
|
}
|
|
}
|
|
|
|
// Mobile Menu Functionality
|
|
function initMobileMenu() {
|
|
const mobileMenuButton = document.getElementById("mobile-menu-button");
|
|
const mobileMenuClose = document.getElementById("mobile-menu-close");
|
|
const mobileMenu = document.getElementById("mobile-menu");
|
|
const mobileMenuOverlay = document.getElementById("mobile-menu-overlay");
|
|
|
|
if (
|
|
!mobileMenuButton ||
|
|
!mobileMenuClose ||
|
|
!mobileMenu ||
|
|
!mobileMenuOverlay
|
|
) {
|
|
console.log("Mobile menu elements not found");
|
|
return;
|
|
}
|
|
|
|
// Function to open mobile menu
|
|
function openMobileMenu() {
|
|
mobileMenu.classList.remove("translate-x-full");
|
|
mobileMenuOverlay.classList.remove("hidden");
|
|
document.body.style.overflow = "hidden"; // Prevent background scrolling
|
|
}
|
|
|
|
// Function to close mobile menu
|
|
function closeMobileMenu() {
|
|
mobileMenu.classList.add("translate-x-full");
|
|
mobileMenuOverlay.classList.add("hidden");
|
|
document.body.style.overflow = ""; // Restore scrolling
|
|
}
|
|
|
|
// Event listeners
|
|
mobileMenuButton.addEventListener("click", openMobileMenu);
|
|
mobileMenuClose.addEventListener("click", closeMobileMenu);
|
|
mobileMenuOverlay.addEventListener("click", closeMobileMenu);
|
|
|
|
// Close menu when clicking on navigation links
|
|
const mobileNavLinks = mobileMenu.querySelectorAll("a");
|
|
mobileNavLinks.forEach((link) => {
|
|
link.addEventListener("click", closeMobileMenu);
|
|
});
|
|
|
|
// Close menu on escape key
|
|
document.addEventListener("keydown", (e) => {
|
|
if (
|
|
e.key === "Escape" &&
|
|
!mobileMenu.classList.contains("translate-x-full")
|
|
) {
|
|
closeMobileMenu();
|
|
}
|
|
});
|
|
|
|
// Handle window resize - close menu if screen becomes large
|
|
window.addEventListener("resize", () => {
|
|
if (window.innerWidth >= 640) {
|
|
// sm breakpoint
|
|
closeMobileMenu();
|
|
}
|
|
});
|
|
}
|
|
|
|
// Version: 4.8 - Added mobile hamburger menu functionality
|