added backend

This commit is contained in:
nabijonovdavronbek619@gmail.com
2025-12-24 14:17:04 +05:00
parent de12e23af1
commit c5d3b02737
11 changed files with 149 additions and 179 deletions

View File

@@ -3,62 +3,68 @@
import Image from "next/image";
import { motion } from "framer-motion";
import { ExternalLink } from "lucide-react";
import type { Product } from "@/lib/products";
import { type Product } from "@/lib/products";
import { useLanguage } from "@/context/language-context";
interface ProductCardProps {
product: Product;
onViewDetails: (slug: string) => void;
onViewDetails: (slug: number) => void;
}
export function ProductCard({ product, onViewDetails }: ProductCardProps) {
const {t} = useLanguage();
const { t, language } = useLanguage();
const languageIndex = language === "uz" ? true : false;
return (
<motion.div
whileHover={{ y: -8 }}
className="bg-white rounded-lg overflow-hidden shadow-md hover:shadow-xl transition-shadow"
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.3 }}
className="group relative h-full flex flex-col bg-white rounded-2xl overflow-hidden shadow-md hover:shadow-2xl transition-all duration-300 border border-gray-100"
>
{/* Image */}
<div className="relative h-48 bg-gray-100 overflow-hidden group">
<Image
src={product.images[0]}
alt={product.nameKey}
fill
className="object-contain group-hover:scale-110 transition-transform duration-300"
/>
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/30 transition-colors" />
{/* Image Container - Fixed Height */}
<div className="relative w-full h-64 overflow-hidden bg-linear-to-br from-gray-50 to-gray-100">
<motion.div
whileHover={{ scale: 1.05 }}
transition={{ duration: 0.4 }}
className="w-full h-full"
>
<img
src={`https://api.serenmebel.uz${product.image}`}
alt={languageIndex?product.name_uz:product.name_ru}
className="w-full h-full object-cover"
/>
</motion.div>
{/* Gradient Overlay */}
<div className="absolute inset-0 bg-linear-to-t from-black/20 via-transparent to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</div>
{/* Content */}
<div className="p-6">
<h3 className="text-xl font-bold text-gray-900 mb-2">
{product.nameKey}
{/* Content Container - Flex Grow */}
<div className="flex flex-col grow p-6">
{/* Product Name */}
<h3 className="text-xl font-bold text-gray-900 mb-3 line-clamp-2 group-hover:text-primary transition-colors duration-300">
{languageIndex?product.name_uz:product.name_ru}
</h3>
<p className="text-gray-600 text-sm mb-4">
{product.shortDescriptionKey}
{/* Short Description - Fixed Height with Line Clamp */}
<p className="text-gray-600 text-sm leading-relaxed mb-4 line-clamp-3 grow">
{languageIndex?product.name_uz:product.name_ru}
</p>
{/* Specs Preview */}
{/* <div className="mb-4 space-y-2">
{product.specs.slice(0, 2).map((spec, idx) => (
<div key={idx} className="flex justify-between text-sm">
<span className="text-gray-600">{spec.key}:</span>
<span className="font-semibold text-gray-900">{spec.value}</span>
</div>
))}
</div> */}
{/* CTA Button */}
{/* CTA Button - Always at Bottom */}
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
onClick={() => onViewDetails(product.slug)}
className="w-full flex items-center justify-center gap-2 px-4 py-2 bg-primary/80 text-white rounded-lg font-medium hover:bg-primary transition-colors"
whileHover={{ scale: 1.02 }}
whileTap={{ scale: 0.98 }}
onClick={() => onViewDetails(product.id)}
className="w-full flex items-center justify-center gap-2 px-6 py-3 bg-primary text-white rounded-xl font-semibold shadow-lg shadow-blue-500/30 hover:shadow-xl hover:shadow-primary/40 transition-all duration-300 group/button"
>
{t.details}
<ExternalLink size={16} />
<span>{t.details}</span>
<ExternalLink className="w-4 h-4 group-hover/button:translate-x-1 transition-transform duration-300" />
</motion.button>
</div>
{/* Decorative Corner */}
<div className="absolute top-0 right-0 w-20 h-20 bg-linear-to-br from-blue-500/10 to-transparent rounded-bl-full opacity-0 group-hover:opacity-100 transition-opacity duration-300" />
</motion.div>
);
}