Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add icon prop to LayoutItem #781

Merged
merged 3 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/components/IconWrapper/IconWrapper.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
@import '../../../styles/variables.scss';
@import '../../../styles/mixins.scss';

$block: '.#{$ns}icon-wrapper';

#{$block} {
$iconSizePositionTop: 32px;
$iconSizePositionLeft: 22px;

display: flex;
flex-direction: column;

&_icon-position {
&_left {
flex-direction: row;
}
}

&__icon {
max-width: 100%;
margin-bottom: $indentXXS;
height: $iconSizePositionTop;
object-fit: contain;
display: block;

&_icon-position {
&_left {
height: $iconSizePositionLeft;
width: $iconSizePositionLeft;
margin: 1px $indentXXS 1px 0px;
}
}
}

&_content {
&_left {
@include add-specificity(&) {
flex: 1 0 0;
}
}
}
}
31 changes: 31 additions & 0 deletions src/components/IconWrapper/IconWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import React, {Fragment, PropsWithChildren} from 'react';

import {IconWrapperProps} from '../../models';
import {block} from '../../utils';
import Image from '../Image/Image';
import {getMediaImage} from '../Media/Image/utils';

import './IconWrapper.scss';

const b = block('icon-wrapper');

const IconWrapper = (props: PropsWithChildren<IconWrapperProps>) => {
const {icon, children} = props;
if (!icon) {
return <Fragment>{children}</Fragment>;
}

const iconProps = getMediaImage(icon.value);
const iconPosition = icon?.position;

return (
<div className={b({['icon-position']: iconPosition})}>
{iconProps && (
<Image {...iconProps} className={b('icon', {['icon-position']: iconPosition})} />
)}
<div className={b({['content']: iconPosition})}>{children}</div>
</div>
);
};

export default IconWrapper;
1 change: 1 addition & 0 deletions src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export {default as MetaInfo} from './MetaInfo/MetaInfo';
export {default as FullscreenMedia} from './FullscreenMedia/FullscreenMedia';
export {default as ContentList} from './ContentList/ContentList';
export {default as InnerForm} from './InnerForm/InnerForm';
export {default as IconWrapper} from './IconWrapper/IconWrapper';

export type {RouterLinkProps} from './RouterLink/RouterLink';
export type {ImageBaseProps} from './ImageBase/ImageBase';
12 changes: 11 additions & 1 deletion src/models/constructor-items/sub-blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ export enum IconPosition {
Left = 'left',
}

export interface PositionedIcon {
value: ImageProps;
position?: IconPosition;
}

export interface IconWrapperProps {
icon?: PositionedIcon;
}

export const SubBlockTypes = Object.values(SubBlockType);

export interface DividerProps {
Expand Down Expand Up @@ -162,10 +171,11 @@ export interface PriceCardProps extends CardBaseProps, Pick<ContentBlockProps, '

export interface LayoutItemProps extends ClassNameProps, AnalyticsEventsBase {
content: Omit<ContentBlockProps, 'colSizes' | 'centered' | 'size'>;
media: MediaProps;
media?: MediaProps;
metaInfo?: string[];
border?: boolean;
fullscreen?: boolean;
icon?: PositionedIcon;
}

// sub-block models
Expand Down
38 changes: 0 additions & 38 deletions src/sub-blocks/BasicCard/BasicCard.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,7 @@
$block: '.#{$ns}basic-card';

#{$block} {
$iconSizePositionTop: 32px;
$iconSizePositionLeft: 22px;

@include add-specificity(&) {
min-height: auto;
}

&__icon {
max-width: 100%;
margin-bottom: $indentXXS;
height: $iconSizePositionTop;
object-fit: contain;
display: block;

&_icon-position {
&_left {
height: $iconSizePositionLeft;
width: $iconSizePositionLeft;
margin: 1px $indentXXS 1px 0px;
}
}
}

&__content {
display: flex;
flex-direction: column;

&_icon-position {
&_left {
flex-direction: row;
}
}
}

&_content-layout {
&_left {
@include add-specificity(&) {
flex: 1 0 0;
}
}
}
}
19 changes: 5 additions & 14 deletions src/sub-blocks/BasicCard/BasicCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import React from 'react';

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

import {Content} from '../';
import CardBase from '../../components/CardBase/CardBase';
import Image from '../../components/Image/Image';
import {getMediaImage} from '../../components/Media/Image/utils';
import IconWrapper from '../../components/IconWrapper/IconWrapper';
import {BasicCardProps} from '../../models';
import {IconPosition} from '../../models/constructor-items/sub-blocks';
import {block} from '../../utils';
import Content from '../Content/Content';

import './BasicCard.scss';

Expand All @@ -25,7 +24,6 @@ const BasicCard = (props: BasicCardProps) => {
iconPosition = IconPosition.Top,
...cardParams
} = props;
const iconProps = icon && getMediaImage(icon);
const titleId = useUniqId();
const descriptionId = useUniqId();

Expand All @@ -36,13 +34,7 @@ const BasicCard = (props: BasicCardProps) => {
extraProps={{'aria-describedby': descriptionId, 'aria-labelledby': titleId}}
>
<CardBase.Content>
<div className={b('content', {['icon-position']: iconPosition})}>
{iconProps && (
<Image
{...iconProps}
className={b('icon', {['icon-position']: iconPosition})}
/>
)}
<IconWrapper icon={icon ? {value: icon, position: iconPosition} : undefined}>
<Content
title={title}
titleId={titleId}
Expand All @@ -51,11 +43,10 @@ const BasicCard = (props: BasicCardProps) => {
additionalInfo={additionalInfo}
links={links}
buttons={buttons}
colSizes={{all: 12, md: 12}}
size="s"
className={b({['content-layout']: iconPosition})}
colSizes={{all: 12, md: 12}}
/>
</div>
</IconWrapper>
</CardBase.Content>
</CardBase>
);
Expand Down
4 changes: 4 additions & 0 deletions src/sub-blocks/LayoutItem/LayoutItem.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,9 @@ $block: '.#{$ns}layout-item';

&__content {
margin: $indentXS $indentXS 0 0;

&_no-media {
margin: 0;
}
}
}
46 changes: 29 additions & 17 deletions src/sub-blocks/LayoutItem/LayoutItem.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';

import {Content} from '..';
import {FullscreenMedia, Media, MetaInfo} from '../../components';
import {LayoutItemProps} from '../../models';
import {FullscreenMedia, IconWrapper, Media, MetaInfo} from '../../components';
import {ContentBlockProps, LayoutItemProps} from '../../models';
import {block} from '../../utils';
import Content from '../Content/Content';

import {getLayoutItemLinks, hasFullscreen, showFullscreenIcon} from './utils';

Expand All @@ -17,11 +17,21 @@ const LayoutItem = ({
media,
border,
fullscreen,
icon,
className,
analyticsEvents,
}: LayoutItemProps) => (
<div className={b(null, className)}>
{fullscreen && hasFullscreen(media) ? (
}: LayoutItemProps) => {
const contentProps: ContentBlockProps = {
...content,
links: getLayoutItemLinks(links),
size: 's',
colSizes: {all: 12, md: 12},
};
const renderMedia = () => {
if (!media) {
return null;
}
return fullscreen && hasFullscreen(media) ? (
<FullscreenMedia showFullscreenIcon={showFullscreenIcon(media)}>
{({
className: mediaClassName,
Expand All @@ -38,17 +48,19 @@ const LayoutItem = ({
</FullscreenMedia>
) : (
<Media {...media} className={b('media', {border})} analyticsEvents={analyticsEvents} />
)}
{metaInfo && <MetaInfo items={metaInfo} className={b('meta-info')} />}
<div className={b('content')}>
<Content
{...content}
links={getLayoutItemLinks(links)}
size="s"
colSizes={{all: 12, md: 12}}
/>
);
};
return (
<div className={b(null, className)}>
{renderMedia()}
{metaInfo && <MetaInfo items={metaInfo} className={b('meta-info')} />}
<div className={b('content', {'no-media': !media})}>
<IconWrapper icon={icon}>
<Content {...contentProps} />
</IconWrapper>
</div>
</div>
</div>
);
);
};

export default LayoutItem;
19 changes: 19 additions & 0 deletions src/sub-blocks/LayoutItem/__stories__/LayoutItem.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,24 @@ const DefaultTemplate: StoryFn<LayoutItemProps> = (args) => (
</div>
);

const WithIconTemplate: StoryFn<LayoutItemProps> = (args) => (
<div>
<div style={{marginBottom: '100px'}}>
<h1>Icon: Top</h1>
<DefaultTemplate {...args} />
</div>
<div>
<h1>Icon: Left</h1>
<DefaultTemplate {...args} icon={data.withIcon.iconLeft as LayoutItemProps['icon']} />
</div>
</div>
);

export const Default = DefaultTemplate.bind({});
export const Fullscreen = DefaultTemplate.bind({});
export const MetaInfo = DefaultTemplate.bind({});
export const Youtube = DefaultTemplate.bind({});
export const WithIcon = WithIconTemplate.bind({});

const DefaultArgs = {
...data.default.content,
Expand All @@ -40,3 +54,8 @@ MetaInfo.args = {
metaInfo: data.metaInfo.content.metaInfo.map((item) => yfmTransform(item)),
} as LayoutItemProps;
Youtube.args = {...DefaultArgs, ...data.youtube.content} as LayoutItemProps;
WithIcon.args = {
...DefaultArgs,
media: undefined,
icon: data.withIcon.iconTop as LayoutItemProps['icon'],
};
10 changes: 10 additions & 0 deletions src/sub-blocks/LayoutItem/__stories__/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,15 @@
"image": "/story-assets/img-mini_4-12_light.png"
}
}
},
"withIcon": {
"iconTop": {
"value": "/story-assets/icon_1_light.svg",
"position": "top"
},
"iconLeft": {
"value": "/story-assets/icon_2_light.svg",
"position": "left"
}
}
}
Loading