diff --git a/src/app/styles/base/_reset.scss b/src/app/styles/base/_reset.scss index 8d685a57..fe9e832e 100644 --- a/src/app/styles/base/_reset.scss +++ b/src/app/styles/base/_reset.scss @@ -1,7 +1,6 @@ body { margin: 0 auto; max-width: 100vw; - min-width: 375px; font-family: Roboto, Arial, diff --git a/src/components/WrapperForMainContent/wrapper.module.scss b/src/components/WrapperForMainContent/wrapper.module.scss index 8252cd26..8c39dca5 100644 --- a/src/components/WrapperForMainContent/wrapper.module.scss +++ b/src/components/WrapperForMainContent/wrapper.module.scss @@ -1,22 +1,10 @@ -@use '../../shared/styles/utils/mixins' as media; - .wrapper { - max-width: 1470px; - width: 100%; - margin: 0 auto; - padding: 25px; display: flex; flex-direction: column; align-items: center; - gap: 20px; - - @include media.respond-to('middle') { - max-width: 768px; - width: 100%; - } - - @include media.respond-to('small') { - width: 390px; - gap: 20px; - } + gap: 48px; + width: 100%; + max-width: 1470px; + margin: 0 auto; + padding: 25px; } diff --git a/src/entities/HeadingBlock/index.tsx b/src/entities/HeadingBlock/index.tsx new file mode 100644 index 00000000..2e4cc5c1 --- /dev/null +++ b/src/entities/HeadingBlock/index.tsx @@ -0,0 +1,2 @@ +import HeadingBlock from './ui/HeadingBlock' +export default HeadingBlock diff --git a/src/entities/HeadingBlock/ui/HeadingBlock.module.scss b/src/entities/HeadingBlock/ui/HeadingBlock.module.scss new file mode 100644 index 00000000..112ffca6 --- /dev/null +++ b/src/entities/HeadingBlock/ui/HeadingBlock.module.scss @@ -0,0 +1,40 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.headingBlock { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + + &__heading { + display: flex; + gap: 15px; + align-items: flex-end; + } + + &__link { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + font-size: 15px; + color: var.$link-color; + fill: var.$link-color; + cursor: pointer; + opacity: 1; + transition: 0.25s; + + &:hover { + opacity: 0.7; + } + + @include media.respond-to('middle') { + display: none; + } + } + + &__arrow { + transform: rotate(270deg); + } +} diff --git a/src/entities/HeadingBlock/ui/HeadingBlock.stories.tsx b/src/entities/HeadingBlock/ui/HeadingBlock.stories.tsx new file mode 100644 index 00000000..f289f89e --- /dev/null +++ b/src/entities/HeadingBlock/ui/HeadingBlock.stories.tsx @@ -0,0 +1,42 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import IconHand from '@/assets/images/img-hand.png.png' + +import HeadingBlock from './HeadingBlock' + +const meta = { + title: 'entities/HeadingBlock', + component: HeadingBlock, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + const title = 'Новости' + const subtitle = 'Все новости' + const link = '#' + + return ( +
+ +
+ ) +} + +Default.args = { + title: 'Новости', + subtitle: 'Все новости', + link: '#' +} diff --git a/src/entities/HeadingBlock/ui/HeadingBlock.tsx b/src/entities/HeadingBlock/ui/HeadingBlock.tsx new file mode 100644 index 00000000..30e983ca --- /dev/null +++ b/src/entities/HeadingBlock/ui/HeadingBlock.tsx @@ -0,0 +1,55 @@ +import { FC } from 'react' + +import ArrowIcon from '@/assets/images/sideBarMenu/IconArrowDown.svg' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Link from '@/shared/ui/Link/Link' + +import styles from './HeadingBlock.module.scss' + +interface IHeadingBlock { + title: string + isIcon?: boolean + image?: string + alt?: string + isLink?: boolean + subtitle?: string + link?: string +} + +/** + * Компонент HeadingBlock - это заголовок с отдельным линком. Отрисовывается на главной странице MainPage в блоках новостей, отзывов и т.п. + * @param {string} title - заголовок блока + * @param {boolean} isIcon - булево значение показывающее линк + * @param {string} image - картинка в заголовке блока + * @param {string} alt - alt картинки в заголовке блока + * @param {boolean} isLink - булево значение показывающее линк + * @param {string} subtitle - название линка + * @param {string} link - ссылка + */ + +const HeadingBlock: FC = ({ + title, + isIcon = false, + image, + alt, + isLink = false, + subtitle, + link +}) => { + return ( +
+ + {title} + {isIcon && {alt}} + + {isLink && ( + + {subtitle} + + + )} +
+ ) +} + +export default HeadingBlock diff --git a/src/pages/MainPage/MainPage.tsx b/src/pages/MainPage/MainPage.tsx index b6cdb63e..22b1eca4 100644 --- a/src/pages/MainPage/MainPage.tsx +++ b/src/pages/MainPage/MainPage.tsx @@ -1,12 +1,14 @@ +import { FC } from 'react' + import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { Routes } from '@/shared/config/routerConfig/routes' import { TEXT_CUSTOMERS_ABOUT_US, LINK_REVIEWS_ALL } from '@/shared/constants/constants' import Advantages from '@/widgets/Advantages/ui/Advantages/Advantages' -import ArticleBlock from '@/widgets/ArticleBlock/ArticleBlock' +import ArticleBlock from '@/widgets/ArticleBlock' import BannerBlock from '@/widgets/BannerBlock/ui/BannerBlock' import BlogBlock from '@/widgets/BlogBlock/ui/BlogBlock' import BrandsBlock from '@/widgets/BrandBlock/ui/BrandBlock/BrandBlock' -import CategoryGrid from '@/widgets/CategoryGrid/CategoryGrid' +import CategoryGrid from '@/widgets/CategoryGrid' import HeroBlock from '@/widgets/HeroBlock/ui/HeroBlock/HeroBlock' import NewsBlock from '@/widgets/NewsBlock/ui/NewsBlock' import ReviewsBlock from '@/widgets/ReviewsBlock/ui/ReviewsBlock/ReviewsBlock' @@ -14,7 +16,7 @@ import StoriesBlock from '@/widgets/StoriesBlock/ui/StoriesBlock' import Subscribe from '@/widgets/Subscribe/Subscribe' import { ViewedProducts } from '@/widgets/ViewedProducts/ViewedProducts' -const MainPage = () => { +const MainPage: FC = () => { return ( <> diff --git a/src/pages/RootPage/RootPage.tsx b/src/pages/RootPage/RootPage.tsx index 4111c809..3da8245d 100644 --- a/src/pages/RootPage/RootPage.tsx +++ b/src/pages/RootPage/RootPage.tsx @@ -9,14 +9,14 @@ import styles from './root.module.scss' const RootPage = () => { return ( -
+ <>
-
+ ) } diff --git a/src/pages/RootPage/root.module.scss b/src/pages/RootPage/root.module.scss index 64b81395..77fac18a 100644 --- a/src/pages/RootPage/root.module.scss +++ b/src/pages/RootPage/root.module.scss @@ -1,12 +1,7 @@ -.rootPageWrapper { - display: grid; - grid-template-rows: auto 1fr auto; - min-height: 100vh; - margin: 0; -} - .main { display: flex; flex-direction: column; - gap: 60px; + align-items: center; + gap: 23px; + width: 100%; } diff --git a/src/shared/ui/CategoryCard/ui/CategoryCard.module.scss b/src/shared/ui/CategoryCard/ui/CategoryCard.module.scss index 17f5b0b5..5cba11f6 100644 --- a/src/shared/ui/CategoryCard/ui/CategoryCard.module.scss +++ b/src/shared/ui/CategoryCard/ui/CategoryCard.module.scss @@ -1,16 +1,28 @@ -@use '../../../styles/utils/variables' as var; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; -.div { +.categoryCard { display: block; padding: 20px 0 0 20px; width: 100%; - min-width: 420px; - height: 300px; + min-width: 450px; + min-height: 300px; border-radius: 10px; background-position: right; background-size: contain; background-repeat: no-repeat; transition: opacity 0.3s ease-in-out; + user-select: none; + + @include media.respond-to('large') { + min-width: 340px; + min-height: 260px; + } + + @include media.respond-to('middle') { + min-width: 260px; + min-height: 260px; + } &:hover { opacity: 0.8; diff --git a/src/shared/ui/CategoryCard/ui/CategoryCard.tsx b/src/shared/ui/CategoryCard/ui/CategoryCard.tsx index 7e177b5d..f81f356d 100644 --- a/src/shared/ui/CategoryCard/ui/CategoryCard.tsx +++ b/src/shared/ui/CategoryCard/ui/CategoryCard.tsx @@ -23,21 +23,20 @@ interface CategoryCardProps { * @param {object} card - объект категории для отображения названия и фотографии; * @param {number} index - индекс элемента массива категорий для выбора цвета; */ + const CategoryCard: FC = ({ card, index }) => { const dispatch = useDispatch() return ( -
  • - { - dispatch(setCategoryId(card.id)) - dispatch(setCategorySlug(card.slug)) - }} - className={styles.div} - style={{ backgroundColor: COLORS[index], backgroundImage: `url(${card.image})` }}> - {card.name} - -
  • + { + dispatch(setCategoryId(card.id)) + dispatch(setCategorySlug(card.slug)) + }} + className={styles.categoryCard} + style={{ backgroundColor: COLORS[index], backgroundImage: `url(${card.image})` }}> + {card.name} + ) } diff --git a/src/shared/ui/Scroll/Scroll.module.scss b/src/shared/ui/Scroll/Scroll.module.scss index 554a83bb..7b213069 100644 --- a/src/shared/ui/Scroll/Scroll.module.scss +++ b/src/shared/ui/Scroll/Scroll.module.scss @@ -1,4 +1,5 @@ -@use '@/app/styles/index' as var; +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; .extra { background-color: orange; @@ -13,21 +14,36 @@ .scroll { display: flex; gap: 20px; - padding: 0 10px 20px; + padding-bottom: 20px; overflow: auto hidden; cursor: grab; + @include media.respond-to('middle') { + gap: 10px; + } + &::-webkit-scrollbar { height: 3px; + + @include media.respond-to('middle') { + height: 2px; + } } &::-webkit-scrollbar-thumb { - background: var.$theme-primary-color; - cursor: grab; + background: var.$footer-form-color; + visibility: hidden; + } + + &:hover { + &::-webkit-scrollbar-thumb { + visibility: visible; + } } - &::-webkit-scrollbar-track { - margin-left: 10px; - margin-right: 10px; + &:active { + &::-webkit-scrollbar-thumb { + visibility: visible; + } } } diff --git a/src/shared/ui/Scroll/Scroll.tsx b/src/shared/ui/Scroll/Scroll.tsx index 5b086e68..0b3b198a 100644 --- a/src/shared/ui/Scroll/Scroll.tsx +++ b/src/shared/ui/Scroll/Scroll.tsx @@ -51,7 +51,7 @@ const Scroll: FC = ({ withManualGrip = false, className, children }) => {children} ) : ( -
    {children}
    +
      {children}
    ) } diff --git a/src/widgets/ArticleBlock/ArticleBlock.tsx b/src/widgets/ArticleBlock/ArticleBlock.tsx deleted file mode 100644 index 359816f6..00000000 --- a/src/widgets/ArticleBlock/ArticleBlock.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { useState } from 'react' - -import ArrowReadNext from '@/assets/icons/ArrowReadNext.svg' -import description from '@/assets/images/articleBlock/description.png' -import { Button } from '@/shared/ui/Button/Button' -import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' -import Paragraph from '@/shared/ui/Paragraph/Paragraph' - -import styles from './articleBlock.module.scss' - -function ArticleBlock() { - const [openText, setTextOpened] = useState(false) - function openTextHandler() { - if (openText === true) { - setTextOpened(false) - } else { - setTextOpened(true) - } - } - - return ( -
    -
    - интерьер -
    - Уникальный магазин техники и гаджетов - - На естественном языке сказать об одном и том же факте можно бесконечным числом способов. Можно - переставлять слова местами, заменять их на синонимы, склонять по падежам (если говорим о языке с - падежами) и тд. - - - Необходимость определять схожесть двух фраз возникла при решении одной небольшой практической - - {openText && ( -
    - - задачи. Я не использовал машинное обучение, не вил нейронные сети, но использовал простые - метрики и собранную статистику для калибровки коэффициентов. - - - На естественном языке сказать об одном и том же факте можно бесконечным числом способов. Можно - переставлять слова местами, заменять их на синонимы, склонять по падежам (если говорим о языке - с падежами) и тд. - - - Необходимость определять схожесть двух фраз возникла при решении одной небольшой практической - задачи. Я не использовал машинное обучение, не вил нейронные сети, но использовал простые - метрики и собранную статистику для калибровки коэффициентов. - - -
    - )} - - {!openText && ( - - )} -
    -
    -
    - ) -} - -export default ArticleBlock diff --git a/src/widgets/ArticleBlock/articleBlock.module.scss b/src/widgets/ArticleBlock/articleBlock.module.scss deleted file mode 100644 index 4afd0973..00000000 --- a/src/widgets/ArticleBlock/articleBlock.module.scss +++ /dev/null @@ -1,88 +0,0 @@ -@use '../../shared/styles/utils/variables' as var; -@use '../../shared/styles/utils/mixins' as media; - -.container { - width: 100%; -} - -.article { - display: flex; - column-gap: 40px; - padding-left: 20px; - padding-right: 20px; - - @include media.respond-to('middle') { - flex-flow: column wrap; - column-gap: 0; - row-gap: 30px; - } - - @include media.respond-to('small') { - padding-left: 10px; - padding-right: 10px; - } - } - -.image { - width: 340px; - height: 200px; - border-radius: 10px; - object-fit: cover; - - @include media.respond-to('small') { - width: 310px; - height: 180px; - } -} - -.wrapper { - display: flex; - flex-direction: column; - color: var.$body-color; - max-width: 760px; - - @include media.respond-to('middle') { - flex-wrap: wrap; - } -} - -.title { - margin: 0; - padding: 0; - color: inherit; - font-size: 20px; - font-weight: 700; - line-height: 24px; - - @include media.respond-to('small') { - width: 100%; - } -} - -.text { - margin-top: 10px; - @include media.respond-to('small') { - max-width: 300px; - } -} - -.link { - display: flex; - align-items: center; - column-gap: 11px; - text-decoration: none; - margin-top: 40px; - justify-content: normal; - padding: 0; - color: var.$link-color; - font-size: 16px; -} - -.link:hover { - opacity: 0.7; -} - -.icon { - transform: rotate(270deg) -} - diff --git a/src/widgets/ArticleBlock/index.tsx b/src/widgets/ArticleBlock/index.tsx new file mode 100644 index 00000000..93f9c9ee --- /dev/null +++ b/src/widgets/ArticleBlock/index.tsx @@ -0,0 +1,2 @@ +import ArticleBlock from './ui/ArticleBlock' +export default ArticleBlock diff --git a/src/widgets/ArticleBlock/ui/ArticleBlock.stories.tsx b/src/widgets/ArticleBlock/ui/ArticleBlock.stories.tsx new file mode 100644 index 00000000..9f859600 --- /dev/null +++ b/src/widgets/ArticleBlock/ui/ArticleBlock.stories.tsx @@ -0,0 +1,21 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import ArticleBlock from './ArticleBlock' + +const meta = { + title: 'widgets/ArticleBlock', + component: ArticleBlock, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = () => { + return +} + +Default.args = {} diff --git a/src/widgets/ArticleBlock/ui/ArticleBlock.tsx b/src/widgets/ArticleBlock/ui/ArticleBlock.tsx new file mode 100644 index 00000000..09f8b3e8 --- /dev/null +++ b/src/widgets/ArticleBlock/ui/ArticleBlock.tsx @@ -0,0 +1,57 @@ +import { FC, useState } from 'react' + +import description from '@/assets/images/articleBlock/description.png' +import ArrowIcon from '@/assets/images/sideBarMenu/IconArrowDown.svg' +import { Button } from '@/shared/ui/Button/Button' +import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' +import Paragraph from '@/shared/ui/Paragraph/Paragraph' + +import styles from './articleBlock.module.scss' + +/** + * Компонент ArticleBlock используется как виджет на главной странице MainPage + */ + +const ArticleBlock: FC = () => { + const [isActive, setIsActive] = useState(false) + function openTextHandler() { + setIsActive(!isActive) + } + + return ( +
    + интерьер +
    + Уникальный магазин техники и гаджетов +
    + + На естественном языке сказать об одном и том же факте можно бесконечным числом способов. Можно + переставлять слова местами, заменять их на синонимы, склонять по падежам (если говорим о языке с + падежами) и тд. + + + Необходимость определять схожесть двух фраз возникла при решении одной небольшой практической + задачи. Я не использовал машинное обучение, не вил нейронные сети, но использовал простые метрики + и собранную статистику для калибровки коэффициентов. + + + На естественном языке сказать об одном и том же факте можно бесконечным числом способов. Можно + переставлять слова местами, заменять их на синонимы, склонять по падежам (если говорим о языке с + падежами) и тд. + + + Необходимость определять схожесть двух фраз возникла при решении одной небольшой практической + задачи. Я не использовал машинное обучение, не вил нейронные сети, но использовал простые метрики + и собранную статистику для калибровки коэффициентов. + +
    + +
    +
    + ) +} + +export default ArticleBlock diff --git a/src/widgets/ArticleBlock/ui/articleBlock.module.scss b/src/widgets/ArticleBlock/ui/articleBlock.module.scss new file mode 100644 index 00000000..773f577a --- /dev/null +++ b/src/widgets/ArticleBlock/ui/articleBlock.module.scss @@ -0,0 +1,72 @@ +@use '@/shared/styles/utils/variables' as var; +@use '@/shared/styles/utils/mixins' as media; + +.articleBlock { + display: flex; + justify-content: center; + width: 100%; + gap: 40px; + + @include media.respond-to('middle') { + flex-direction: column; + gap: 30px; + } +} + +.image { + display: block; + width: 100%; + max-width: 340px; + height: 187px; + border-radius: 10px; + object-fit: cover; +} + +.wrapper { + display: flex; + flex-direction: column; +} + +.container { + display: flex; + flex-direction: column; + gap: 10px; + height: 97px; + padding-top: 10px; + transition: 0.25s ease-in-out; + overflow: hidden; + + @include media.respond-to('middle') { + height: 60px; + } + + &_open { + height: 100%; + overflow: auto; + } +} + +.link { + display: flex; + justify-content: normal; + align-items: center; + gap: 10px; + font-size: 15px; + color: var.$link-color; + fill: var.$link-color; + margin-top: 40px; + padding: 0; + transition: 0.25s; + + &:hover { + opacity: 0.7; + } +} + +.hide { + transform: rotate(180deg); +} + +.read { + transform: rotate(270deg); +} diff --git a/src/widgets/CategoryGrid/CategoryGrid.module.scss b/src/widgets/CategoryGrid/CategoryGrid.module.scss deleted file mode 100644 index 5f382421..00000000 --- a/src/widgets/CategoryGrid/CategoryGrid.module.scss +++ /dev/null @@ -1,38 +0,0 @@ -@use '@/shared/styles/utils/variables' as var; -@use '@/shared/styles/utils/mixins' as media; - -.section { - width: 100%; - padding: 10px; - margin: 0 auto; - display: flex; - flex-direction: column; - gap: 18px; - - .ul { - display: flex; - gap: 10px; - padding: 0 0 20px; - overflow: auto hidden; - cursor: grab; - - &::-webkit-scrollbar { - height: 3px; - } - - &::-webkit-scrollbar-thumb { - background: var.$theme-primary-color; - cursor: grab; - } - - &::-webkit-scrollbar-track { - margin-left: 10px; - margin-right: 10px; - } - - @include media.respond-to('xl') { - display: grid; - grid-template-columns: repeat(3, 1fr); - } - } -} diff --git a/src/widgets/CategoryGrid/CategoryGrid.tsx b/src/widgets/CategoryGrid/CategoryGrid.tsx deleted file mode 100644 index d0c0ea5c..00000000 --- a/src/widgets/CategoryGrid/CategoryGrid.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useEffect } from 'react' -import { useDispatch, useSelector } from 'react-redux' - -import { AppDispatch } from '@/app/providers/StoreProvider/config/store' -import { TEXT_POPULAR_CATEGORIES } from '@/shared/constants/constants' -import CategoryCard from '@/shared/ui/CategoryCard/ui/CategoryCard' -import Heading from '@/shared/ui/Heading/Heading' - -import styles from './CategoryGrid.module.scss' -import { getCategoryListSelector } from './model/selectors/selectors' -import { getCategoryList } from './model/services/getCategoryList' - -/** - * Компонент сетки с карточками популярных категорий для главной страницы. - */ - -const CategoryGrid = () => { - const dispatch = useDispatch() - const data = useSelector(getCategoryListSelector) - - useEffect(() => { - dispatch(getCategoryList()) - }, []) - - return ( -
    - {TEXT_POPULAR_CATEGORIES} -
      - {data.categoryList.map((card, index) => ( - - ))} -
    -
    - ) -} - -export default CategoryGrid diff --git a/src/widgets/CategoryGrid/index.tsx b/src/widgets/CategoryGrid/index.tsx new file mode 100644 index 00000000..397ff036 --- /dev/null +++ b/src/widgets/CategoryGrid/index.tsx @@ -0,0 +1,2 @@ +import CategoryGrid from './ui/CategoryGrid' +export default CategoryGrid diff --git a/src/widgets/CategoryGrid/ui/CategoryGrid.module.scss b/src/widgets/CategoryGrid/ui/CategoryGrid.module.scss new file mode 100644 index 00000000..f10b2444 --- /dev/null +++ b/src/widgets/CategoryGrid/ui/CategoryGrid.module.scss @@ -0,0 +1,14 @@ +.categoryGrid { + width: 100%; + padding: 10px; + margin: 0 auto; + display: flex; + flex-direction: column; + gap: 18px; + + &__list { + display: flex; + flex-wrap: wrap; + gap: 20px; + } +} diff --git a/src/widgets/CategoryGrid/ui/CategoryGrid.stories.tsx b/src/widgets/CategoryGrid/ui/CategoryGrid.stories.tsx new file mode 100644 index 00000000..7a357792 --- /dev/null +++ b/src/widgets/CategoryGrid/ui/CategoryGrid.stories.tsx @@ -0,0 +1,17 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import CategoryGrid from './CategoryGrid' + +const meta = { + title: 'widgets/CategoryGrid', + component: CategoryGrid, + parameters: { + layout: 'centered' + }, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} diff --git a/src/widgets/CategoryGrid/ui/CategoryGrid.tsx b/src/widgets/CategoryGrid/ui/CategoryGrid.tsx new file mode 100644 index 00000000..ec6ffca7 --- /dev/null +++ b/src/widgets/CategoryGrid/ui/CategoryGrid.tsx @@ -0,0 +1,56 @@ +import { FC, useEffect } from 'react' +import { useDispatch, useSelector } from 'react-redux' + +import { AppDispatch } from '@/app/providers/StoreProvider/config/store' +import HeadingBlock from '@/entities/HeadingBlock' +import { TEXT_POPULAR_CATEGORIES } from '@/shared/constants/constants' +import { useResize } from '@/shared/libs/hooks/useResize' +import CategoryCard from '@/shared/ui/CategoryCard/ui/CategoryCard' +import Scroll from '@/shared/ui/Scroll/Scroll' + +import { getCategoryListSelector } from '../model/selectors/selectors' +import { getCategoryList } from '../model/services/getCategoryList' + +import styles from './CategoryGrid.module.scss' + +/** + * Компонент сетки с карточками популярных категорий для главной страницы. + */ + +const CategoryGrid: FC = () => { + const dispatch = useDispatch() + const data = useSelector(getCategoryListSelector) + const { isScreenMd } = useResize() + + useEffect(() => { + dispatch(getCategoryList()) + }, []) + + return ( + data.categoryList?.length !== 0 && ( +
    + + + {isScreenMd ? ( +
      + {data.categoryList.map((card, index) => ( +
    • + +
    • + ))} +
    + ) : ( + + {data.categoryList.map((card, index) => ( +
  • + +
  • + ))} +
    + )} +
    + ) + ) +} + +export default CategoryGrid