From 5998d473a9c9e7e55a7627961005b25ebaa5820d Mon Sep 17 00:00:00 2001 From: Margarita Shumilina Date: Sat, 20 Apr 2024 16:43:40 +0300 Subject: [PATCH 1/2] #305-skeletons --- package-lock.json | 15 +++++ package.json | 1 + .../PageDescription.module.scss | 5 ++ .../PageDescription/PageDescription.tsx | 30 ++++++---- src/pages/ProductsPage/ProductsPage.tsx | 17 +++++- src/pages/ProductsPage/selectors/selectors.ts | 5 ++ .../PageControlsSkeletons.module.scss | 28 +++++++++ .../PageControlsSkeletons.stories.tsx | 23 ++++++++ .../PageControlsSkeletons.tsx | 21 +++++++ .../ProductSkeleton.module.scss | 57 +++++++++++++++++++ .../ProductSkeleton.stories.tsx | 23 ++++++++ .../ProductSkeleton/ProductSkeleton.tsx | 30 ++++++++++ .../CategoryList/CategoryList.module.scss | 7 +++ src/widgets/CategoryList/CategoryList.tsx | 18 +++--- 14 files changed, 261 insertions(+), 19 deletions(-) create mode 100644 src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss create mode 100644 src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx create mode 100644 src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx create mode 100644 src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.module.scss create mode 100644 src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.stories.tsx create mode 100644 src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx diff --git a/package-lock.json b/package-lock.json index 9c41807f..f4f90c29 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "react-dom": "18.2.0", "react-input-mask": "^2.0.4", "react-leaflet": "^4.2.1", + "react-loading-skeleton": "^3.4.0", "react-redux": "8.1.2", "react-router": "6.15.0", "react-router-dom": "6.15.0", @@ -17311,6 +17312,14 @@ "react-dom": "^18.0.0" } }, + "node_modules/react-loading-skeleton": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.4.0.tgz", + "integrity": "sha512-1oJEBc9+wn7BbkQQk7YodlYEIjgeR+GrRjD+QXkVjwZN7LGIcAFHrx4NhT7UHGBxNY1+zax3c+Fo6XQM4R7CgA==", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/react-redux": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", @@ -33317,6 +33326,12 @@ "@react-leaflet/core": "^2.1.0" } }, + "react-loading-skeleton": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/react-loading-skeleton/-/react-loading-skeleton-3.4.0.tgz", + "integrity": "sha512-1oJEBc9+wn7BbkQQk7YodlYEIjgeR+GrRjD+QXkVjwZN7LGIcAFHrx4NhT7UHGBxNY1+zax3c+Fo6XQM4R7CgA==", + "requires": {} + }, "react-redux": { "version": "8.1.2", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-8.1.2.tgz", diff --git a/package.json b/package.json index 0f551ffe..25fa73a9 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "react-dom": "18.2.0", "react-input-mask": "^2.0.4", "react-leaflet": "^4.2.1", + "react-loading-skeleton": "^3.4.0", "react-redux": "8.1.2", "react-router": "6.15.0", "react-router-dom": "6.15.0", diff --git a/src/components/PageDescription/PageDescription.module.scss b/src/components/PageDescription/PageDescription.module.scss index cdf37807..5d72e7b8 100644 --- a/src/components/PageDescription/PageDescription.module.scss +++ b/src/components/PageDescription/PageDescription.module.scss @@ -27,3 +27,8 @@ text-decoration: none; color: var.$body-color-light-grey; } + +.sk-content { + width: 330px !important; + height:30px +} diff --git a/src/components/PageDescription/PageDescription.tsx b/src/components/PageDescription/PageDescription.tsx index 737ebbb7..91a0ef12 100644 --- a/src/components/PageDescription/PageDescription.tsx +++ b/src/components/PageDescription/PageDescription.tsx @@ -1,5 +1,9 @@ import { FC } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' +import { useSelector } from 'react-redux' +import { getLoading } from '@/pages/ProductsPage/selectors/selectors' import { getNoun } from '@/shared/libs/helpers/getNoun' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' @@ -22,18 +26,24 @@ export const PageDescription: FC = ({ count, heading }) => { { heading: heading, href: '/categories/' + heading } ] + const isLoading = useSelector(getLoading) + return (
-
- {heading}{' '} - {count >= 0 ? ( - - {count} {getNoun(count, 'товар', 'товара', 'товаров')} - - ) : ( - '' - )} -
+ {isLoading ? ( + + ) : ( +
+ {heading}{' '} + {count >= 0 ? ( + + {count} {getNoun(count, 'товар', 'товара', 'товаров')} + + ) : ( + '' + )} +
+ )}
) diff --git a/src/pages/ProductsPage/ProductsPage.tsx b/src/pages/ProductsPage/ProductsPage.tsx index bcd4797d..7b6948a6 100644 --- a/src/pages/ProductsPage/ProductsPage.tsx +++ b/src/pages/ProductsPage/ProductsPage.tsx @@ -10,11 +10,13 @@ import { Pagination } from '@/components/Pagination/Pagination' import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' import { TOTAL_PAGES } from '@/mockData/productsPageOptions' -import { getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' +import { getLoading, getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' import { getProducts } from '@/pages/ProductsPage/services/getProducts' import { ITEMS_PER_PAGE_OPTION, SORT_OPTION } from '@/shared/constants/constants' import { useAppDispatch } from '@/shared/libs/hooks/store' import { ECardView } from '@/shared/model/types/common' +import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' +import { ProductSkeleton } from '@/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton' import { CategoryList } from '@/widgets/CategoryList/CategoryList' import { ProductsList } from '@/widgets/ProductsList/ProductsList' @@ -46,6 +48,8 @@ export const ProductsPage = () => { const selectQuantityFilter = useSelector(selectFilterQuantity) const filterQuantity = selectQuantityFilter ? `&limit=${selectQuantityFilter.value}` : '' + const isLoading = useSelector(getLoading) + const handleSortChange: React.ChangeEventHandler = event => { const selectedOption = event.target.value const setCategoryFilters = SORT_OPTION.find(item => item.name === selectedOption) @@ -88,7 +92,16 @@ export const ProductsPage = () => {
- {categoriesProducts.results.length > 0 ? ( + {isLoading ? ( + <> + + {Array(15) + .fill(0) + .map(sk => ( + + ))} + + ) : categoriesProducts.results.length > 0 ? ( <> { return state.categoryProduct.productsData } + +export const getLoading = (state: RootState) => { + return state.categoryProduct.isLoading +} diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss new file mode 100644 index 00000000..3de5b968 --- /dev/null +++ b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss @@ -0,0 +1,28 @@ +@use '../../../styles/utils/variables' as var; + +.sk-page-controls { + width: 100%; + display: flex; + justify-content: space-between; + + &__dropdowns { + display: flex; + gap: 12px; + } + + &__dropdown { + width: 150px; + height: 36px; + } + + &__cards-controls { + display: flex; + gap: 10px; + } + + &__cards-control { + width: 36px; + height: 36px; + border-radius: 6px; + } +} diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx new file mode 100644 index 00000000..717b0643 --- /dev/null +++ b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx @@ -0,0 +1,23 @@ +import { Meta, StoryObj } from '@storybook/react' +import { type FC } from 'react' + +import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' + +const StorybookWrapper: FC = () => { + return ( +
+ +
+ ) +} + +const meta = { + title: 'shared/PageControlsSkeletons', + component: StorybookWrapper, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx new file mode 100644 index 00000000..e15eacb4 --- /dev/null +++ b/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx @@ -0,0 +1,21 @@ +import { type FC } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' + +import styles from './PageControlsSkeletons.module.scss' + +export const PageControlsSkeletons: FC = () => { + return ( +
+
+ + +
+
    + + + +
+
+ ) +} diff --git a/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.module.scss b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.module.scss new file mode 100644 index 00000000..28973916 --- /dev/null +++ b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.module.scss @@ -0,0 +1,57 @@ +@use '../../../styles/utils/variables' as var; + +.sk-product-item { + padding: 20px; + background-color: var.$white; + border-radius: 10px; + + + &_type_grid { + flex-direction: column; + width: 292px; + } + + &__header { + display: flex; + justify-content: end; + } + + &__buttons { + display: flex; + width: 50px; + height: 40px; +} + + &__carousel { + height: 300px; + } + + + &__indicator { + margin-top: 10px; + margin-bottom: 15px; + } + + &__dot { + width: 100%; + height: 2px; + background-color: #ebebeb; +} + + &__description-container { + display: flex; + flex-direction: column; + gap: 10px; +} + + &__info { + height: 33px +} + + &__price { + font-size: 18px; + font-weight: 900; + width: 55px; + height: 25px; + margin-top: 10px; +}} diff --git a/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.stories.tsx b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.stories.tsx new file mode 100644 index 00000000..18d492cb --- /dev/null +++ b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.stories.tsx @@ -0,0 +1,23 @@ +import { Meta, StoryObj } from '@storybook/react' +import { type FC } from 'react' + +import { ProductSkeleton } from '@/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton' + +const StorybookWrapper: FC = () => { + return ( +
+ +
+ ) +} + +const meta = { + title: 'shared/ProductSkeleton', + component: StorybookWrapper, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} diff --git a/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx new file mode 100644 index 00000000..cdcec39d --- /dev/null +++ b/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx @@ -0,0 +1,30 @@ +import { type FC } from 'react' +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' + +import styles from './ProductSkeleton.module.scss' + +export const ProductSkeleton: FC = () => { + return ( +
+
+ +
+
+ +
+
+
+
+
+
+ + +
+ +
+
+
+
+ ) +} diff --git a/src/widgets/CategoryList/CategoryList.module.scss b/src/widgets/CategoryList/CategoryList.module.scss index 025056d3..057feec2 100644 --- a/src/widgets/CategoryList/CategoryList.module.scss +++ b/src/widgets/CategoryList/CategoryList.module.scss @@ -19,3 +19,10 @@ https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/61 */ max-height: calc(100% - 50px); overflow-y: auto; } + +.sk-category-list__item { + display: flex; + min-height: 45px; + border-radius: 5px; + margin-bottom: 5px; +} diff --git a/src/widgets/CategoryList/CategoryList.tsx b/src/widgets/CategoryList/CategoryList.tsx index 8e02ec3c..b6fe9179 100644 --- a/src/widgets/CategoryList/CategoryList.tsx +++ b/src/widgets/CategoryList/CategoryList.tsx @@ -1,9 +1,11 @@ -import { FC, useEffect } from 'react' +import { type FC, useEffect } from 'react' +import Skeleton from 'react-loading-skeleton' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' import { CategoryItem } from '@/features/CategoryItem/CategoryItem' +import { getLoading } from '@/pages/ProductsPage/selectors/selectors' import { useAppDispatch } from '@/shared/libs/hooks/store' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' import { getCategoryBranchesSelector, getCategorySelector } from '@/widgets/CategoryList/selectors/selectors' @@ -24,14 +26,12 @@ export const CategoryList: FC = () => { const { slug } = useParams() - useEffect(() => { - dispatch(getCategoryBranches(slug)) - }, []) + const isLoading = useSelector(getLoading) useEffect(() => { - dispatch(getCategoryBranches(categorySlug)) + dispatch(getCategoryBranches(slug)) dispatch(getCategories()) - }, [categorySlug]) + }, [categorySlug, slug]) return (
@@ -39,7 +39,11 @@ export const CategoryList: FC = () => { Категории
    - {categoryBranches.branches?.length > 0 + {isLoading + ? Array(15) + .fill(0) + .map(sk => ) + : categoryBranches.branches?.length > 0 ? categoryBranches.branches.map(item => ( Date: Mon, 22 Apr 2024 14:09:30 +0300 Subject: [PATCH 2/2] #305-skeletons(improvements) --- .../PageControlsSkeletons.module.scss | 2 +- .../PageControlsSkeletons.stories.tsx | 2 +- .../PageControlsSkeletons.tsx | 0 .../PageDescription.module.scss | 5 --- .../PageDescription/PageDescription.tsx | 36 ++++++++----------- .../PageDescriptionSkeleton.module.scss | 17 +++++++++ .../PageDescriptionSkeleton.stories.tsx | 23 ++++++++++++ .../PageDescriptionSkeleton.tsx | 15 ++++++++ .../CategoryItemSkeleton.module.scss | 6 ++++ .../CategoryItemSkeleton.stories.tsx | 23 ++++++++++++ .../CategoryItemSkeleton.tsx | 8 +++++ src/pages/ProductsPage/ProductsPage.tsx | 19 ++++++---- src/shared/constants/constants.ts | 4 +++ .../CategoryList/CategoryList.module.scss | 7 ---- src/widgets/CategoryList/CategoryList.tsx | 7 ++-- .../ProductSkeleton.module.scss | 2 +- .../ProductSkeleton.stories.tsx | 2 +- .../ProductSkeleton/ProductSkeleton.tsx | 0 18 files changed, 131 insertions(+), 47 deletions(-) rename src/{shared/ui/Skeletons => components/PageControls}/PageControlsSkeletons/PageControlsSkeletons.module.scss (86%) rename src/{shared/ui/Skeletons => components/PageControls}/PageControlsSkeletons/PageControlsSkeletons.stories.tsx (79%) rename src/{shared/ui/Skeletons => components/PageControls}/PageControlsSkeletons/PageControlsSkeletons.tsx (100%) create mode 100644 src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss create mode 100644 src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx create mode 100644 src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx create mode 100644 src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.module.scss create mode 100644 src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.stories.tsx create mode 100644 src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.tsx rename src/{shared/ui/Skeletons => widgets/ProductItem}/ProductSkeleton/ProductSkeleton.module.scss (92%) rename src/{shared/ui/Skeletons => widgets/ProductItem}/ProductSkeleton/ProductSkeleton.stories.tsx (87%) rename src/{shared/ui/Skeletons => widgets/ProductItem}/ProductSkeleton/ProductSkeleton.tsx (100%) diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss similarity index 86% rename from src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss rename to src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss index 3de5b968..ffc7909f 100644 --- a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.module.scss +++ b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.module.scss @@ -1,4 +1,4 @@ -@use '../../../styles/utils/variables' as var; +@use '../../../shared/styles/utils/variables' as var; .sk-page-controls { width: 100%; diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.stories.tsx similarity index 79% rename from src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx rename to src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.stories.tsx index 717b0643..236034bb 100644 --- a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.stories.tsx +++ b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.stories.tsx @@ -1,7 +1,7 @@ import { Meta, StoryObj } from '@storybook/react' import { type FC } from 'react' -import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' +import { PageControlsSkeletons } from '@/components/PageControls/PageControlsSkeletons/PageControlsSkeletons' const StorybookWrapper: FC = () => { return ( diff --git a/src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx b/src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx similarity index 100% rename from src/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons.tsx rename to src/components/PageControls/PageControlsSkeletons/PageControlsSkeletons.tsx diff --git a/src/components/PageDescription/PageDescription.module.scss b/src/components/PageDescription/PageDescription.module.scss index 5d72e7b8..cdf37807 100644 --- a/src/components/PageDescription/PageDescription.module.scss +++ b/src/components/PageDescription/PageDescription.module.scss @@ -27,8 +27,3 @@ text-decoration: none; color: var.$body-color-light-grey; } - -.sk-content { - width: 330px !important; - height:30px -} diff --git a/src/components/PageDescription/PageDescription.tsx b/src/components/PageDescription/PageDescription.tsx index 91a0ef12..f38c8dff 100644 --- a/src/components/PageDescription/PageDescription.tsx +++ b/src/components/PageDescription/PageDescription.tsx @@ -1,9 +1,7 @@ -import { FC } from 'react' -import Skeleton from 'react-loading-skeleton' +import { type FC } from 'react' import 'react-loading-skeleton/dist/skeleton.css' -import { useSelector } from 'react-redux' +import { useParams } from 'react-router-dom' -import { getLoading } from '@/pages/ProductsPage/selectors/selectors' import { getNoun } from '@/shared/libs/helpers/getNoun' import Breadcrumbs from '@/shared/ui/Breadcrumbs/Breadcrumbs' import Heading from '@/shared/ui/Heading/Heading' @@ -21,29 +19,25 @@ type Props = { * @param {string} heading - наименование-заголовок; */ export const PageDescription: FC = ({ count, heading }) => { + const { slug } = useParams() + const links = [ { heading: 'Главная', href: '/' }, - { heading: heading, href: '/categories/' + heading } + { heading: heading, href: '/categories/' + slug } ] - const isLoading = useSelector(getLoading) - return (
    - {isLoading ? ( - - ) : ( -
    - {heading}{' '} - {count >= 0 ? ( - - {count} {getNoun(count, 'товар', 'товара', 'товаров')} - - ) : ( - '' - )} -
    - )} +
    + {heading}{' '} + {count >= 0 ? ( + + {count} {getNoun(count, 'товар', 'товара', 'товаров')} + + ) : ( + '' + )} +
    ) diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss new file mode 100644 index 00000000..61a7cd45 --- /dev/null +++ b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss @@ -0,0 +1,17 @@ +@use '../../../shared/styles/utils/variables' as var; + +.sk-content { + width: 330px; + height:30px +} + +.sk-content__description { + display: flex; + flex-direction: column; + align-self: flex-start; + gap: 10px; +} + +.sk-content__breadcrumbs { + height: 16px; +} diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx new file mode 100644 index 00000000..ea2a2d68 --- /dev/null +++ b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.stories.tsx @@ -0,0 +1,23 @@ +import { Meta, StoryObj } from '@storybook/react' +import { type FC } from 'react' + +import { PageDescriptionSkeleton } from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' + +const StorybookWrapper: FC = () => { + return ( +
    + +
    + ) +} + +const meta = { + title: 'shared/PageDescriptionSkeleton', + component: StorybookWrapper, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} diff --git a/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx new file mode 100644 index 00000000..9de55a5e --- /dev/null +++ b/src/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.tsx @@ -0,0 +1,15 @@ +import { type FC } from 'react' +import Skeleton from 'react-loading-skeleton' + +import styles from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton.module.scss' + +export const PageDescriptionSkeleton: FC = () => { + return ( +
    +
    + +
    + +
    + ) +} diff --git a/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.module.scss b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.module.scss new file mode 100644 index 00000000..eee44f42 --- /dev/null +++ b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.module.scss @@ -0,0 +1,6 @@ +.sk-category-list__item { + display: flex; + min-height: 45px; + border-radius: 5px; + margin-bottom: 5px; +} diff --git a/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.stories.tsx b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.stories.tsx new file mode 100644 index 00000000..a17a45df --- /dev/null +++ b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.stories.tsx @@ -0,0 +1,23 @@ +import { Meta, StoryObj } from '@storybook/react' +import { type FC } from 'react' + +import { CategoryItemSkeleton } from '@/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton' + +const StorybookWrapper: FC = () => { + return ( +
    + +
    + ) +} + +const meta = { + title: 'features/CategoryItemSkeleton', + component: StorybookWrapper, + tags: ['autodocs'] +} satisfies Meta + +export default meta +type Story = StoryObj + +export const Default: Story = {} diff --git a/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.tsx b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.tsx new file mode 100644 index 00000000..f754ce2e --- /dev/null +++ b/src/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.tsx @@ -0,0 +1,8 @@ +import { type FC } from 'react' +import Skeleton from 'react-loading-skeleton' + +import styles from '@/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton.module.scss' + +export const CategoryItemSkeleton: FC = () => { + return +} diff --git a/src/pages/ProductsPage/ProductsPage.tsx b/src/pages/ProductsPage/ProductsPage.tsx index 7b6948a6..a6778b27 100644 --- a/src/pages/ProductsPage/ProductsPage.tsx +++ b/src/pages/ProductsPage/ProductsPage.tsx @@ -5,19 +5,20 @@ import { useLocation } from 'react-router' import { selectFilterProducts, selectFilterQuantity } from '@/components/Dropdown/selectors/selectors' import { setFilterProducts, setProductQuantityFilter } from '@/components/Dropdown/slice/filtersSlice' import { PageControls } from '@/components/PageControls/PageControls' +import { PageControlsSkeletons } from '@/components/PageControls/PageControlsSkeletons/PageControlsSkeletons' import { PageDescription } from '@/components/PageDescription/PageDescription' +import { PageDescriptionSkeleton } from '@/components/PageDescription/PageDescriptionSkeleton/PageDescriptionSkeleton' import { Pagination } from '@/components/Pagination/Pagination' import WrapperForMainContent from '@/components/WrapperForMainContent/WrapperForMainContent' import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' import { TOTAL_PAGES } from '@/mockData/productsPageOptions' import { getLoading, getProductsOfCategorySelector } from '@/pages/ProductsPage/selectors/selectors' import { getProducts } from '@/pages/ProductsPage/services/getProducts' -import { ITEMS_PER_PAGE_OPTION, SORT_OPTION } from '@/shared/constants/constants' +import { ITEMS_PER_PAGE_OPTION, NUMBER_OF_PRODUCTS, SORT_OPTION } from '@/shared/constants/constants' import { useAppDispatch } from '@/shared/libs/hooks/store' import { ECardView } from '@/shared/model/types/common' -import { PageControlsSkeletons } from '@/shared/ui/Skeletons/PageControlsSkeletons/PageControlsSkeletons' -import { ProductSkeleton } from '@/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton' import { CategoryList } from '@/widgets/CategoryList/CategoryList' +import { ProductSkeleton } from '@/widgets/ProductItem/ProductSkeleton/ProductSkeleton' import { ProductsList } from '@/widgets/ProductsList/ProductsList' import styles from './ProductsPage.module.scss' @@ -87,7 +88,11 @@ export const ProductsPage = () => { return ( <> - + {isLoading ? ( + + ) : ( + + )}
    @@ -95,10 +100,10 @@ export const ProductsPage = () => { {isLoading ? ( <> - {Array(15) + {Array(NUMBER_OF_PRODUCTS) .fill(0) - .map(sk => ( - + .map((_, i) => ( + ))} ) : categoriesProducts.results.length > 0 ? ( diff --git a/src/shared/constants/constants.ts b/src/shared/constants/constants.ts index ecb8f8cc..f58a7f24 100644 --- a/src/shared/constants/constants.ts +++ b/src/shared/constants/constants.ts @@ -93,3 +93,7 @@ export const ITEMS_PER_PAGE_OPTION = [ { name: '75', value: '75' }, { name: '100', value: '100' } ] + +//For Skeleton +export const NUMBER_OF_CATEGORY_LINES = 15 +export const NUMBER_OF_PRODUCTS = 15 diff --git a/src/widgets/CategoryList/CategoryList.module.scss b/src/widgets/CategoryList/CategoryList.module.scss index 057feec2..025056d3 100644 --- a/src/widgets/CategoryList/CategoryList.module.scss +++ b/src/widgets/CategoryList/CategoryList.module.scss @@ -19,10 +19,3 @@ https://github.com/Studio-Yandex-Practicum/maxboom_frontend/issues/61 */ max-height: calc(100% - 50px); overflow-y: auto; } - -.sk-category-list__item { - display: flex; - min-height: 45px; - border-radius: 5px; - margin-bottom: 5px; -} diff --git a/src/widgets/CategoryList/CategoryList.tsx b/src/widgets/CategoryList/CategoryList.tsx index b6fe9179..778b9787 100644 --- a/src/widgets/CategoryList/CategoryList.tsx +++ b/src/widgets/CategoryList/CategoryList.tsx @@ -1,11 +1,12 @@ import { type FC, useEffect } from 'react' -import Skeleton from 'react-loading-skeleton' import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { selectCategorySlug } from '@/entities/Category/selectors/categorySelectors' import { CategoryItem } from '@/features/CategoryItem/CategoryItem' +import { CategoryItemSkeleton } from '@/features/CategoryItem/CategoryItemSkeleton/CategoryItemSkeleton' import { getLoading } from '@/pages/ProductsPage/selectors/selectors' +import { NUMBER_OF_CATEGORY_LINES } from '@/shared/constants/constants' import { useAppDispatch } from '@/shared/libs/hooks/store' import Heading, { HeadingType } from '@/shared/ui/Heading/Heading' import { getCategoryBranchesSelector, getCategorySelector } from '@/widgets/CategoryList/selectors/selectors' @@ -40,9 +41,9 @@ export const CategoryList: FC = () => {
      {isLoading - ? Array(15) + ? Array(NUMBER_OF_CATEGORY_LINES) .fill(0) - .map(sk => ) + .map((_, i) => ) : categoryBranches.branches?.length > 0 ? categoryBranches.branches.map(item => ( { return ( diff --git a/src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx b/src/widgets/ProductItem/ProductSkeleton/ProductSkeleton.tsx similarity index 100% rename from src/shared/ui/Skeletons/ProductSkeleton/ProductSkeleton.tsx rename to src/widgets/ProductItem/ProductSkeleton/ProductSkeleton.tsx