refactor: add product image zoom container

This commit is contained in:
2025-05-18 11:38:08 +05:30
parent 8834c88421
commit 344b03b048
2 changed files with 56 additions and 7 deletions

View File

@@ -1,5 +1,5 @@
"use client";
import React, { useContext, useState } from "react";
import React, { useContext, useState, useRef } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { ChevronLeft, ChevronRight, Award } from "lucide-react"; // Added Award icon
@@ -9,8 +9,10 @@ import Image from "next/image";
const ProductGallery = ({ productId }) => {
const { products } = useContext(ProductContext);
const [currentImageIndex, setCurrentImageIndex] = useState(0);
const [showZoom, setShowZoom] = useState(false);
const [zoomPosition, setZoomPosition] = useState({ x: 0, y: 0 });
const imageContainerRef = useRef(null);
const nextImage = () => {
setCurrentImageIndex((prevIndex) => (prevIndex + 1) % productImages.length);
@@ -22,6 +24,7 @@ const ProductGallery = ({ productId }) => {
(prevIndex - 1 + productImages.length) % productImages.length
);
};
const product = products?.find((pr) => pr.id == productId);
if (!product) {
return null;
@@ -30,6 +33,23 @@ const ProductGallery = ({ productId }) => {
const productImages = product?.images?.map((img) => img.image) || [];
const hasCertificate = product.certificate && product.certificate !== "NA";
const handleMouseMove = (e) => {
if (!imageContainerRef.current) return;
const { left, top, width, height } = imageContainerRef.current.getBoundingClientRect();
// Calculate position as percentage
const x = ((e.clientX - left) / width) * 100;
const y = ((e.clientY - top) / height) * 100;
setZoomPosition({ x, y });
setShowZoom(true);
};
const handleMouseLeave = () => {
setShowZoom(false);
};
return (
<div className="flex flex-col md:flex-row gap-4 p-4 sm:w-[70%] ">
<div className="hidden md:flex flex-col gap-2">
@@ -38,8 +58,8 @@ const ProductGallery = ({ productId }) => {
key={index}
src={`${backendUrl}${src}`}
alt={`Thumbnail ${index + 1}`}
width={160} // Width of w-40 (160px)
height={128} // Height of h-32 (128px)
width={160}
height={128}
className="object-cover cursor-pointer border border-gray-300 hover:border-blue-500"
onClick={() => setCurrentImageIndex(index)}
/>
@@ -55,14 +75,18 @@ const ProductGallery = ({ productId }) => {
</div>
)}
{/* Main image with carousel controls */}
<div className="relative mb-4 h-full">
<div
className="relative mb-4 h-full"
ref={imageContainerRef}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
>
<Image
src={`${backendUrl}${productImages[currentImageIndex]}`}
alt="Main product"
width={500}
height={500}
className="object-cover w-full h-full"
className="object-cover w-full h-full cursor-zoom-in"
/>
<Button
className="absolute top-1/2 left-2 transform -translate-y-1/2 md:hidden"
@@ -78,6 +102,24 @@ const ProductGallery = ({ productId }) => {
>
<ChevronRight />
</Button>
{/* Zoom overlay */}
{showZoom && (
<div className="absolute top-0 right-0 w-40 h-40 md:w-60 md:h-60 lg:w-[300px] lg:h-[300px] border-2 border-gray-300 overflow-hidden z-20 bg-white shadow-lg">
<div
className="absolute w-[1000px] h-[1000px]"
style={{
backgroundImage: `url(${backendUrl}${productImages[currentImageIndex]})`,
backgroundPosition: `${zoomPosition.x}% ${zoomPosition.y}%`,
backgroundSize: '250%',
backgroundRepeat: 'no-repeat',
transform: 'translate(-50%, -50%)',
left: '50%',
top: '50%',
}}
/>
</div>
)}
</div>
</Card>
<div className="my-6">

View File

@@ -221,6 +221,13 @@ function ProductDetails({ productId }) {
className="text-sm prose prose-sm max-w-none"
/>
</div>
<div className="mt-8 border-t pt-6">
<h2 className="text-xl font-semibold mb-4">Beej Mantra</h2>
<div
dangerouslySetInnerHTML={{ __html: product.beej_mantra }}
className="text-sm prose prose-sm max-w-none"
/>
</div>
</div>
{showCertificate && !product.certificate.toLowerCase().endsWith('.pdf') && (