Add new features: product favorites, hero slider, and product improvements

This commit is contained in:
belikovme 2025-02-26 18:57:27 +07:00
parent 9f0d3aba35
commit 01e10367ba
13 changed files with 437 additions and 161 deletions

View File

@ -0,0 +1,43 @@
"use client"
import { useState, useEffect } from "react"
export default function CookieNotification() {
const [isVisible, setIsVisible] = useState(false);
// Проверяем, было ли уже показано уведомление
useEffect(() => {
const cookieAccepted = localStorage.getItem('cookieAccepted');
if (!cookieAccepted) {
// Показываем уведомление с небольшой задержкой
const timer = setTimeout(() => {
setIsVisible(true);
}, 2000);
return () => clearTimeout(timer);
}
}, []);
const acceptCookies = () => {
localStorage.setItem('cookieAccepted', 'true');
setIsVisible(false);
};
if (!isVisible) return null;
return (
<div className="fixed bottom-4 right-4 bg-white p-4 shadow-lg rounded-lg max-w-sm z-50 animate-fade-in">
<h3 className="font-bold mb-2">Уведомление о Cookies</h3>
<p className="text-sm mb-4">
Наш сайт использует файлы cookie. Продолжая пользоваться сайтом, вы соглашаетесь на использование наших файлов
cookie.
</p>
<button
onClick={acceptCookies}
className="bg-black text-white px-4 py-2 rounded hover:bg-gray-800 transition-colors"
>
Хорошо, спасибо
</button>
</div>
);
}

75
components/Header.tsx Normal file
View File

@ -0,0 +1,75 @@
import Link from "next/link";
import { Search, Heart, User, ShoppingCart } from "lucide-react";
import { useState, useEffect } from "react";
import { motion } from "framer-motion";
import Image from "next/image";
export default function Header() {
// Состояние для отслеживания прокрутки страницы
const [scrolled, setScrolled] = useState(false);
// Эффект для отслеживания прокрутки
useEffect(() => {
const handleScroll = () => {
const isScrolled = window.scrollY > 50;
if (isScrolled !== scrolled) {
setScrolled(isScrolled);
}
};
window.addEventListener('scroll', handleScroll);
return () => {
window.removeEventListener('scroll', handleScroll);
};
}, [scrolled]);
return (
<header className={`fixed w-full z-50 transition-all duration-300 ${scrolled ? 'bg-white shadow-sm' : 'bg-transparent'}`}>
<nav className={`py-4 transition-all duration-300 ${scrolled ? 'text-black' : 'text-white'}`}>
<div className="container mx-auto px-4 flex items-center justify-between">
<div className="flex items-center space-x-6">
<Link href="/catalog" className="text-sm font-medium hover:opacity-70 transition-opacity">
Каталог
</Link>
<Link href="/new" className="text-sm font-medium hover:opacity-70 transition-opacity">
Новинки
</Link>
<Link href="/stores" className="text-sm font-medium hover:opacity-70 transition-opacity">
Магазины
</Link>
</div>
<Link href="/" className="text-2xl font-bold">
<div className="relative h-10 w-32">
<Image
src="/logo.png"
alt="Brand Logo"
layout="fill"
objectFit="contain"
/>
</div>
</Link>
<div className="flex items-center space-x-5">
<button className="hover:opacity-70 transition-opacity">
<Search className="w-5 h-5" />
</button>
<Link href="/favorites" className="relative hover:opacity-70 transition-opacity">
<Heart className="w-5 h-5" />
<span className={`absolute -top-2 -right-2 ${scrolled ? 'bg-black text-white' : 'bg-white text-black'} text-xs rounded-full w-4 h-4 flex items-center justify-center`}>
0
</span>
</Link>
<Link href="/account" className="hover:opacity-70 transition-opacity">
<User className="w-5 h-5" />
</Link>
<Link href="/cart" className="relative hover:opacity-70 transition-opacity">
<ShoppingCart className="w-5 h-5" />
<span className={`absolute -top-2 -right-2 ${scrolled ? 'bg-black text-white' : 'bg-white text-black'} text-xs rounded-full w-4 h-4 flex items-center justify-center`}>
0
</span>
</Link>
</div>
</div>
</nav>
</header>
);
}

135
components/Hero.tsx Normal file
View File

@ -0,0 +1,135 @@
import { useState, useEffect } from "react";
import Image from "next/image";
import { ChevronLeft, ChevronRight } from "lucide-react";
import { motion, AnimatePresence } from "framer-motion";
// Типы для свойств компонента
interface HeroProps {
images?: string[];
}
export default function Hero({ images = [] }: HeroProps) {
// Состояние для текущего индекса слайда
const [currentIndex, setCurrentIndex] = useState(0);
// Состояние для автоматического воспроизведения
const [autoplay, setAutoplay] = useState(true);
// Состояние для направления анимации: 1 - следующий слайд, -1 - предыдущий слайд
const [direction, setDirection] = useState(0);
// Если изображения не переданы или массив пуст, используем стандартное изображение
const heroImages = images.length > 0
? images
: ['/photos/head_photo.png'];
// Функция для перехода к следующему слайду
const nextSlide = () => {
setDirection(1);
setCurrentIndex((prevIndex) =>
prevIndex === heroImages.length - 1 ? 0 : prevIndex + 1
);
};
// Функция для перехода к предыдущему слайду
const prevSlide = () => {
setDirection(-1);
setCurrentIndex((prevIndex) =>
prevIndex === 0 ? heroImages.length - 1 : prevIndex - 1
);
};
// Эффект для автоматического воспроизведения слайдера
useEffect(() => {
let interval: NodeJS.Timeout;
if (autoplay) {
interval = setInterval(() => {
nextSlide();
}, 5000); // Смена слайда каждые 5 секунд
}
return () => {
if (interval) clearInterval(interval);
};
}, [autoplay, currentIndex]);
// Определяем варианты анимации для эффекта "скольжения"
const variants = {
enter: (direction: number) => ({
x: direction > 0 ? "100%" : "-100%",
opacity: 0
}),
center: {
x: 0,
opacity: 1
},
exit: (direction: number) => ({
x: direction > 0 ? "-100%" : "100%",
opacity: 0
}),
};
return (
<div className="relative h-screen overflow-hidden">
<AnimatePresence custom={direction} mode="wait">
<motion.div
key={currentIndex}
custom={direction}
variants={variants}
initial="enter"
animate="center"
exit="exit"
transition={{ duration: 0.7 }}
className="absolute inset-0"
>
<Image
src={heroImages[currentIndex]}
alt="New Arrivals"
layout="fill"
objectFit="cover"
quality={100}
priority
/>
{/* Убрали затемнение изображения */}
</motion.div>
</AnimatePresence>
<button
className="absolute left-4 top-1/2 transform -translate-y-1/2 bg-white bg-opacity-50 p-2 rounded-full hover:bg-opacity-70 transition-all"
onClick={() => {
prevSlide();
setAutoplay(false);
}}
>
<ChevronLeft className="w-6 h-6 text-black" />
</button>
<button
className="absolute right-4 top-1/2 transform -translate-y-1/2 bg-white bg-opacity-50 p-2 rounded-full hover:bg-opacity-70 transition-all"
onClick={() => {
nextSlide();
setAutoplay(false);
}}
>
<ChevronRight className="w-6 h-6 text-black" />
</button>
{/* Индикаторы слайдов */}
<div className="absolute bottom-8 left-0 right-0 flex justify-center space-x-2">
{heroImages.map((_, index) => (
<button
key={index}
onClick={() => {
// Определяем направление в зависимости от выбранного индекса
setDirection(index > currentIndex ? 1 : -1);
setCurrentIndex(index);
setAutoplay(false);
}}
className={`w-3 h-3 rounded-full ${
index === currentIndex ? 'bg-white' : 'bg-white/50'
}`}
/>
))}
</div>
</div>
);
}

82
package-lock.json generated
View File

@ -9,7 +9,9 @@
"version": "1.0.0",
"dependencies": {
"@heroicons/react": "^2.0.18",
"@tailwindcss/line-clamp": "^0.4.4",
"framer-motion": "^10.16.4",
"lucide-react": "^0.476.0",
"next": "^13.4.19",
"react": "^18.2.0",
"react-dom": "^18.2.0"
@ -203,7 +205,6 @@
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "2.0.5",
@ -217,7 +218,6 @@
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@ -227,7 +227,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.scandir": "2.1.5",
@ -246,6 +245,15 @@
"tslib": "^2.4.0"
}
},
"node_modules/@tailwindcss/line-clamp": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/@tailwindcss/line-clamp/-/line-clamp-0.4.4.tgz",
"integrity": "sha512-5U6SY5z8N42VtrCrKlsTAA35gy2VSyYtHWCsg1H87NU1SXnEfekTVlrga9fzUDrrHcGi2Lb5KenUWb4lRQT5/g==",
"license": "MIT",
"peerDependencies": {
"tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1"
}
},
"node_modules/@types/node": {
"version": "20.17.19",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz",
@ -278,7 +286,6 @@
"version": "7.4.1",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
"dev": true,
"license": "MIT",
"bin": {
"acorn": "bin/acorn"
@ -291,7 +298,6 @@
"version": "1.8.2",
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"acorn": "^7.0.0",
@ -303,7 +309,6 @@
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4.0"
@ -313,7 +318,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
@ -327,7 +331,6 @@
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
"integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
"dev": true,
"license": "MIT"
},
"node_modules/autoprefixer": {
@ -368,7 +371,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
@ -381,7 +383,6 @@
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
"dev": true,
"license": "MIT",
"dependencies": {
"fill-range": "^7.1.1"
@ -438,7 +439,6 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@ -468,7 +468,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dev": true,
"license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
@ -493,7 +492,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@ -512,14 +510,12 @@
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"dev": true,
"license": "MIT"
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
"dev": true,
"license": "MIT",
"bin": {
"cssesc": "bin/cssesc"
@ -539,7 +535,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
"integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -549,7 +544,6 @@
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
"integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn-node": "^1.8.2",
@ -567,14 +561,12 @@
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
"dev": true,
"license": "MIT"
},
"node_modules/electron-to-chromium": {
@ -598,7 +590,6 @@
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz",
"integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@ -615,7 +606,6 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
@ -628,7 +618,6 @@
"version": "1.19.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.0.tgz",
"integrity": "sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==",
"dev": true,
"license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
@ -638,7 +627,6 @@
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
"dev": true,
"license": "MIT",
"dependencies": {
"to-regex-range": "^5.0.1"
@ -689,7 +677,6 @@
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
@ -704,7 +691,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -714,7 +700,6 @@
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.3"
@ -739,7 +724,6 @@
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@ -752,7 +736,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
@ -765,7 +748,6 @@
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
@ -781,7 +763,6 @@
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -791,7 +772,6 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-extglob": "^2.1.1"
@ -804,7 +784,6 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.12.0"
@ -820,7 +799,6 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
"integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@ -838,11 +816,19 @@
"loose-envify": "cli.js"
}
},
"node_modules/lucide-react": {
"version": "0.476.0",
"resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.476.0.tgz",
"integrity": "sha512-x6cLTk8gahdUPje0hSgLN1/MgiJH+Xl90Xoxy9bkPAsMPOUiyRSKR4JCDPGVCEpyqnZXH3exFWNItcvra9WzUQ==",
"license": "ISC",
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 8"
@ -852,7 +838,6 @@
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
"dev": true,
"license": "MIT",
"dependencies": {
"braces": "^3.0.3",
@ -866,7 +851,6 @@
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -975,7 +959,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -995,7 +978,6 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 6"
@ -1005,7 +987,6 @@
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
"node_modules/picocolors": {
@ -1018,7 +999,6 @@
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8.6"
@ -1031,7 +1011,6 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
@ -1041,7 +1020,6 @@
"version": "8.4.20",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.20.tgz",
"integrity": "sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -1066,7 +1044,6 @@
"version": "14.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz",
"integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.0.0",
@ -1084,7 +1061,6 @@
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
"integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
"dev": true,
"license": "MIT",
"dependencies": {
"lilconfig": "^2.0.5",
@ -1114,7 +1090,6 @@
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.0.tgz",
"integrity": "sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==",
"dev": true,
"license": "MIT",
"dependencies": {
"postcss-selector-parser": "^6.0.10"
@ -1134,7 +1109,6 @@
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
"integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
"dev": true,
"license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
@ -1148,14 +1122,12 @@
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
"dev": true,
"license": "MIT"
},
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
"dev": true,
"funding": [
{
"type": "github",
@ -1176,7 +1148,6 @@
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=10"
@ -1214,7 +1185,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
"dev": true,
"license": "MIT",
"dependencies": {
"pify": "^2.3.0"
@ -1224,7 +1194,6 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
"dev": true,
"license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
@ -1237,7 +1206,6 @@
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
@ -1258,7 +1226,6 @@
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
"dev": true,
"license": "MIT",
"engines": {
"iojs": ">=1.0.0",
@ -1269,7 +1236,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
"dev": true,
"funding": [
{
"type": "github",
@ -1342,7 +1308,6 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -1355,7 +1320,6 @@
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.2.4.tgz",
"integrity": "sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"arg": "^5.0.2",
@ -1397,7 +1361,6 @@
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz",
"integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==",
"dev": true,
"funding": [
{
"type": "opencollective",
@ -1426,7 +1389,6 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
"dev": true,
"license": "MIT",
"dependencies": {
"camelcase-css": "^2.0.1"
@ -1446,7 +1408,6 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-number": "^7.0.0"
@ -1517,7 +1478,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true,
"license": "MIT"
},
"node_modules/watchpack": {
@ -1537,7 +1497,6 @@
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.4"
@ -1547,7 +1506,6 @@
"version": "1.10.2",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"dev": true,
"license": "ISC",
"engines": {
"node": ">= 6"

View File

@ -9,7 +9,9 @@
},
"dependencies": {
"@heroicons/react": "^2.0.18",
"@tailwindcss/line-clamp": "^0.4.4",
"framer-motion": "^10.16.4",
"lucide-react": "^0.476.0",
"next": "^13.4.19",
"react": "^18.2.0",
"react-dom": "^18.2.0"

View File

@ -2,35 +2,34 @@ import { motion } from 'framer-motion';
import Head from 'next/head';
import Image from 'next/image';
import { useState, useEffect } from 'react';
import Header from '../components/Header';
import Hero from '../components/Hero';
import CookieNotification from '../components/CookieNotification';
import fs from 'fs';
import path from 'path';
import { Heart } from 'lucide-react';
export default function Home() {
// Данные о товарах
const products = [
{
id: 1,
name: 'Пальто',
price: 15000,
images: ['/wear/palto1.jpg', '/wear/palto2.jpg'],
description: 'Элегантное пальто высокого качества'
},
{
id: 2,
name: 'Пиджак',
price: 12000,
images: ['/wear/pidzak1.jpg', '/wear/pidzak2.jpg'],
description: 'Стильный пиджак для особых случаев'
},
{
id: 3,
name: 'Сорочка',
price: 5000,
images: ['/wear/sorochka1.jpg', '/wear/sorochka2.jpg'],
description: 'Классическая сорочка из премиальных материалов'
}
];
// Типы для свойств компонента
interface HomeProps {
heroImages: string[];
products: Product[];
}
// Тип для товара
interface Product {
id: number;
name: string;
price: number;
images: string[];
description: string;
isNew?: boolean;
}
export default function Home({ heroImages, products }: HomeProps) {
// Состояние для отслеживания наведения на карточки товаров
const [hoveredProduct, setHoveredProduct] = useState<number | null>(null);
// Состояние для отслеживания избранных товаров
const [favorites, setFavorites] = useState<number[]>([]);
// Состояние для отслеживания прокрутки страницы
const [scrolled, setScrolled] = useState(false);
@ -50,109 +49,90 @@ export default function Home() {
};
}, [scrolled]);
// Функция для добавления/удаления товара из избранного
const toggleFavorite = (id: number, e: React.MouseEvent) => {
e.stopPropagation();
setFavorites(prev =>
prev.includes(id)
? prev.filter(itemId => itemId !== id)
: [...prev, id]
);
};
return (
<div className="min-h-screen bg-white 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" />
<link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;500;600;700&display=swap" rel="stylesheet" />
</Head>
<header className={`fixed w-full z-50 transition-all duration-300 ${scrolled ? 'bg-white/80 backdrop-blur-md shadow-sm' : 'bg-transparent'}`}>
<nav className="container mx-auto px-6 py-4">
<div className="flex items-center justify-between">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
className="flex items-center"
>
<div className="relative h-12 w-12">
<Image
src="/logo.png"
alt="Brand Logo"
layout="fill"
objectFit="contain"
/>
</div>
</motion.div>
<div className="hidden md:flex space-x-8">
<a href="#" className={`transition-colors ${scrolled ? 'text-primary hover:text-accent' : 'text-white hover:text-gray-200'}`}>Коллекция</a>
<a href="#" className={`transition-colors ${scrolled ? 'text-primary hover:text-accent' : 'text-white hover:text-gray-200'}`}>О нас</a>
<a href="#" className={`transition-colors ${scrolled ? 'text-primary hover:text-accent' : 'text-white hover:text-gray-200'}`}>Контакты</a>
</div>
</div>
</nav>
</header>
<Header />
<main>
{/* Секция с фоновым изображением */}
<section className="relative h-screen">
<div className="absolute inset-0 w-full h-full">
<Image
src="/photos/head_photo.png"
alt="Главное фото"
layout="fill"
objectFit="cover"
priority
/>
</div>
</section>
{/* Секция с HERO элементом */}
<Hero images={heroImages} />
{/* Секция с приветственным текстом */}
<section className="py-20 bg-white">
{/* Секция с товарами */}
<section className="py-16 bg-white">
<div className="container mx-auto px-6">
<motion.div
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
transition={{ delay: 0.2 }}
className="text-center max-w-3xl mx-auto"
className="text-3xl text-center font-medium mb-12"
>
<h1 className="text-5xl md:text-6xl text-primary mb-6">
Элегантность в каждой детали
</h1>
<p className="text-lg text-gray-600 mb-8">
Откройте для себя новую коллекцию 2024
</p>
<button className="bg-primary text-white px-8 py-3 rounded-full hover:bg-accent transition-colors">
Смотреть коллекцию
</button>
</motion.div>
</div>
</section>
{/* Секция с товарами */}
<section className="py-20 bg-gray-50">
<div className="container mx-auto px-6">
{/* <h2 className="text-3xl text-primary text-center mb-16">Наши товары</h2> */}
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-16">
Новинки
</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.2 }}
className="group"
transition={{ delay: index * 0.1 }}
className="group relative"
onMouseEnter={() => setHoveredProduct(product.id)}
onMouseLeave={() => setHoveredProduct(null)}
>
<div className="relative h-[600px] w-full overflow-hidden mb-6">
{/* Метка "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[1] : product.images[0]}
src={hoveredProduct === product.id && product.images.length > 1 ? product.images[1] : product.images[0]}
alt={product.name}
layout="fill"
objectFit="contain"
className="transition-opacity duration-300"
objectFit="cover"
className="transition-all duration-500 hover:scale-105"
/>
</div>
<div className="p-4">
<h3 className="text-2xl text-primary mb-3">{product.name}</h3>
<p className="text-gray-600 mb-5 text-lg">{product.description}</p>
<div className="flex justify-between items-center">
<span className="text-xl font-semibold text-primary">{product.price.toLocaleString()} </span>
<button className="bg-primary text-white px-6 py-3 rounded-full hover:bg-accent transition-colors">
Подробнее
</button>
</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>
))}
@ -193,6 +173,80 @@ export default function Home() {
</div>
</div>
</footer>
<CookieNotification />
</div>
);
}
// Функция для получения данных на стороне сервера
export async function getStaticProps() {
// Данные о товарах
const products = [
{
id: 1,
name: 'Пальто оверсайз',
price: 43800,
images: ['/wear/palto1.jpg', '/wear/palto2.jpg'],
description: 'Элегантное пальто оверсайз высокого качества',
isNew: true
},
{
id: 2,
name: 'Костюм хлопок',
price: 12800,
images: ['/wear/pidzak1.jpg', '/wear/pidzak2.jpg'],
description: 'Стильный костюм для особых случаев',
isNew: true
},
{
id: 3,
name: 'Блузка',
price: 3500,
images: ['/wear/sorochka1.jpg', '/wear/sorochka2.jpg'],
description: 'Классическая блузка в коричневом цвете',
isNew: true
},
{
id: 4,
name: 'Платье со сборкой',
price: 28800,
images: ['/wear/jumpsuit_1.jpg', '/wear/jumpsuit_2.jpg'],
description: 'Элегантное платье высокого качества',
isNew: true
}
];
// Получение изображений для слайдера из папки hero_photos
const heroImagesDirectory = path.join(process.cwd(), 'public/hero_photos');
let heroImages = [];
try {
const fileNames = fs.readdirSync(heroImagesDirectory);
// Фильтруем только изображения
const imageExtensions = ['.jpg', '.jpeg', '.png', '.webp', '.gif'];
const imageFiles = fileNames.filter(file =>
imageExtensions.some(ext => file.toLowerCase().endsWith(ext))
);
if (imageFiles.length > 0) {
heroImages = imageFiles.map(fileName => `/hero_photos/${fileName}`);
} else {
// Если нет изображений, используем изображения из папки photos
heroImages = ['/photos/head_photo.png'];
}
} catch (error) {
console.error('Error reading hero_photos directory:', error);
// Если папка не существует или пуста, используем изображение из папки photos
heroImages = ['/photos/head_photo.png'];
}
return {
props: {
heroImages,
products,
},
// Перегенерация страницы каждые 10 минут
revalidate: 600,
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 441 KiB

BIN
public/wear/jumpsuit_1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
public/wear/jumpsuit_2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -16,6 +16,15 @@ module.exports = {
sans: ['Inter', 'sans-serif'],
serif: ['Playfair Display', 'serif'],
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
},
keyframes: {
fadeIn: {
'0%': { opacity: 0 },
'100%': { opacity: 1 },
},
},
},
},
plugins: [],