Compare commits

...

5 commits

Author SHA1 Message Date
a648abe2d0 refactor: streamline sizes array formatting in products.json for consistency and readability 2025-09-17 20:52:22 -07:00
18cf5c8ed3 Implement image enlargement modal and enhance product detail functionality
- 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.
2025-09-17 20:52:03 -07:00
6caa3ee6c4 Fix galleryPairs for all 88 products to ensure at least 2 images
- Updated products 1-88 to have minimum 2 images in galleryPairs array
- Fixed empty galleryPairs by copying first 2 images from images array
- Fixed single-image galleryPairs by adding first image from images array
- Ensures carousel functionality works properly for all products
- Special case: Product 84 (Sphere) only had 1 image, copied it twice
2025-09-17 19:56:17 -07:00
d84c6196d1 refactor: update products.json to enhance product galleries with new image pairs for various training tables and screens 2025-09-17 19:43:10 -07:00
7295bcba7e refactor: enhance product detail page with dynamic content loading and improved gallery functionality
- Updated product-detail.html to replace static content with dynamic placeholders for images, title, description, sizes, and colors.
- Modified main.js to implement dynamic loading of product details, including title, description, images, sizes, and colors.
- Improved gallery functionality to support a carousel view for product images, including navigation buttons.
- Adjusted CSS to add new transition durations and easing functions for smoother animations.
2025-09-17 19:40:13 -07:00
7 changed files with 1222 additions and 1046 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 417 KiB

File diff suppressed because it is too large Load diff

View file

@ -164,7 +164,7 @@
<!-- Background Image -->
<div class="absolute inset-0 w-full h-full">
<img
src="assets/images/potty.jpg"
src="assets/images/prod-catalog.jpg"
alt="Product catalog background"
class="w-full h-full object-cover object-center"
style="filter: blur(3px)"

View file

@ -194,71 +194,33 @@
<div
class="flex flex-row md:flex-col gap-3 md:gap-4 w-full md:w-32 overflow-x-auto md:overflow-visible"
>
<div
class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer"
>
<img
src="assets/images/outdoor_sofa_set.png"
alt="Outdoor sofa set"
class="w-full h-full object-cover"
/>
</div>
<div
class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer"
>
<img
src="assets/images/outdoor_sofa_set.png"
alt="Outdoor sofa set 2"
class="w-full h-full object-cover"
/>
</div>
<div
class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer"
>
<img
src="assets/images/outdoor_sofa_set.png"
alt="Stuart sofa"
class="w-full h-full object-cover"
/>
</div>
<div
class="w-32 h-32 bg-floral-white rounded-lg overflow-hidden cursor-pointer"
>
<img
src="assets/images/outdoor_sofa_set.png"
alt="Maya sofa three seater"
class="w-full h-full object-cover"
/>
</div>
<!-- Thumbnail images will be populated dynamically -->
</div>
<!-- Main Product Image -->
<div
class="w-full h-80 md:w-[500px] md:h-[500px] bg-floral-white rounded-lg overflow-hidden"
>
<img
src="assets/images/asgaard_sofa.png"
alt="Asgaard sofa"
class="w-full h-full object-cover"
/>
<!-- Main product image will be populated dynamically -->
</div>
</div>
<!-- Right Section - Product Details -->
<div class="w-full md:w-[500px]">
<!-- Product Title -->
<h1 class="font-playfair font-normal text-4xl text-black mb-8">
Asgaard sofa
<h1
class="font-playfair font-normal text-4xl text-black mb-8"
id="product-title"
>
<!-- Product title will be populated dynamically -->
</h1>
<!-- Product Description -->
<p
class="font-playfair font-normal text-sm text-black mb-12 max-w-md"
id="product-description"
>
Setting the bar as one of the loudest speakers in its class, the
Kilburn is a compact, stout-hearted hero with a well-balanced
audio which boasts a clear midrange and extended highs for a
sound.
<!-- Product description will be populated dynamically -->
</p>
<!-- Size Options -->
@ -269,36 +231,7 @@
Size
</h3>
<div class="grid grid-cols-6 gap-2" id="size-buttons-container">
<button
class="w-8 h-8 bg-uc-gold text-white font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
L
</button>
<button
class="w-8 h-8 bg-floral-white text-black font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
XL
</button>
<button
class="w-8 h-8 bg-floral-white text-black font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
XS
</button>
<button
class="w-8 h-8 bg-floral-white text-black font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
S
</button>
<button
class="w-8 h-8 bg-floral-white text-black font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
M
</button>
<button
class="w-8 h-8 bg-floral-white text-black font-playfair font-normal text-sm rounded flex items-center justify-center size-button"
>
2XL
</button>
<!-- Size buttons will be populated dynamically -->
</div>
</div>
@ -309,42 +242,13 @@
>
Color
</h3>
<div class="flex gap-4">
<button
class="w-8 h-8 bg-purple-500 rounded-full border-2 border-black"
></button>
<button class="w-8 h-8 bg-black rounded-full"></button>
<button class="w-8 h-8 bg-uc-gold rounded-full"></button>
<div class="flex gap-4" id="color-buttons-container">
<!-- Color buttons will be populated dynamically -->
</div>
</div>
<!-- Quantity and Action Buttons -->
<div class="flex flex-col md:flex-row gap-4 md:gap-6 mb-8">
<!-- Quantity Selector -->
<div
class="inline-flex items-center justify-between w-[180px] h-[64px] min-h-[64px] bg-white border border-quick-silver rounded-[15px] px-4 box-border shadow-sm hover:shadow-md transition-all duration-200"
>
<button
id="qty-decr"
aria-label="Decrease quantity"
class="font-playfair font-light text-[20px] leading-none text-black w-8 h-8 flex items-center justify-center rounded-lg hover:bg-light-bg transition-colors cursor-pointer"
>
-
</button>
<span
id="qty-value"
class="font-playfair font-light text-[20px] leading-none text-black"
>1</span
>
<button
id="qty-incr"
aria-label="Increase quantity"
class="font-playfair font-light text-[20px] leading-none text-black w-8 h-8 flex items-center justify-center rounded-lg hover:bg-light-bg transition-colors cursor-pointer"
>
+
</button>
</div>
<!-- Action Buttons -->
<a
href="contact.html"
@ -365,62 +269,7 @@
<!-- Product Metadata -->
<div class="space-y-4">
<div class="flex items-center">
<span
class="font-playfair font-normal text-base text-quick-silver w-20"
>Model No.</span
>
<span
class="font-playfair font-medium text-base text-quick-silver mx-2"
>:</span
>
<span
class="font-playfair font-normal text-base text-quick-silver"
>SS001</span
>
</div>
<div class="flex items-center">
<span
class="font-playfair font-normal text-base text-quick-silver w-20"
>Category</span
>
<span
class="font-playfair font-medium text-base text-quick-silver mx-2"
>:</span
>
<span
class="font-playfair font-normal text-base text-quick-silver"
>Sofas</span
>
</div>
<div class="flex items-center">
<span
class="font-playfair font-normal text-base text-quick-silver w-20"
>Tags</span
>
<span
class="font-playfair font-medium text-base text-quick-silver mx-2"
>:</span
>
<span
class="font-playfair font-normal text-base text-quick-silver"
>Sofa, Chair, Home, Shop</span
>
</div>
<div class="flex items-center">
<span
class="font-playfair font-normal text-base text-quick-silver w-20"
>Dimension</span
>
<span
class="font-playfair font-medium text-base text-quick-silver mx-2"
>:</span
>
<span
class="font-playfair font-normal text-base text-quick-silver"
>180cm x 85cm x 75cm</span
>
</div>
<!-- Product metadata will be populated dynamically -->
</div>
</div>
</div>
@ -439,45 +288,61 @@
</div>
<!-- Copy -->
<div class="max-w-5xl mx-auto space-y-6">
<p
class="font-playfair text-base leading-6 text-[#333333] text-justify"
>
Embodying the raw, wayward spirit of rock ‘n’ roll, the Kilburn
portable active stereo speaker takes the unmistakable look and
sound of Marshall, unplugs the chords, and takes the show on the
road.
</p>
<p
class="font-playfair text-base leading-6 text-[#333333] text-justify"
>
Weighing in under 7 pounds, the Kilburn is a lightweight piece of
vintage styled engineering. Setting the bar as one of the loudest
speakers in its class, the Kilburn is a compact, stout-hearted
hero with a well-balanced audio which boasts a clear midrange and
extended highs for a sound that is both articulate and pronounced.
The analogue knobs allow you to fine tune the controls to your
personal preferences while the guitar-influenced leather strap
enables easy and stylish travel.
</p>
<div
class="max-w-5xl mx-auto space-y-6"
id="product-description-content"
>
<!-- Product description content will be populated dynamically -->
</div>
<!-- Images -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-8 mt-10">
<div class="rounded-[10px] bg-floral-white p-6">
<img
src="assets/images/asgaard_sofa.png"
alt="Sofa variant left"
class="w-full h-80 object-contain mx-auto"
/>
</div>
<div class="rounded-[10px] bg-floral-white p-6">
<img
src="assets/images/asgaard_sofa.png"
alt="Sofa variant right"
class="w-full h-80 object-contain mx-auto"
/>
<div class="relative mt-10">
<div
class="grid grid-cols-1 md:grid-cols-2 gap-8"
id="product-gallery-images"
>
<!-- Product gallery images will be populated dynamically -->
</div>
<!-- Back Arrow -->
<button
id="gallery-back-btn"
class="absolute top-1/2 left-0 transform -translate-y-1/2 bg-white border border-gray-300 rounded-full p-3 shadow-lg hover:shadow-xl transition-all duration-200 opacity-0 pointer-events-none"
style="display: none"
>
<svg
class="w-6 h-6 text-gray-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M15 19l-7-7 7-7"
></path>
</svg>
</button>
<!-- Forward Arrow -->
<button
id="gallery-next-btn"
class="absolute top-1/2 right-0 transform -translate-y-1/2 bg-white border border-gray-300 rounded-full p-3 shadow-lg hover:shadow-xl transition-all duration-200 opacity-0 pointer-events-none"
style="display: none"
>
<svg
class="w-6 h-6 text-gray-600"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5l7 7-7 7"
></path>
</svg>
</button>
</div>
</div>
</section>
@ -648,6 +513,45 @@
</div>
</footer>
<!-- Image Enlargement Modal -->
<div
id="image-modal"
class="fixed inset-0 bg-black bg-opacity-90 z-50 hidden flex items-center justify-center p-4 transition-opacity duration-300"
>
<div
class="relative max-w-7xl max-h-full w-full h-full flex items-center justify-center"
>
<!-- Close Button -->
<button
id="modal-close-btn"
class="absolute top-4 right-4 z-10 bg-white bg-opacity-20 hover:bg-opacity-30 text-white rounded-full p-3 transition-all duration-200 backdrop-blur-sm"
aria-label="Close modal"
>
<svg
class="w-6 h-6"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
></path>
</svg>
</button>
<!-- Enlarged Image -->
<img
id="modal-image"
src=""
alt=""
class="w-[95vw] h-[95vh] object-contain rounded-lg shadow-2xl transform transition-transform duration-300 scale-95"
/>
</div>
</div>
<script src="scripts/main.js?v=3.5"></script>
</body>
</html>

View file

@ -55,27 +55,6 @@ function initSite() {
window.addEventListener("scroll", updateActiveLink);
updateActiveLink();
// Quantity controls on product detail page
(function initQuantityControls() {
const decr = document.getElementById("qty-decr");
const incr = document.getElementById("qty-incr");
const valueEl = document.getElementById("qty-value");
if (!decr || !incr || !valueEl) return; // Not on product detail page
function parseQty() {
const n = parseInt(valueEl.textContent || "1", 10);
return Number.isFinite(n) && n > 0 ? n : 1;
}
decr.addEventListener("click", () => {
const next = Math.max(1, parseQty() - 1);
valueEl.textContent = String(next);
});
incr.addEventListener("click", () => {
const next = parseQty() + 1;
valueEl.textContent = String(next);
});
})();
// Related products (dynamic)
(async function initRelated() {
const grid = document.getElementById("related-grid");
@ -222,342 +201,530 @@ function initSite() {
});
});
}
}
// Product detail page functionality
(async function initProductDetail() {
console.log("Product detail script running...");
// 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");
// 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");
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;
}
// 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);
console.log("Loading product:", product);
if (!productId) {
console.log("No product ID found in URL");
return;
// 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;
}
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);
// 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);
}
if (!product) {
console.error("Product not found:", productId);
// 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("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"
console.log(
"Rendering gallery carousel with",
window.currentGalleryImages.length,
"images"
);
if (productDetailsTitle) {
productDetailsTitle.textContent = product.name;
// 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";
}
// Update product title (the main product title, not the breadcrumb)
const allH1s = document.querySelectorAll("h1");
console.log("All H1 elements:", allH1s);
if (allH1s.length > 1) {
const mainProductTitle = allH1s[1]; // The second h1 should be the product title
console.log("Main product title element:", mainProductTitle);
if (mainProductTitle) {
mainProductTitle.textContent = product.name;
}
}
// Add click event listeners to gallery images for enlargement
console.log("About to call addImageEnlargementListeners for gallery...");
addImageEnlargementListeners();
}
// Update product description - find by text content
const allParagraphs = document.querySelectorAll("p");
console.log("All paragraphs:", allParagraphs);
const descriptionEl = Array.from(allParagraphs).find(
(p) =>
p.textContent &&
p.textContent.includes(
"Setting the bar as one of the loudest speakers"
)
// 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,
}))
);
console.log("Description element:", descriptionEl);
if (descriptionEl) {
descriptionEl.textContent = product.description;
}
// Update main product image - find by alt text
const allImages = document.querySelectorAll("img");
console.log("All images:", allImages);
const mainImage = Array.from(allImages).find(
(img) => img.alt && img.alt.includes("Asgaard sofa")
// Filter related products by category (excluding current product)
const allRelatedProducts = data.products.filter(
(p) => p.category === product.category && p.id !== product.id
);
console.log("Main image element:", mainImage);
if (mainImage) {
mainImage.src = product.image;
mainImage.alt = product.alt || product.name;
}
// Update thumbnail images - find by alt text
if (product.images && product.images.length > 0) {
const allImages = document.querySelectorAll("img");
const thumbnails = Array.from(allImages).filter(
(img) =>
img.alt &&
(img.alt.includes("Outdoor sofa set") ||
img.alt.includes("Stuart sofa") ||
img.alt.includes("Maya sofa"))
);
console.log("Thumbnail images found:", thumbnails);
product.images.forEach((imageSrc, index) => {
if (thumbnails[index]) {
thumbnails[index].src = imageSrc;
thumbnails[index].alt = product.alt || product.name;
}
});
}
console.log("All related products found:", allRelatedProducts);
// Update size options - use the specific size-button class
if (product.sizes) {
const sizeButtons = document.querySelectorAll(".size-button");
console.log("Size buttons found:", sizeButtons);
let currentPage = 1;
const pageSize = 4;
// Hide all size buttons first
sizeButtons.forEach((button) => {
button.style.display = "none";
});
function renderRelatedProducts() {
const start = 0;
const end = currentPage * pageSize;
const productsToShow = allRelatedProducts.slice(start, end);
// Show and update only the buttons we need
product.sizes.forEach((size, index) => {
if (sizeButtons[index]) {
sizeButtons[index].style.display = "flex";
sizeButtons[index].textContent = size;
sizeButtons[index].setAttribute("data-size", size);
// Set selected size
if (size === product.selectedSize) {
sizeButtons[index].classList.remove(
"bg-floral-white",
"text-black"
);
sizeButtons[index].classList.add("bg-uc-gold", "text-white");
sizeButtons[index].classList.add("selected");
} else {
sizeButtons[index].classList.remove(
"bg-uc-gold",
"text-white",
"selected"
);
sizeButtons[index].classList.add("bg-floral-white", "text-black");
}
}
});
// Add click event listeners for size buttons
sizeButtons.forEach((button) => {
button.addEventListener("click", function () {
// Remove selected state from all size buttons
sizeButtons.forEach((btn) => {
btn.classList.remove("bg-uc-gold", "text-white", "selected");
btn.classList.add("bg-floral-white", "text-black");
});
// Add selected state to clicked button
this.classList.remove("bg-floral-white", "text-black");
this.classList.add("bg-uc-gold", "text-white", "selected");
});
});
}
// Update color options - find only the rounded color buttons, not size buttons
if (product.colors) {
const allButtons = document.querySelectorAll("button");
const colorButtons = Array.from(allButtons).filter(
(button) =>
button.classList.contains("w-8") &&
button.classList.contains("h-8") &&
button.classList.contains("rounded-full") &&
!button.textContent // Color buttons should not have text content
);
console.log("Color buttons found:", colorButtons);
product.colors.forEach((color, index) => {
if (colorButtons[index]) {
colorButtons[index].style.backgroundColor = color.value;
colorButtons[index].setAttribute(
"data-color",
color.name || color.value
);
// Set selected color
if (color.selected) {
colorButtons[index].classList.add(
"border-2",
"border-black",
"selected"
);
} else {
colorButtons[index].classList.remove(
"border-2",
"border-black",
"selected"
);
}
}
});
// Add click event listeners for color buttons
colorButtons.forEach((button) => {
button.addEventListener("click", function () {
// Remove selected state from all color buttons
colorButtons.forEach((btn) => {
btn.classList.remove("border-2", "border-black", "selected");
});
// Add selected state to clicked button
this.classList.add("border-2", "border-black", "selected");
});
});
}
// 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 Tags
const tagsLabel = Array.from(allSpans).find(
(span) => span.textContent === "Tags"
);
if (tagsLabel && product.tags) {
const tagsValue =
tagsLabel.parentElement.querySelector("span:last-child");
if (tagsValue) {
tagsValue.textContent = product.tags.join(", ");
}
}
// 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
if (product.descriptionLong) {
const descriptionContainer = document.querySelector(
".max-w-5xl.mx-auto.space-y-6"
);
if (descriptionContainer) {
const descriptionParagraphs =
descriptionContainer.querySelectorAll("p");
console.log("Description paragraphs found:", descriptionParagraphs);
// Update each paragraph with the product's description content
product.descriptionLong.forEach((paragraph, index) => {
if (descriptionParagraphs[index]) {
descriptionParagraphs[index].textContent = paragraph;
}
});
}
}
// Update gallery images
if (product.galleryPairs) {
// Find gallery images by alt text
const allImages = document.querySelectorAll("img");
const galleryImages = Array.from(allImages).filter(
(img) =>
img.alt &&
(img.alt.includes("Sofa variant left") ||
img.alt.includes("Sofa variant right"))
);
console.log("Gallery images found:", galleryImages);
product.galleryPairs.forEach((pair, index) => {
if (galleryImages[index * 2]) {
galleryImages[index * 2].src = pair.left;
galleryImages[index * 2].alt = product.alt || product.name;
}
if (galleryImages[index * 2 + 1]) {
galleryImages[index * 2 + 1].src = pair.right;
galleryImages[index * 2 + 1].alt = product.alt || product.name;
}
});
}
// 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) => `
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 ${
@ -566,8 +733,8 @@ function initSite() {
: "bg-white"
} flex items-center justify-center">
<img src="${p.image}" alt="${
p.alt || p.name
}" class="w-full h-full object-cover" />
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">${
@ -577,38 +744,37 @@ function initSite() {
</div>
</a>
`
)
.join("");
)
.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
// Handle "Show More" button visibility
const showMoreBtn = document.getElementById("related-show-more");
if (showMoreBtn) {
showMoreBtn.addEventListener("click", () => {
currentPage += 1;
renderRelatedProducts();
});
const hasMore = allRelatedProducts.length > end;
showMoreBtn.style.display = hasMore ? "inline-flex" : "none";
showMoreBtn.classList.add(
"inline-flex",
"items-center",
"justify-center"
);
}
// Initial render
renderRelatedProducts();
}
} catch (error) {
console.error("Error loading product data:", error);
// 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
@ -1001,6 +1167,8 @@ if (window.location.pathname.includes("product-detail.html")) {
"Product detail page detected, initializing compare functionality immediately"
);
initProductDetailCompare();
// Also initialize product detail loading
initProductDetail();
}
// Also try to initialize on DOMContentLoaded
@ -1009,6 +1177,8 @@ document.addEventListener("DOMContentLoaded", function () {
if (window.location.pathname.includes("product-detail.html")) {
console.log("Product detail page detected in DOMContentLoaded");
initProductDetailCompare();
// Also initialize product detail loading
initProductDetail();
}
});

View file

@ -123,6 +123,11 @@ class ProductManager {
.join("");
this.updateResultsCount();
this.updatePagination();
// Re-add image enlargement listeners after products are rendered
setTimeout(() => {
addImageEnlargementListeners();
}, 50);
}
// Create individual product card HTML
@ -140,7 +145,8 @@ class ProductManager {
<img
src="${product.image}"
alt="${product.alt}"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300"
class="w-full h-full object-cover group-hover:scale-105 transition-transform duration-300 cursor-pointer"
data-enlarge-src="${product.image}"
/>
<!-- Hover Overlay -->
<div class="absolute inset-0 bg-dark-charcoal bg-opacity-70 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center">
@ -454,7 +460,76 @@ class ProductManager {
// Initialize product manager
const productManager = new ProductManager();
// Image enlargement modal functionality
function addImageEnlargementListeners() {
const productImages = document.querySelectorAll(
"#product-grid img[data-enlarge-src]"
);
const modal = document.getElementById("image-modal");
const modalImage = document.getElementById("modal-image");
const modalCloseBtn = document.getElementById("modal-close-btn");
if (!modal || !modalImage || !modalCloseBtn) return;
productImages.forEach((img) => {
img.addEventListener("click", function (e) {
e.preventDefault(); // Prevent any default behavior
e.stopPropagation(); // Stop event bubbling to parent elements
const imageSrc = this.getAttribute("data-enlarge-src");
const imageAlt = this.getAttribute("alt");
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();
}
});
}
// Load products when DOM is ready
document.addEventListener("DOMContentLoaded", () => {
productManager.loadProducts();
// Add image enlargement listeners after products are loaded
setTimeout(() => {
addImageEnlargementListeners();
}, 100);
});

View file

@ -673,6 +673,10 @@ video {
top: 20rem;
}
.top-4 {
top: 1rem;
}
.z-10 {
z-index: 10;
}
@ -779,10 +783,6 @@ video {
margin-top: 2.5rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-20 {
margin-top: 5rem;
}
@ -791,10 +791,18 @@ video {
margin-top: 0.75rem;
}
.mt-12 {
margin-top: 3rem;
}
.mt-6 {
margin-top: 1.5rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.box-border {
box-sizing: border-box;
}
@ -883,22 +891,22 @@ video {
height: 24rem;
}
.h-\[22vh\] {
height: 22vh;
.h-\[145px\] {
height: 145px;
}
.h-\[29vh\] {
height: 29vh;
.h-\[301px\] {
height: 301px;
}
.h-\[446px\] {
height: 446px;
}
.h-\[64px\] {
height: 64px;
}
.h-\[6vh\] {
height: 6vh;
}
.h-auto {
height: auto;
}
@ -915,6 +923,54 @@ video {
height: 100vh;
}
.h-\[320px\] {
height: 320px;
}
.h-\[220px\] {
height: 220px;
}
.h-\[100px\] {
height: 100px;
}
.h-\[25vh\] {
height: 25vh;
}
.h-\[18vh\] {
height: 18vh;
}
.h-\[7vh\] {
height: 7vh;
}
.h-\[30vh\] {
height: 30vh;
}
.h-\[22vh\] {
height: 22vh;
}
.h-\[8vh\] {
height: 8vh;
}
.h-\[29vh\] {
height: 29vh;
}
.h-\[21vh\] {
height: 21vh;
}
.h-\[6vh\] {
height: 6vh;
}
.h-\[31vh\] {
height: 31vh;
}
@ -927,8 +983,12 @@ video {
height: 32vh;
}
.h-\[25vh\] {
height: 25vh;
.h-\[95vh\] {
height: 95vh;
}
.max-h-full {
max-height: 100%;
}
.min-h-\[64px\] {
@ -1015,6 +1075,10 @@ video {
width: 100%;
}
.w-\[95vw\] {
width: 95vw;
}
.max-w-2xl {
max-width: 42rem;
}
@ -1047,6 +1111,14 @@ video {
max-width: 20rem;
}
.max-w-4xl {
max-width: 56rem;
}
.max-w-full {
max-width: 100%;
}
.flex-1 {
flex: 1 1 0%;
}
@ -1070,6 +1142,18 @@ video {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.scale-95 {
--tw-scale-x: .95;
--tw-scale-y: .95;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.scale-100 {
--tw-scale-x: 1;
--tw-scale-y: 1;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
.transform {
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
}
@ -1164,14 +1248,14 @@ video {
gap: 1.5rem;
}
.gap-7 {
gap: 1.75rem;
}
.gap-8 {
gap: 2rem;
}
.gap-7 {
gap: 1.75rem;
}
.space-x-10 > :not([hidden]) ~ :not([hidden]) {
--tw-space-x-reverse: 0;
margin-right: calc(2.5rem * var(--tw-space-x-reverse));
@ -1208,6 +1292,12 @@ video {
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
}
.space-y-16 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(4rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(4rem * var(--tw-space-y-reverse));
}
.space-y-2 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));
@ -1442,6 +1532,14 @@ video {
--tw-bg-opacity: 0.7;
}
.bg-opacity-20 {
--tw-bg-opacity: 0.2;
}
.bg-opacity-90 {
--tw-bg-opacity: 0.9;
}
.object-contain {
-o-object-fit: contain;
object-fit: contain;
@ -1590,6 +1688,10 @@ video {
padding-right: 1.5rem;
}
.pt-0 {
padding-top: 0px;
}
.pt-12 {
padding-top: 3rem;
}
@ -1860,6 +1962,12 @@ video {
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.shadow-2xl {
--tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);
--tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
}
.blur {
--tw-blur: blur(8px);
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
@ -1874,6 +1982,11 @@ video {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
}
.backdrop-blur-sm {
--tw-backdrop-blur: blur(4px);
backdrop-filter: var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia);
}
.transition {
transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color;
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter;
@ -1922,10 +2035,22 @@ video {
transition-duration: 300ms;
}
.duration-500 {
transition-duration: 500ms;
}
.duration-1000 {
transition-duration: 1000ms;
}
.ease-in-out {
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
.ease-out {
transition-timing-function: cubic-bezier(0, 0, 0.2, 1);
}
.hover\:-translate-y-0\.5:hover {
--tw-translate-y: -0.125rem;
transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));
@ -1956,6 +2081,10 @@ video {
--tw-bg-opacity: 0.9;
}
.hover\:bg-opacity-30:hover {
--tw-bg-opacity: 0.3;
}
.hover\:text-black:hover {
--tw-text-opacity: 1;
color: rgb(0 0 0 / var(--tw-text-opacity, 1));
@ -1985,6 +2114,10 @@ video {
opacity: 0.8;
}
.hover\:opacity-90:hover {
opacity: 0.9;
}
.hover\:shadow-lg:hover {
--tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);
@ -2257,18 +2390,90 @@ video {
margin-left: 2rem;
}
.lg\:mt-16 {
margin-top: 4rem;
}
.lg\:mt-8 {
margin-top: 2rem;
}
.lg\:h-\[70vh\] {
height: 70vh;
}
.lg\:h-\[90vh\] {
height: 90vh;
}
.lg\:h-\[50vh\] {
height: 50vh;
}
.lg\:h-\[600px\] {
height: 600px;
}
.lg\:h-\[500px\] {
height: 500px;
}
.lg\:h-\[85vh\] {
height: 85vh;
}
.lg\:h-\[60vh\] {
height: 60vh;
}
.lg\:h-\[65vh\] {
height: 65vh;
}
.lg\:min-h-screen {
min-height: 100vh;
}
.lg\:min-h-\[90vh\] {
min-height: 90vh;
}
.lg\:min-h-\[100vh\] {
min-height: 100vh;
}
.lg\:min-h-\[150vh\] {
min-height: 150vh;
}
.lg\:min-h-\[900px\] {
min-height: 900px;
}
.lg\:min-h-\[800px\] {
min-height: 800px;
}
.lg\:min-h-\[700px\] {
min-height: 700px;
}
.lg\:min-h-\[600px\] {
min-height: 600px;
}
.lg\:min-h-\[60vh\] {
min-height: 60vh;
}
.lg\:min-h-\[65vh\] {
min-height: 65vh;
}
.lg\:min-h-\[80vh\] {
min-height: 80vh;
}
.lg\:w-36 {
width: 9rem;
}
@ -2305,6 +2510,18 @@ video {
gap: 2rem;
}
.lg\:space-y-10 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(2.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(2.5rem * var(--tw-space-y-reverse));
}
.lg\:space-y-6 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(1.5rem * calc(1 - var(--tw-space-y-reverse)));
margin-bottom: calc(1.5rem * var(--tw-space-y-reverse));
}
.lg\:space-y-4 > :not([hidden]) ~ :not([hidden]) {
--tw-space-y-reverse: 0;
margin-top: calc(1rem * calc(1 - var(--tw-space-y-reverse)));
@ -2328,6 +2545,11 @@ video {
padding-top: 12rem;
}
.lg\:text-2xl {
font-size: 1.5rem;
line-height: 2rem;
}
.lg\:text-3xl {
font-size: 1.875rem;
line-height: 2.25rem;
@ -2348,6 +2570,11 @@ video {
line-height: 1.75rem;
}
.lg\:text-lg {
font-size: 1.125rem;
line-height: 1.75rem;
}
.lg\:leading-snug {
line-height: 1.375;
}