Files
stash-ui/site/sections/Cards.tsx
T
CNWei 17a09f22b6 feat(ui): 新增 EntryRow / EntryTile,收掉应用里两套手写内容卡
- EntryRow:头像 + 标题(可带角标)+ 单行描述,整行可点;
  点击语义内置(无修饰键接管,按住 Ctrl/Cmd/Shift/Alt 保留浏览器默认)
- EntryTile:上图下文白卡,由 Card padding=none hoverable + Cover 拼成
- 展示页 #cards 补两个示例与 props,COMPONENTS.md 补契约与 changelog

兼容性:纯新增;应用侧的旧类名(.app-card / .ces-card / .ces-body)随之删除
2026-11-01 16:08:39 +08:00

146 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { Badge, Card, EntryRow, EntryTile, Icon, IconButton, ItemBadge, Space } from '../../src'
import { Demo } from '../components/Demo'
import { PropsTable } from '../components/PropsTable'
import { Section } from '../components/Section'
export function Cards() {
return (
<Section
id="cards"
title="卡片"
api="Card"
desc="白色容器 + 1px 细边 + 极轻阴影,是页面里的基本承载单位。Card 只负责容器,标题栏、角标、操作区由使用方组合。"
>
<Demo
title="基础用法"
desc="默认 md 内边距(20px)。放在白底页面上时,靠 1px 描边而不是阴影区分边界,和主题一致。"
muted
layout="column"
code={`<Card>
<p>卡片内容</p>
</Card>`}
>
<Card>
<Space direction="column" gap="sm" align="start">
<strong style={{ fontWeight: 500 }}>常用推荐</strong>
<span style={{ color: 'var(--su-text-muted)' }}>
卡片是最小布局单元,内容完全由使用方决定。
</span>
</Space>
</Card>
</Demo>
<Demo
title="内边距"
desc="padding=none 用于封面贴边的卡片;sm 用于紧凑列表;lg 用于详情页大块内容。"
code={`<Card padding="none">…</Card>
<Card padding="sm">…</Card>
<Card padding="lg">…</Card>`}
>
<Card padding="sm">
<span style={{ color: 'var(--su-text-muted)' }}>sm · 12px</span>
</Card>
<Card padding="md">
<span style={{ color: 'var(--su-text-muted)' }}>md · 20px</span>
</Card>
<Card padding="lg">
<span style={{ color: 'var(--su-text-muted)' }}>lg · 24px</span>
</Card>
</Demo>
<Demo
title="可点击卡片"
desc="hoverable 只加深阴影,不改变尺寸,避免列表在悬停时抖动。"
code={`<Card hoverable>整张卡片可点击</Card>`}
>
<Card hoverable padding="sm">
<span style={{ color: 'var(--su-text-muted)' }}>把鼠标放上来</span>
</Card>
</Demo>
<Demo
title="组合出标题栏"
desc="卡片本身不带标题栏;色条 + 标题 + 角标 + 更多按钮是一组可复用的「分区头部」,这里用基础组件拼出来。"
muted
layout="column"
code={`<Card>
<Space justify="between">
<Space gap="md">
<span style={{ width: 4, height: 16, background: 'var(--su-color-primary)' }} />
<strong>常用站点</strong>
<Badge count={18} />
</Space>
<IconButton label="查看全部" icon={<Icon name="more_3_line" />} />
</Space>
…
</Card>`}
>
<Card>
<Space justify="between">
<Space gap="md">
<span
style={{
width: 4,
height: 16,
borderRadius: 2,
backgroundColor: 'var(--su-color-primary)',
}}
/>
<strong style={{ fontWeight: 500 }}>常用站点</strong>
<Badge count={18} />
</Space>
<IconButton label="查看全部" icon={<Icon name="more_3_line" />} />
</Space>
</Card>
</Demo>
<Demo
title="条目行与条目磁贴"
desc="同一份内容数据的两种版式:EntryRow 是横向一行(头像 + 标题 + 描述),EntryTile 是上图下文的白卡。点击语义一致——不带修饰键时接管点击,按住 Ctrl/Cmd 时保留浏览器默认行为。"
layout="column"
code={`<EntryRow title="GitHub" description="代码托管与开源社区" fallback="G" badge={<ItemBadge tone="hot">HOT</ItemBadge>} />
<EntryTile title="可塑性极强的玻璃" description="前沿科技" ratio={16 / 10} />`}
>
<EntryRow
title="GitHub"
description="代码托管与开源社区"
fallback="G"
badge={<ItemBadge tone="hot">HOT</ItemBadge>}
onOpen={() => undefined}
/>
<EntryRow title="知乎" description="深度内容问答社区" fallback="知" onOpen={() => undefined} />
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 'var(--su-space-3)' }}>
<EntryTile
title="可塑性极强的玻璃,在设计师手里能变成什么"
description="前沿科技"
ratio={16 / 10}
onOpen={() => undefined}
/>
<EntryTile title="废旧共享单车如何变成微型共享…" description="环保设计" ratio={16 / 10} />
</div>
</Demo>
<PropsTable
rows={[
{ name: 'as', type: "'div' | 'section' | 'article' | 'aside'", defaultValue: "'div'", desc: '渲染标签,按语义选' },
{ name: 'padding', type: "'none' | 'sm' | 'md' | 'lg'", defaultValue: "'md'", desc: '内边距档位' },
{ name: 'hoverable', type: 'boolean', defaultValue: 'false', desc: '悬停加深阴影' },
{ name: 'className / style', type: 'string / CSSProperties', desc: '布局微调,例如绝对定位角标' },
{ name: 'EntryRow.title', type: 'string', required: true, desc: '标题' },
{ name: 'EntryRow.description', type: 'string', desc: '单行描述' },
{ name: 'EntryRow.href', type: 'string', desc: '整行链接地址' },
{ name: 'EntryRow.avatar / fallback', type: 'string', desc: '头像图片 / 首字占位' },
{ name: 'EntryRow.verified', type: 'boolean', desc: '头像右下角认证勾' },
{ name: 'EntryRow.badge', type: 'ReactNode', desc: '标题右侧角标(如 HOT)' },
{ name: 'EntryRow.onOpen', type: '() => void', desc: '接管点击;不传保持链接行为' },
{ name: 'EntryTile.title', type: 'string', required: true, desc: '标题' },
{ name: 'EntryTile.description', type: 'string', desc: '单行描述' },
{ name: 'EntryTile.cover', type: 'string', desc: '封面地址' },
{ name: 'EntryTile.ratio', type: 'number', defaultValue: '16 / 10', desc: '封面宽高比' },
{ name: 'EntryTile.onOpen', type: '() => void', desc: '点击整张卡' },
]}
/>
</Section>
)
}