Skip to content

Commit

Permalink
feat: added card
Browse files Browse the repository at this point in the history
  • Loading branch information
benjitrosch committed Mar 9, 2022
1 parent 2823b6b commit 2363da7
Show file tree
Hide file tree
Showing 5 changed files with 192 additions and 47 deletions.
83 changes: 81 additions & 2 deletions src/Card/Card.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import { Story, Meta } from '@storybook/react'

import Card, { CardProps } from '.'
import { Button } from '../..'

export default {
title: 'Data Display/Card',
Expand All @@ -10,7 +11,85 @@ export default {

export const Default: Story<CardProps> = (args) => {
return (
<Card {...args} />
<Card {...args}>
<figure>
<img
src="https://api.lorem.space/image/shoes?w=400&h=225"
alt="Shoes"
/>
</figure>
<Card.Body>
<Card.Title tag="h2">Shoes!</Card.Title>
<p>If a dog chews shoes whose shoes does he choose?</p>
<Card.Actions className="justify-end">
<Button color="primary">Buy Now</Button>
</Card.Actions>
</Card.Body>
</Card>
)
}

export const Responsive: Story<CardProps> = (args) => {
return (
<div>
<div className="mb-3">
(vertical on small screen, horizontal on large screen)
</div>
<Card {...args} side="lg">
<figure>
<img
src="https://api.lorem.space/image/shoes?w=400&h=225"
alt="Shoes"
/>
</figure>
<Card.Body>
<Card.Title tag="h2">Shoes!</Card.Title>
<p>If a dog chews shoes whose shoes does he choose?</p>
<Card.Actions className="justify-end">
<Button color="primary">Buy Now</Button>
</Card.Actions>
</Card.Body>
</Card>
</div>
)
}

export const Centered: Story<CardProps> = (args) => {
return (
<Card {...args}>
<figure>
<img
src="https://api.lorem.space/image/shoes?w=400&h=225"
alt="Shoes"
/>
</figure>
<Card.Body className="items-center text-center">
<Card.Title tag="h2">Shoes!</Card.Title>
<p>If a dog chews shoes whose shoes does he choose?</p>
<Card.Actions className="justify-end">
<Button color="primary">Buy Now</Button>
</Card.Actions>
</Card.Body>
</Card>
)
}

export const ImageOverlay: Story<CardProps> = (args) => {
return (
<Card {...args} imageFull>
<figure>
<img
src="https://api.lorem.space/image/shoes?w=400&h=225"
alt="Shoes"
/>
</figure>
<Card.Body>
<Card.Title tag="h2">Shoes!</Card.Title>
<p>If a dog chews shoes whose shoes does he choose?</p>
<Card.Actions className="justify-end">
<Button color="primary">Buy Now</Button>
</Card.Actions>
</Card.Body>
</Card>
)
}
Default.args = {}
114 changes: 69 additions & 45 deletions src/Card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,81 @@
import React, { ReactNode } from 'react'
import clsx from 'clsx'

import { IComponentBaseProps } from '../types'
import { IComponentBaseProps, ComponentSize } from '../types'

import CardActions, { CardActionsProps as ActionProps } from './CardActions'
import CardBody, { CardBodyProps as BodyProps } from './CardBody'
import CardTitle, { CardTitleProps as TitleProps } from './CardTitle'

export type CardActionsProps = ActionProps
export type CardBodyProps = BodyProps
export type CardTitleProps = TitleProps

export interface CardProps extends IComponentBaseProps {
src?: string
title?: string
description?: string
actions?: ReactNode | ReactNode[]
children?: ReactNode
bordered?: boolean
compact?: boolean
imageFull?: boolean

// responsive props
normal?: ComponentSize | boolean // Applies default paddings
compact?: ComponentSize | boolean // Applies smaller padding
side?: ComponentSize | boolean // The image in <figure> will be on to the side
}

interface ModifierMap {
[key: string]: {
[key: string]: string | undefined
}
}

const DYNAMIC_MODIFIERS: ModifierMap = {
compact: {
true: 'card-compact',
xs: 'xs:card-compact',
sm: 'sm:card-compact',
md: 'md:card-compact',
lg: 'lg:card-compact',
},
normal: {
true: 'card-normal',
xs: 'xs:card-normal',
sm: 'sm:card-normal',
md: 'md:card-normal',
lg: 'lg:card-normal',
},
side: {
true: 'card-side',
xs: 'xs:card-side',
sm: 'sm:card-side',
md: 'md:card-side',
lg: 'lg:card-side',
},
}

const Card = ({
src,
title,
description,
actions,
bordered,
compact,
dataTheme,
className,
style,
}: CardProps): JSX.Element => {
const classes = clsx(
'card',
className,
{
'bordered': bordered,
'compact': compact,
}
)

return (
<div
data-theme={dataTheme}
className={classes}
style={style}
>
<div className="card-body">
<figure>
<img src={src} />
</figure>
<h2 className="card-title">
{title}
</h2>
<p>{description}</p>
<div className="card-actions">
{actions}
</div>
</div>
</div>
)
}
bordered = true,
imageFull,
normal,
compact,
side,
...props
}: CardProps) => (
<div
className={clsx('card', className, {
'card-bordered': bordered,
'image-full': imageFull,
[(compact && DYNAMIC_MODIFIERS.compact[compact.toString()]) || '']:
compact,
[(normal && DYNAMIC_MODIFIERS.normal[normal.toString()]) || '']: normal,
[(side && DYNAMIC_MODIFIERS.side[side.toString()]) || '']: side,
})}
{...props}
/>
)

Card.Actions = CardActions
Card.Body = CardBody
Card.Title = CardTitle

export default Card
13 changes: 13 additions & 0 deletions src/Card/CardActions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { ReactNode } from 'react'
import clsx from 'clsx'
import { IComponentBaseProps } from '../types'

export interface CardActionsProps extends IComponentBaseProps {
children?: ReactNode
}

const CardActions = ({ className, ...props }: CardActionsProps) => (
<div className={clsx('card-actions', className)} {...props} />
)

export default CardActions
13 changes: 13 additions & 0 deletions src/Card/CardBody.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { ReactNode } from 'react'
import clsx from 'clsx'
import { IComponentBaseProps } from '../types'

export interface CardBodyProps extends IComponentBaseProps {
children?: ReactNode
}

const CardBody = ({ className, ...props }: CardBodyProps) => (
<div className={clsx('card-body', className)} {...props} />
)

export default CardBody
16 changes: 16 additions & 0 deletions src/Card/CardTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import React, { ElementType, ReactNode } from 'react'
import clsx from 'clsx'
import { IComponentBaseProps } from '../types'

export interface CardTitleProps extends IComponentBaseProps {
children?: ReactNode
tag?: ElementType
}

const CardTitle = ({ className, tag = 'div', ...props }: CardTitleProps) => {
const Tag = tag

return <Tag className={clsx('card-title', className)} {...props} />
}

export default CardTitle

0 comments on commit 2363da7

Please sign in to comment.