stories/atoms/components/card/Card.stories.mdx
import { ArgsTable, Meta, Story, Canvas } from '@storybook/addon-docs'
import { Card } from 'ui/atoms/card/Card'
import { Icon } from 'ui/atoms/icon/Icon'
import { Button } from 'ui/atoms/button/Button'
import { Typography } from 'ui/atoms/typography/Typography'
import { ThemeProvider } from 'ui/atoms/theme/ThemeProvider'
import { ThemeSwitcher } from 'ui/atoms/theme/ThemeSwitcher'
import PatrickStar from '../../../assets/patrick-star.png'
import './card.scss'
import '../component.scss'
<Meta
title="Atoms/Card"
component={Card}
decorators={[
Story => (
<ThemeProvider>
<div className="story-theme-switcher">
<ThemeSwitcher />
</div>
<div className="component-story-main">
<Story />
</div>
</ThemeProvider>
)
]}
/>
# Card
> A window that presents high level information to entice browsing users to learn more.
[![stability-unstable](https://img.shields.io/badge/stability-unstable-yellow.svg)](https://github.com/emersion/stability-badges#unstable)
## Description
Cards are an entry point for further exploration. They present summarized information meant to describe further content.
Card have a `header`, `content` and a `footer` that allow you to fill it with information that catch the readers attention. You can also
decide its `background` and `size`, as well as if it should be `withBorder`or not.
## Overview
<Story
name="Overview"
argTypes={{
header: {
control: false,
table: {
type: { summary: 'Node' }
}
},
content: {
control: false,
table: {
type: { summary: 'Node' }
}
},
footer: {
control: false,
table: {
type: { summary: 'Node' }
}
}
}}
args={{
background: 'primary',
size: 'medium',
withBorder: true
}}
>
{args => (
<div
style={{
display: 'flex',
justifyContent: 'center',
padding: '24px 0'
}}
>
<Card
{...args}
header={
<div style={{ display: 'flex', justifyContent: 'flex-end' }}>
<Typography fontSize="small" style={{ border: 'solid 1px', padding: '4px 8px' }}>
Header
</Typography>
</div>
}
content={
<Typography
as="div"
style={{ textAlign: 'center' }}
fontFamily="secondary"
fontSize="x-large"
fontWeight="xlight"
>
Content
</Typography>
}
footer={
<Typography
as="div"
style={{ textAlign: 'start', marginBottom: '4px' }}
fontWeight="bold"
>
Footer
</Typography>
}
/>
</div>
)}
</Story>
---
### Properties
<ArgsTable story="Overview" />
## Backgrounds
Card comes with two backgrounds to choose from:
- **primary** (default): Discreet `background` with a solid color.
- **secondary**: Gradient colored `background`. Makes the card stand out more.
<Canvas>
<Story name="Backgrounds">
{() => {
const cards = {
primary: {
background: 'primary',
contentText: 'Primary',
footerText: 'ØKP4 Design System'
},
secondary: {
background: 'secondary',
contentText: 'Secondary',
footerText: 'Blockchain'
}
}
return (
<div
style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: '40px' }}
>
{Object.values(cards).map(({ background, contentText, footerText }) => (
<Card
background={background}
header={
<div style={{ display: 'flex' }}>
<Typography fontSize="small" style={{ border: 'solid 1px', padding: '4px 8px' }}>
Article
</Typography>
</div>
}
content={
<Typography as="div" style={{ textAlign: 'center' }} fontSize="x-large">
{contentText}
</Typography>
}
footer={
<Typography
as="div"
style={{ textAlign: 'end', marginBottom: '4px' }}
fontSize="small"
>
{footerText}
</Typography>
}
/>
))}
</div>
)
}}
</Story>
</Canvas>
## Sizes
There are three sizes to choose from:
- **small**: Great for small screens where page real estate is limited and when you don't want your page to become too long.
- **medium** (default): Middle ground option. Perfect for when you want the card to contain a lot of information but also want to render several cards.
- **large**: Will take up a lot of the page and can contain a lot of information. Suitable for desktop pages.
<Canvas>
<Story name="Sizes">
{() => {
const cards = {
small: {
size: 'small',
contentText: 'Small'
},
medium: {
size: 'medium',
contentText: 'Medium'
},
large: {
size: 'large',
contentText: 'Large'
}
}
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '40px'
}}
>
{Object.values(cards).map(({ size, contentText }) => (
<Card
size={size}
background="secondary"
withBorder="true"
content={
<Typography as="div" style={{ textAlign: 'center' }} fontSize="x-large">
{contentText}
</Typography>
}
/>
))}
</div>
)
}}
</Story>
</Canvas>
## Border
Using `withBorder` adds a thin border to the card, this can help you avoid problems with contrast.
Card comes with a border as default value.
<Canvas>
<Story name="Border">
{() => {
const cards = {
withBorder: {
withBorder: true,
headerText: 'With border',
footerText: '🫶 Ahh I can clearly see where the card ends'
},
withoutBorder: {
withBorder: false,
headerText: 'Without border',
footerText: '🙀 Where did the border go?!'
}
}
return (
<div
style={{
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
gap: '40px'
}}
>
{Object.values(cards).map(({ withBorder, headerText, footerText }) => (
<Card
withBorder={withBorder}
header={
<Typography as="div" fontSize="x-large">
{headerText}
</Typography>
}
footer={
<Typography
as="div"
style={{ textAlign: 'end', marginBottom: '4px' }}
fontSize="small"
>
{footerText}
</Typography>
}
/>
))}
</div>
)
}}
</Story>
</Canvas>
## Header, Content and Footer
The heart of the card is its `header`, `content` and `footer` elements. They constitute the content
meant to inform and entice the reader.
The elements are layed out the same way a page would be organised, with the header on top, content in the middle
and footer on the bottom. These are just landmarks though and its up to you to style your card they way you want it.
<Canvas>
<Story name="Header / Content / Footer">
{() => {
const handleClick = () => {
window.open('https://www.linkedin.com/company/okp4-open-knowledge-protocol-for/mycompany/')
}
const cards = {
shareData: {
headerElement: (
<div class="card-story-content-first-header">
<Typography as="h1" fontFamily="secondary" fontWeight="bold">
SHARE DATA
</Typography>
</div>
),
footerElement: (
<div className="card-story-content-first-footer">
<img src={PatrickStar} alt="Patrick Star from Spongebob" />
<div className="card-story-content-first-footer-quote">
<Typography as="div" fontSize="small">
“We're not cavemen, we have technology"
</Typography>
</div>
</div>
)
},
openWeatherData: {
headerElement: (
<Typography
as="div"
fontSize="small"
fontWeight="bold"
style={{
border: '1px solid',
padding: '6px 8px',
width: 'fit-content',
marginLeft: 'auto'
}}
>
Popular
</Typography>
),
contentElement: (
<div class="card-story-content-second-content">
<Typography as="div" fontFamily="secondary">
Open Weather Data
</Typography>
<Typography as="div" fontSize="small">
Public data on the weather
</Typography>
</div>
),
footerElement: (
<div class="card-story-content-second-footer">
<Typography as="div" fontSize="small" fontWeight="bold">
All Data Sets
</Typography>
<Icon name="next" />
</div>
)
},
linkedin: {
headerElement: (
<div class="card-story-content-third-header">
<Typography style={{ flexShrink: '0' }} fontFamily="secondary" fontWeight="bold">
Linkedin
</Typography>
<Icon name="linkedin-square" className="card-story-content-third-header-icon" />
</div>
),
contentElement: (
<div class="card-story-content-third-content">
<Typography as="div" fontWeight="xlight">
Connect with ØKP4 on LinkedIn
</Typography>
</div>
),
footerElement: (
<div class="card-story-content-third-footer">
<Button label="Connect nøw!" onClick={handleClick} />
</div>
)
}
}
return (
<div class="card-story-content">
{Object.values(cards).map(
({ headerElement, contentElement, footerElement, background }) => (
<Card
header={headerElement}
content={contentElement}
footer={footerElement}
background="secondary"
/>
)
)}
</div>
)
}}
</Story>
</Canvas>