103 lines
3.7 KiB
TypeScript
103 lines
3.7 KiB
TypeScript
import { motion } from 'framer-motion';
|
||
import Image from 'next/image';
|
||
import { useState } from 'react';
|
||
import { Heart } from 'lucide-react';
|
||
|
||
// Типы для свойств компонента
|
||
interface NewArrivalsProps {
|
||
products: Product[];
|
||
}
|
||
|
||
// Тип для товара
|
||
interface Product {
|
||
id: number;
|
||
name: string;
|
||
price: number;
|
||
images: string[];
|
||
description: string;
|
||
isNew?: boolean;
|
||
}
|
||
|
||
export default function NewArrivals({ products }: NewArrivalsProps) {
|
||
// Состояние для отслеживания наведения на карточки товаров
|
||
const [hoveredProduct, setHoveredProduct] = useState<number | null>(null);
|
||
// Состояние для отслеживания избранных товаров
|
||
const [favorites, setFavorites] = useState<number[]>([]);
|
||
|
||
// Функция для добавления/удаления товара из избранного
|
||
const toggleFavorite = (id: number, e: React.MouseEvent) => {
|
||
e.stopPropagation();
|
||
setFavorites(prev =>
|
||
prev.includes(id)
|
||
? prev.filter(itemId => itemId !== id)
|
||
: [...prev, id]
|
||
);
|
||
};
|
||
|
||
return (
|
||
<section className="py-8 bg-white">
|
||
<div className="container mx-auto px-6">
|
||
<motion.h2
|
||
initial={{ opacity: 0, y: 20 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: 0.2 }}
|
||
className="text-3xl text-center font-medium mb-12"
|
||
>
|
||
Новинки
|
||
</motion.h2>
|
||
|
||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-x-6 gap-y-12">
|
||
{products.map((product, index) => (
|
||
<motion.div
|
||
key={product.id}
|
||
initial={{ opacity: 0, y: 20 }}
|
||
whileInView={{ opacity: 1, y: 0 }}
|
||
transition={{ delay: index * 0.1 }}
|
||
className="group relative"
|
||
onMouseEnter={() => setHoveredProduct(product.id)}
|
||
onMouseLeave={() => setHoveredProduct(null)}
|
||
>
|
||
{/* Метка "New" */}
|
||
{product.isNew && (
|
||
<div className="absolute top-4 left-4 z-10 bg-gray-100 text-gray-700 text-xs px-3 py-1 rounded-full">
|
||
New
|
||
</div>
|
||
)}
|
||
|
||
{/* Кнопка избранного */}
|
||
<button
|
||
onClick={(e) => toggleFavorite(product.id, e)}
|
||
className="absolute top-4 right-4 z-10 p-1"
|
||
>
|
||
<Heart
|
||
className={`w-6 h-6 transition-colors ${
|
||
favorites.includes(product.id)
|
||
? 'fill-black text-black'
|
||
: 'text-gray-400 hover:text-black'
|
||
}`}
|
||
/>
|
||
</button>
|
||
|
||
{/* Изображение товара */}
|
||
<div className="relative aspect-[3/4] w-full overflow-hidden mb-4">
|
||
<Image
|
||
src={hoveredProduct === product.id && product.images.length > 1 ? product.images[1] : product.images[0]}
|
||
alt={product.name}
|
||
layout="fill"
|
||
objectFit="cover"
|
||
className="transition-all duration-500 hover:scale-105"
|
||
/>
|
||
</div>
|
||
|
||
{/* Информация о товаре */}
|
||
<div className="px-1">
|
||
<h3 className="text-sm text-gray-700 mb-2 line-clamp-2">{product.name}</h3>
|
||
<p className="text-base font-medium">{product.price.toLocaleString()} ₽</p>
|
||
</div>
|
||
</motion.div>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
}
|