feat(card): append types to card

This commit is contained in:
unix
2020-04-09 08:58:18 +08:00
parent d35d9bf43c
commit 29876a3b4f
5 changed files with 202 additions and 9 deletions

View File

@@ -1,14 +1,18 @@
import React, { useMemo } from 'react'
import withDefaults from '../utils/with-defaults'
import useTheme from '../styles/use-theme'
import { CardTypes } from '../utils/prop-types'
import { getStyles } from './styles'
interface Props {
hoverable?: boolean
shadow?: boolean
className?: string
type?: CardTypes
}
const defaultProps = {
type: 'default' as CardTypes,
hoverable: false,
shadow: false,
className: '',
@@ -18,13 +22,17 @@ type NativeAttrs = Omit<React.HTMLAttributes<any>, keyof Props>
export type CardProps = Props & typeof defaultProps & NativeAttrs
const Card: React.FC<React.PropsWithChildren<CardProps>> = React.memo(({
children, hoverable, className, shadow, ...props
children, hoverable, className, shadow, type, ...props
}) => {
const theme = useTheme()
const hoverShadow = useMemo(() => {
if (shadow) return theme.expressiveness.shadowMedium
return hoverable ? theme.expressiveness.shadowSmall : 'none'
}, [hoverable, shadow, theme.expressiveness])
const { color, bgColor, borderColor } = useMemo(
() => getStyles(type, theme.palette, shadow),
[type, theme.palette, shadow],
)
return (
<div className={`card ${className}`} {...props}>
@@ -37,19 +45,23 @@ const Card: React.FC<React.PropsWithChildren<CardProps>> = React.memo(({
transition: all .2s ease;
padding: ${theme.layout.gap} ${theme.layout.gap};
border-radius: ${theme.layout.radius};
border: 1px solid ${shadow ? 'transparent' : theme.palette.border};
box-shadow: ${shadow ? theme.expressiveness.shadowSmall : 'none'};
box-sizing: border-box;
color: ${color};
background-color: ${bgColor};
border: 1px solid ${borderColor};
}
.card:hover {
box-shadow: ${hoverShadow};
}
.card :global(p), .card :global(h1), .card :global(h2),
.card :global(h3), .card :global(h4), .card :global(h5),
.card :global(h6) {
margin: 0;
.card :global(*:first-child) {
margin-top: 0;
}
.card :global(*:last-child) {
margin-bottom: 0;
}
`}</style>
</div>

66
components/card/styles.ts Normal file
View File

@@ -0,0 +1,66 @@
import { CardTypes } from '../utils/prop-types'
import { ZeitUIThemesPalette } from '../styles/themes'
export type CardStyles = {
color: string
bgColor: string
borderColor: string
}
export const getStyles = (
type: CardTypes,
palette: ZeitUIThemesPalette,
isShadow?: boolean,
): CardStyles => {
const colors: { [key in CardTypes]: Omit<CardStyles, 'borderColor'> } = {
default: {
color: palette.foreground,
bgColor: palette.background,
},
dark: {
color: palette.background,
bgColor: palette.foreground,
},
secondary: {
color: palette.background,
bgColor: palette.secondary,
},
success: {
color: palette.background,
bgColor: palette.success,
},
warning: {
color: palette.background,
bgColor: palette.warning,
},
error: {
color: palette.background,
bgColor: palette.error,
},
lite: {
color: palette.foreground,
bgColor: palette.background,
},
alert: {
color: 'white',
bgColor: palette.alert,
},
purple: {
color: 'white',
bgColor: palette.purple,
},
violet: {
color: 'white',
bgColor: palette.violet,
},
cyan: {
color: 'black',
bgColor: palette.cyan,
},
}
const showBorder = type === 'default' && !isShadow
return {
...colors[type],
borderColor: showBorder ? palette.border : 'transparent',
}
}

View File

@@ -40,6 +40,20 @@ const snippetTypes = tuple(
'lite',
)
const cardTypes = tuple(
'default',
'secondary',
'success',
'warning',
'error',
'dark',
'lite',
'alert',
'purple',
'violet',
'cyan',
)
const copyTypes = tuple(
'default',
'slient',
@@ -76,6 +90,8 @@ export type ThemeTypes = typeof themeTypes[number]
export type SnippetTypes = typeof snippetTypes[number]
export type CardTypes = typeof cardTypes[number]
export type CopyTypes = typeof copyTypes[number]
export type TriggerTypes = typeof triggerTypes[number]

View File

@@ -1,5 +1,5 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Card } from 'components'
import { Card, Spacer, Row, Col } from 'components'
export const meta = {
title: 'card',
@@ -39,6 +39,37 @@ A common container component.
</Card>
`} />
<Playground
title="Types"
desc="Show different states with colors."
scope={{ Card, Spacer, Row, Col }}
code={`
() => {
const typeLeft = ['secondary', 'success', 'warning', 'error', 'dark']
const typeRight = ['alert', 'purple', 'violet', 'cyan', 'lite']
return (
<>
{typeLeft.map((left, index) => (
<Row justify="space-around" key={left} style={{ marginBottom: '18px' }}>
<Col span="10">
<Card type={left}>
<h4 style={{ textTransform: 'capitalize' }}>{left}</h4>
<span>{left}</span>
</Card>
</Col>
<Col span="10">
<Card type={typeRight[index]}>
<h4 style={{ textTransform: 'capitalize' }}>{typeRight[index]}</h4>
<span>{typeRight[index]}</span>
</Card>
</Col>
</Row>
))}
</>
)
}
`} />
<Attributes edit="/pages/en-us/components/card.mdx">
<Attributes.Title>Card.Props</Attributes.Title>
@@ -46,8 +77,25 @@ A common container component.
| ---------- | ---------- | ---- | -------------- | ------ |
| **hoverable** | add effect on hover | `boolean` | - | `false` |
| **shadow** | show shadow | `boolean` | - | `false` |
| **type** | card type | [CardType](#cardtype) | - | `default` |
| ... | native props | `HTMLAttributes` | `'className', ...` | - |
<Attributes.Title>CardType</Attributes.Title>
```ts
type CardType = 'default'
| 'secondary'
| 'success'
| 'warning'
| 'error'
| 'dark'
| 'lite'
| 'alert'
| 'purple'
| 'violet'
| 'cyan'
```
</Attributes>
export default ({ children }) => <Layout meta={meta}>{children}</Layout>

View File

@@ -1,5 +1,5 @@
import { Layout, Playground, Attributes } from 'lib/components'
import { Card } from 'components'
import { Card, Row, Col } from 'components'
export const meta = {
title: '卡片 Card',
@@ -10,7 +10,6 @@ export const meta = {
基础的组件容器。
<Playground
scope={{ Card }}
code={`
@@ -38,6 +37,41 @@ export const meta = {
</Card>
`} />
<Playground
title="类型"
desc="以各式色彩表达不同的类型或状态。"
scope={{ Card, Row, Col }}
code={`
() => {
const typeLeft = ['secondary', 'success', 'warning', 'error', 'dark']
const typeRight = ['alert', 'purple', 'violet', 'cyan', 'lite']
const locales = {
secondary: '次要的', success: '成功', warning: '警告', error: '错误', dark: '暗黑',
alert: '提示', purple: '紫色', violet: '紫罗兰', cyan: '青色', lite: '精简',
}
return (
<>
{typeLeft.map((left, index) => (
<Row justify="space-around" key={left} style={{ marginBottom: '18px' }}>
<Col span="10">
<Card type={left}>
<h4 style={{ textTransform: 'capitalize' }}>{locales[left]}</h4>
<span>{left}</span>
</Card>
</Col>
<Col span="10">
<Card type={typeRight[index]}>
<h4 style={{ textTransform: 'capitalize' }}>{locales[typeRight[index]]}</h4>
<span>{typeRight[index]}</span>
</Card>
</Col>
</Row>
))}
</>
)
}
`} />
<Attributes edit="/pages/zh-cn/components/card.mdx">
<Attributes.Title>Card.Props</Attributes.Title>
@@ -45,8 +79,25 @@ export const meta = {
| ---------- | ---------- | ---- | -------------- | ------ |
| **hoverable** | 是否在悬停时增加阴影 | `boolean` | - | `false` |
| **shadow** | 是否总是显示阴影 | `boolean` | - | `false` |
| **type** | 卡片的类型 | [CardType](#cardtype) | - | `default` |
| ... | 原生属性 | `HTMLAttributes` | `'className', ...` | - |
<Attributes.Title>CardType</Attributes.Title>
```ts
type CardType = 'default'
| 'secondary'
| 'success'
| 'warning'
| 'error'
| 'dark'
| 'lite'
| 'alert'
| 'purple'
| 'violet'
| 'cyan'
```
</Attributes>
export default ({ children }) => <Layout meta={meta}>{children}</Layout>