Skip to content

Commit

Permalink
fixup! fixup! fixup! Feat(web-react): Introduce Card component #1535
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelklibani committed Nov 21, 2024
1 parent c82da00 commit a9cc091
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 140 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
CardLink,
CardMedia,
CardTitle,
Container,
Grid,
UseCardStyleProps,
} from '../../../src/components';
Expand All @@ -19,6 +20,7 @@ type CardCompositionType = {
cardElementType: ElementType;
contentText: string;
eyebrowText: string;
gridCols: GridColumns;
image: string;
numCards: number;
showContent: boolean;
Expand All @@ -29,6 +31,7 @@ type CardCompositionType = {
titleElementType: ElementType;
titleText: string;
titleWithLink: boolean;
wrapInContainer: boolean;
} & UseCardStyleProps;

export default {
Expand All @@ -55,10 +58,9 @@ export default {
contentText: {
control: 'text',
description: 'Text for the user content.',
name: 'show content text',
name: 'children',
table: {
category: 'CardBody',
subcategory: 'Demo settings',
defaultValue: {
summary: '',
},
Expand All @@ -82,6 +84,12 @@ export default {
defaultValue: { summary: '' },
},
},
gridCols: {
control: 'select',
name: 'grid columns',
description: 'Number of columns in the grid.',
options: [1, 2, 3, 4, 5, 6, 12],
},
hasFilledHeight: {
control: 'boolean',
description: 'Fill the height of the media.',
Expand All @@ -97,7 +105,6 @@ export default {
table: {
category: 'CardMedia',
subcategory: 'Demo settings',
defaultValue: '',
},
},
isBoxed: {
Expand All @@ -121,7 +128,7 @@ export default {
description: 'If true, the CardTitle will render as a heading.',
table: {
category: 'CardTitle',
defaultValue: { summary: false },
defaultValue: { summary: true },
},
},
numCards: {
Expand All @@ -137,7 +144,6 @@ export default {
table: {
category: 'CardFooter',
subcategory: 'Demo settings',
defaultValue: { summary: true },
},
},
showContent: {
Expand All @@ -147,7 +153,6 @@ export default {
table: {
category: 'CardBody',
subcategory: 'Demo settings',
defaultValue: { summary: true },
},
},
showEyebrow: {
Expand All @@ -157,7 +162,6 @@ export default {
table: {
category: 'CardEyebrow',
subcategory: 'Demo settings',
defaultValue: { summary: true },
},
},
showMedia: {
Expand All @@ -167,7 +171,6 @@ export default {
table: {
category: 'CardMedia',
subcategory: 'Demo settings',
defaultValue: { summary: true },
},
},
showTitle: {
Expand All @@ -177,7 +180,6 @@ export default {
table: {
category: 'CardTitle',
subcategory: 'Demo settings',
defaultValue: { summary: true },
},
},
size: {
Expand Down Expand Up @@ -214,9 +216,13 @@ export default {
table: {
category: 'CardTitle',
subcategory: 'Demo settings',
defaultValue: { summary: false },
},
},
wrapInContainer: {
control: 'boolean',
description: 'Wrap the card in a container.',
name: 'wrap cards in container',
},
},
args: {
alignmentX: AlignmentX.LEFT,
Expand All @@ -225,11 +231,12 @@ export default {
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida, nulla nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat. Morbi fringilla convallis sapien. Sed ac felis. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. Nunc imperdiet justo nec dolor.',
direction: Direction.VERTICAL,
eyebrowText: 'Eyebrow title',
gridCols: 3,
hasFilledHeight: false,
image: MEDIA_IMAGE,
isBoxed: false,
isExpanded: false,
isHeading: false,
isHeading: true,
numCards: 3,
showFooter: true,
showContent: true,
Expand All @@ -240,6 +247,7 @@ export default {
titleElementType: 'h4',
titleText: 'Card Title',
titleWithLink: false,
wrapInContainer: true,
},
};

Expand All @@ -250,6 +258,7 @@ export const CardComposition = (args: CardCompositionType) => {
contentText,
direction,
eyebrowText,
gridCols,
hasFilledHeight,
image,
isBoxed,
Expand All @@ -265,35 +274,18 @@ export const CardComposition = (args: CardCompositionType) => {
titleElementType,
titleText,
titleWithLink,
wrapInContainer,
...restProps
} = args;

const numOfColumnsOnDesktop = () => {
if (numCards > 7) {
return 6;
}

if (numCards === 7) {
return 5;
}

return numCards as GridColumns;
};

const renderTitle = () => (
<CardTitle isHeading={isHeading} elementType={titleElementType}>
{titleWithLink ? <CardLink href="#">{titleText}</CardLink> : titleText}
</CardTitle>
);

return (
<Grid
cols={{
mobile: 1,
tablet: numCards > 2 ? 2 : (numCards as GridColumns),
desktop: numOfColumnsOnDesktop(),
}}
>
const renderCard = () => (
<Grid cols={gridCols}>
{Array.from({ length: numCards }, (_, index) => (
<Card key={index} elementType={cardElementType} {...restProps} isBoxed={isBoxed} direction={direction}>
{showMedia && (
Expand All @@ -318,4 +310,6 @@ export const CardComposition = (args: CardCompositionType) => {
))}
</Grid>
);

return wrapInContainer ? <Container>{renderCard()}</Container> : renderCard();
};
3 changes: 2 additions & 1 deletion packages/web-react/src/components/Card/Card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import classNames from 'classnames';
import React, { ElementType } from 'react';
import { Direction } from '../../constants';
import { useStyleProps } from '../../hooks';
import { SpiritCardProps } from '../../types';
import { useCardStyleProps } from './useCardStyleProps';

const defaultProps: Partial<SpiritCardProps> = {
elementType: 'article',
direction: 'vertical',
direction: Direction.VERTICAL,
isBoxed: false,
};

Expand Down
3 changes: 2 additions & 1 deletion packages/web-react/src/components/Card/CardFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import classNames from 'classnames';
import React from 'react';
import { AlignmentX } from '../../constants';
import { useStyleProps } from '../../hooks';
import { SpiritCardFooterProps } from '../../types';
import { useCardStyleProps } from './useCardStyleProps';

const defaultProps: Partial<SpiritCardFooterProps> = {
alignmentX: 'left',
alignmentX: AlignmentX.LEFT,
};

const CardFooter = (props: SpiritCardFooterProps) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/web-react/src/components/Card/CardTitle.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { useCardStyleProps } from './useCardStyleProps';

const defaultProps: Partial<SpiritCardTitleProps> = {
elementType: 'h4',
isHeading: false,
isHeading: true,
};

const CardTitle = <T extends ElementType = 'h4'>(props: SpiritCardTitleProps<T>) => {
Expand Down
4 changes: 2 additions & 2 deletions packages/web-react/src/components/Card/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Basic usage:
Advanced example:

```jsx
<CardTitle elementType="h2" isHeading>
<CardTitle elementType="h2" isHeading={false}>
<CardLink href="#"></CardLink>
</CardTitle>
```
Expand All @@ -101,7 +101,7 @@ Advanced example:
| Name | Type | Default | Required | Description |
| ------------- | ------------- | ------- | -------- | ------------------------------------------ |
| `elementType` | `ElementType` | `h4` || Type of element |
| `isHeading` | `bool` | `false` || Whether the title is rendered as a heading |
| `isHeading` | `bool` | `true` || Whether the title is rendered as a heading |

On top of the API options, the components accept [additional attributes][readme-additional-attributes].
If you need more control over the styling of a component, you can use [style props][readme-style-props]
Expand Down
41 changes: 22 additions & 19 deletions packages/web-react/src/components/Card/stories/Card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { Direction } from '../../../constants';
import { Button } from '../../Button';
import { Container } from '../../Container';
import Card from '../Card';
import CardBody from '../CardBody';
import CardEyebrow from '../CardEyebrow';
Expand Down Expand Up @@ -53,24 +54,26 @@ type Story = StoryObj<typeof Card>;
export const CardComponent: Story = {
name: 'Card',
render: (args) => (
<Card {...args}>
<CardMedia size="medium">
<img src={MEDIA_IMAGE} alt="media img" />
</CardMedia>
<CardBody>
<CardEyebrow>Card Title</CardEyebrow>
<CardTitle>Card Title</CardTitle>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida,
nulla nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat. Morbi
fringilla convallis sapien. Sed ac felis. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. Nunc
imperdiet justo nec dolor.
</p>
</CardBody>
<CardFooter>
<Button color="primary">Primary</Button>
<Button color="secondary">Secondary</Button>
</CardFooter>
</Card>
<Container>
<Card {...args}>
<CardMedia size="medium">
<img src={MEDIA_IMAGE} alt="media img" />
</CardMedia>
<CardBody>
<CardEyebrow>Card Title</CardEyebrow>
<CardTitle>Card Title</CardTitle>
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla accumsan, metus ultrices eleifend gravida,
nulla nunc varius lectus, nec rutrum justo nibh eu lectus. Ut vulputate semper dui. Fusce erat. Morbi
fringilla convallis sapien. Sed ac felis. Aliquam erat volutpat. Aliquam euismod. Aenean vel lectus. Nunc
imperdiet justo nec dolor.
</p>
</CardBody>
<CardFooter>
<Button color="primary">Primary</Button>
<Button color="secondary">Secondary</Button>
</CardFooter>
</Card>
</Container>
),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Markdown } from '@storybook/blocks';
import type { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import { Button } from '../../Button';
import { Container } from '../../Container';
import Card from '../Card';
import CardBody from '../CardBody';
import CardEyebrow from '../CardEyebrow';
import CardFooter from '../CardFooter';
import CardMedia from '../CardMedia';
import CardTitle from '../CardTitle';
import { MEDIA_IMAGE } from '../demo/constants';
import ReadMe from '../README.md';

const meta: Meta<typeof CardBody> = {
title: 'Components/Card',
component: CardBody,
parameters: {
docs: {
page: () => <Markdown>{ReadMe}</Markdown>,
},
},
argTypes: {
children: {
control: 'text',
description: 'Text to display in the CardBody.',
table: {
defaultValue: { summary: 'CardBody Text' },
},
},
},
args: {
children: 'CardBody Text',
},
};

export default meta;
type Story = StoryObj<typeof CardBody>;

export const CardBodyComponent: Story = {
name: 'CardBody',
render: (args) => {
const { children } = args;

return (
<Container>
<Card>
<CardMedia size="medium">
<img src={MEDIA_IMAGE} alt="media img" />
</CardMedia>
<CardBody {...args}>
<CardEyebrow>Card Title</CardEyebrow>
<CardTitle>Card Title</CardTitle>
{children}
</CardBody>
<CardFooter>
<Button color="primary">Primary</Button>
<Button color="secondary">Secondary</Button>
</CardFooter>
</Card>
</Container>
);
},
};
Loading

0 comments on commit a9cc091

Please sign in to comment.