Skip to content

Commit

Permalink
feat: add PriceCard (#697)
Browse files Browse the repository at this point in the history
* feat: add price-card

* feat: made content-list a separate component
  • Loading branch information
qradle-yndx authored Nov 20, 2023
1 parent 77286c5 commit 527a335
Show file tree
Hide file tree
Showing 22 changed files with 632 additions and 38 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
@import '../../../../styles/variables.scss';
@import '../../../../styles/mixins.scss';
@import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss';

$block: '.#{$ns}content-list';
$iconSizeL: 22px;
$iconSizeS: 20px;
$iconSizeXS: 18px;
$marginIconSizeS: 2px;
$marginIconSizeL: 1px;

Expand All @@ -23,6 +24,14 @@ $marginIconSizeL: 1px;
margin-top: $marginIconSizeL;
margin-bottom: $marginIconSizeL;
margin-right: $indentXXS;

&_without_title {
width: $iconSizeS;
height: $iconSizeS;
margin-top: 0;
margin-bottom: 0;
margin-right: $indentXXXS;
}
}

#{$block}__item {
Expand All @@ -47,6 +56,13 @@ $marginIconSizeL: 1px;
margin-top: $marginIconSizeS;
margin-bottom: $marginIconSizeS;
margin-right: $indentXXXS;

&_without_title {
width: $iconSizeXS;
height: $iconSizeXS;
margin-top: 0;
margin-bottom: 0;
}
}

#{$block}__text {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,13 @@ import React from 'react';

import {v4 as uuidv4} from 'uuid';

import {YFMWrapper} from '../../../components';
import Image from '../../../components/Image/Image';
import {getMediaImage} from '../../../components/Media/Image/utils';
import {useTheme} from '../../../context/theme';
import {ContentItemProps, ContentSize} from '../../../models';
import {QAProps} from '../../../models/common';
import {block, getThemedValue} from '../../../utils';
import {getQaAttrubutes} from '../../../utils/blocks';
import {ContentListProps, ContentSize} from '../../models';
import {QAProps} from '../../models/common';
import {block} from '../../utils';
import {getQaAttrubutes} from '../../utils/blocks';
import YFMWrapper from '../YFMWrapper/YFMWrapper';

import ItemIcon from './ContentListItemIcon';

import './ContentList.scss';

Expand All @@ -25,25 +24,20 @@ function getHeadingLevel(size: ContentSize) {
}
}

interface ContentListProps {
list: ContentItemProps[];
size: ContentSize;
}

const ContentList = ({list, size, qa}: ContentListProps & QAProps) => {
const theme = useTheme();
const ContentList = ({list, size = 'l', qa}: ContentListProps & QAProps) => {
const qaAttributes = getQaAttrubutes(qa, ['image', 'title', 'text']);

return (
<div className={b({size})} data-qa={qa}>
{list?.map((item) => {
const {icon, title, text} = item;
const iconThemed = getThemedValue(icon, theme);
const iconData = getMediaImage(iconThemed);

return (
<div className={b('item')} key={uuidv4()}>
<Image {...iconData} className={b('icon')} qa={qaAttributes.image} />
<ItemIcon
icon={icon}
className={b('icon', {without_title: !title})}
qa={qaAttributes.image}
/>
<div>
{title &&
React.createElement(
Expand Down
33 changes: 33 additions & 0 deletions src/components/ContentList/ContentListItemIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';

import {useTheme} from '../../context/theme';
import {ClassNameProps, ImageProps, QAProps, SVGIcon} from '../../models';
import {ThemeSupporting, getThemedValue} from '../../utils';
import Image from '../Image/Image';
import {getMediaImage} from '../Media/Image/utils';

interface ListItemProps extends QAProps, ClassNameProps {
icon: ThemeSupporting<ImageProps | SVGIcon>;
}

function isIconSvg(icon: ImageProps | SVGIcon): icon is SVGIcon {
return typeof icon === 'function';
}

const ContentListItemIcon = ({icon, className, qa}: ListItemProps) => {
const theme = useTheme();
const iconThemed = getThemedValue(icon, theme);

if (isIconSvg(iconThemed)) {
const Icon = iconThemed;
return (
<div>
<Icon className={className} />
</div>
);
}
const iconData = getMediaImage(iconThemed);
return <Image {...iconData} className={className} qa={qa} />;
};

export default ContentListItemIcon;
16 changes: 16 additions & 0 deletions src/components/ContentList/__stories__/ContentList.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import {Meta} from '@storybook/blocks';

import {StoryTemplate} from '../../../demo/StoryTemplate.mdx';
import * as ContentListStories from './ContentList.stories.tsx';

<Meta of={ContentListStories} />
<StoryTemplate>
## Parameters

- `size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default)

`list: Array` - An Array of items with icon
- [`icon: string | ImageObjectProps | ReactNode` — Icon](?path=/docs/documentation-types--docs#imageobjectprops---image-property).
- `title?: string` — Title.
- `text?: string` — Text (with YFM support)
</StoryTemplate>
37 changes: 37 additions & 0 deletions src/components/ContentList/__stories__/ContentList.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from 'react';

import {Meta, StoryFn} from '@storybook/react';

import {yfmTransform} from '../../../../.storybook/utils';
import {ContentItemProps, ContentListProps} from '../../../models';
import ContentList from '../ContentList';

import data from './data.json';

const transformList = (item: ContentItemProps) => ({
...item,
text: item?.text && yfmTransform(item.text),
});

export default {
args: {list: data.default.content.map(transformList), size: 'l'},
component: ContentList,
title: 'Components/ContentList',
} as Meta;

const DefaultTemplate: StoryFn<ContentListProps> = (args) => (
<div style={{paddingBottom: '64px'}}>
<ContentList {...args} />
</div>
);

const DifferentSizeTemplate: StoryFn<ContentListProps> = (args) => (
<div>
<h2>Size L</h2>
<DefaultTemplate {...args} size="l" />
<h2>Size S</h2>
<DefaultTemplate {...args} size="s" />
</div>
);
export const Default = DefaultTemplate.bind({});
export const Size = DifferentSizeTemplate.bind({});
33 changes: 33 additions & 0 deletions src/components/ContentList/__stories__/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"centered": {
"content": {
"centered": true
}
},
"default": {
"content": [
{
"icon": {
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_1_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_1_dark.svg"
},
"title": "Default",
"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."
},
{
"icon": {
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_dark.svg"
},
"title": "With title only"
},
{
"icon": {
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_dark.svg"
},
"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."
}
]
}
}
2 changes: 1 addition & 1 deletion src/components/FileLink/FileLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export enum FileExtension {
}

export function getFileExt(name: string) {
if (name.includes(FIGMA_URL)) {
if (name?.includes(FIGMA_URL)) {
return FileExtension.FIG;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
Expand Down
1 change: 0 additions & 1 deletion src/components/Link/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,6 @@ const LinkBlock = (props: WithChildren<LinkFullProps>) => {
return null;
}
};

return (
<div className={b({size: textSize || defaultTextSize}, className)}>{getLinkByType()}</div>
);
Expand Down
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {default as RouterLink} from './RouterLink/RouterLink';
export {default as HTML} from './HTML/HTML';
export {default as MetaInfo} from './MetaInfo/MetaInfo';
export {default as FullscreenMedia} from './FullscreenMedia/FullscreenMedia';
export {default as ContentList} from './ContentList/ContentList';

export type {RouterLinkProps} from './RouterLink/RouterLink';
export type {ImageBaseProps} from './ImageBase/ImageBase';
10 changes: 9 additions & 1 deletion src/models/constructor-items/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
HeaderOffset,
HeaderWidth,
ImageDeviceProps,
ImageProps,
Justify,
LegendTableMarkerType,
LinkProps,
Expand Down Expand Up @@ -348,10 +349,17 @@ export interface ContentLayoutBlockProps extends ContentLayoutBlockParams {
fileContent?: FileLinkProps[];
}

export type SVGIcon = React.FC<React.SVGProps<SVGSVGElement>>;

export interface ContentItemProps {
title?: string;
text?: string;
icon: ThemedImage;
icon: ThemeSupporting<ImageProps | SVGIcon>;
}

export interface ContentListProps {
list: ContentItemProps[];
size: ContentSize;
}

export interface ContentBlockProps {
Expand Down
14 changes: 14 additions & 0 deletions src/models/constructor-items/sub-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
DividerSize,
ImageObjectProps,
ImageProps,
LinkProps,
MediaProps,
PriceDetailedProps,
TextTheme,
Expand All @@ -38,6 +39,7 @@ export enum SubBlockType {
* @deprecated Will be removed, use BasicCard instead
*/
Card = 'card',
PriceCard = 'price-card',
}

export enum IconPosition {
Expand Down Expand Up @@ -134,6 +136,18 @@ export interface BannerCardProps {

export interface MediaCardProps extends MediaProps, AnalyticsEventsBase, CardBaseProps {}

export interface PriceCardProps extends CardBaseProps, Pick<ContentBlockProps, 'theme'> {
title: string;
price: string;
pricePeriod?: string;
priceDetails?: string;
description?: string;
buttons?: ButtonProps[];
links?: LinkProps[];
backgroundColor?: string;
list?: string[];
}

export interface LayoutItemProps extends ClassNameProps, AnalyticsEventsBase {
content: Omit<ContentBlockProps, 'colSizes' | 'centered' | 'size'>;
media: MediaProps;
Expand Down
1 change: 1 addition & 0 deletions src/schema/validators/sub-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export * from '../../sub-blocks/LayoutItem/schema';
export * from '../../sub-blocks/Quote/schema';
export * from '../../sub-blocks/Divider/schema';
export * from '../../sub-blocks/BasicCard/schema';
export * from '../../sub-blocks/PriceCard/schema';
5 changes: 1 addition & 4 deletions src/sub-blocks/Content/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,13 @@ import React from 'react';

import {useUniqId} from '@gravity-ui/uikit';

import {Button, Title, YFMWrapper} from '../../components';
import LinkBlock from '../../components/Link/Link';
import {Button, ContentList, Link as LinkBlock, Title, YFMWrapper} from '../../components';
import {Col} from '../../grid';
import {ClassNameProps, ContentBlockProps, ContentSize, TitleItemProps} from '../../models';
import {QAProps} from '../../models/common';
import {block} from '../../utils';
import {getQaAttrubutes} from '../../utils/blocks';

import ContentList from './ContentList/ContentList';

import './Content.scss';

const b = block('content');
Expand Down
5 changes: 1 addition & 4 deletions src/sub-blocks/Content/__stories__/Content.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,5 @@ import * as ContentStories from './Content.stories.tsx';
- `lg: number` — On a screen wider than 1081px.
- `xl: number` — On a screen wider than 1185px.

`list: Array` - An Array of items with icon
- [`icon: string | ImageObjectProps` — Icon](?path=/docs/documentation-types--docs#imageobjectprops---image-property).
- `title?: string` — Title.
- `text?: string` — Text (with YFM support)
`list: Array` - An Array of items with icon - [ContentList](?path=/story/components-contentlist--docs&viewMode=docs)
</StoryTemplate>
12 changes: 6 additions & 6 deletions src/sub-blocks/Content/__stories__/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,17 @@
},
{
"icon": {
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_dark.svg"
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_dark.svg"
},
"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."
"title": "Lorem ipsum ipsum"
},
{
"icon": {
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_3_dark.svg"
"light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_light.svg",
"dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_2_dark.svg"
},
"title": "Lorem ipsum ipsum"
"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."
}
]
}
Expand Down
Loading

0 comments on commit 527a335

Please sign in to comment.