diff --git a/src/blocks/CardLayout/CardLayout.scss b/src/blocks/CardLayout/CardLayout.scss index 5e72b3b5f..71d05ab37 100644 --- a/src/blocks/CardLayout/CardLayout.scss +++ b/src/blocks/CardLayout/CardLayout.scss @@ -8,5 +8,28 @@ $block: '.#{$ns}card-layout-block'; margin-top: $indentSM; } + &__content { + position: relative; + + &_with-background { + padding: $indentXXXS $indentM $indentL; + margin-top: $indentSM; + } + } + + &__image { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 40px; + + img { + object-fit: cover; + object-position: left; + } + } + @include animate-slides(#{$block}__item); } diff --git a/src/blocks/CardLayout/CardLayout.tsx b/src/blocks/CardLayout/CardLayout.tsx index 8d7fdbae3..ef35acf4a 100644 --- a/src/blocks/CardLayout/CardLayout.tsx +++ b/src/blocks/CardLayout/CardLayout.tsx @@ -1,6 +1,8 @@ import React from 'react'; -import {AnimateBlock, Title} from '../../components'; +import isEmpty from 'lodash/isEmpty'; + +import {AnimateBlock, BackgroundImage, Title} from '../../components'; import {Col, GridColumnSizesType, Row} from '../../grid'; import { CardLayoutBlockProps as CardLayoutBlockParams, @@ -29,19 +31,29 @@ const CardLayout: React.FC = ({ children, className, titleClassName, -}) => ( - - {(title || description) && ( - - )} - <Row> - {React.Children.map(children, (child, index) => ( - <Col key={index} sizes={colSizes} className={b('item')}> - {child} - </Col> - ))} - </Row> - </AnimateBlock> -); + background, +}) => { + return ( + <AnimateBlock className={b(null, className)} animate={animated}> + {(title || description) && ( + <Title title={title} subtitle={description} className={titleClassName} /> + )} + <div + className={b('content', { + 'with-background': !isEmpty(background), + })} + > + <BackgroundImage className={b('image')} {...background} /> + <Row> + {React.Children.map(children, (child, index) => ( + <Col key={index} sizes={colSizes} className={b('item')}> + {child} + </Col> + ))} + </Row> + </div> + </AnimateBlock> + ); +}; export default CardLayout; diff --git a/src/blocks/CardLayout/__stories__/CardLayout.mdx b/src/blocks/CardLayout/__stories__/CardLayout.mdx index ad3ca1ef8..9ce23bd7a 100644 --- a/src/blocks/CardLayout/__stories__/CardLayout.mdx +++ b/src/blocks/CardLayout/__stories__/CardLayout.mdx @@ -15,6 +15,8 @@ import * as CardLayoutStories from './CardLayout.stories.tsx'; `colSizes?: Object` — more info [here](?path=/docs/documentation-types--docs#colsizes). +`background?: BackgroundImage` — See [background](?path=/story/components-pics-video-datalens-backgroundimage--docs&viewMode=docs) properties. + `children:[]` — You can add an array of any available cards here. The following blocks are currently supported: @@ -22,5 +24,6 @@ The following blocks are currently supported: - [`BasicCard` — Basic card](?path=/story/components-cards-basiccard--default&viewMode=docs) - [`Price Detailed` — Pricing](?path=/story/components-cards-pricedetailed--marked-list&viewMode=docs) - [`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) </StoryTemplate> diff --git a/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx b/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx index e7571db01..9c12b970a 100644 --- a/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx +++ b/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx @@ -3,13 +3,7 @@ import React, {Fragment} from 'react'; import {Meta, StoryFn} from '@storybook/react'; import {PageConstructor} from '../../../containers/PageConstructor'; -import { - CardLayoutBlockModel, - CardLayoutBlockProps, - LayoutItemModel, - LayoutItemProps, - SubBlockModels, -} from '../../../models'; +import {CardLayoutBlockModel, CardLayoutBlockProps, SubBlockModels} from '../../../models'; import CardLayout from '../CardLayout'; import data from './data.json'; @@ -19,13 +13,72 @@ export default { component: CardLayout, } as Meta; -const createCardArray: (count: number, shared: LayoutItemProps) => SubBlockModels[] = ( - count, - shared, -) => Array.from({length: count}, () => ({...shared} as LayoutItemModel)); +const createCardArray: ( + count: number, + shared: Omit<SubBlockModels, 'type'> & {type: string}, +) => SubBlockModels[] = (count, shared) => + Array.from({length: count}, () => ({...shared} as SubBlockModels)); const DefaultTemplate: StoryFn<CardLayoutBlockModel> = (args) => ( - <PageConstructor content={{blocks: [args]}} /> + <PageConstructor + content={{ + blocks: [ + { + ...args, + children: createCardArray(6, data.cards.basicCard), + }, + { + ...args, + title: 'Card layout with layout items', + children: createCardArray(3, data.cards.layoutItem), + }, + { + ...args, + title: 'Card layout with background cards', + children: createCardArray(3, data.cards.backgroundCard), + }, + { + ...args, + title: 'Card layout with price cards', + children: [ + { + ...data.cards.priceCard, + buttons: [ + { + text: 'Button', + url: 'https://example.com', + width: 'max', + theme: 'outlined', + }, + ], + }, + { + ...data.cards.priceCard, + buttons: [ + { + text: 'Button', + url: 'https://example.com', + width: 'max', + theme: 'action', + }, + ], + }, + { + ...data.cards.priceCard, + buttons: [ + { + text: 'Button', + url: 'https://example.com', + width: 'max', + theme: 'monochrome', + }, + ], + }, + ], + }, + ], + }} + /> ); const ColSizeTemplate: StoryFn<CardLayoutBlockModel> = (args) => ( @@ -109,13 +162,66 @@ const WithCustomIndentsTemplate: StoryFn<CardLayoutBlockModel> = ({title, ...res </Fragment> ); +const WithBackgroundTemplate: StoryFn<CardLayoutBlockModel> = (args) => ( + <PageConstructor + content={{ + blocks: [ + { + ...args, + background: { + src: 'https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/content-bg-img_light.png', + disableCompress: true, + }, + children: createCardArray(8, data.cards.basicCard), + }, + { + ...args, + title: 'Card layout with background color (basic cards)', + background: { + style: { + backgroundColor: '#EEF2F8', + }, + }, + children: createCardArray(4, data.cards.basicCard), + }, + { + ...args, + background: { + style: { + backgroundColor: '#7CCEA0', + }, + }, + title: 'Card layout with background color and shadow (layout items)', + description: + 'Three cards in a row on the desktop, three cards in a row on a tablet, one card in a row on a mobile phone.', + colSizes: { + all: 12, + sm: 4, + md: 4, + }, + children: createCardArray(3, data.cards.layoutItem), + }, + { + ...args, + title: 'Card layout with background image (price cards)', + background: { + src: 'https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/content-bg-img_light.png', + disableCompress: true, + }, + children: createCardArray(4, data.cards.priceCard), + }, + ], + }} + /> +); + export const Default = DefaultTemplate.bind({}); export const ColSize = ColSizeTemplate.bind({}); export const WithCustomIndents = WithCustomIndentsTemplate.bind({}); +export const WithBackground = WithBackgroundTemplate.bind({}); Default.args = { ...data.default.content, - children: createCardArray(6, data.default.card), } as CardLayoutBlockProps; ColSize.args = { @@ -125,5 +231,9 @@ ColSize.args = { WithCustomIndents.args = { ...data.default.content, - children: createCardArray(3, data.default.card), + children: createCardArray(3, data.cards.layoutItem), +} as CardLayoutBlockProps; + +WithBackground.args = { + ...data.withBackground.content, } as CardLayoutBlockProps; diff --git a/src/blocks/CardLayout/__stories__/data.json b/src/blocks/CardLayout/__stories__/data.json index 0fc457535..d4526dcd2 100644 --- a/src/blocks/CardLayout/__stories__/data.json +++ b/src/blocks/CardLayout/__stories__/data.json @@ -1,18 +1,54 @@ { - "default": { - "card": { + "cards": { + "basicCard": { + "type": "basic-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.", + "icon": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/icon_1_light.svg" + }, + "layoutItem": { "type": "layout-item", "media": { "image": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-mini_4-12_light.png" }, "content": { - "title": "Lorem ipsum", - "text": "Dolor sit amet" + "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." + } + }, + "backgroundCard": { + "type": "background-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.", + "background": { + "light": { + "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-bg_nopadding_4-12_light.png", + "alt": "Lorem ipsumt", + "disableCompress": true + }, + "dark": { + "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-bg_nopadding_4-12_dark.png", + "alt": "Lorem ipsumt" + } } }, + "priceCard": { + "type": "price-card", + "title": "Lorem ipsum", + "price": "299.99 $", + "pricePeriod": "month", + "priceDetails": "plan details", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", + "list": [ + "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." + ] + } + }, + "default": { "content": { "type": "card-layout-block", - "title": "Card Layout", + "title": "Card layout with basic cards", "description": "Three cards in a row on the desktop, two cards in a row on a tablet, one card in a row on a mobile phone." } }, @@ -51,5 +87,18 @@ "all": 6 } } + }, + "withBackground": { + "content": { + "type": "card-layout-block", + "title": "Card layout with background image (basic cards)", + "description": "Four cards in a row on the desktop, three cards in a row on the mini-desktop, two cards in a row on a tablet, one card in a row on a mobile phone.", + "colSizes": { + "all": 12, + "sm": 6, + "md": 4, + "lg": 3 + } + } } } diff --git a/src/blocks/CardLayout/schema.ts b/src/blocks/CardLayout/schema.ts index 21984cd97..6b09c8c1a 100644 --- a/src/blocks/CardLayout/schema.ts +++ b/src/blocks/CardLayout/schema.ts @@ -1,3 +1,4 @@ +import {ImageObjectProps} from '../../components/Image/schema'; import { AnimatableProps, BlockBaseProps, @@ -14,6 +15,7 @@ export const CardLayoutProps = { ...AnimatableProps, ...BlockHeaderProps, colSizes: containerSizesObject, + background: ImageObjectProps, children: ChildrenCardsProps, }, }; diff --git a/src/models/constructor-items/blocks.ts b/src/models/constructor-items/blocks.ts index 181863704..645ae817f 100644 --- a/src/models/constructor-items/blocks.ts +++ b/src/models/constructor-items/blocks.ts @@ -305,6 +305,7 @@ export interface CardLayoutBlockProps extends Childable, Animatable, LoadableChi titleClassName?: string; description?: string; colSizes?: GridColumnSizesType; + background?: BackgroundImageProps; } export type FilterTag = {