Обновить дизайн и функциональность страниц каталога, коллекций и категорий с использованием новой цветовой палитры

This commit is contained in:
belikovme 2025-02-27 18:51:51 +07:00
parent 1430cbd25b
commit bc51acede3
28 changed files with 402 additions and 167 deletions

View File

@ -3,39 +3,39 @@ import { Facebook, Instagram, Twitter, Youtube } from "lucide-react";
export default function Footer() {
return (
<footer className="bg-gray-100 text-gray-800 py-12">
<footer className="bg-[#2B5F47] text-white py-12">
<div className="container mx-auto px-6">
<div className="grid grid-cols-1 md:grid-cols-4 gap-8">
<div>
<h4 className="text-lg font-medium mb-4">Помощь</h4>
<ul className="space-y-2">
<li><Link href="/contact" className="text-sm hover:underline">Связаться с нами</Link></li>
<li><Link href="/faq" className="text-sm hover:underline">Часто задаваемые вопросы</Link></li>
<li><Link href="/shipping" className="text-sm hover:underline">Доставка и возврат</Link></li>
<li><Link href="/track-order" className="text-sm hover:underline">Отследить заказ</Link></li>
<li><Link href="/size-guide" className="text-sm hover:underline">Руководство по размерам</Link></li>
<li><Link href="/contact" className="text-sm hover:text-[#E2E2C1] transition-colors">Связаться с нами</Link></li>
<li><Link href="/faq" className="text-sm hover:text-[#E2E2C1] transition-colors">Часто задаваемые вопросы</Link></li>
<li><Link href="/shipping" className="text-sm hover:text-[#E2E2C1] transition-colors">Доставка и возврат</Link></li>
<li><Link href="/track-order" className="text-sm hover:text-[#E2E2C1] transition-colors">Отследить заказ</Link></li>
<li><Link href="/size-guide" className="text-sm hover:text-[#E2E2C1] transition-colors">Руководство по размерам</Link></li>
</ul>
</div>
<div>
<h4 className="text-lg font-medium mb-4">Магазин</h4>
<ul className="space-y-2">
<li><Link href="/women" className="text-sm hover:underline">Женщинам</Link></li>
<li><Link href="/men" className="text-sm hover:underline">Мужчинам</Link></li>
<li><Link href="/accessories" className="text-sm hover:underline">Аксессуары</Link></li>
<li><Link href="/collections" className="text-sm hover:underline">Коллекции</Link></li>
<li><Link href="/sale" className="text-sm hover:underline">Распродажа</Link></li>
<li><Link href="/women" className="text-sm hover:text-[#E2E2C1] transition-colors">Женщинам</Link></li>
<li><Link href="/men" className="text-sm hover:text-[#E2E2C1] transition-colors">Мужчинам</Link></li>
<li><Link href="/accessories" className="text-sm hover:text-[#E2E2C1] transition-colors">Аксессуары</Link></li>
<li><Link href="/collections" className="text-sm hover:text-[#E2E2C1] transition-colors">Коллекции</Link></li>
<li><Link href="/sale" className="text-sm hover:text-[#E2E2C1] transition-colors">Распродажа</Link></li>
</ul>
</div>
<div>
<h4 className="text-lg font-medium mb-4">О компании</h4>
<ul className="space-y-2">
<li><Link href="/about" className="text-sm hover:underline">О нас</Link></li>
<li><Link href="/careers" className="text-sm hover:underline">Карьера</Link></li>
<li><Link href="/sustainability" className="text-sm hover:underline">Устойчивое развитие</Link></li>
<li><Link href="/press" className="text-sm hover:underline">Пресса</Link></li>
<li><Link href="/affiliates" className="text-sm hover:underline">Партнерская программа</Link></li>
<li><Link href="/about" className="text-sm hover:text-[#E2E2C1] transition-colors">О нас</Link></li>
<li><Link href="/careers" className="text-sm hover:text-[#E2E2C1] transition-colors">Карьера</Link></li>
<li><Link href="/sustainability" className="text-sm hover:text-[#E2E2C1] transition-colors">Устойчивое развитие</Link></li>
<li><Link href="/press" className="text-sm hover:text-[#E2E2C1] transition-colors">Пресса</Link></li>
<li><Link href="/affiliates" className="text-sm hover:text-[#E2E2C1] transition-colors">Партнерская программа</Link></li>
</ul>
</div>
@ -46,35 +46,35 @@ export default function Footer() {
<input
type="email"
placeholder="Ваш email"
className="bg-white px-4 py-2 text-sm border border-gray-300 rounded-l focus:outline-none flex-grow"
className="bg-white px-4 py-2 text-sm border border-[#63823B] rounded-l focus:outline-none focus:border-[#E2E2C1] text-[#2B5F47] flex-grow"
/>
<button className="bg-black text-white px-4 py-2 text-sm rounded-r hover:bg-gray-800 transition-colors">
<button className="bg-[#63823B] text-white px-4 py-2 text-sm rounded-r hover:bg-[#63823B]/80 transition-colors">
</button>
</div>
<div className="flex space-x-4">
<a href="#" className="text-gray-600 hover:text-black transition-colors">
<a href="#" className="text-white hover:text-[#E2E2C1] transition-colors">
<Facebook size={20} />
</a>
<a href="#" className="text-gray-600 hover:text-black transition-colors">
<a href="#" className="text-white hover:text-[#E2E2C1] transition-colors">
<Instagram size={20} />
</a>
<a href="#" className="text-gray-600 hover:text-black transition-colors">
<a href="#" className="text-white hover:text-[#E2E2C1] transition-colors">
<Twitter size={20} />
</a>
<a href="#" className="text-gray-600 hover:text-black transition-colors">
<a href="#" className="text-white hover:text-[#E2E2C1] transition-colors">
<Youtube size={20} />
</a>
</div>
</div>
</div>
<div className="border-t border-gray-200 mt-8 pt-8 flex flex-col md:flex-row justify-between items-center">
<p className="text-xs text-gray-500 mb-4 md:mb-0">© {new Date().getFullYear()} Brand Store. Все права защищены.</p>
<div className="border-t border-[#63823B] mt-8 pt-8 flex flex-col md:flex-row justify-between items-center">
<p className="text-xs text-[#E2E2C1]/80 mb-4 md:mb-0">© {new Date().getFullYear()} Brand Store. Все права защищены.</p>
<div className="flex space-x-4">
<Link href="/privacy" className="text-xs text-gray-500 hover:underline">Политика конфиденциальности</Link>
<Link href="/terms" className="text-xs text-gray-500 hover:underline">Условия использования</Link>
<Link href="/cookies" className="text-xs text-gray-500 hover:underline">Политика использования файлов cookie</Link>
<Link href="/privacy" className="text-xs text-[#E2E2C1]/80 hover:text-[#E2E2C1] transition-colors">Политика конфиденциальности</Link>
<Link href="/terms" className="text-xs text-[#E2E2C1]/80 hover:text-[#E2E2C1] transition-colors">Условия использования</Link>
<Link href="/cookies" className="text-xs text-[#E2E2C1]/80 hover:text-[#E2E2C1] transition-colors">Политика использования файлов cookie</Link>
</div>
</div>
</div>

View File

@ -56,13 +56,13 @@ export default function TabSelector({ onTabChange }: TabSelectorProps) {
}, [])
return (
<div className="flex justify-center items-center w-full py-8 bg-white">
<div className="flex justify-center items-center w-full py-8 bg-[#E2E2C1]">
<div className="w-full max-w-[1200px] h-[60px] relative flex items-center justify-center">
<div className="p-0">
<div className="relative">
{/* Hover Highlight */}
<div
className="absolute h-[30px] transition-all duration-300 ease-out bg-[#0e0f1114] rounded-[6px] flex items-center"
className="absolute h-[30px] transition-all duration-300 ease-out bg-[#63823B]/20 rounded-[6px] flex items-center"
style={{
...hoverStyle,
opacity: hoveredIndex !== null ? 1 : 0,
@ -71,7 +71,7 @@ export default function TabSelector({ onTabChange }: TabSelectorProps) {
{/* Active Indicator */}
<div
className="absolute bottom-[-6px] h-[2px] bg-black transition-all duration-300 ease-out"
className="absolute bottom-[-6px] h-[2px] bg-[#2B5F47] transition-all duration-300 ease-out"
style={activeStyle}
/>
@ -82,7 +82,7 @@ export default function TabSelector({ onTabChange }: TabSelectorProps) {
key={index}
ref={(el) => (tabRefs.current[index] = el)}
className={`px-3 py-2 cursor-pointer transition-colors duration-300 h-[30px] ${
index === activeIndex ? "text-black font-medium" : "text-gray-500"
index === activeIndex ? "text-[#2B5F47] font-medium" : "text-[#2B5F47]/70"
}`}
onMouseEnter={() => setHoveredIndex(index)}
onMouseLeave={() => setHoveredIndex(null)}

View File

@ -21,7 +21,7 @@ export const collections: Collection[] = [
{
id: 2,
name: 'Осень-Зима 2023',
image: '/photos/photo2.jpg',
image: '/photos/autumn_winter.jpg',
description: 'Теплые и уютные модели для холодного времени года. Коллекция сочетает в себе комфорт и стиль, предлагая элегантные решения для зимнего гардероба.',
url: '/collections/autumn-winter-2023',
slug: 'autumn-winter-2023'
@ -29,7 +29,7 @@ export const collections: Collection[] = [
{
id: 3,
name: 'Базовый гардероб',
image: '/photos/head_photo.png',
image: '/photos/based_outfit.jpg',
description: 'Классические модели, которые никогда не выходят из моды. Эта коллекция представляет собой основу любого гардероба, включая вневременные предметы одежды высокого качества.',
url: '/collections/basic',
slug: 'basic'
@ -37,7 +37,7 @@ export const collections: Collection[] = [
{
id: 4,
name: 'Вечерняя коллекция',
image: '/photos/evening.jpg',
image: '/photos/night_dress.jpg',
description: 'Элегантные наряды для особых случаев. Изысканные ткани и утонченный дизайн создают неповторимые образы для вечерних мероприятий и торжественных событий.',
url: '/collections/evening',
slug: 'evening'
@ -45,7 +45,7 @@ export const collections: Collection[] = [
{
id: 5,
name: 'Деловой стиль',
image: '/photos/business.jpg',
image: '/photos/business_outfit.jpg',
description: 'Стильная и функциональная одежда для работы и деловых встреч. Коллекция сочетает в себе профессионализм и элегантность, подчеркивая ваш статус и вкус.',
url: '/collections/business',
slug: 'business'

View File

@ -1,5 +1,6 @@
// Тип для товара
export interface Product {
inStock: any;
id: number;
name: string;
price: number;
@ -20,7 +21,8 @@ export const products: Product[] = [
description: 'Элегантное пальто оверсайз высокого качества. Изготовлено из премиальных материалов, обеспечивающих комфорт и тепло. Идеально подходит для холодного сезона и создания стильного образа.',
isNew: true,
categoryId: 6,
slug: 'palto-oversaiz'
slug: 'palto-oversaiz',
inStock: true
},
{
id: 2,
@ -30,7 +32,8 @@ export const products: Product[] = [
description: 'Стильный костюм для особых случаев. Выполнен из высококачественного хлопка, обеспечивающего комфорт и элегантный внешний вид. Идеально подходит для деловых встреч и официальных мероприятий.',
isNew: true,
categoryId: 6,
slug: 'kostyum-hlopok'
slug: 'kostyum-hlopok',
inStock: true
},
{
id: 3,
@ -40,7 +43,8 @@ export const products: Product[] = [
description: 'Классическая блузка в коричневом цвете. Изготовлена из мягкой и приятной к телу ткани. Универсальная модель, которая подойдет как для офиса, так и для повседневного образа.',
isNew: true,
categoryId: 7,
slug: 'bluzka'
slug: 'bluzka',
inStock: true
},
{
id: 4,
@ -50,57 +54,63 @@ export const products: Product[] = [
description: 'Элегантное платье высокого качества со сборкой. Подчеркивает фигуру и создает женственный силуэт. Идеально подходит для особых случаев и вечерних мероприятий.',
isNew: true,
categoryId: 5,
slug: 'plate-so-sborkoy'
slug: 'plate-so-sborkoy',
inStock: true
},
{
id: 5,
name: 'Кожаные туфли',
name: 'Кожаные ботинки',
price: 15600,
images: ['/wear/shoes1.jpg', '/wear/shoes2.jpg'],
description: 'Элегантные кожаные туфли ручной работы. Изготовлены из натуральной кожи высшего качества. Комфортная колодка и стильный дизайн делают эту модель незаменимой в гардеробе.',
isNew: false,
images: ['/wear/kozh_boots1.jpg', '/wear/kozh_boots2.jpg'],
description: 'Элегантные кожаные ботинки ручной работы. Изготовлены из натуральной кожи высшего качества. Комфортная колодка и стильный дизайн делают эту модель незаменимой в гардеробе.',
isNew: true,
categoryId: 1,
slug: 'kozhanye-tufli'
slug: 'kozhanye-botinki',
inStock: true
},
{
id: 6,
name: 'Шелковый шарф',
price: 5900,
images: ['/wear/scarf1.jpg', '/wear/scarf2.jpg'],
images: ['/wear/silk_scarf1.jpg', '/wear/silk_scarf2.jpg'],
description: 'Роскошный шелковый шарф с уникальным принтом. Изготовлен из 100% натурального шелка. Добавит элегантности и шарма любому образу.',
isNew: false,
categoryId: 8,
slug: 'shelkovyj-sharf'
slug: 'shelkovyj-sharf',
inStock: true
},
{
id: 7,
name: 'Шерстяной свитер',
price: 8700,
images: ['/wear/sweater1.jpg', '/wear/sweater2.jpg'],
images: ['/wear/sherst_sweater1.jpg', '/wear/sherst_sweater2.jpg'],
description: 'Теплый шерстяной свитер крупной вязки. Изготовлен из мягкой шерсти мериноса. Идеально подходит для холодного времени года.',
isNew: false,
categoryId: 4,
slug: 'sherstyanoj-sviter'
slug: 'sherstyanoj-sviter',
inStock: true
},
{
id: 8,
name: 'Классические брюки',
price: 7500,
images: ['/wear/pants1.jpg', '/wear/pants2.jpg'],
images: ['/wear/classic_bruk1.jpg', '/wear/classic_bruk2.jpg'],
description: 'Классические брюки прямого кроя. Выполнены из высококачественной ткани с добавлением эластана для комфортной посадки. Универсальная модель для офиса и повседневной носки.',
isNew: false,
categoryId: 3,
slug: 'klassicheskie-bryuki'
slug: 'klassicheskie-bryuki',
inStock: true
},
{
id: 9,
name: 'Фетровая шляпа',
price: 6200,
images: ['/wear/hat1.jpg', '/wear/hat2.jpg'],
images: ['/wear/hat1.jpg'],
description: 'Элегантная фетровая шляпа ручной работы. Изготовлена из высококачественного фетра. Дополнит любой образ и защитит от непогоды.',
isNew: false,
categoryId: 2,
slug: 'fetrovaya-shlyapa'
slug: 'fetrovaya-shlyapa',
inStock: true
},
{
id: 10,
@ -110,7 +120,8 @@ export const products: Product[] = [
description: 'Роскошная шелковая блузка с элегантным дизайном. Изготовлена из 100% натурального шелка. Идеально подходит для создания изысканного образа.',
isNew: true,
categoryId: 7,
slug: 'shelkovaya-bluzka'
slug: 'shelkovaya-bluzka',
inStock: true
},
{
id: 11,
@ -120,7 +131,8 @@ export const products: Product[] = [
description: 'Стильная кожаная сумка ручной работы. Изготовлена из натуральной кожи высшего качества. Вместительная и функциональная модель для повседневного использования.',
isNew: false,
categoryId: 8,
slug: 'kozhanaya-sumka'
slug: 'kozhanaya-sumka',
inStock: true
},
{
id: 12,
@ -130,7 +142,8 @@ export const products: Product[] = [
description: 'Роскошное кашемировое пальто классического кроя. Изготовлено из 100% кашемира высшего качества. Элегантная модель, которая прослужит долгие годы.',
isNew: true,
categoryId: 6,
slug: 'kashemirovoe-palto'
slug: 'kashemirovoe-palto',
inStock: true
}
];

View File

@ -31,105 +31,122 @@ export default function CategoryPage({ category, products }: CategoryPageProps)
// Если страница еще загружается, показываем заглушку
if (router.isFallback) {
return (
<div className="min-h-screen flex items-center justify-center">
<div className="animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900"></div>
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo'] flex items-center justify-center">
<div className="animate-spin rounded-full h-16 w-16 border-t-2 border-b-2 border-[#2B5F47]"></div>
</div>
)
}
// Функция для добавления/удаления товара из избранного
const toggleFavorite = (id: number, e: React.MouseEvent) => {
e.stopPropagation()
e.preventDefault()
e.stopPropagation()
setFavorites((prev) => (prev.includes(id) ? prev.filter((itemId) => itemId !== id) : [...prev, id]))
}
return (
<div className="min-h-screen bg-white font-['Arimo']">
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo']">
<Head>
<title>{category.name} | Brand Store</title>
<link rel="icon" href="/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Arimo:wght@400;500;600;700&display=swap" rel="stylesheet" />
</Head>
<Header />
<main className="max-w-7xl mx-auto px-4 py-12 md:px-8">
<div className="mb-12">
<Link href="/category" className="text-gray-600 hover:text-black transition-colors">
Все категории
</Link>
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-4xl font-bold mt-4 font-['Playfair_Display']"
>
{category.name}
</motion.h1>
<p className="mt-2 text-gray-600 max-w-3xl">{category.description}</p>
</div>
<main className="pt-24 pb-16 px-4 md:px-8">
<div className="container mx-auto">
<div className="relative mb-12 rounded-lg overflow-hidden h-64 md:h-80">
<Image
src={category.image}
alt={category.name}
fill
className="object-cover"
/>
<div className="absolute inset-0 bg-[#2B5F47]/50 flex items-center justify-center">
<div className="text-center">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-5xl font-bold mb-4 text-white"
>
{category.name}
</motion.h1>
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="text-white/90 max-w-2xl mx-auto px-4"
>
{category.description}
</motion.p>
</div>
</div>
</div>
{products.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-8">
{products.map((product) => (
<motion.div
key={product.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: product.id * 0.05 }}
whileHover={{ y: -5, transition: { duration: 0.2 } }}
>
<Link
href={`/product/${product.slug}`}
className="block h-full"
{products.length > 0 ? (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.3 }}
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"
>
{products.map((product, index) => (
<motion.div
key={product.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 * index }}
className="bg-white rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow"
onMouseEnter={() => setHoveredProduct(product.id)}
onMouseLeave={() => setHoveredProduct(null)}
>
<div className="relative overflow-hidden rounded-xl">
<div className="aspect-[3/4] relative overflow-hidden rounded-xl">
<Link href={`/product/${product.slug}`}>
<div className="relative h-64 w-full overflow-hidden">
<Image
src={
hoveredProduct === product.id && product.images.length > 1
? product.images[1]
: product.images[0]
}
src={product.images[0]}
alt={product.name}
fill
sizes="(max-width: 640px) 100vw, (max-width: 768px) 50vw, (max-width: 1024px) 33vw, 25vw"
className="object-cover transition-all duration-500 group-hover:scale-105"
className="object-cover transition-transform duration-500 ease-in-out"
style={{
transform: hoveredProduct === product.id && product.images.length > 1
? 'scale(1.1)'
: 'scale(1)'
}}
/>
{product.isNew && (
<span className="absolute top-4 left-4 bg-black text-white text-sm py-1 px-3 rounded">
Новинка
</span>
)}
<button
onClick={(e) => toggleFavorite(product.id, e)}
className="absolute top-4 right-4 bg-white/80 hover:bg-white rounded-full p-2 transition-all"
aria-label={favorites.includes(product.id) ? "Удалить из избранного" : "Добавить в избранное"}
className="absolute top-3 right-3 p-2 rounded-full bg-white/80 hover:bg-white transition-colors z-10"
>
<Heart
className={`w-5 h-5 ${favorites.includes(product.id) ? "fill-red-500 text-red-500" : "text-gray-700"}`}
<Heart
className={`w-5 h-5 ${favorites.includes(product.id) ? 'fill-[#63823B] text-[#63823B]' : 'text-gray-600'}`}
/>
</button>
</div>
</div>
<div className="mt-4">
<h3 className="text-lg font-medium">{product.name}</h3>
<p className="mt-1 text-lg font-bold">{formatPrice(product.price)} </p>
</div>
</Link>
</motion.div>
))}
</div>
) : (
<div className="text-center py-12">
<p className="text-xl text-gray-600">В этой категории пока нет товаров</p>
<Link href="/" className="mt-4 inline-block bg-black text-white px-6 py-2 rounded-md hover:bg-gray-800 transition-colors">
Вернуться на главную
</Link>
</div>
)}
<div className="p-4">
<h3 className="text-lg font-medium text-[#2B5F47] mb-1">{product.name}</h3>
<p className="text-sm text-gray-600 mb-2 line-clamp-2">{product.description}</p>
<div className="flex justify-between items-center">
<span className="font-bold text-[#2B5F47]">{formatPrice(product.price)} </span>
<span className="text-sm text-[#63823B]">
{product.inStock ? 'В наличии' : 'Нет в наличии'}
</span>
</div>
</div>
</Link>
</motion.div>
))}
</motion.div>
) : (
<div className="text-center py-12">
<p className="text-xl text-[#2B5F47] mb-4">В этой категории пока нет товаров</p>
<Link href="/category" className="inline-block px-6 py-3 bg-[#63823B] text-white rounded-md hover:bg-[#2B5F47] transition-colors">
Вернуться к категориям
</Link>
</div>
)}
</div>
</main>
<Footer />

View File

@ -1 +1,81 @@
import { useState } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import Image from 'next/image';
import { motion } from 'framer-motion';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
import { Category, categories } from '../../data/categories';
export default function Categories() {
const [hoveredCategory, setHoveredCategory] = useState<number | null>(null);
return (
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo']">
<Head>
<title>Каталог категорий | Brand Store</title>
<link rel="icon" href="/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Arimo:wght@400;500;600;700&display=swap" rel="stylesheet" />
</Head>
<Header />
<main className="pt-24 pb-16 px-4 md:px-8">
<div className="container mx-auto">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-4xl font-bold mb-8 text-[#2B5F47] text-center"
>
Каталог категорий
</motion.h1>
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-8"
>
{categories.map((category, index) => (
<motion.div
key={category.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 * index }}
className="relative overflow-hidden rounded-lg shadow-md bg-white"
onMouseEnter={() => setHoveredCategory(category.id)}
onMouseLeave={() => setHoveredCategory(null)}
>
<Link href={`/category/${category.slug}`}>
<div className="relative h-80 w-full overflow-hidden">
<Image
src={category.image}
alt={category.name}
fill
className={`object-cover transition-transform duration-500 ${
hoveredCategory === category.id ? 'scale-110' : 'scale-100'
}`}
/>
<div className="absolute inset-0 bg-gradient-to-t from-[#2B5F47]/70 to-transparent"></div>
</div>
<div className="absolute bottom-0 left-0 right-0 p-6">
<h2 className="text-xl font-semibold text-white mb-2">{category.name}</h2>
<p className="text-white/80 text-sm mb-4 line-clamp-2">{category.description}</p>
<div className={`inline-block px-4 py-2 bg-[#63823B] text-white rounded-md transition-transform duration-300 ${
hoveredCategory === category.id ? 'translate-y-0' : 'translate-y-8 opacity-0'
}`}>
Смотреть товары
</div>
</div>
</Link>
</motion.div>
))}
</motion.div>
</div>
</main>
<Footer />
</div>
);
}

View File

@ -1,69 +1,77 @@
import { useState } from 'react';
import Head from 'next/head';
import Image from 'next/image';
import Link from 'next/link';
import Image from 'next/image';
import { motion } from 'framer-motion';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
import { Collection, collections } from '../../data/collections';
import { motion } from 'framer-motion';
export default function Collections() {
const [hoveredCollection, setHoveredCollection] = useState<number | null>(null);
return (
<div className="min-h-screen bg-white font-['Arimo']">
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo']">
<Head>
<title>Коллекции | Brand Store</title>
<link rel="icon" href="/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Arimo:wght@400;500;600;700&display=swap" rel="stylesheet" />
</Head>
<Header />
<main className="max-w-7xl mx-auto px-4 py-12 md:px-8">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-4xl font-bold mb-8 font-['Playfair_Display']"
>
Коллекции
</motion.h1>
<main className="pt-24 pb-16 px-4 md:px-8">
<div className="container mx-auto">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-4xl font-bold mb-8 text-[#2B5F47] text-center"
>
Наши коллекции
</motion.h1>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{collections.map((collection) => (
<motion.div
key={collection.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: collection.id * 0.1 }}
whileHover={{ y: -5, transition: { duration: 0.2 } }}
>
<Link
href={`/collections/${collection.slug}`}
className="block h-full"
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="grid grid-cols-1 md:grid-cols-2 gap-8"
>
{collections.map((collection, index) => (
<motion.div
key={collection.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 * index }}
className="relative overflow-hidden rounded-lg shadow-md bg-white"
onMouseEnter={() => setHoveredCollection(collection.id)}
onMouseLeave={() => setHoveredCollection(null)}
>
<div className="relative overflow-hidden rounded-xl aspect-[16/9]">
<Image
src={collection.image}
alt={collection.name}
fill
className={`object-cover transition-all duration-500 ${
hoveredCollection === collection.id ? 'scale-110' : 'scale-100'
}`}
/>
<div className="absolute inset-0 bg-black bg-opacity-30 transition-opacity duration-300"></div>
<div className="absolute inset-0 flex items-center justify-center">
<h2 className="text-white text-xl md:text-2xl font-bold text-center px-4 font-['Playfair_Display']">
{collection.name}
</h2>
<Link href={`/collections/${collection.slug}`}>
<div className="relative h-96 w-full overflow-hidden">
<Image
src={collection.image}
alt={collection.name}
fill
className={`object-cover transition-transform duration-500 ${
hoveredCollection === collection.id ? 'scale-110' : 'scale-100'
}`}
/>
<div className="absolute inset-0 bg-gradient-to-t from-[#2B5F47]/80 to-transparent"></div>
</div>
</div>
<p className="mt-4 text-gray-600 line-clamp-3">{collection.description}</p>
</Link>
</motion.div>
))}
<div className="absolute bottom-0 left-0 right-0 p-8">
<h2 className="text-2xl font-semibold text-white mb-3">{collection.name}</h2>
<p className="text-white/90 text-sm mb-6 line-clamp-3">{collection.description}</p>
<div className={`inline-block px-5 py-2 bg-[#63823B] text-white rounded-md transition-transform duration-300 ${
hoveredCollection === collection.id ? 'translate-y-0' : 'translate-y-8 opacity-0'
}`}>
Смотреть коллекцию
</div>
</div>
</Link>
</motion.div>
))}
</motion.div>
</div>
</main>

View File

@ -81,7 +81,7 @@ export default function Home({ heroImages, products, collections, categories }:
};
return (
<div className="min-h-screen bg-white font-['Arimo']">
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo']">
<Head>
<title>Brand Store | Элегантная мода</title>
<link rel="icon" href="/favicon.ico" />

View File

@ -0,0 +1,117 @@
import { useState } from 'react';
import Head from 'next/head';
import Link from 'next/link';
import Image from 'next/image';
import { motion } from 'framer-motion';
import { Heart } from 'lucide-react';
import Header from '../../components/Header';
import Footer from '../../components/Footer';
import { Product, products } from '../../data/products';
export default function NewArrivals() {
const [hoveredProduct, setHoveredProduct] = useState<number | null>(null);
const [favorites, setFavorites] = useState<number[]>([]);
// Фильтруем только новые товары
const newProducts = products.filter(product => product.isNew);
// Функция для добавления/удаления товара из избранного
const toggleFavorite = (id: number, e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
setFavorites(prev =>
prev.includes(id)
? prev.filter(itemId => itemId !== id)
: [...prev, id]
);
};
return (
<div className="min-h-screen bg-[#E2E2C1] font-['Arimo']">
<Head>
<title>Новинки | Brand Store</title>
<link rel="icon" href="/favicon.ico" />
<link href="https://fonts.googleapis.com/css2?family=Arimo:wght@400;500;600;700&display=swap" rel="stylesheet" />
</Head>
<Header />
<main className="pt-24 pb-16 px-4 md:px-8">
<div className="container mx-auto">
<motion.h1
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
className="text-3xl md:text-4xl font-bold mb-8 text-[#2B5F47] text-center"
>
Новые поступления
</motion.h1>
{newProducts.length > 0 ? (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.2 }}
className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6"
>
{newProducts.map((product, index) => (
<motion.div
key={product.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, delay: 0.1 * index }}
className="bg-white rounded-lg overflow-hidden shadow-md hover:shadow-lg transition-shadow"
onMouseEnter={() => setHoveredProduct(product.id)}
onMouseLeave={() => setHoveredProduct(null)}
>
<Link href={`/product/${product.slug}`}>
<div className="relative h-64 w-full overflow-hidden">
<Image
src={hoveredProduct === product.id && product.images.length > 1
? product.images[1]
: product.images[0]}
alt={product.name}
fill
className="object-cover transition-transform duration-500 ease-in-out"
/>
<div className="absolute top-3 left-3 bg-[#63823B] text-white text-xs py-1 px-3 rounded-md">
Новинка
</div>
<button
onClick={(e) => toggleFavorite(product.id, e)}
className="absolute top-3 right-3 p-2 rounded-full bg-white/80 hover:bg-white transition-colors z-10"
>
<Heart
className={`w-5 h-5 ${favorites.includes(product.id) ? 'fill-[#63823B] text-[#63823B]' : 'text-gray-600'}`}
/>
</button>
</div>
<div className="p-4">
<h3 className="text-lg font-medium text-[#2B5F47] mb-1">{product.name}</h3>
<p className="text-sm text-gray-600 mb-2 line-clamp-2">{product.description}</p>
<div className="flex justify-between items-center">
<span className="font-bold text-[#2B5F47]">{product.price} </span>
<span className="text-sm text-[#63823B]">
{product.inStock ? 'В наличии' : 'Нет в наличии'}
</span>
</div>
</div>
</Link>
</motion.div>
))}
</motion.div>
) : (
<div className="text-center py-12">
<p className="text-xl text-[#2B5F47] mb-4">Новинок пока нет</p>
<Link href="/" className="inline-block px-6 py-3 bg-[#63823B] text-white rounded-md hover:bg-[#2B5F47] transition-colors">
Вернуться на главную
</Link>
</div>
)}
</div>
</main>
<Footer />
</div>
);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 113 KiB

BIN
public/wear/bag1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
public/wear/bag2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
public/wear/coat1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
public/wear/coat2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
public/wear/hat1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/wear/kozh_boots1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
public/wear/kozh_boots2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
public/wear/silk1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
public/wear/silk2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
public/wear/silk_scarf1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
public/wear/silk_scarf2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB