@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,99 @@
1
+ import { RichText } from '@cloud-ru/uikit-product-site-rich-text';
2
+ import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
3
+ import { AccordionPrimary } from '@snack-uikit/accordion';
4
+ import { Typography } from '@snack-uikit/typography';
5
+
6
+ import { SectionColor } from '../../types';
7
+ import { SectionBasic } from '../SectionBasic';
8
+ import styles from './styles.module.scss';
9
+ import { AccordionItem } from './types';
10
+ import { getBlockDescriptionSize, getBlockTitleProps } from './utils';
11
+
12
+ // Had to copy props to save proper typings
13
+ type AccordionPropsCopy =
14
+ | {
15
+ selectionMode: 'single';
16
+ expandedDefault?: string;
17
+ onExpandedChange?(value?: string): void;
18
+ }
19
+ | {
20
+ selectionMode: 'multiple';
21
+ expandedDefault?: string[];
22
+ onExpandedChange?(value?: string[]): void;
23
+ };
24
+
25
+ export type SectionAccordionProps = WithSupportProps<
26
+ AccordionPropsCopy &
27
+ WithLayoutType<{
28
+ /** id секции */
29
+ id?: string;
30
+ /** Название секции */
31
+ title: string;
32
+ /** Массив айтемов */
33
+ items: AccordionItem[];
34
+ /** Цвет фона */
35
+ backgroundColor?: SectionColor;
36
+ /** Внешний бордер для блоков */
37
+ outline?: boolean;
38
+ /** CSS-класс */
39
+ className?: string;
40
+ }>
41
+ >;
42
+
43
+ export function SectionAccordion({
44
+ id,
45
+ title,
46
+ items,
47
+ selectionMode = 'multiple',
48
+ layoutType,
49
+ backgroundColor,
50
+ outline,
51
+ onExpandedChange,
52
+ expandedDefault,
53
+ className,
54
+ ...rest
55
+ }: SectionAccordionProps) {
56
+ return (
57
+ <SectionBasic
58
+ id={id}
59
+ title={title}
60
+ layoutType={layoutType}
61
+ backgroundColor={backgroundColor}
62
+ {...extractSupportProps(rest)}
63
+ >
64
+ {/* @ts-expect-error types mismatch because of union */}
65
+ <AccordionPrimary
66
+ selectionMode={selectionMode}
67
+ expandedDefault={expandedDefault}
68
+ onExpandedChange={onExpandedChange}
69
+ className={styles.accordion}
70
+ >
71
+ {items.map(({ title, description, onClick }, index) => (
72
+ <AccordionPrimary.CollapseBlock
73
+ key={index}
74
+ id={index.toString()}
75
+ header={
76
+ <Typography family='sans' {...getBlockTitleProps(layoutType)} className={styles.title}>
77
+ <RichText richText={title} />
78
+ </Typography>
79
+ }
80
+ className={className}
81
+ removeContentFromDOM={false}
82
+ outline={outline}
83
+ onClick={onClick}
84
+ >
85
+ <Typography
86
+ family='sans'
87
+ purpose='body'
88
+ tag='div'
89
+ size={getBlockDescriptionSize(layoutType)}
90
+ className={styles.description}
91
+ >
92
+ <RichText richText={description} />
93
+ </Typography>
94
+ </AccordionPrimary.CollapseBlock>
95
+ ))}
96
+ </AccordionPrimary>
97
+ </SectionBasic>
98
+ );
99
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionAccordion';
@@ -0,0 +1,13 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/components/styles-tokens-element' as ste;
2
+
3
+ .accordion {
4
+ gap: 1px;
5
+ }
6
+
7
+ .description {
8
+ color: ste.$sys-neutral-text-support;
9
+ }
10
+
11
+ .title {
12
+ color: ste.$sys-neutral-text-main;
13
+ }
@@ -0,0 +1,11 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ import { CollapseBlockPrimaryProps } from '@snack-uikit/accordion';
4
+
5
+ /** Элемент аккордиона */
6
+ export type AccordionItem = Pick<CollapseBlockPrimaryProps, 'onClick'> & {
7
+ /** Заголовок блока */
8
+ title: string;
9
+ /** Описание блока (rich text) */
10
+ description: string | ReactNode;
11
+ };
@@ -0,0 +1,29 @@
1
+ import { LayoutType } from '@cloud-ru/uikit-product-utils';
2
+ import { TypographyProps } from '@snack-uikit/typography';
3
+
4
+ export const getBlockTitleProps = (layoutType: LayoutType): Pick<TypographyProps, 'purpose' | 'size'> => {
5
+ switch (layoutType) {
6
+ case 'tablet':
7
+ case 'mobile':
8
+ return {
9
+ purpose: 'title',
10
+ size: 'm',
11
+ };
12
+
13
+ default:
14
+ return {
15
+ purpose: 'headline',
16
+ size: 's',
17
+ };
18
+ }
19
+ };
20
+
21
+ export const getBlockDescriptionSize = (layoutType: LayoutType): TypographyProps['size'] => {
22
+ switch (layoutType) {
23
+ case 'tablet':
24
+ case 'mobile':
25
+ return 'm';
26
+ default:
27
+ return 'l';
28
+ }
29
+ };
@@ -0,0 +1,157 @@
1
+ import cn from 'classnames';
2
+ import { MouseEvent, MouseEventHandler, ReactNode, useState } from 'react';
3
+
4
+ import { useLocale } from '@cloud-ru/uikit-product-locale';
5
+ import { AdaptiveFieldSelect, FieldSelectProps } from '@cloud-ru/uikit-product-mobile-fields';
6
+ import { Layout } from '@cloud-ru/uikit-product-site-layout';
7
+ import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
8
+ import { ButtonOutline } from '@snack-uikit/button';
9
+ import { Pagination, PaginationProps } from '@snack-uikit/pagination';
10
+ import { Tabs } from '@snack-uikit/tabs';
11
+
12
+ import { SECTION_COLORS } from '../../constants';
13
+ import { SectionTitle, SectionTitleProps } from '../../helperComponents';
14
+ import { SectionColor } from '../../types';
15
+ import styles from './styles.module.scss';
16
+
17
+ type TabBarItem = WithSupportProps<{
18
+ value: string;
19
+ label: string;
20
+ disabled?: boolean;
21
+ className?: string;
22
+ counter?: number;
23
+ onClick?(event: MouseEvent<HTMLButtonElement>): void;
24
+ }>;
25
+
26
+ export type SectionBasicProps = WithLayoutType<
27
+ WithSupportProps<
28
+ Pick<
29
+ SectionTitleProps,
30
+ 'title' | 'subtitle' | 'description' | 'titleSectionSize' | 'titleTag' | 'subtitleTag' | 'titleAlign'
31
+ > & {
32
+ /** id секции */
33
+ id?: string;
34
+ children: ReactNode;
35
+ /** Массив табов */
36
+ tabBarItems?: TabBarItem[];
37
+ /** Массив фильтров */
38
+ filterItems?: FieldSelectProps[];
39
+ /** Настройки пагинации */
40
+ pagination?: PaginationProps;
41
+ /** Цвет фона */
42
+ backgroundColor?: SectionColor;
43
+ /** CSS-класс */
44
+ className?: string;
45
+ /** Кнопка внизу секции */
46
+ moreButton?: {
47
+ label?: string;
48
+ href?: string;
49
+ onClick: MouseEventHandler<HTMLElement>;
50
+ 'data-test-id'?: string;
51
+ };
52
+ }
53
+ >
54
+ >;
55
+
56
+ const getInitialTab = (tabBarItems?: TabBarItem[]) => {
57
+ if (!tabBarItems || tabBarItems.length < 1) {
58
+ return undefined;
59
+ }
60
+
61
+ const [firstTab] = tabBarItems;
62
+ return firstTab.value;
63
+ };
64
+
65
+ export function SectionBasic({
66
+ id,
67
+ children,
68
+ title,
69
+ subtitle,
70
+ description,
71
+ titleSectionSize = 'm',
72
+ titleTag,
73
+ subtitleTag,
74
+ tabBarItems,
75
+ filterItems,
76
+ moreButton,
77
+ className,
78
+ pagination,
79
+ backgroundColor = SECTION_COLORS.NeutralBackground1Level,
80
+ layoutType,
81
+ titleAlign,
82
+ ...rest
83
+ }: SectionBasicProps) {
84
+ const [currentTab, setCurrentTab] = useState<string | undefined>(getInitialTab(tabBarItems));
85
+ const { t } = useLocale('SiteSection');
86
+ const showFooter = Boolean(pagination || moreButton);
87
+
88
+ return (
89
+ <Layout.SectionWrapper
90
+ id={id}
91
+ layoutType={layoutType}
92
+ className={cn(className, styles.wrapper)}
93
+ data-section-background={backgroundColor}
94
+ {...extractSupportProps(rest)}
95
+ >
96
+ <div className={styles.sectionBasic} data-layout-type={layoutType}>
97
+ <SectionTitle
98
+ layoutType={layoutType}
99
+ title={title}
100
+ description={description}
101
+ titleSectionSize={titleSectionSize}
102
+ titleTag={titleTag}
103
+ titleAlign={titleAlign}
104
+ subtitle={subtitle}
105
+ subtitleTag={subtitleTag}
106
+ />
107
+
108
+ {tabBarItems?.length && (
109
+ <div className={styles.sectionTabs}>
110
+ <Tabs value={currentTab} onChange={setCurrentTab}>
111
+ <Tabs.TabBar>
112
+ {tabBarItems.map(tabProps => (
113
+ <Tabs.Tab key={tabProps.value} {...tabProps} />
114
+ ))}
115
+ </Tabs.TabBar>
116
+ </Tabs>
117
+ </div>
118
+ )}
119
+
120
+ {filterItems?.length && (
121
+ <div className={styles.sectionFilters} data-layout-type={layoutType}>
122
+ {filterItems.map(filterProps => (
123
+ <AdaptiveFieldSelect
124
+ key={filterProps.id}
125
+ {...filterProps}
126
+ className={cn(filterProps.className, styles.filter)}
127
+ layoutType={layoutType}
128
+ size='l'
129
+ />
130
+ ))}
131
+ </div>
132
+ )}
133
+
134
+ {children}
135
+
136
+ {showFooter && (
137
+ <div className={styles.footer} data-layout-type={layoutType}>
138
+ {pagination && <Pagination {...pagination} />}
139
+ {moreButton && (
140
+ <ButtonOutline
141
+ className={styles.showMoreButton}
142
+ label={moreButton.label ?? t('Basic.showMore')}
143
+ onClick={moreButton.onClick}
144
+ href={moreButton.href}
145
+ data-test-id={moreButton['data-test-id'] ?? 'section__more-btn'}
146
+ appearance='neutral'
147
+ size='l'
148
+ type='button'
149
+ data-layout-type={layoutType}
150
+ />
151
+ )}
152
+ </div>
153
+ )}
154
+ </div>
155
+ </Layout.SectionWrapper>
156
+ );
157
+ }
@@ -0,0 +1 @@
1
+ export * from './SectionBasic';
@@ -0,0 +1,88 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .sectionBasic {
4
+ display: flex;
5
+ flex-direction: column;
6
+
7
+ gap: var.$dimension-5m;
8
+ padding: var.$dimension-7m 0;
9
+
10
+ &[data-layout-type='tablet'] {
11
+ gap: var.$dimension-4m;
12
+ padding: var.$dimension-5m 0;
13
+ }
14
+
15
+ &[data-layout-type='mobile'] {
16
+ gap: var.$dimension-3m;
17
+ padding: var.$dimension-4m 0;
18
+ }
19
+ }
20
+
21
+ .wrapper {
22
+ &[data-section-background='neutral-background1-level'] {
23
+ background-color: var.$sys-neutral-background1-level;
24
+ }
25
+
26
+ &[data-section-background='neutral-background'] {
27
+ background-color: var.$sys-neutral-background;
28
+ }
29
+ }
30
+
31
+ .sectionTitle {
32
+ display: flex;
33
+ flex-direction: column;
34
+ gap: var.$dimension-1m;
35
+ }
36
+
37
+ .title {
38
+ color: var.$sys-neutral-text-main;
39
+ }
40
+
41
+ .description {
42
+ color: var.$sys-neutral-text-support;
43
+ }
44
+
45
+ .sectionTabs {
46
+ display: flex;
47
+ flex-direction: column;
48
+ gap: var.$dimension-4m;
49
+ color: var.$sys-neutral-text-main;
50
+ }
51
+
52
+ .sectionFilters {
53
+ display: grid;
54
+ grid-template-columns: repeat(3, 1fr);
55
+ gap: var.$dimension-4m;
56
+
57
+ &[data-layout-type='tablet'] {
58
+ grid-template-columns: repeat(2, 1fr);
59
+ gap: var.$dimension-2m;
60
+ }
61
+
62
+ &[data-layout-type='mobile'] {
63
+ grid-template-columns: repeat(1, 1fr);
64
+ gap: var.$dimension-3m;
65
+ }
66
+ }
67
+
68
+ .footer {
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+
73
+ gap: var.$dimension-5m;
74
+
75
+ &[data-layout-type='tablet'] {
76
+ gap: var.$dimension-4m;
77
+ }
78
+
79
+ &[data-layout-type='mobile'] {
80
+ gap: var.$dimension-3m;
81
+ }
82
+ }
83
+
84
+ .showMoreButton {
85
+ &[data-layout-type='mobile'] {
86
+ width: 100%;
87
+ }
88
+ }
@@ -0,0 +1,163 @@
1
+ import { MouseEvent, useMemo, useState } from 'react';
2
+
3
+ import { CardBasic, CardInfo, CardProduct } from '@cloud-ru/uikit-product-site-cards';
4
+ import { Grid, GridProps } from '@cloud-ru/uikit-product-site-grid';
5
+ import { extractSupportProps, WithLayoutType, WithSupportProps } from '@cloud-ru/uikit-product-utils';
6
+ import { Typography } from '@snack-uikit/typography';
7
+
8
+ import { SectionButton, SectionTitleProps } from '../../helperComponents';
9
+ import { SectionButtonProps } from '../../helperComponents/SectionButton/types';
10
+ import { SectionColor } from '../../types';
11
+ import { SectionBasic } from '../SectionBasic';
12
+ import { CardNumeric } from './components';
13
+ import styles from './styles.module.scss';
14
+ import { ContentBasic, ContentInfo, ContentNumeric, ContentProduct } from './types';
15
+
16
+ export type SectionBenefitsProps = WithSupportProps<
17
+ WithLayoutType<{
18
+ /** id секции */
19
+ id?: string;
20
+ /** Название секции */
21
+ title?: string;
22
+ /** Название подзаголовка секции */
23
+ subtitle?: string;
24
+ /** Цвет фона секции */
25
+ backgroundColor?: SectionColor;
26
+ /** Тег заголовка */
27
+ titleTag?: SectionTitleProps['titleTag'];
28
+ /** Тег заголовка */
29
+ subtitleTag?: SectionTitleProps['subtitleTag'];
30
+ /** Описание секции */
31
+ description?: string;
32
+ /** Конфигурация настройки колонок для разных layoutType */
33
+ columnsConfig: GridProps['columnsConfig'];
34
+ /** Текст нижней сноски */
35
+ note?: string;
36
+
37
+ buttons?: SectionButtonProps[];
38
+ /**
39
+ * Выравнивание кнопок по горизонтали
40
+ * @default 'left'
41
+ */
42
+ buttonsAlign?: 'left' | 'center';
43
+ }>
44
+ > &
45
+ (ContentBasic | ContentInfo | ContentNumeric | ContentProduct);
46
+
47
+ export function SectionBenefits({
48
+ id,
49
+ title,
50
+ titleTag,
51
+ subtitle,
52
+ subtitleTag,
53
+ description,
54
+ type,
55
+ content,
56
+ tabBarItems,
57
+ columnsConfig,
58
+ layoutType,
59
+ buttons,
60
+ note,
61
+ backgroundColor,
62
+ buttonsAlign = 'left',
63
+ ...rest
64
+ }: SectionBenefitsProps) {
65
+ const [activeTab, setActiveTab] = useState(tabBarItems && tabBarItems[0].value);
66
+
67
+ const tabs = useMemo(
68
+ () =>
69
+ tabBarItems?.map(tab => ({
70
+ ...tab,
71
+ onClick: (e: MouseEvent<HTMLButtonElement>) => {
72
+ setActiveTab(tab.value);
73
+ tab.onClick?.(e);
74
+ },
75
+ })),
76
+ [tabBarItems],
77
+ );
78
+
79
+ const outline = (rest as ContentInfo).outline;
80
+ const gap = type === 'basic' ? 'l' : 's';
81
+ const backgroundColorSection = type === 'basic' || outline ? 'neutral-background1-level' : 'neutral-background';
82
+
83
+ return (
84
+ <SectionBasic
85
+ id={id}
86
+ title={title}
87
+ titleTag={titleTag}
88
+ subtitle={subtitle}
89
+ subtitleTag={subtitleTag}
90
+ description={description}
91
+ layoutType={layoutType}
92
+ backgroundColor={backgroundColor || backgroundColorSection}
93
+ tabBarItems={tabs}
94
+ {...extractSupportProps(rest)}
95
+ >
96
+ {!tabBarItems && (
97
+ <Grid layoutType={layoutType} columnsConfig={columnsConfig} gap={gap}>
98
+ {type === 'info' &&
99
+ content.map((item, index) => <CardInfo key={index} {...item} outline={outline} layoutType={layoutType} />)}
100
+
101
+ {type === 'numeric' &&
102
+ content.map((item, index) => (
103
+ <CardNumeric key={index} {...item} number={index + 1} layoutType={layoutType} />
104
+ ))}
105
+
106
+ {type === 'product' &&
107
+ content.map((item, index) => <CardProduct key={index} {...item} layoutType={layoutType} />)}
108
+
109
+ {type === 'basic' &&
110
+ content.map((item, index) => <CardBasic key={index} {...item} layoutType={layoutType} />)}
111
+ </Grid>
112
+ )}
113
+
114
+ {tabBarItems && (
115
+ <Grid layoutType={layoutType} columnsConfig={columnsConfig} gap={gap}>
116
+ {type === 'info' &&
117
+ content
118
+ .filter(({ tabValue }) => tabValue === activeTab)
119
+ .map(({ cards }) =>
120
+ cards.map((card, index) => (
121
+ <CardInfo key={index} layoutType={layoutType} {...card} outline={outline} />
122
+ )),
123
+ )}
124
+
125
+ {type === 'numeric' &&
126
+ content
127
+ .filter(({ tabValue }) => tabValue === activeTab)
128
+ .map(({ cards }) =>
129
+ cards.map((card, index) => (
130
+ <CardNumeric key={index} layoutType={layoutType} {...card} number={index + 1} />
131
+ )),
132
+ )}
133
+
134
+ {type === 'product' &&
135
+ content
136
+ .filter(({ tabValue }) => tabValue === activeTab)
137
+ .map(({ cards }) =>
138
+ cards.map((card, index) => <CardProduct key={index} layoutType={layoutType} {...card} />),
139
+ )}
140
+
141
+ {type === 'basic' &&
142
+ content
143
+ .filter(({ tabValue }) => tabValue === activeTab)
144
+ .map(({ cards }) =>
145
+ cards.map((card, index) => <CardBasic key={index} layoutType={layoutType} {...card} />),
146
+ )}
147
+ </Grid>
148
+ )}
149
+
150
+ {note && (
151
+ <Typography.SansBodyM className={styles.note}>
152
+ <span dangerouslySetInnerHTML={{ __html: note }} />
153
+ </Typography.SansBodyM>
154
+ )}
155
+
156
+ {buttons && (
157
+ <div className={styles.buttons} data-buttons-align={buttonsAlign}>
158
+ {buttons.map(button => SectionButton(button))}
159
+ </div>
160
+ )}
161
+ </SectionBasic>
162
+ );
163
+ }
@@ -0,0 +1,17 @@
1
+ import { CardInfo, CardInfoProps } from '@cloud-ru/uikit-product-site-cards';
2
+ import { Typography } from '@snack-uikit/typography';
3
+
4
+ import styles from './styles.module.scss';
5
+
6
+ type CardNumericProps = Omit<CardInfoProps, 'icon'> & {
7
+ number: number;
8
+ };
9
+
10
+ export function CardNumeric({ number, ...props }: CardNumericProps) {
11
+ return (
12
+ <CardInfo
13
+ {...props}
14
+ icon={<Typography.SansHeadlineM className={styles.number}>{number}</Typography.SansHeadlineM>}
15
+ />
16
+ );
17
+ }
@@ -0,0 +1 @@
1
+ export * from './CardNumeric';
@@ -0,0 +1,6 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as var;
2
+
3
+ .number {
4
+ color: var.$sys-neutral-text-main;
5
+ min-width: 20px;
6
+ }
@@ -0,0 +1 @@
1
+ export * from './CardNumeric';
@@ -0,0 +1 @@
1
+ export * from './SectionBenefits';
@@ -0,0 +1,15 @@
1
+ @use '@sbercloud/figma-tokens-cloud-platform/build/scss/styles-theme-variables' as ste;
2
+
3
+ .buttons {
4
+ display: flex;
5
+ flex-wrap: wrap;
6
+ gap: 8px;
7
+
8
+ &[data-buttons-align='center'] {
9
+ justify-content: center;
10
+ }
11
+ }
12
+
13
+ .note {
14
+ color: ste.$sys-neutral-text-support;
15
+ }