diff --git a/src/entities/Notification/Notification.module.scss b/src/entities/Notification/Notification.module.scss index 258e9f9..9d67c00 100644 --- a/src/entities/Notification/Notification.module.scss +++ b/src/entities/Notification/Notification.module.scss @@ -21,6 +21,12 @@ @include background(.3); @apply rounded-xl; + [class="light"] & { + @include background(1); + + backdrop-filter: none; + } + @media (max-width: theme('screens.sm')) { width: calc(100% - 10px * 2); @@ -47,7 +53,7 @@ } .closing { - animation: fadeOut .3s ease-out forwards; + animation: fadeOut var(--animation-close-duration-notification) ease-out forwards; } @keyframes fadeOut { @@ -62,8 +68,44 @@ } } +.swipeLeft { + animation: swipeLeft var(--animation-close-duration-notification) ease-out forwards; +} + +.swipeRight { + animation: swipeRight var(--animation-close-duration-notification) ease-out forwards; +} + +@keyframes swipeLeft { + 0% { + opacity: 1; + transform: translate(-50%, 0); + } + + 100% { + opacity: 0; + transform: translate(-100%, 0); + } +} + +@keyframes swipeRight { + 0% { + opacity: 1; + transform: translate(-50%, 0); + } + + 100% { + opacity: 0; + transform: translate(100%, 0); + } +} + .icon { opacity: .5; + + &svg *[fill] { + fill: var(--color-main-inverted); + } } .content { diff --git a/src/entities/Notification/Notification.tsx b/src/entities/Notification/Notification.tsx index c50be04..85f05b4 100644 --- a/src/entities/Notification/Notification.tsx +++ b/src/entities/Notification/Notification.tsx @@ -1,13 +1,15 @@ 'use client'; +import { BookmarkIcon } from '@/shared/assets/icon/Bookmark'; +import { CrossIcon } from '@/shared/assets/icon/Cross'; import { Button } from '@/shared/ui/Button'; import { Progress } from '@nextui-org/react'; import cn from 'clsx'; import { useTranslations } from 'next-intl'; -import Image from 'next/image'; import { CSSProperties, FC, + TouchEvent, memo, useCallback, useEffect, @@ -18,6 +20,7 @@ import cls from './Notification.module.scss'; interface NotificationProps { message: string; duration?: number; + animationCloseDuration?: number; closable?: boolean; onClose?: () => void; onCancel?: () => void; @@ -25,10 +28,21 @@ interface NotificationProps { } export const Notification: FC = memo( - ({ message, duration = 7000, closable = true, onClose, onCancel, icon }) => { + ({ + message, + duration = 7000, + animationCloseDuration = 300, + closable = true, + onClose, + onCancel, + icon, + }) => { const t = useTranslations('Notification'); const [visible, setVisible] = useState(true); const [closing, setClosing] = useState(false); + const [touchStartX, setTouchStartX] = useState(0); + const [touchEndX, setTouchEndX] = useState(0); + const [swipeClose, setSwipeClose] = useState(false); const handleClose = useCallback(() => { setClosing(true); @@ -36,8 +50,8 @@ export const Notification: FC = memo( setVisible(false); setClosing(false); if (onClose) onClose(); - }, 300); // Animation duration - }, [onClose]); + }, animationCloseDuration); + }, [animationCloseDuration, onClose]); useEffect(() => { const timer = setTimeout(() => { @@ -52,7 +66,31 @@ export const Notification: FC = memo( setVisible(false); setClosing(false); if (onCancel) onCancel(); - }, 300); // Animation duration + }, animationCloseDuration); + }; + + const handleTouchStart = (e: TouchEvent) => { + setTouchStartX(e.touches[0].clientX); + }; + + const handleTouchMove = (e: TouchEvent) => { + setTouchEndX(e.touches[0].clientX); + }; + + const handleTouchEnd = () => { + const deltaX = touchEndX - touchStartX; + + // Set threshold for swipe action + const threshold = 100; + + if (Math.abs(deltaX) > threshold) { + setSwipeClose(true); + setTimeout(() => { + setSwipeClose(false); + setVisible(false); + if (onClose) onClose(); + }, animationCloseDuration); + } }; if (!visible) { @@ -63,12 +101,18 @@ export const Notification: FC = memo(
touchStartX && !closing, })} style={ { '--animation-duration-notification': `${duration}ms`, + '--animation-close-duration-notification': `${animationCloseDuration}ms`, } as CSSProperties } + onTouchStart={handleTouchStart} + onTouchMove={handleTouchMove} + onTouchEnd={handleTouchEnd} > = memo( />
{icon && ( - {t('icon')} + // {t('icon')} + )}

{message}

{closable && ( )} {onCancel && } diff --git a/src/shared/assets/icon/ArrowUp.jsx b/src/shared/assets/icon/ArrowUp.jsx new file mode 100644 index 0000000..46f2d96 --- /dev/null +++ b/src/shared/assets/icon/ArrowUp.jsx @@ -0,0 +1,20 @@ +export const ArrowUpIcon = ({ + color = 'var(--color-main-inverted)', + ...props +}) => ( + + + +); diff --git a/src/shared/assets/icon/Bookmark.jsx b/src/shared/assets/icon/Bookmark.jsx new file mode 100644 index 0000000..fa0a787 --- /dev/null +++ b/src/shared/assets/icon/Bookmark.jsx @@ -0,0 +1,30 @@ +export const BookmarkIcon = ({ + color = 'var(--color-main-inverted)', + ...props +}) => ( + + + + + + + + + + +); diff --git a/src/shared/assets/icon/Cross.jsx b/src/shared/assets/icon/Cross.jsx new file mode 100644 index 0000000..5706b21 --- /dev/null +++ b/src/shared/assets/icon/Cross.jsx @@ -0,0 +1,19 @@ +export const CrossIcon = ({ + color = 'var(--color-main-inverted)', + ...props +}) => ( + + + +); diff --git a/src/shared/assets/icon/Gmail.jsx b/src/shared/assets/icon/Gmail.jsx new file mode 100644 index 0000000..7dd6e0a --- /dev/null +++ b/src/shared/assets/icon/Gmail.jsx @@ -0,0 +1,18 @@ +export const GmailIcon = ({ + color = 'var(--color-main-inverted)', + ...props +}) => ( + + + +); diff --git a/src/shared/assets/icon/Telegram.jsx b/src/shared/assets/icon/Telegram.jsx new file mode 100644 index 0000000..d8ff5c3 --- /dev/null +++ b/src/shared/assets/icon/Telegram.jsx @@ -0,0 +1,18 @@ +export const TelegramIcon = ({ + color = 'var(--color-main-inverted)', + ...props +}) => ( + + + +); diff --git a/src/shared/ui/Blackhole/Blackhole.module.scss b/src/shared/ui/Blackhole/Blackhole.module.scss index 9e5dc7b..0b280b8 100644 --- a/src/shared/ui/Blackhole/Blackhole.module.scss +++ b/src/shared/ui/Blackhole/Blackhole.module.scss @@ -15,6 +15,10 @@ transition: all .5s ease; animation: fadeInBlackhole 1s ease-out forwards; + [class="light"] & { + display: none; + } + @media (max-width: theme('screens.md')) { height: 600px; } diff --git a/src/shared/ui/Button/Button.module.scss b/src/shared/ui/Button/Button.module.scss index 0e97d94..cc447d5 100644 --- a/src/shared/ui/Button/Button.module.scss +++ b/src/shared/ui/Button/Button.module.scss @@ -312,18 +312,29 @@ box-shadow: inset -3px -4px 8px 0 rgb(255, 255, 255, 10%), 0 2px 32px 0 rgb(176, 74, 255, 30%); + &:hover { + color: #caa9ff; + border: solid 1px #9442ffaf; + box-shadow: inset 0 0 6px #bf97ff70; + } + + [class="light"] & { + border: solid 1px #caa2ffaf; + box-shadow: none; + + &:hover { + color: #a369ff; + border: solid 1px#af72ffaf; + box-shadow: none; + } + } + /* stylelint-disable-next-line no-descending-specificity */ img, svg { opacity: 1; transition: all 0.2s ease; } - - &:hover { - color: #caa9ff; - border: solid 1px #9442ffaf; - box-shadow: inset 0 0 6px #bf97ff70; - } } .squareItem { diff --git a/src/shared/ui/Card/Card/Card.module.scss b/src/shared/ui/Card/Card/Card.module.scss index b146d77..8c78772 100644 --- a/src/shared/ui/Card/Card/Card.module.scss +++ b/src/shared/ui/Card/Card/Card.module.scss @@ -120,6 +120,10 @@ svg { width: 18px; + + @media (max-width: theme('screens.sm')) { + width: 14px; + } } } diff --git a/src/shared/ui/Card/Card/Card.tsx b/src/shared/ui/Card/Card/Card.tsx index 3dcd271..483bdd6 100644 --- a/src/shared/ui/Card/Card/Card.tsx +++ b/src/shared/ui/Card/Card/Card.tsx @@ -6,12 +6,14 @@ import { ReviewIcon } from '@/shared/assets/icon/Review'; import { StarIcon } from '@/shared/assets/icon/Star'; import { PathnamesKeys } from '@/shared/config/i18n/config'; import { Link } from '@/shared/config/i18n/navigation'; +import { MediaSize } from '@/shared/config/mediaQuery/sizes'; import { numberToCurrency } from '@/shared/lib/numberToCurrency'; import { Market, MarketType } from '@/shared/types'; import { Button } from '@/shared/ui/Button'; import { Tooltip } from '@nextui-org/react'; import Image from 'next/image'; import { FC, MouseEvent, useRef, useState } from 'react'; +import { useMediaQuery } from 'react-responsive'; import 'swiper/css/pagination'; import { Pagination } from 'swiper/modules'; import { Swiper, SwiperRef, SwiperSlide } from 'swiper/react'; @@ -46,8 +48,8 @@ export const Card: FC = ({ const formattedPrice = numberToCurrency(price); const formattedOldPrice = numberToCurrency(oldPrice || price); const [isLiked, setIsLiked] = useState(false); - const swiperRef = useRef(null); + const isPhone = useMediaQuery({ maxWidth: MediaSize.MD }); const handleMouseMove = (e: MouseEvent) => { const sliderLength = swiperRef.current?.swiper.slides.length; @@ -73,7 +75,7 @@ export const Card: FC = ({ el: '[data-slider-dots]', bulletClass: cls.bullet, bulletActiveClass: cls.bulletActive, - renderBullet(index, className) { + renderBullet(index: number, className: string) { return `
`; }, }; @@ -88,6 +90,7 @@ export const Card: FC = ({ pagination={pagination} className='h-full' ref={swiperRef} + loop={isPhone} > {images.map((image, index) => ( @@ -140,9 +143,15 @@ export const Card: FC = ({ } className={cls.tooltip} > -
*/} + test
diff --git a/src/shared/ui/Card/CardWide/CardWide.module.scss b/src/shared/ui/Card/CardWide/CardWide.module.scss index d9c0f25..f88b394 100644 --- a/src/shared/ui/Card/CardWide/CardWide.module.scss +++ b/src/shared/ui/Card/CardWide/CardWide.module.scss @@ -10,6 +10,7 @@ $z-index-card: 1; height: 200px; padding: 20px; overflow: hidden; + color: white; cursor: pointer; border: 1px solid var(--color-border); diff --git a/src/shared/ui/Wave/Wave.module.scss b/src/shared/ui/Wave/Wave.module.scss index d86b396..dc5f644 100644 --- a/src/shared/ui/Wave/Wave.module.scss +++ b/src/shared/ui/Wave/Wave.module.scss @@ -5,6 +5,10 @@ overflow: hidden; opacity: .4; + [class="light"] { + display: none; + } + @media (width <=--display-notebook) { display: none; } diff --git a/src/views/ShopPage/ShopPage.module.scss b/src/views/ShopPage/ShopPage.module.scss index 9ea9d73..b2bb2df 100644 --- a/src/views/ShopPage/ShopPage.module.scss +++ b/src/views/ShopPage/ShopPage.module.scss @@ -40,6 +40,10 @@ backdrop-filter: var(--blur-xs); border: 1px solid var(--color-border); + @media (max-width: theme('screens.md')) { + @include background(1); + } + header { display: flex; align-items: center; @@ -77,6 +81,12 @@ &Column, &Row { + [class="light"] & { + button { + color: rgb(var(--color-text), .8); + } + } + @media (max-width: theme('screens.md')) { &>* { flex-grow: 1; @@ -143,6 +153,10 @@ width: 100%; transition: all .3s ease; + @media (max-width: theme('screens.md')) { + @include background(1); + } + input { color: rgb(255, 255, 255, 50%); background: none; diff --git a/src/views/ShopPage/ShopPage.tsx b/src/views/ShopPage/ShopPage.tsx index 9c1101a..9d55350 100644 --- a/src/views/ShopPage/ShopPage.tsx +++ b/src/views/ShopPage/ShopPage.tsx @@ -1,5 +1,8 @@ 'use client'; +/* eslint-disable react/jsx-curly-newline */ +/* eslint-disable implicit-arrow-linebreak */ +/* eslint-disable i18next/no-literal-string */ import { Button } from '@/shared/ui/Button'; import { Card } from '@/shared/ui/Card'; import { Input } from '@/shared/ui/Input'; @@ -13,7 +16,7 @@ import cls from './ShopPage.module.scss'; export const ShopPage: FC = () => { // const t = useTranslations('ShopPage'); const minPrice = 0; - const maxPrice = 1000; + const maxPrice = 5000; const [startPrice, setStartPrice] = useState(minPrice); const [endPrice, setEndPrice] = useState(maxPrice); @@ -66,8 +69,10 @@ export const ShopPage: FC = () => { + setStartPrice(parseInt(value, 10)) + } endContent={
@@ -77,8 +82,10 @@ export const ShopPage: FC = () => { + setEndPrice(parseInt(value, 10)) + } endContent={
@@ -90,13 +97,45 @@ export const ShopPage: FC = () => { size='sm' minValue={minPrice} maxValue={maxPrice} + step={100} value={[startPrice, endPrice]} - onChange={([start, end]) => { - setStartPrice(start); - setEndPrice(end); + onChange={(value: number | number[]) => { + if (typeof value === 'number') { + setStartPrice(value); + } else if (Array.isArray(value)) { + const [start, end] = value; + setStartPrice(start); + setEndPrice(end); + } }} className='max-w-md' /> +
+ + + +
@@ -164,7 +203,7 @@ export const ShopPage: FC = () => { src='/' links={{ src: 'https://megamarket.ru/catalog/details/nike-zoom-hyperspeed-court-krossovki-voleybolnye-belyy-chernyy-41-100061411115_98494/', - market: 'yandex', + market: 'ozon', }} images={['cat.png', 'cat.png']} title='Сквиши антистресс игрушки подарочный набор 2 кота Xiaomi Mi Power Bank 3 20000 mAh' @@ -184,13 +223,6 @@ export const ShopPage: FC = () => { reviewCount={456} price={28546} /> - {/* - - - - - - */}
diff --git a/src/widgets/Advantages/Advantages.module.scss b/src/widgets/Advantages/Advantages.module.scss index 3a251e0..20f4e21 100644 --- a/src/widgets/Advantages/Advantages.module.scss +++ b/src/widgets/Advantages/Advantages.module.scss @@ -107,8 +107,8 @@ position: absolute; top: 0; z-index: calc(var(--z-index-blackhole) - 2); - border-right: 1px solid rgb(226, 232, 255, 10%); - border-bottom: 1px solid rgb(226, 232, 255, 10%); + border-right: 1px solid rgb(var(--color-main-inverted-rgb), 10%); + border-bottom: 1px solid rgb(var(--color-main-inverted-rgb), 10%); border-bottom-right-radius: 12px; &:nth-child(1) { @@ -139,7 +139,7 @@ bottom: -4px; width: 12px; height: 12px; - background: var(--color-main); + background: var(--color-background); } &::after { @@ -147,7 +147,7 @@ z-index: 2; width: 4px; height: 4px; - background: #202039; + background: rgba(var(--color-main-inverted-rgb), .1); } &::before, diff --git a/src/widgets/Advantages/Advantages.tsx b/src/widgets/Advantages/Advantages.tsx index 0574c9d..f79a46c 100644 --- a/src/widgets/Advantages/Advantages.tsx +++ b/src/widgets/Advantages/Advantages.tsx @@ -6,6 +6,7 @@ import { CardRotate } from '@/shared/ui/CardRotate'; import cn from 'clsx'; import { motion } from 'framer-motion'; import { useTranslations } from 'next-intl'; +import { useTheme } from 'next-themes'; import Image from 'next/image'; import { FC } from 'react'; import MediaQuery from 'react-responsive'; @@ -17,6 +18,7 @@ interface AdvantagesProps { export const Advantages: FC = ({ className = '' }) => { const t = useTranslations('Advantages'); + const { theme } = useTheme(); return (
@@ -78,20 +80,22 @@ export const Advantages: FC = ({ className = '' }) => { text={t('card-3-description')} /> - - test - + {theme === 'dark' && ( + + test + + )}
); }; diff --git a/src/widgets/BestProduct/BestProduct.module.scss b/src/widgets/BestProduct/BestProduct.module.scss index 6f65584..eef5840 100644 --- a/src/widgets/BestProduct/BestProduct.module.scss +++ b/src/widgets/BestProduct/BestProduct.module.scss @@ -66,7 +66,7 @@ position: relative; display: flex; width: fit-content !important; - padding: 0 10px; + padding: 0 5px; overflow: hidden; background: var(--bg-noise), var(--color-main); border: 1px solid var(--color-border); @@ -87,7 +87,7 @@ .bullet { position: relative; width: 18px; - height: 22px; + height: 18px; cursor: pointer; &::after { diff --git a/src/widgets/BestProduct/BestProduct.tsx b/src/widgets/BestProduct/BestProduct.tsx index 06867df..295cdda 100644 --- a/src/widgets/BestProduct/BestProduct.tsx +++ b/src/widgets/BestProduct/BestProduct.tsx @@ -8,6 +8,7 @@ import { Heading } from '@/widgets/Heading'; import cn from 'clsx'; import { motion } from 'framer-motion'; import { useTranslations } from 'next-intl'; +import { useTheme } from 'next-themes'; import Image from 'next/image'; import { FC, useRef } from 'react'; import { useMediaQuery } from 'react-responsive'; @@ -23,6 +24,7 @@ export const BestProduct: FC = () => { const prevRef = useRef(null); const nextRef = useRef(null); const isMobile = useMediaQuery({ maxWidth: MediaSize.SM }); + const { theme } = useTheme(); const cards = []; for (let i = 0; i < 7; i++) { @@ -43,21 +45,22 @@ export const BestProduct: FC = () => { return (
- - {t('background-glow-image-alt')} - - + {theme === 'dark' && ( + + {t('background-glow-image-alt')} + + )} { > {cards}
-
-
diff --git a/src/widgets/Footer/Footer.module.scss b/src/widgets/Footer/Footer.module.scss index 0325d8e..e6080e2 100644 --- a/src/widgets/Footer/Footer.module.scss +++ b/src/widgets/Footer/Footer.module.scss @@ -31,13 +31,16 @@ display: flex; gap: 10px; - img { + img, + svg { opacity: .3; transition: all .1s ease; } a:hover { - img { + + img, + svg { opacity: 1; } } diff --git a/src/widgets/Footer/Footer.tsx b/src/widgets/Footer/Footer.tsx index d5f6249..dff9ebc 100644 --- a/src/widgets/Footer/Footer.tsx +++ b/src/widgets/Footer/Footer.tsx @@ -1,9 +1,10 @@ +import { GmailIcon } from '@/shared/assets/icon/Gmail'; +import { TelegramIcon } from '@/shared/assets/icon/Telegram'; import { Links } from '@/shared/const/links'; import { Logo } from '@/shared/ui/Logo'; import { Wave } from '@/shared/ui/Wave'; import cn from 'clsx'; import { useTranslations } from 'next-intl'; -import Image from 'next/image'; import Link from 'next/link'; import { FC } from 'react'; import cls from './Footer.module.scss'; @@ -26,23 +27,25 @@ export const Footer: FC = ({ className = '' }) => {

{t('copyright')}

- {t('icon-telegram')} + /> */} + - {t('icon-gmail')} + /> */} +
diff --git a/src/widgets/Navbar/ui/Navbar/Navbar.module.scss b/src/widgets/Navbar/ui/Navbar/Navbar.module.scss index da02915..98fbafc 100644 --- a/src/widgets/Navbar/ui/Navbar/Navbar.module.scss +++ b/src/widgets/Navbar/ui/Navbar/Navbar.module.scss @@ -10,6 +10,12 @@ @include background(.5); + [class="light"] & { + @include background(1); + + backdrop-filter: none; + } + @media (max-width: theme('screens.sm')) { bottom: 0; height: var(--navbar-height-mobile); diff --git a/src/widgets/Ready/Ready.tsx b/src/widgets/Ready/Ready.tsx index df13386..c4bba62 100644 --- a/src/widgets/Ready/Ready.tsx +++ b/src/widgets/Ready/Ready.tsx @@ -6,6 +6,7 @@ import { Button } from '@/shared/ui/Button'; import cn from 'clsx'; import { motion } from 'framer-motion'; import { useTranslations } from 'next-intl'; +import { useTheme } from 'next-themes'; import Image from 'next/image'; import { FC } from 'react'; import cls from './Ready.module.scss'; @@ -16,6 +17,7 @@ interface ReadyProps { export const Ready: FC = ({ className = '' }) => { const t = useTranslations('Ready'); + const { theme } = useTheme(); return (
@@ -47,20 +49,22 @@ export const Ready: FC = ({ className = '' }) => { {t('button')} - - {t('background-image-alt')} - + {theme === 'dark' && ( + + {t('background-image-alt')} + + )}
); }; diff --git a/src/widgets/ReviewsCarousel/ReviewsCarousel.module.scss b/src/widgets/ReviewsCarousel/ReviewsCarousel.module.scss index c3faf44..3c657e0 100644 --- a/src/widgets/ReviewsCarousel/ReviewsCarousel.module.scss +++ b/src/widgets/ReviewsCarousel/ReviewsCarousel.module.scss @@ -17,6 +17,10 @@ mix-blend-mode: lighten; transform: translateY(-50%); + [class="light"] & { + display: none; + } + // @media (max-width: theme('screens.md')) { // width: 100%; // } diff --git a/src/widgets/ReviewsCarousel/ReviewsCarousel.tsx b/src/widgets/ReviewsCarousel/ReviewsCarousel.tsx index bd721ae..5d01bee 100644 --- a/src/widgets/ReviewsCarousel/ReviewsCarousel.tsx +++ b/src/widgets/ReviewsCarousel/ReviewsCarousel.tsx @@ -5,6 +5,7 @@ import { SlideHeading } from '@/shared/ui/HeadingSlide'; import { StarRating } from '@/shared/ui/StarRating'; import { User } from '@nextui-org/react'; import cn from 'clsx'; +import { useTheme } from 'next-themes'; import Image from 'next/image'; import Link from 'next/link'; import { FC } from 'react'; @@ -16,6 +17,7 @@ import cls from './ReviewsCarousel.module.scss'; export const ReviewsCarousel: FC = () => { // const t = useTranslations('ReviewsCarousel'); const isMobile = useMediaQuery({ maxWidth: MediaSize.SM }); + const { theme } = useTheme(); const cards = []; for (let i = 0; i < 5; i++) { diff --git a/src/widgets/ScrollUp/ScrollUp.module.scss b/src/widgets/ScrollUp/ScrollUp.module.scss index 19919db..5a35e19 100644 --- a/src/widgets/ScrollUp/ScrollUp.module.scss +++ b/src/widgets/ScrollUp/ScrollUp.module.scss @@ -14,13 +14,6 @@ bottom: auto; } - &::before { - width: 20px; - height: 20px; - content: ''; - background-image: url("/images/icons/arrow-up.svg"); - } - &.visible { opacity: .7; transition: all .3s ease; diff --git a/src/widgets/ScrollUp/ScrollUp.tsx b/src/widgets/ScrollUp/ScrollUp.tsx index e3d3d92..0fef758 100644 --- a/src/widgets/ScrollUp/ScrollUp.tsx +++ b/src/widgets/ScrollUp/ScrollUp.tsx @@ -1,5 +1,6 @@ 'use client'; +import { ArrowUpIcon } from '@/shared/assets/icon/ArrowUp'; import { Button } from '@/shared/ui/Button'; import cn from 'clsx'; import { useTranslations } from 'next-intl'; @@ -48,6 +49,7 @@ export const ScrollUp: FC = ({ className = '' }) => { 'rounded-full', )} > + {t('top')} );