- Renamed sections in product-comparison.html for better alignment with product details, changing "Sales Package" to "Materials", "Model Number" to "Design", and "Secondary Material" to "Use Cases". - Removed redundant product and dimensions sections from the HTML as per request to streamline the comparison layout. - Updated main.js to reflect changes in the HTML, limiting the sections updated in the comparison table to "general" and "warranty" only, and adjusted data retrieval to match new section names.
1455 lines
47 KiB
JavaScript
1455 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 product specifications
|
|
const specificationsContainer = document.getElementById(
|
|
"product-specifications"
|
|
);
|
|
console.log("Specifications container:", specificationsContainer);
|
|
if (specificationsContainer && product.additionalInformation) {
|
|
const specifications = [];
|
|
|
|
// Add key specifications from additionalInformation
|
|
if (product.additionalInformation.Material) {
|
|
specifications.push({
|
|
label: "Material",
|
|
value: product.additionalInformation.Material,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Design) {
|
|
specifications.push({
|
|
label: "Design",
|
|
value: product.additionalInformation.Design,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation["Finish Options"]) {
|
|
specifications.push({
|
|
label: "Finish Options",
|
|
value: product.additionalInformation["Finish Options"],
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Headrest) {
|
|
specifications.push({
|
|
label: "Headrest",
|
|
value: product.additionalInformation.Headrest,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation["Use Cases"]) {
|
|
specifications.push({
|
|
label: "Use Cases",
|
|
value: product.additionalInformation["Use Cases"],
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Ergonomics) {
|
|
specifications.push({
|
|
label: "Ergonomics",
|
|
value: product.additionalInformation.Ergonomics,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Maintenance) {
|
|
specifications.push({
|
|
label: "Maintenance",
|
|
value: product.additionalInformation.Maintenance,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Durability) {
|
|
specifications.push({
|
|
label: "Durability",
|
|
value: product.additionalInformation.Durability,
|
|
});
|
|
}
|
|
|
|
if (product.additionalInformation.Warranty) {
|
|
specifications.push({
|
|
label: "Warranty",
|
|
value: product.additionalInformation.Warranty,
|
|
});
|
|
}
|
|
|
|
// Render specifications
|
|
specificationsContainer.innerHTML = specifications
|
|
.map(
|
|
(spec) => `
|
|
<div class="flex justify-between items-start py-1 border-b border-gray-100 last:border-b-0">
|
|
<span class="font-playfair font-normal text-xs text-quick-silver flex-shrink-0 mr-4">
|
|
${spec.label}:
|
|
</span>
|
|
<span class="font-playfair font-normal text-xs text-black text-right">
|
|
${spec.value}
|
|
</span>
|
|
</div>
|
|
`
|
|
)
|
|
.join("");
|
|
|
|
console.log(
|
|
"Updated specifications with",
|
|
specifications.length,
|
|
"items"
|
|
);
|
|
}
|
|
|
|
// 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 only sections present in the HTML
|
|
const sections = ["general", "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.additionalInformation?.Material || "N/A", // Materials
|
|
product.additionalInformation?.Design || "N/A", // Design
|
|
product.additionalInformation?.["Use Cases"] || "N/A", // Use Cases
|
|
];
|
|
break;
|
|
case "warranty":
|
|
sectionData = [
|
|
product.additionalInformation?.Warranty || "N/A", // Warranty Summary only
|
|
];
|
|
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
|