Skip to content

Commit

Permalink
feat: add image card sub-block
Browse files Browse the repository at this point in the history
  • Loading branch information
qradle-yndx committed Feb 9, 2024
1 parent b2ecf4a commit 605c7db
Show file tree
Hide file tree
Showing 13 changed files with 269 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/blocks/CardLayout/__stories__/CardLayout.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,5 @@ The following blocks are currently supported:
- [`BackgroundCard` — Background card](?path=/story/components-cards-backgroundcard--default&viewMode=docs)
- [`PriceCard` — Price card](?path=/story/components-cards-pricecard--default&viewMode=docs)
- [`LayoutItem` — Component part of `Layout` component, consists with `Media` and `Content`](?path=/story/components-cards-layoutitem--default&viewMode=docs)
- [`ImageCard` — Image card](?path=/story/components-cards-imagecard--default&viewMode=docs)
</StoryTemplate>
5 changes: 5 additions & 0 deletions src/blocks/CardLayout/__stories__/CardLayout.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ const DefaultTemplate: StoryFn<CardLayoutBlockModel> = (args) => (
},
],
},
{
...args,
title: 'Card layout with image cards',
children: createCardArray(3, data.cards.imageCard),
},
],
}}
/>
Expand Down
6 changes: 6 additions & 0 deletions src/blocks/CardLayout/__stories__/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@
"Ut enim ad minim veniam exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.",
"Ut enim ad minim veniam exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
]
},
"imageCard": {
"type": "image-card",
"title": "Tell a story and build a narrative",
"text": "We are all storytellers. Stories are a powerful way to communicate ideas and share information. The right story can lead to a better understanding of a situation, make us laugh, or even inspire us to do something in the future.",
"image": "/story-assets/img_8-12_light.png"
}
},
"buttons": {
Expand Down
2 changes: 2 additions & 0 deletions src/constructor-items.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import {
BasicCard,
Content,
Divider,
ImageCard,
LayoutItem,
MediaCard,
PriceCard,
Expand Down Expand Up @@ -73,6 +74,7 @@ export const subBlockMap = {
[SubBlockType.Content]: Content,
[SubBlockType.Quote]: Quote,
[SubBlockType.PriceCard]: PriceCard,
[SubBlockType.ImageCard]: ImageCard,
};

export const navItemMap = {
Expand Down
26 changes: 25 additions & 1 deletion src/models/constructor-items/sub-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,25 @@ export enum SubBlockType {
*/
Card = 'card',
PriceCard = 'price-card',
ImageCard = 'image-card',
}

export enum IconPosition {
Top = 'top',
Left = 'left',
}

export enum ImageCardMargins {
None = 'none',
Small = 's',
Medium = 'm',
}

export enum ImageCardDirection {
Direct = 'direct',
Reverse = 'reverse',
}

export const SubBlockTypes = Object.values(SubBlockType);

export interface DividerProps {
Expand Down Expand Up @@ -168,6 +180,13 @@ export interface LayoutItemProps extends ClassNameProps, AnalyticsEventsBase {
fullscreen?: boolean;
}

export interface ImageCardProps extends CardBaseProps, Pick<ContentBlockProps, 'title' | 'text'> {
image: ImageProps;
margins?: ImageCardMargins;
direction?: ImageCardDirection;
backgroundColor?: string;
}

// sub-block models
export type DividerModel = {
type: SubBlockType.Divider;
Expand Down Expand Up @@ -209,6 +228,10 @@ export type PriceCardModel = {
type: SubBlockType.PriceCard;
} & PriceCardProps;

export type ImageCardModel = {
type: SubBlockType.ImageCard;
} & ImageCardProps;

export type SubBlockModels =
| DividerModel
| QuoteModel
Expand All @@ -219,6 +242,7 @@ export type SubBlockModels =
| BannerCardModel
| BasicCardModel
| PriceCardModel
| LayoutItemModel;
| LayoutItemModel
| ImageCardModel;

export type SubBlock = SubBlockModels;
3 changes: 3 additions & 0 deletions src/schema/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
BackgroundCard,
BasicCard,
Divider,
ImageCard,
MediaCardBlock,
PriceCardBlock,
PriceDetailedBlock,
Expand Down Expand Up @@ -63,6 +64,7 @@ export const cardSchemas = {
...Quote,
...BasicCard,
...PriceCardBlock,
...ImageCard,
};

export const constructorBlockSchemaNames = [
Expand Down Expand Up @@ -102,4 +104,5 @@ export const constructorCardSchemaNames = [
'basic-card',
'layout-item',
'price-card',
'image-card',
];
1 change: 1 addition & 0 deletions src/schema/validators/sub-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from '../../sub-blocks/Divider/schema';
export * from '../../sub-blocks/BasicCard/schema';
export * from '../../sub-blocks/PriceCard/schema';
export * from '../../sub-blocks/HubspotForm/schema';
export * from '../../sub-blocks/ImageCard/schema';
48 changes: 48 additions & 0 deletions src/sub-blocks/ImageCard/ImageCard.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
@import '../../../styles/variables.scss';
@import '../../../styles/mixins';

$block: '.#{$ns}image-card';

$paddingS: 4px;

#{$block} {
@include card();
border-radius: $indentSM;

&__content {
padding: $indentSM $indentM $indentM $indentM;
}

$image: #{&}__image;

#{$image} {
&_inner {
width: 100%;
display: block;
}

&_margins {
&_s {
padding: $paddingS;

#{$image}_inner {
border-radius: $indentS;
}
}

&_m {
padding: $indentM;
}
}
}

&_with-content {
#{$image}_direction_direct {
padding-bottom: 0;
}

#{$image}_direction_reverse {
padding-top: 0;
}
}
}
63 changes: 63 additions & 0 deletions src/sub-blocks/ImageCard/ImageCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import React from 'react';

import {Image} from '../../components';
import {getMediaImage} from '../../components/Media/Image/utils';
import {ImageCardDirection, ImageCardMargins, ImageCardProps} from '../../models';
import {block} from '../../utils';
import Content from '../Content/Content';

import './ImageCard.scss';

const b = block('image-card');

const ImageCard = (props: ImageCardProps) => {
const {
border = 'shadow',
title,
text,
image,
direction = ImageCardDirection.Direct,
margins = ImageCardMargins.None,
backgroundColor,
} = props;

const hasContent = Boolean(text || title);

const renderContent = () => {
if (!hasContent) {
return null;
}
return (
<div className={b('content')}>
<Content title={title} text={text} colSizes={{all: 12, md: 12}} size="s" />
</div>
);
};
const renderImage = () => {
const imageProps = getMediaImage(image);
return (
<div className={b('image', {margins, direction})}>
<Image className={b('image_inner')} {...imageProps} />
</div>
);
};

return (
<div className={b({border, 'with-content': hasContent})} style={{backgroundColor}}>
{direction === ImageCardDirection.Direct && (
<React.Fragment>
{renderImage()}
{renderContent()}
</React.Fragment>
)}
{direction === ImageCardDirection.Reverse && (
<React.Fragment>
{renderContent()}
{renderImage()}
</React.Fragment>
)}
</div>
);
};

export default ImageCard;
47 changes: 47 additions & 0 deletions src/sub-blocks/ImageCard/__stories__/ImageCard.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';

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

import {ImageCardProps} from '../../../models';
import ImageCard from '../ImageCard';

import data from './data.json';

export default {
component: ImageCard,
title: 'Components/Cards/ImageCard',
args: data.default.content,
argTypes: {
backgroundColor: {
control: {type: 'color'},
},
},
} as Meta;

const DefaultTemplate: StoryFn<ImageCardProps> = (args) => (
<div style={{width: 400, margin: 20}}>
<ImageCard {...args} />
</div>
);

const MultipleTemplate: StoryFn<ImageCardProps> = (args) => (
<div style={{display: 'flex', flexWrap: 'wrap', flexDirection: 'row'}}>
<div style={{width: 400, margin: 20}}>
<ImageCard {...args} {...(data.margins.none as Partial<ImageCardProps>)} />
</div>
<div style={{width: 400, margin: 20}}>
<ImageCard {...args} {...(data.margins.small as Partial<ImageCardProps>)} />
</div>
<div style={{width: 400, margin: 20}}>
<ImageCard {...args} {...(data.margins.medium as Partial<ImageCardProps>)} />
</div>
</div>
);

export const Default = DefaultTemplate.bind({});
export const Margins = MultipleTemplate.bind({});
export const DirectionReverse = MultipleTemplate.bind({});
export const BackgroundColor = MultipleTemplate.bind({});

DirectionReverse.args = {direction: 'reverse'} as Partial<ImageCardProps>;
BackgroundColor.args = {...data.backgroundColor.content};
36 changes: 36 additions & 0 deletions src/sub-blocks/ImageCard/__stories__/data.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"default": {
"content": {
"title": "Tell a story and build a narrative",
"text": "We are all storytellers. Stories are a powerful way to communicate ideas and share information. The right story can lead to a better understanding of a situation, make us laugh, or even inspire us to do something in the future.",
"image": "/story-assets/img_8-12_light.png",
"margins": "none",
"direction": "direct",
"border": "shadow"
}
},
"margins": {
"none": {
"margins": "none",
"title": "margins: 'none'"
},
"small": {
"margins": "s",
"title": "margins: 's'"
},
"medium": {
"margins": "m",
"title": "margins: 'm'"
}
},
"direction": {
"content": {
"direction": "reverse"
}
},
"backgroundColor": {
"content": {
"backgroundColor": "#ccf0d2"
}
}
}
31 changes: 31 additions & 0 deletions src/sub-blocks/ImageCard/schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pick from 'lodash/pick';

import {BaseProps, CardBase} from '../../schema/validators/common';
import {ImageProps} from '../../schema/validators/components';
import {ContentBase} from '../Content/schema';

const ImageCardBlockContentProps = pick(ContentBase, ['title', 'text']);

export const ImageCard = {
'image-card': {
additionalProperties: false,
required: ['image'],
properties: {
...BaseProps,
...CardBase,
...ImageCardBlockContentProps,
image: ImageProps,
direction: {
type: 'string',
enum: ['direct', 'reverse'],
},
margins: {
type: 'string',
enum: ['none', 's', 'm'],
},
backgroundColor: {
type: 'string',
},
},
},
};
1 change: 1 addition & 0 deletions src/sub-blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export {default as BasicCard} from './BasicCard/BasicCard';
export {default as Content} from './Content/Content';
export {default as HubspotForm} from './HubspotForm';
export {default as PriceCard} from './PriceCard/PriceCard';
export {default as ImageCard} from './ImageCard/ImageCard';

0 comments on commit 605c7db

Please sign in to comment.