Skip to content

Commit

Permalink
feat(PlaceholderContainer): add component and showcases (#1741)
Browse files Browse the repository at this point in the history
  • Loading branch information
Marginy605 authored Sep 6, 2024
1 parent aeba7a0 commit 1632acc
Show file tree
Hide file tree
Showing 10 changed files with 800 additions and 0 deletions.
1 change: 1 addition & 0 deletions CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
/src/components/Pagination @jhoncool
/src/components/Palette @Ruminat
/src/components/PinInput @amje
/src/components/PlaceholderContainer @Marginy605
/src/components/Popover @kseniya57
/src/components/Popup @amje
/src/components/Portal @amje
Expand Down
224 changes: 224 additions & 0 deletions src/components/PlaceholderContainer/PlaceholderContainer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
@import '../variables';
@import '../../../styles/mixins';

$imageSmallSize: 100px;
$imageMediumSize: 150px;
$imageLargeSize: 230px;

$contentHeightSmallSize: 130px;
$contentHeightMediumSize: 180px;
$contentHeightLargeSize: 320px;

$containerSmallRowSize: 320px;
$containerMediumRowSize: 430px;
$containerLargeRowSize: 600px;

$containerSmallColSize: 320px;
$containerMediumColSize: 320px;
$containerLargeColSize: 430px;

$normalOffset: var(--g-spacing-5);
$mediumOffset: var(--g-spacing-7);
$bigOffset: var(--g-spacing-10);

$block: '.#{$ns}placeholder-container';

@mixin container-row-sizes($bodyWidth, $imageSize, $contentHeight, $contentOffset) {
#{$block}__body {
max-width: $bodyWidth;
}

#{$block}__image {
width: $imageSize;

& > * {
max-width: $imageSize;
display: block;
}
}

#{$block}__content {
margin-inline-start: $contentOffset;
min-height: $contentHeight;
}
}

@mixin container-column-sizes($bodyWidth, $imageSize) {
#{$block}__body {
max-width: $bodyWidth;
}

#{$block}__image {
max-height: $imageSize;

& > * {
max-height: $imageSize;
}
}
}

#{$block} {
box-sizing: border-box;
display: flex;
align-items: center;
padding: $mediumOffset;

&#{$block}_align {
&_left {
justify-content: flex-start;
}

&_center {
justify-content: center;
}
}

&__body {
box-sizing: border-box;
display: flex;
align-items: center;
}

&_size_s {
padding: $normalOffset;

#{$block}__description {
margin-block-start: var(--g-spacing-1);
}
}

&_size_m {
padding: $mediumOffset;

#{$block}__description {
margin-block-start: var(--g-spacing-2);
}
}

&_size_promo,
&_size_l {
#{$block}__description {
margin-block-start: var(--g-spacing-3);
}
}

&__image {
flex-shrink: 0;

img {
display: block;
}
}

&__content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
flex-grow: 1;
}

&__title {
#{$block}_size_s & {
@include text-subheader-1();
}

#{$block}_size_m & {
@include text-subheader-2();
}

#{$block}_size_l & {
@include text-subheader-3();
}

#{$block}_size_promo & {
@include text-header-1();
}
}

&__actions {
margin-block-start: $normalOffset;
display: flex;
flex-direction: row;
}

&_direction_row {
&#{$block}_size_s {
@include container-row-sizes(
$containerSmallRowSize,
$imageSmallSize,
$contentHeightSmallSize,
$normalOffset
);
}

&#{$block}_size_m {
@include container-row-sizes(
$containerMediumRowSize,
$imageMediumSize,
$contentHeightMediumSize,
$mediumOffset
);
}

&#{$block}_size_l {
@include container-row-sizes(
$containerLargeRowSize,
$imageLargeSize,
$contentHeightLargeSize,
$bigOffset
);
}

&#{$block}_size_promo {
@include container-row-sizes($containerLargeRowSize, $imageLargeSize, none, $bigOffset);
}
}

&_direction_column {
#{$block}__body {
flex-direction: column;
}

#{$block}__content {
margin-block-start: $normalOffset;
align-items: center;
text-align: center;
flex-shrink: 0;
}

#{$block}__image {
flex-shrink: 0;
}

&#{$block}_size_s {
@include container-column-sizes($containerSmallColSize, $imageSmallSize);
}

&#{$block}_size_m {
@include container-column-sizes($containerMediumColSize, $imageMediumSize);
}

&#{$block}_size_l {
@include container-column-sizes($containerLargeColSize, $imageLargeSize);
}

&#{$block}_size_promo {
padding: $normalOffset;

@include container-column-sizes($containerLargeColSize, $imageLargeSize);

#{$block}__body {
width: 100%;
}
}
}

&__action {
margin-inline-end: $normalOffset;
}

&__action:last-child {
margin-inline-end: 0;
}
}
107 changes: 107 additions & 0 deletions src/components/PlaceholderContainer/PlaceholderContainer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from 'react';

import {Button} from '../Button';
import {block} from '../utils/cn';

import {componentClassName} from './constants';
import type {PlaceholderContainerActionProps, PlaceholderContainerProps} from './types';

import './PlaceholderContainer.scss';

const b = block(componentClassName);

const PlaceholderContainerAction = (props: PlaceholderContainerActionProps) => {
return (
<div className={b('action')}>
<Button
className={b('action-btn')}
view={props.view || 'normal'}
size={props.size || 'm'}
loading={Boolean(props.loading)}
disabled={Boolean(props.disabled)}
href={props.href || ''}
{...(props.onClick ? {onClick: props.onClick} : {})}
>
{props.text}
</Button>
</div>
);
};

export const PlaceholderContainer = ({
direction = 'row',
align = 'center',
size = 'l',
className,
title,
description,
image,
content,
actions,
}: PlaceholderContainerProps) => {
const renderTitle = () => {
if (!title) {
return null;
}

return <div className={b('title')}>{title}</div>;
};
const renderDescription = () => {
if (!description) {
return null;
}

return <div className={b('description')}>{description}</div>;
};

const renderImage = (): NonNullable<React.ReactNode> => {
if (typeof image === 'object' && 'src' in image) {
return <img src={image.src} alt={image.alt || ''} />;
}

return image;
};

const renderAction = () => {
if (!actions || !(React.isValidElement(actions) || Array.isArray(actions))) {
return null;
}

if (React.isValidElement(actions)) {
return <React.Fragment>{actions}</React.Fragment>;
}

return (
<div className={b('actions')}>
{(actions as PlaceholderContainerActionProps[]).map((actionItem) => (
<PlaceholderContainerAction key={actionItem.text} {...actionItem} />
))}
</div>
);
};

const renderContent = () => {
const contentNode = content || (
<React.Fragment>
{renderTitle()}
{renderDescription()}
</React.Fragment>
);

return (
<div className={b('content', {size})}>
{contentNode}
{renderAction()}
</div>
);
};

return (
<div className={b({direction, align, size}, className || '')}>
<div className={b('body')}>
<div className={b('image', {size})}>{renderImage()}</div>
{renderContent()}
</div>
</div>
);
};
Loading

0 comments on commit 1632acc

Please sign in to comment.