Обновить футер и главную страницу с добавлением новых компонентов и улучшением навигации
63
components/Collections.tsx
Normal file
@ -0,0 +1,63 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
// Типы для свойств компонента
|
||||
interface CollectionsProps {
|
||||
collections: Collection[];
|
||||
}
|
||||
|
||||
// Тип для коллекции
|
||||
interface Collection {
|
||||
id: number;
|
||||
name: string;
|
||||
image: string;
|
||||
description: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function Collections({ collections }: CollectionsProps) {
|
||||
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-3 gap-8">
|
||||
{collections.map((collection, index) => (
|
||||
<motion.div
|
||||
key={collection.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="group relative overflow-hidden rounded-lg"
|
||||
>
|
||||
<Link href={collection.url}>
|
||||
<div className="relative aspect-[4/3] w-full overflow-hidden">
|
||||
<Image
|
||||
src={collection.image}
|
||||
alt={collection.name}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
className="transition-all duration-500 group-hover:scale-105"
|
||||
/>
|
||||
<div className="absolute inset-0 bg-black bg-opacity-20 transition-opacity group-hover:bg-opacity-30" />
|
||||
</div>
|
||||
<div className="absolute bottom-0 left-0 right-0 p-6 text-white">
|
||||
<h3 className="text-xl font-medium mb-2">{collection.name}</h3>
|
||||
<p className="text-sm opacity-90">{collection.description}</p>
|
||||
</div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
@ -1,37 +1,83 @@
|
||||
export default function Footer() {
|
||||
import Link from "next/link";
|
||||
import { Facebook, Instagram, Twitter, Youtube } from "lucide-react";
|
||||
|
||||
export default function Footer() {
|
||||
return (
|
||||
<footer className="bg-primary text-white py-12">
|
||||
<div className="container mx-auto px-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8">
|
||||
<div>
|
||||
<h4 className="text-xl mb-4">О нас</h4>
|
||||
<p className="text-gray-400">
|
||||
Мы создаем элегантную одежду для тех, кто ценит качество и стиль.
|
||||
</p>
|
||||
<footer className="bg-gray-100 text-gray-800 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>
|
||||
</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>
|
||||
</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>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4 className="text-lg font-medium mb-4">Подписаться</h4>
|
||||
<p className="text-sm mb-4">Подпишитесь на нашу рассылку, чтобы получать новости о новых коллекциях и эксклюзивных предложениях.</p>
|
||||
<div className="flex mb-6">
|
||||
<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"
|
||||
/>
|
||||
<button className="bg-black text-white px-4 py-2 text-sm rounded-r hover:bg-gray-800 transition-colors">
|
||||
→
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-xl mb-4">Контакты</h4>
|
||||
<p className="text-gray-400">
|
||||
Email: info@brandstore.com<br />
|
||||
Телефон: +7 (999) 123-45-67
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="text-xl mb-4">Подписаться</h4>
|
||||
<div className="flex">
|
||||
<input
|
||||
type="email"
|
||||
placeholder="Ваш email"
|
||||
className="bg-white/10 px-4 py-2 rounded-l-full focus:outline-none"
|
||||
/>
|
||||
<button className="bg-accent px-6 rounded-r-full hover:bg-accent/90 transition-colors">
|
||||
→
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex space-x-4">
|
||||
<a href="#" className="text-gray-600 hover:text-black transition-colors">
|
||||
<Facebook size={20} />
|
||||
</a>
|
||||
<a href="#" className="text-gray-600 hover:text-black transition-colors">
|
||||
<Instagram size={20} />
|
||||
</a>
|
||||
<a href="#" className="text-gray-600 hover:text-black transition-colors">
|
||||
<Twitter size={20} />
|
||||
</a>
|
||||
<a href="#" className="text-gray-600 hover:text-black transition-colors">
|
||||
<Youtube size={20} />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<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="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>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
103
components/NewArrivals.tsx
Normal file
@ -0,0 +1,103 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
58
components/PopularCategories.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import { motion } from 'framer-motion';
|
||||
import Image from 'next/image';
|
||||
import Link from 'next/link';
|
||||
|
||||
// Типы для свойств компонента
|
||||
interface PopularCategoriesProps {
|
||||
categories: Category[];
|
||||
}
|
||||
|
||||
// Тип для категории
|
||||
interface Category {
|
||||
id: number;
|
||||
name: string;
|
||||
image: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function PopularCategories({ categories }: PopularCategoriesProps) {
|
||||
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-2 md:grid-cols-4 gap-6">
|
||||
{categories.map((category, index) => (
|
||||
<motion.div
|
||||
key={category.id}
|
||||
initial={{ opacity: 0, y: 20 }}
|
||||
whileInView={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: index * 0.1 }}
|
||||
className="group"
|
||||
>
|
||||
<Link href={category.url} className="block">
|
||||
<div className="relative aspect-square w-full overflow-hidden mb-4 bg-gray-100">
|
||||
<Image
|
||||
src={category.image}
|
||||
alt={category.name}
|
||||
layout="fill"
|
||||
objectFit="cover"
|
||||
className="transition-all duration-500 group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
<h3 className="text-center text-sm font-medium">{category.name}</h3>
|
||||
</Link>
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
102
components/TabSelector.tsx
Normal file
@ -0,0 +1,102 @@
|
||||
"use client"
|
||||
|
||||
import { useState, useRef, useEffect } from "react"
|
||||
|
||||
const tabs = ["Новинки", "Коллекции", "Популярное"]
|
||||
|
||||
interface TabSelectorProps {
|
||||
onTabChange: (index: number) => void;
|
||||
}
|
||||
|
||||
export default function TabSelector({ onTabChange }: TabSelectorProps) {
|
||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null)
|
||||
const [activeIndex, setActiveIndex] = useState(0)
|
||||
const [hoverStyle, setHoverStyle] = useState({})
|
||||
const [activeStyle, setActiveStyle] = useState({ left: "0px", width: "0px" })
|
||||
const tabRefs = useRef<(HTMLDivElement | null)[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
if (hoveredIndex !== null) {
|
||||
const hoveredElement = tabRefs.current[hoveredIndex]
|
||||
if (hoveredElement) {
|
||||
const { offsetLeft, offsetWidth } = hoveredElement
|
||||
setHoverStyle({
|
||||
left: `${offsetLeft}px`,
|
||||
width: `${offsetWidth}px`,
|
||||
})
|
||||
}
|
||||
}
|
||||
}, [hoveredIndex])
|
||||
|
||||
useEffect(() => {
|
||||
const activeElement = tabRefs.current[activeIndex]
|
||||
if (activeElement) {
|
||||
const { offsetLeft, offsetWidth } = activeElement
|
||||
setActiveStyle({
|
||||
left: `${offsetLeft}px`,
|
||||
width: `${offsetWidth}px`,
|
||||
})
|
||||
}
|
||||
|
||||
// Вызываем функцию обратного вызова при изменении активного таба
|
||||
onTabChange(activeIndex);
|
||||
}, [activeIndex, onTabChange])
|
||||
|
||||
useEffect(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const firstElement = tabRefs.current[0]
|
||||
if (firstElement) {
|
||||
const { offsetLeft, offsetWidth } = firstElement
|
||||
setActiveStyle({
|
||||
left: `${offsetLeft}px`,
|
||||
width: `${offsetWidth}px`,
|
||||
})
|
||||
}
|
||||
})
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="flex justify-center items-center w-full py-8 bg-white">
|
||||
<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"
|
||||
style={{
|
||||
...hoverStyle,
|
||||
opacity: hoveredIndex !== null ? 1 : 0,
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Active Indicator */}
|
||||
<div
|
||||
className="absolute bottom-[-6px] h-[2px] bg-black transition-all duration-300 ease-out"
|
||||
style={activeStyle}
|
||||
/>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="relative flex space-x-[24px] items-center">
|
||||
{tabs.map((tab, index) => (
|
||||
<div
|
||||
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"
|
||||
}`}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
onClick={() => setActiveIndex(index)}
|
||||
>
|
||||
<div className="text-sm leading-5 whitespace-nowrap flex items-center justify-center h-full">
|
||||
{tab}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
195
pages/index.tsx
@ -5,6 +5,10 @@ import { useState, useEffect } from 'react';
|
||||
import Header from '../components/Header';
|
||||
import Hero from '../components/Hero';
|
||||
import CookieNotification from '../components/CookieNotification';
|
||||
import TabSelector from '../components/TabSelector';
|
||||
import NewArrivals from '../components/NewArrivals';
|
||||
import Collections from '../components/Collections';
|
||||
import PopularCategories from '../components/PopularCategories';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { Heart } from 'lucide-react';
|
||||
@ -14,6 +18,8 @@ import Footer from '../components/Footer';
|
||||
interface HomeProps {
|
||||
heroImages: string[];
|
||||
products: Product[];
|
||||
collections: Collection[];
|
||||
categories: Category[];
|
||||
}
|
||||
|
||||
// Тип для товара
|
||||
@ -26,11 +32,30 @@ interface Product {
|
||||
isNew?: boolean;
|
||||
}
|
||||
|
||||
export default function Home({ heroImages, products }: HomeProps) {
|
||||
// Тип для коллекции
|
||||
interface Collection {
|
||||
id: number;
|
||||
name: string;
|
||||
image: string;
|
||||
description: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
// Тип для категории
|
||||
interface Category {
|
||||
id: number;
|
||||
name: string;
|
||||
image: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export default function Home({ heroImages, products, collections, categories }: HomeProps) {
|
||||
// Состояние для отслеживания наведения на карточки товаров
|
||||
const [hoveredProduct, setHoveredProduct] = useState<number | null>(null);
|
||||
// Состояние для отслеживания избранных товаров
|
||||
const [favorites, setFavorites] = useState<number[]>([]);
|
||||
// Состояние для отслеживания активного таба
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
|
||||
// Состояние для отслеживания прокрутки страницы
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
@ -60,6 +85,25 @@ export default function Home({ heroImages, products }: HomeProps) {
|
||||
);
|
||||
};
|
||||
|
||||
// Функция для обработки изменения активного таба
|
||||
const handleTabChange = (index: number) => {
|
||||
setActiveTab(index);
|
||||
};
|
||||
|
||||
// Рендерим контент в зависимости от активного таба
|
||||
const renderTabContent = () => {
|
||||
switch (activeTab) {
|
||||
case 0:
|
||||
return <NewArrivals products={products} />;
|
||||
case 1:
|
||||
return <Collections collections={collections} />;
|
||||
case 2:
|
||||
return <PopularCategories categories={categories} />;
|
||||
default:
|
||||
return <NewArrivals products={products} />;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-white font-['Arimo']">
|
||||
<Head>
|
||||
@ -75,71 +119,11 @@ export default function Home({ heroImages, products }: HomeProps) {
|
||||
{/* Секция с HERO элементом */}
|
||||
<Hero images={heroImages} />
|
||||
|
||||
{/* Секция с товарами */}
|
||||
<section className="py-16 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-3 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>
|
||||
{/* Табы для выбора категорий */}
|
||||
<TabSelector onTabChange={handleTabChange} />
|
||||
|
||||
{/* Контент в зависимости от выбранного таба */}
|
||||
{renderTabContent()}
|
||||
</main>
|
||||
|
||||
<Footer />
|
||||
@ -187,6 +171,83 @@ export async function getStaticProps() {
|
||||
}
|
||||
];
|
||||
|
||||
// Данные о коллекциях
|
||||
const collections = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Весна-Лето 2024',
|
||||
image: '/photos/photo1.jpg',
|
||||
description: 'Легкие ткани и яркие цвета для теплого сезона',
|
||||
url: '/collections/spring-summer-2024'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Осень-Зима 2023',
|
||||
image: '/photos/photo2.jpg',
|
||||
description: 'Теплые и уютные модели для холодного времени года',
|
||||
url: '/collections/autumn-winter-2023'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Базовый гардероб',
|
||||
image: '/photos/head_photo.png',
|
||||
description: 'Классические модели, которые никогда не выходят из моды',
|
||||
url: '/collections/basic'
|
||||
}
|
||||
];
|
||||
|
||||
// Данные о категориях
|
||||
const categories = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Женская обувь',
|
||||
image: '/category/shoes.jpg',
|
||||
url: '/category/shoes'
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Шляпы и перчатки',
|
||||
image: '/category/hat.jpg',
|
||||
url: '/category/hats-and-gloves'
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Штаны и брюки',
|
||||
image: '/category/pants.jpg',
|
||||
url: '/category/pants'
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Свитеры и кардиганы',
|
||||
image: '/category/sweaters.jpg',
|
||||
url: '/category/sweaters'
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Платья и юбки',
|
||||
image: '/category/dress.jpg',
|
||||
url: '/category/dress'
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Костюмы',
|
||||
image: '/category/jacket.jpg',
|
||||
url: '/category/jackets'
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'Женский шелк',
|
||||
image: '/category/silk.jpg',
|
||||
url: '/category/womens-silk'
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'Аксессуары',
|
||||
image: '/category/scarf.jpg',
|
||||
url: '/category/accessories'
|
||||
}
|
||||
];
|
||||
|
||||
// Получение изображений для слайдера из папки hero_photos
|
||||
const heroImagesDirectory = path.join(process.cwd(), 'public/hero_photos');
|
||||
let heroImages = [];
|
||||
@ -215,6 +276,8 @@ export async function getStaticProps() {
|
||||
props: {
|
||||
heroImages,
|
||||
products,
|
||||
collections,
|
||||
categories
|
||||
},
|
||||
// Перегенерация страницы каждые 10 минут
|
||||
revalidate: 600,
|
||||
|
||||
BIN
public/category/dress.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/category/hat.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/category/jacket.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
BIN
public/category/pants.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/category/scarf.jpg
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
public/category/shoes.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
public/category/silk.jpg
Normal file
|
After Width: | Height: | Size: 10 KiB |
BIN
public/category/sweaters.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 230 KiB |