khy_website/scripts/main.js
George Birikorang 4d901448eb refactor: update product comparison layout and JavaScript for improved clarity
- 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.
2025-09-18 03:42:37 -07:00

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