Skip to content

Commit 527a335

Browse files
authored
feat: add PriceCard (#697)
* feat: add price-card * feat: made content-list a separate component
1 parent 77286c5 commit 527a335

File tree

22 files changed

+632
-38
lines changed

22 files changed

+632
-38
lines changed

src/sub-blocks/Content/ContentList/ContentList.scss renamed to src/components/ContentList/ContentList.scss

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
@import '../../../../styles/variables.scss';
2-
@import '../../../../styles/mixins.scss';
1+
@import '../../../styles/variables.scss';
2+
@import '../../../styles/mixins.scss';
33

44
$block: '.#{$ns}content-list';
55
$iconSizeL: 22px;
66
$iconSizeS: 20px;
7+
$iconSizeXS: 18px;
78
$marginIconSizeS: 2px;
89
$marginIconSizeL: 1px;
910

@@ -23,6 +24,14 @@ $marginIconSizeL: 1px;
2324
margin-top: $marginIconSizeL;
2425
margin-bottom: $marginIconSizeL;
2526
margin-right: $indentXXS;
27+
28+
&_without_title {
29+
width: $iconSizeS;
30+
height: $iconSizeS;
31+
margin-top: 0;
32+
margin-bottom: 0;
33+
margin-right: $indentXXXS;
34+
}
2635
}
2736

2837
#{$block}__item {
@@ -47,6 +56,13 @@ $marginIconSizeL: 1px;
4756
margin-top: $marginIconSizeS;
4857
margin-bottom: $marginIconSizeS;
4958
margin-right: $indentXXXS;
59+
60+
&_without_title {
61+
width: $iconSizeXS;
62+
height: $iconSizeXS;
63+
margin-top: 0;
64+
margin-bottom: 0;
65+
}
5066
}
5167

5268
#{$block}__text {

src/sub-blocks/Content/ContentList/ContentList.tsx renamed to src/components/ContentList/ContentList.tsx

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@ import React from 'react';
22

33
import {v4 as uuidv4} from 'uuid';
44

5-
import {YFMWrapper} from '../../../components';
6-
import Image from '../../../components/Image/Image';
7-
import {getMediaImage} from '../../../components/Media/Image/utils';
8-
import {useTheme} from '../../../context/theme';
9-
import {ContentItemProps, ContentSize} from '../../../models';
10-
import {QAProps} from '../../../models/common';
11-
import {block, getThemedValue} from '../../../utils';
12-
import {getQaAttrubutes} from '../../../utils/blocks';
5+
import {ContentListProps, ContentSize} from '../../models';
6+
import {QAProps} from '../../models/common';
7+
import {block} from '../../utils';
8+
import {getQaAttrubutes} from '../../utils/blocks';
9+
import YFMWrapper from '../YFMWrapper/YFMWrapper';
10+
11+
import ItemIcon from './ContentListItemIcon';
1312

1413
import './ContentList.scss';
1514

@@ -25,25 +24,20 @@ function getHeadingLevel(size: ContentSize) {
2524
}
2625
}
2726

28-
interface ContentListProps {
29-
list: ContentItemProps[];
30-
size: ContentSize;
31-
}
32-
33-
const ContentList = ({list, size, qa}: ContentListProps & QAProps) => {
34-
const theme = useTheme();
27+
const ContentList = ({list, size = 'l', qa}: ContentListProps & QAProps) => {
3528
const qaAttributes = getQaAttrubutes(qa, ['image', 'title', 'text']);
3629

3730
return (
3831
<div className={b({size})} data-qa={qa}>
3932
{list?.map((item) => {
4033
const {icon, title, text} = item;
41-
const iconThemed = getThemedValue(icon, theme);
42-
const iconData = getMediaImage(iconThemed);
43-
4434
return (
4535
<div className={b('item')} key={uuidv4()}>
46-
<Image {...iconData} className={b('icon')} qa={qaAttributes.image} />
36+
<ItemIcon
37+
icon={icon}
38+
className={b('icon', {without_title: !title})}
39+
qa={qaAttributes.image}
40+
/>
4741
<div>
4842
{title &&
4943
React.createElement(
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import React from 'react';
2+
3+
import {useTheme} from '../../context/theme';
4+
import {ClassNameProps, ImageProps, QAProps, SVGIcon} from '../../models';
5+
import {ThemeSupporting, getThemedValue} from '../../utils';
6+
import Image from '../Image/Image';
7+
import {getMediaImage} from '../Media/Image/utils';
8+
9+
interface ListItemProps extends QAProps, ClassNameProps {
10+
icon: ThemeSupporting<ImageProps | SVGIcon>;
11+
}
12+
13+
function isIconSvg(icon: ImageProps | SVGIcon): icon is SVGIcon {
14+
return typeof icon === 'function';
15+
}
16+
17+
const ContentListItemIcon = ({icon, className, qa}: ListItemProps) => {
18+
const theme = useTheme();
19+
const iconThemed = getThemedValue(icon, theme);
20+
21+
if (isIconSvg(iconThemed)) {
22+
const Icon = iconThemed;
23+
return (
24+
<div>
25+
<Icon className={className} />
26+
</div>
27+
);
28+
}
29+
const iconData = getMediaImage(iconThemed);
30+
return <Image {...iconData} className={className} qa={qa} />;
31+
};
32+
33+
export default ContentListItemIcon;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import {Meta} from '@storybook/blocks';
2+
3+
import {StoryTemplate} from '../../../demo/StoryTemplate.mdx';
4+
import * as ContentListStories from './ContentList.stories.tsx';
5+
6+
<Meta of={ContentListStories} />
7+
<StoryTemplate>
8+
## Parameters
9+
10+
- `size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)
11+
12+
`list: Array` - An Array of items with icon
13+
- [`icon: string | ImageObjectProps | ReactNode` — Icon](?path=/docs/documentation-types--docs#imageobjectprops---image-property).
14+
- `title?: string` — Title.
15+
- `text?: string` — Text (with YFM support)
16+
</StoryTemplate>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import React from 'react';
2+
3+
import {Meta, StoryFn} from '@storybook/react';
4+
5+
import {yfmTransform} from '../../../../.storybook/utils';
6+
import {ContentItemProps, ContentListProps} from '../../../models';
7+
import ContentList from '../ContentList';
8+
9+
import data from './data.json';
10+
11+
const transformList = (item: ContentItemProps) => ({
12+
...item,
13+
text: item?.text && yfmTransform(item.text),
14+
});
15+
16+
export default {
17+
args: {list: data.default.content.map(transformList), size: 'l'},
18+
component: ContentList,
19+
title: 'Components/ContentList',
20+
} as Meta;
21+
22+
const DefaultTemplate: StoryFn<ContentListProps> = (args) => (
23+
<div style={{paddingBottom: '64px'}}>
24+
<ContentList {...args} />
25+
</div>
26+
);
27+
28+
const DifferentSizeTemplate: StoryFn<ContentListProps> = (args) => (
29+
<div>
30+
<h2>Size L</h2>
31+
<DefaultTemplate {...args} size="l" />
32+
<h2>Size S</h2>
33+
<DefaultTemplate {...args} size="s" />
34+
</div>
35+
);
36+
export const Default = DefaultTemplate.bind({});
37+
export const Size = DifferentSizeTemplate.bind({});
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"centered": {
3+
"content": {
4+
"centered": true
5+
}
6+
},
7+
"default": {
8+
"content": [
9+
{
10+
"icon": {
11+
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_1_light.svg",
12+
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_1_dark.svg"
13+
},
14+
"title": "Default",
15+
"text": "**Ut enim ad minim veniam** [quis nostrud](https://example.com) exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
16+
},
17+
{
18+
"icon": {
19+
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_light.svg",
20+
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_dark.svg"
21+
},
22+
"title": "With title only"
23+
},
24+
{
25+
"icon": {
26+
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_light.svg",
27+
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_dark.svg"
28+
},
29+
"text": "With text only. **Ut enim ad minim veniam** [quis nostrud](https://example.com) exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
30+
}
31+
]
32+
}
33+
}

src/components/FileLink/FileLink.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export enum FileExtension {
2222
}
2323

2424
export function getFileExt(name: string) {
25-
if (name.includes(FIGMA_URL)) {
25+
if (name?.includes(FIGMA_URL)) {
2626
return FileExtension.FIG;
2727
}
2828
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion

src/components/Link/Link.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,6 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
134134
return null;
135135
}
136136
};
137-
138137
return (
139138
<div className={b({size: textSize || defaultTextSize}, className)}>{getLinkByType()}</div>
140139
);

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export {default as RouterLink} from './RouterLink/RouterLink';
3434
export {default as HTML} from './HTML/HTML';
3535
export {default as MetaInfo} from './MetaInfo/MetaInfo';
3636
export {default as FullscreenMedia} from './FullscreenMedia/FullscreenMedia';
37+
export {default as ContentList} from './ContentList/ContentList';
3738

3839
export type {RouterLinkProps} from './RouterLink/RouterLink';
3940
export type {ImageBaseProps} from './ImageBase/ImageBase';

src/models/constructor-items/blocks.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
HeaderOffset,
2121
HeaderWidth,
2222
ImageDeviceProps,
23+
ImageProps,
2324
Justify,
2425
LegendTableMarkerType,
2526
LinkProps,
@@ -348,10 +349,17 @@ export interface ContentLayoutBlockProps extends ContentLayoutBlockParams {
348349
fileContent?: FileLinkProps[];
349350
}
350351

352+
export type SVGIcon = React.FC<React.SVGProps<SVGSVGElement>>;
353+
351354
export interface ContentItemProps {
352355
title?: string;
353356
text?: string;
354-
icon: ThemedImage;
357+
icon: ThemeSupporting<ImageProps | SVGIcon>;
358+
}
359+
360+
export interface ContentListProps {
361+
list: ContentItemProps[];
362+
size: ContentSize;
355363
}
356364

357365
export interface ContentBlockProps {

0 commit comments

Comments
 (0)