@cloud-ru/uikit-product-site-section 0.23.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. package/CHANGELOG.md +1406 -0
  2. package/LICENSE +201 -0
  3. package/README.md +335 -0
  4. package/package.json +70 -0
  5. package/src/components/SectionAccordion/SectionAccordion.tsx +99 -0
  6. package/src/components/SectionAccordion/index.ts +1 -0
  7. package/src/components/SectionAccordion/styles.module.scss +13 -0
  8. package/src/components/SectionAccordion/types.ts +11 -0
  9. package/src/components/SectionAccordion/utils.ts +29 -0
  10. package/src/components/SectionBasic/SectionBasic.tsx +157 -0
  11. package/src/components/SectionBasic/index.ts +1 -0
  12. package/src/components/SectionBasic/styles.module.scss +88 -0
  13. package/src/components/SectionBenefits/SectionBenefits.tsx +163 -0
  14. package/src/components/SectionBenefits/components/CardNumeric/CardNumeric.tsx +17 -0
  15. package/src/components/SectionBenefits/components/CardNumeric/index.ts +1 -0
  16. package/src/components/SectionBenefits/components/CardNumeric/styles.module.scss +6 -0
  17. package/src/components/SectionBenefits/components/index.ts +1 -0
  18. package/src/components/SectionBenefits/index.ts +1 -0
  19. package/src/components/SectionBenefits/styles.module.scss +15 -0
  20. package/src/components/SectionBenefits/types.ts +91 -0
  21. package/src/components/SectionBenefitsBanner/SectionBenefitsBanner.tsx +91 -0
  22. package/src/components/SectionBenefitsBanner/index.ts +1 -0
  23. package/src/components/SectionBenefitsBanner/styles.module.scss +119 -0
  24. package/src/components/SectionBenefitsBanner/types.ts +42 -0
  25. package/src/components/SectionBenefitsBanner/utils.ts +15 -0
  26. package/src/components/SectionBlogCarousel/SectionBlogCarousel.tsx +22 -0
  27. package/src/components/SectionBlogCarousel/index.ts +1 -0
  28. package/src/components/SectionBlogCarousel/utils.ts +29 -0
  29. package/src/components/SectionCaseCarousel/SectionCaseCarousel.tsx +22 -0
  30. package/src/components/SectionCaseCarousel/index.ts +1 -0
  31. package/src/components/SectionCaseCarousel/styles.module.scss +3 -0
  32. package/src/components/SectionCaseCarousel/utils.ts +24 -0
  33. package/src/components/SectionCatalog/SectionCatalog.tsx +105 -0
  34. package/src/components/SectionCatalog/constants.ts +5 -0
  35. package/src/components/SectionCatalog/index.ts +1 -0
  36. package/src/components/SectionCatalog/styles.module.scss +45 -0
  37. package/src/components/SectionClientsCarousel/SectionClientsCarousel.tsx +23 -0
  38. package/src/components/SectionClientsCarousel/index.ts +1 -0
  39. package/src/components/SectionClientsCarousel/utils.ts +29 -0
  40. package/src/components/SectionContent/SectionContent.tsx +98 -0
  41. package/src/components/SectionContent/index.ts +1 -0
  42. package/src/components/SectionContent/styles.module.scss +70 -0
  43. package/src/components/SectionContentList/SectionContentList.tsx +99 -0
  44. package/src/components/SectionContentList/index.ts +1 -0
  45. package/src/components/SectionContentList/styles.module.scss +56 -0
  46. package/src/components/SectionContentTabs/SectionContentTabs.tsx +156 -0
  47. package/src/components/SectionContentTabs/index.ts +1 -0
  48. package/src/components/SectionContentTabs/styles.module.scss +85 -0
  49. package/src/components/SectionExpertsCarousel/SectionExpertsCarousel.tsx +18 -0
  50. package/src/components/SectionExpertsCarousel/constants.ts +2 -0
  51. package/src/components/SectionExpertsCarousel/index.ts +1 -0
  52. package/src/components/SectionExpertsCarousel/types.ts +6 -0
  53. package/src/components/SectionLeading/SectionLeading.tsx +116 -0
  54. package/src/components/SectionLeading/index.ts +1 -0
  55. package/src/components/SectionLeading/styles.module.scss +30 -0
  56. package/src/components/SectionLeading/utils.ts +11 -0
  57. package/src/components/SectionMarketplaceCarousel/SectionMarketplaceCarousel.tsx +23 -0
  58. package/src/components/SectionMarketplaceCarousel/index.ts +1 -0
  59. package/src/components/SectionMarketplaceCarousel/utils.ts +33 -0
  60. package/src/components/SectionMedia/SectionMedia.tsx +57 -0
  61. package/src/components/SectionMedia/index.ts +1 -0
  62. package/src/components/SectionMedia/styles.module.scss +9 -0
  63. package/src/components/SectionPersonalManager/SectionPersonalManager.tsx +135 -0
  64. package/src/components/SectionPersonalManager/index.ts +1 -0
  65. package/src/components/SectionPersonalManager/styles.module.scss +146 -0
  66. package/src/components/SectionPersonalManager/utils.ts +15 -0
  67. package/src/components/SectionPromoList/SectionPromoList.tsx +66 -0
  68. package/src/components/SectionPromoList/index.ts +1 -0
  69. package/src/components/SectionPromoList/styles.module.scss +52 -0
  70. package/src/components/SectionSocial/SectionSocial.tsx +66 -0
  71. package/src/components/SectionSocial/constants.ts +5 -0
  72. package/src/components/SectionSocial/index.ts +1 -0
  73. package/src/components/SectionSocial/styles.module.scss +4 -0
  74. package/src/components/SectionTable/SectionTable.tsx +46 -0
  75. package/src/components/SectionTable/index.ts +1 -0
  76. package/src/components/SectionTable/styles.module.scss +19 -0
  77. package/src/components/index.ts +19 -0
  78. package/src/constants.ts +4 -0
  79. package/src/helperComponents/BenefitItem/BenefitItem.tsx +34 -0
  80. package/src/helperComponents/BenefitItem/index.ts +1 -0
  81. package/src/helperComponents/BenefitItem/styles.module.scss +34 -0
  82. package/src/helperComponents/BenefitItem/utils.ts +28 -0
  83. package/src/helperComponents/CardClient/CardClient.tsx +15 -0
  84. package/src/helperComponents/CardClient/index.ts +1 -0
  85. package/src/helperComponents/CardClient/styles.module.scss +25 -0
  86. package/src/helperComponents/CardLeading/CardLeading.tsx +29 -0
  87. package/src/helperComponents/CardLeading/index.ts +2 -0
  88. package/src/helperComponents/CardLeading/styles.module.scss +43 -0
  89. package/src/helperComponents/CardLeading/types.ts +12 -0
  90. package/src/helperComponents/CardLeading/utils.ts +28 -0
  91. package/src/helperComponents/CardSocial/CardSocial.tsx +105 -0
  92. package/src/helperComponents/CardSocial/index.ts +1 -0
  93. package/src/helperComponents/CardSocial/styles.module.scss +48 -0
  94. package/src/helperComponents/CardSocial/utils.ts +13 -0
  95. package/src/helperComponents/Expert/Expert.tsx +28 -0
  96. package/src/helperComponents/Expert/index.ts +1 -0
  97. package/src/helperComponents/Expert/styles.module.scss +39 -0
  98. package/src/helperComponents/PromoList/PromoList.tsx +26 -0
  99. package/src/helperComponents/PromoList/index.ts +1 -0
  100. package/src/helperComponents/PromoList/styles.module.scss +46 -0
  101. package/src/helperComponents/SectionButton/SectionButton.tsx +19 -0
  102. package/src/helperComponents/SectionButton/index.tsx +1 -0
  103. package/src/helperComponents/SectionButton/types.ts +9 -0
  104. package/src/helperComponents/SectionCarousel/SectionCarousel.tsx +109 -0
  105. package/src/helperComponents/SectionCarousel/index.ts +2 -0
  106. package/src/helperComponents/SectionCarousel/styles.module.scss +8 -0
  107. package/src/helperComponents/SectionCarousel/types.ts +42 -0
  108. package/src/helperComponents/SectionCarousel/utils.ts +10 -0
  109. package/src/helperComponents/SectionCatalogFooter/SectionCatalogFooter.tsx +29 -0
  110. package/src/helperComponents/SectionCatalogFooter/index.ts +1 -0
  111. package/src/helperComponents/SectionCatalogFooter/styles.module.scss +10 -0
  112. package/src/helperComponents/SectionTitle/SectionTitle.tsx +72 -0
  113. package/src/helperComponents/SectionTitle/constants.ts +5 -0
  114. package/src/helperComponents/SectionTitle/index.ts +1 -0
  115. package/src/helperComponents/SectionTitle/styles.module.scss +33 -0
  116. package/src/helperComponents/SectionTitle/types.ts +7 -0
  117. package/src/helperComponents/SectionTitle/utils.ts +83 -0
  118. package/src/helperComponents/index.ts +10 -0
  119. package/src/index.ts +2 -0
  120. package/src/types.ts +23 -0
@@ -0,0 +1,91 @@
1
+ import { CardBasicProps, CardInfoProps, CardProductProps } from '@cloud-ru/uikit-product-site-cards';
2
+
3
+ import { SectionBasicProps } from '../SectionBasic';
4
+
5
+ type CardBasicArray = Omit<CardBasicProps, 'layoutType'>[];
6
+ type CardInfoArray = Omit<CardInfoProps, 'layoutType'>[];
7
+ type CardNumericArray = Omit<CardInfoProps, 'layoutType' | 'icon'>[];
8
+ type CardProductArray = Omit<CardProductProps, 'layoutType'>[];
9
+
10
+ type ContentBasicTab = {
11
+ tabValue: string;
12
+ cards: CardBasicArray;
13
+ };
14
+
15
+ type ContentInfoTab = {
16
+ tabValue: string;
17
+ cards: CardInfoArray;
18
+ };
19
+
20
+ type ContentNumericTab = {
21
+ tabValue: string;
22
+ cards: CardNumericArray;
23
+ };
24
+
25
+ type ContentProductTab = {
26
+ tabValue: string;
27
+ cards: CardProductArray;
28
+ };
29
+
30
+ type ContentBasicWithoutTabs = {
31
+ type: 'basic';
32
+ content: CardBasicArray;
33
+
34
+ tabBarItems?: never;
35
+ };
36
+
37
+ type ContentBasicWithTabs = {
38
+ type: 'basic';
39
+ content: ContentBasicTab[];
40
+
41
+ tabBarItems: NonNullable<SectionBasicProps['tabBarItems']>;
42
+ };
43
+
44
+ type ContentNumericWithoutTabs = {
45
+ type: 'numeric';
46
+ content: CardNumericArray;
47
+
48
+ tabBarItems?: never;
49
+ };
50
+
51
+ type ContentNumericWithTabs = {
52
+ type: 'numeric';
53
+ content: ContentNumericTab[];
54
+
55
+ tabBarItems: NonNullable<SectionBasicProps['tabBarItems']>;
56
+ };
57
+
58
+ type ContentInfoWithoutTabs = {
59
+ type: 'info';
60
+ outline?: boolean;
61
+ content: CardInfoArray;
62
+
63
+ tabBarItems?: never;
64
+ };
65
+
66
+ type ContentInfoWithTabs = {
67
+ type: 'info';
68
+ outline?: boolean;
69
+ content: ContentInfoTab[];
70
+
71
+ tabBarItems: NonNullable<SectionBasicProps['tabBarItems']>;
72
+ };
73
+
74
+ type ContentProductWithoutTabs = {
75
+ type: 'product';
76
+ content: CardProductArray;
77
+
78
+ tabBarItems?: never;
79
+ };
80
+
81
+ type ContentProdctWithTabs = {
82
+ type: 'product';
83
+ content: ContentProductTab[];
84
+
85
+ tabBarItems: NonNullable<SectionBasicProps['tabBarItems']>;
86
+ };
87
+
88
+ export type ContentBasic = ContentBasicWithTabs | ContentBasicWithoutTabs;
89
+ export type ContentInfo = ContentInfoWithTabs | ContentInfoWithoutTabs;
90
+ export type ContentProduct = ContentProdctWithTabs | ContentProductWithoutTabs;
91
+ export type ContentNumeric = ContentNumericWithTabs | ContentNumericWithoutTabs;
@@ -0,0 +1,91 @@
1
+ import cn from 'classnames';
2
+
3
+ import { RichText } from '@cloud-ru/uikit-product-site-rich-text';
4
+ import { WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
5
+ import { Typography, TypographyProps } from '@snack-uikit/typography';
6
+
7
+ import { BenefitItem, BenefitItemProps } from '../../helperComponents';
8
+ import { SectionBasic } from '../SectionBasic';
9
+ import styles from './styles.module.scss';
10
+ import { BackgroundType } from './types';
11
+ import { getTitleTypographyProps } from './utils';
12
+
13
+ type ItemProps = Omit<BenefitItemProps, 'layoutType'>;
14
+
15
+ export type SectionBenefitsBannerProps = WithSupportProps<
16
+ WithLayoutType<
17
+ {
18
+ /** Заголовок */
19
+ title?: string;
20
+ /** Тэг заголовка */
21
+ titleTag?: TypographyProps['tag'];
22
+ /** Выгоды */
23
+ items: ItemProps[];
24
+ /** Описание под баннером */
25
+ description?: string[] | string;
26
+ /** CSS класс */
27
+ className?: string;
28
+ } & BackgroundType
29
+ >
30
+ >;
31
+
32
+ export function SectionBenefitsBanner({
33
+ title,
34
+ titleTag = 'h3',
35
+ items,
36
+ layoutType,
37
+ backgroundType = 'color',
38
+ appearance = 'brand',
39
+ color,
40
+ backgroundImage,
41
+ description,
42
+ className,
43
+ ...rest
44
+ }: SectionBenefitsBannerProps) {
45
+ return (
46
+ <SectionBasic layoutType={layoutType} className={className} {...rest}>
47
+ <div className={styles.bannerWrapper} data-layout-type={layoutType}>
48
+ <div
49
+ className={cn(styles.banner, {
50
+ [styles.white]: backgroundType && backgroundType === 'image',
51
+ })}
52
+ data-layout-type={layoutType}
53
+ data-appearance={appearance}
54
+ data-color={color}
55
+ >
56
+ {backgroundImage && (
57
+ <img
58
+ className={styles.illustration}
59
+ src={backgroundImage}
60
+ alt='benefits-illustration'
61
+ data-layout-type={layoutType}
62
+ />
63
+ )}
64
+ <div className={styles.contentWrapper}>
65
+ {title && (
66
+ <Typography family='light' tag={titleTag} {...getTitleTypographyProps(layoutType)}>
67
+ <RichText richText={title} />
68
+ </Typography>
69
+ )}
70
+ <div className={styles.benefitItems} data-items-amount={items.length} data-layout-type={layoutType}>
71
+ {items.map(item => (
72
+ <BenefitItem key={item.description} {...item} layoutType={layoutType} />
73
+ ))}
74
+ </div>
75
+ </div>
76
+ </div>
77
+ {description && (
78
+ <div className={styles.description} data-attribute='no_search_index'>
79
+ <Typography family='sans' purpose='body' size='m' tag='div'>
80
+ {Array.isArray(description) ? (
81
+ description.map(item => <RichText key={item} richText={item} />)
82
+ ) : (
83
+ <RichText richText={description} />
84
+ )}
85
+ </Typography>
86
+ </div>
87
+ )}
88
+ </div>
89
+ </SectionBasic>
90
+ );
91
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionBenefitsBanner';
@@ -0,0 +1,119 @@
1
+ @use '@sbercloud/figma-tokens-web/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ $colors: (
4
+ neutral: ste.$sys-neutral-background,
5
+ white: ste.$sys-neutral-background1-level,
6
+ violet: ste.$sys-violet-background,
7
+ blue: ste.$sys-blue-background,
8
+ );
9
+
10
+ $decor: 'decor';
11
+ $graphite: 'graphite';
12
+ $brand: 'brand';
13
+
14
+ @mixin decor-background-colors {
15
+ @each $color, $value in $colors {
16
+ &[data-color='#{$color}'][data-appearance='#{$decor}'] {
17
+ background-color: $value;
18
+ }
19
+ }
20
+ }
21
+
22
+ @mixin appearance {
23
+ &[data-appearance='#{$graphite}'] {
24
+ background-color: ste.$sys-graphite-accent-default;
25
+
26
+ color: ste.$sys-invert-neutral-text-main;
27
+ }
28
+
29
+ &[data-appearance='#{$brand}'] {
30
+ background-color: ste.$sys-primary-accent-default;
31
+ }
32
+ }
33
+
34
+ .bannerWrapper {
35
+ display: flex;
36
+ flex-direction: column;
37
+ gap: ste.$dimension-2m;
38
+ }
39
+
40
+ .banner {
41
+ position: relative;
42
+ overflow: hidden;
43
+
44
+ color: ste.$sys-graphite-text-main;
45
+ padding: ste.$dimension-5m;
46
+
47
+ &[data-layout-type='tablet'] {
48
+ padding: ste.$dimension-4m;
49
+ }
50
+
51
+ &[data-layout-type='mobile'] {
52
+ padding: ste.$dimension-3m;
53
+ }
54
+
55
+ @include decor-background-colors;
56
+ @include appearance;
57
+ }
58
+
59
+ .contentWrapper {
60
+ position: relative;
61
+
62
+ /* stylelint-disable-next-line declaration-property-value-allowed-list */
63
+ z-index: 1;
64
+
65
+ display: flex;
66
+ flex-direction: column;
67
+ gap: ste.$dimension-4m;
68
+ }
69
+
70
+ .banner.white {
71
+ color: ste.$sys-graphite-on-accent;
72
+ background: transparent;
73
+ }
74
+
75
+ .benefitItems {
76
+ display: grid;
77
+ grid-template-columns: repeat(4, 1fr);
78
+ gap: ste.$dimension-2m;
79
+
80
+ &[data-layout-type='tablet'] {
81
+ grid-template-columns: repeat(2, 1fr);
82
+ gap: ste.$dimension-4m ste.$dimension-6m;
83
+ }
84
+
85
+ &[data-layout-type='mobile'] {
86
+ grid-template-columns: 100%;
87
+ gap: ste.$dimension-3m;
88
+ }
89
+
90
+ &[data-items-amount='3'] {
91
+ grid-template-columns: repeat(3, 1fr);
92
+
93
+ &[data-layout-type='tablet'] {
94
+ grid-template-columns: repeat(3, 1fr);
95
+ }
96
+ &[data-layout-type='mobile'] {
97
+ grid-template-columns: 100%;
98
+ }
99
+ }
100
+ }
101
+
102
+ .description {
103
+ color: ste.$sys-neutral-text-support;
104
+ }
105
+
106
+ .illustration {
107
+ position: absolute;
108
+ pointer-events: none;
109
+
110
+ /* stylelint-disable-next-line declaration-property-value-allowed-list */
111
+ z-index: 0;
112
+
113
+ width: 100%;
114
+ height: 100%;
115
+ object-fit: cover;
116
+ object-position: center 0;
117
+ top: 0;
118
+ left: 0;
119
+ }
@@ -0,0 +1,42 @@
1
+ import { ValueOf } from '@snack-uikit/utils';
2
+
3
+ export const Appearance = {
4
+ Decor: 'decor',
5
+ Brand: 'brand',
6
+ Graphite: 'graphite',
7
+ } as const;
8
+
9
+ export const Color = {
10
+ Neutral: 'neutral',
11
+ White: 'white',
12
+ Violet: 'violet',
13
+ Blue: 'blue',
14
+ } as const;
15
+
16
+ type ColorType = ValueOf<typeof Color>;
17
+
18
+ export type AppearanceType = ValueOf<typeof Appearance>;
19
+
20
+ export type WithColor = {
21
+ appearance: Exclude<AppearanceType, 'brand' | 'graphite'>;
22
+ color?: ColorType;
23
+ };
24
+
25
+ export type WithoutColor = {
26
+ appearance: Exclude<AppearanceType, 'decor'>;
27
+ color?: never;
28
+ };
29
+
30
+ export type ColorsProps = (WithColor | WithoutColor) & {
31
+ backgroundType: 'color';
32
+ backgroundImage?: never;
33
+ };
34
+
35
+ type WithBgImage = {
36
+ backgroundType: 'image';
37
+ backgroundImage: string;
38
+ appearance?: never;
39
+ color?: never;
40
+ };
41
+
42
+ export type BackgroundType = ColorsProps | WithBgImage;
@@ -0,0 +1,15 @@
1
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
2
+ import { TypographyProps } from '@snack-uikit/typography';
3
+
4
+ export function getTitleTypographyProps(layoutType: LayoutType): Pick<TypographyProps, 'purpose' | 'size'> {
5
+ switch (layoutType) {
6
+ case 'mobile':
7
+ case 'tablet':
8
+ return { purpose: 'headline', size: 's' };
9
+
10
+ case 'desktop':
11
+ case 'desktopSmall':
12
+ default:
13
+ return { purpose: 'headline', size: 'l' };
14
+ }
15
+ }
@@ -0,0 +1,22 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { CardMedia, CardMediaProps } from '@cloud-ru/uikit-product-site-cards';
4
+
5
+ import { LimitedSectionCarouselProps, SectionCarousel } from '../../helperComponents';
6
+ import { getCarouselProps } from './utils';
7
+
8
+ export type BlogCarouselItem = Omit<CardMediaProps, 'size' | 'layoutType'>;
9
+
10
+ export type SectionBlogCarouselProps = Omit<LimitedSectionCarouselProps<BlogCarouselItem>, 'gap' | 'titleLink'>;
11
+
12
+ export function SectionBlogCarousel({ items, ...props }: SectionBlogCarouselProps) {
13
+ const carouselProps = useMemo(() => getCarouselProps(props.layoutType), [props.layoutType]);
14
+
15
+ return (
16
+ <SectionCarousel {...props} {...carouselProps}>
17
+ {items.map(item => (
18
+ <CardMedia key={item.title} {...item} size='m' layoutType={props.layoutType} />
19
+ ))}
20
+ </SectionCarousel>
21
+ );
22
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionBlogCarousel';
@@ -0,0 +1,29 @@
1
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
2
+
3
+ import { SectionCarouselProps } from '../../helperComponents';
4
+
5
+ export const getCarouselProps = (
6
+ layoutType: LayoutType,
7
+ ): Pick<SectionCarouselProps, 'itemMinWidth' | 'maxItemsPerPage'> => {
8
+ switch (layoutType) {
9
+ case 'mobile':
10
+ return {
11
+ itemMinWidth: 270,
12
+ maxItemsPerPage: 1,
13
+ };
14
+
15
+ case 'tablet':
16
+ return {
17
+ itemMinWidth: 340,
18
+ maxItemsPerPage: 2,
19
+ };
20
+
21
+ case 'desktop':
22
+ case 'desktopSmall':
23
+ default:
24
+ return {
25
+ itemMinWidth: 340,
26
+ maxItemsPerPage: 3,
27
+ };
28
+ }
29
+ };
@@ -0,0 +1,22 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { CaseCard, CaseCardProps } from '@cloud-ru/uikit-product-site-case-card';
4
+
5
+ import { LimitedSectionCarouselProps, SectionCarousel } from '../../helperComponents';
6
+ import { getCarouselProps } from './utils';
7
+
8
+ export type CaseItem = Omit<CaseCardProps, 'layoutType'>;
9
+
10
+ export type SectionCaseCarouselProps = Omit<LimitedSectionCarouselProps<CaseItem>, 'description' | 'gap' | 'titleLink'>;
11
+
12
+ export function SectionCaseCarousel({ items, layoutType, ...props }: SectionCaseCarouselProps) {
13
+ const carouselProps = useMemo(() => getCarouselProps(layoutType), [layoutType]);
14
+
15
+ return (
16
+ <SectionCarousel {...props} {...carouselProps} layoutType={layoutType}>
17
+ {items.map(item => (
18
+ <CaseCard key={item.description} {...item} layoutType={layoutType} />
19
+ ))}
20
+ </SectionCarousel>
21
+ );
22
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionCaseCarousel';
@@ -0,0 +1,3 @@
1
+ .card {
2
+ height: 100%;
3
+ }
@@ -0,0 +1,24 @@
1
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
2
+
3
+ import { SectionCarouselProps } from '../../helperComponents';
4
+
5
+ export const getCarouselProps = (
6
+ layoutType: LayoutType,
7
+ ): Pick<SectionCarouselProps, 'itemMinWidth' | 'maxItemsPerPage'> => {
8
+ switch (layoutType) {
9
+ case 'tablet':
10
+ case 'mobile':
11
+ return {
12
+ itemMinWidth: 270,
13
+ maxItemsPerPage: 1,
14
+ };
15
+
16
+ case 'desktop':
17
+ case 'desktopSmall':
18
+ default:
19
+ return {
20
+ itemMinWidth: 320,
21
+ maxItemsPerPage: 2,
22
+ };
23
+ }
24
+ };
@@ -0,0 +1,105 @@
1
+ import cn from 'classnames';
2
+ import { useUncontrolledProp } from 'uncontrollable';
3
+
4
+ import { CardProduct, CardProductProps } from '@cloud-ru/uikit-product-site-cards';
5
+ import { Grid } from '@cloud-ru/uikit-product-site-grid';
6
+ import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
7
+ import { Tabs } from '@snack-uikit/tabs';
8
+
9
+ import { SectionCatalogFooter, SectionCatalogFooterProps } from '../../helperComponents';
10
+ import { SectionColor } from '../../types';
11
+ import { SectionBasic } from '../SectionBasic';
12
+ import { GRID_CONFIG } from './constants';
13
+ import styles from './styles.module.scss';
14
+
15
+ type ProductCategory = {
16
+ id: string;
17
+ label: string;
18
+ items: Omit<CardProductProps, 'layoutType'>[];
19
+ };
20
+
21
+ export type SectionCatalogProps = WithSupportProps<
22
+ WithLayoutType<{
23
+ /** id секции */
24
+ id?: string;
25
+ /** CSS-класс */
26
+ className?: string;
27
+ /** Заголовок */
28
+ title: string;
29
+ /** Цвет фона */
30
+ backgroundColor?: SectionColor;
31
+ /** Список продуктов по категориям */
32
+ categories: ProductCategory[];
33
+ /** Выбранная категория продуктов */
34
+ selectedCategory?: string;
35
+ /** Колбек смены выбранной категории продуктов */
36
+ onCategorySelect?(category: string): void;
37
+ /** Список элементов для футера в каталоге */
38
+ footer?: SectionCatalogFooterProps['items'];
39
+ }>
40
+ >;
41
+
42
+ export function SectionCatalog({
43
+ id,
44
+ layoutType,
45
+ className,
46
+ title,
47
+ backgroundColor,
48
+ selectedCategory: selectedCategoryProp,
49
+ onCategorySelect,
50
+ categories,
51
+ footer,
52
+ ...rest
53
+ }: SectionCatalogProps) {
54
+ const [selectedCategory, setSelectedCategory] = useUncontrolledProp(
55
+ selectedCategoryProp,
56
+ categories[0].id,
57
+ onCategorySelect,
58
+ );
59
+
60
+ const isDesktop = ['desktop', 'desktopSmall'].includes(layoutType);
61
+
62
+ const isOutlineCard = backgroundColor === 'neutral-background1-level';
63
+
64
+ return (
65
+ <SectionBasic
66
+ id={id}
67
+ title={title}
68
+ backgroundColor={backgroundColor}
69
+ layoutType={layoutType}
70
+ className={cn(className, styles.sectionCatalog)}
71
+ {...extractSupportProps(rest)}
72
+ >
73
+ <div className={styles.body}>
74
+ <Tabs value={selectedCategory} onChange={setSelectedCategory}>
75
+ <div className={cn(styles.categoryList, { [styles.desktopCategoryList]: isDesktop })}>
76
+ <Tabs.TabBar
77
+ type='primary'
78
+ orientation={isDesktop ? 'vertical' : 'horizontal'}
79
+ markerPosition={isDesktop ? 'before' : 'after'}
80
+ className={cn({ [styles.desktopTabs]: isDesktop })}
81
+ >
82
+ {categories.map(({ id, label }) => (
83
+ <Tabs.Tab key={id} value={id} label={label} />
84
+ ))}
85
+ </Tabs.TabBar>
86
+
87
+ {footer && isDesktop && <SectionCatalogFooter items={footer} layoutType={layoutType} />}
88
+ </div>
89
+
90
+ {categories.map(({ id, items }) => (
91
+ <Tabs.TabContent key={id} value={id} className={styles.tabContent}>
92
+ <Grid columnsConfig={GRID_CONFIG} gap='s' layoutType={layoutType}>
93
+ {items.map(item => (
94
+ <CardProduct key={item.title} layoutType={layoutType} outline={isOutlineCard} {...item} />
95
+ ))}
96
+ </Grid>
97
+ </Tabs.TabContent>
98
+ ))}
99
+ </Tabs>
100
+
101
+ {footer && !isDesktop && <SectionCatalogFooter items={footer} layoutType={layoutType} />}
102
+ </div>
103
+ </SectionBasic>
104
+ );
105
+ }
@@ -0,0 +1,5 @@
1
+ export const GRID_CONFIG = {
2
+ desktop: { amount: 3, minWidth: 280 },
3
+ tablet: { amount: 2, minWidth: 280 },
4
+ mobile: { amount: 2, minWidth: 280 },
5
+ };
@@ -0,0 +1 @@
1
+ export * from './SectionCatalog';
@@ -0,0 +1,45 @@
1
+ .sectionCatalog {
2
+ width: 100%;
3
+ position: relative;
4
+ }
5
+
6
+ .body {
7
+ display: flex;
8
+ gap: 32px;
9
+ width: 100%;
10
+
11
+ [data-layout-type='tablet'] & {
12
+ flex-direction: column;
13
+ gap: 32px;
14
+ }
15
+
16
+ [data-layout-type='mobile'] & {
17
+ flex-direction: column;
18
+ gap: 24px;
19
+ }
20
+ }
21
+
22
+ .categoryList {
23
+ display: flex;
24
+ flex-direction: column;
25
+ gap: 16px;
26
+ }
27
+
28
+ .tabContent {
29
+ width: 100%;
30
+ }
31
+
32
+ .desktopTabs button {
33
+ text-wrap: auto;
34
+ text-align: left;
35
+ box-sizing: border-box;
36
+ padding-top: 12px;
37
+ padding-bottom: 12px;
38
+ }
39
+
40
+ .desktopCategoryList,
41
+ .desktopTabs,
42
+ .desktopTabs button {
43
+ max-width: 280px;
44
+ flex-shrink: 0;
45
+ }
@@ -0,0 +1,23 @@
1
+ import { useMemo } from 'react';
2
+
3
+ import { themeVars } from '@sbercloud/figma-tokens-cloud-platform';
4
+
5
+ import { CardClient, CardClientProps, LimitedSectionCarouselProps, SectionCarousel } from '../../helperComponents';
6
+ import { getCarouselProps } from './utils';
7
+
8
+ export type SectionClientsCarouselProps = Omit<
9
+ LimitedSectionCarouselProps<CardClientProps>,
10
+ 'description' | 'gap' | 'titleLink'
11
+ >;
12
+
13
+ export function SectionClientsCarousel({ items, ...props }: SectionClientsCarouselProps) {
14
+ const carouselProps = useMemo(() => getCarouselProps(props.layoutType), [props.layoutType]);
15
+
16
+ return (
17
+ <SectionCarousel autoSwipe={0} {...props} {...carouselProps} gap={themeVars.dimension['1m']}>
18
+ {items.map(item => (
19
+ <CardClient key={item.alt} {...item} />
20
+ ))}
21
+ </SectionCarousel>
22
+ );
23
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionClientsCarousel';