笔记
0工具
0此页用于记录用户反馈问题后的每一次改进
关于
“写笔记”支持四种格式——Word 文档、Excel 表格、Markdown、纯文本,起稿或二次编辑时都能随时切换,同一篇笔记想用哪种形态来记,都由你说了算。
md、txt、csv、json 这类纯文本则原样载入,不做多余加工。拿一张现成的表倒进来、改几笔、再导出去,等于白用一台免费的格式转换器。
要带走就在右上角点“下载”,可导出 PDF、Word、Markdown、Excel、TXT 等格式;列表卡片“⋯”菜单里,也有同样的下载入口。
在“工具”页点“+ 上传工具”即可发布:填好名称与链接,再用 Markdown 把使用方法写清楚——能解决什么问题、怎么装、怎么用,比堆介绍实在。
要分发安装包就一并上传压缩包(ZIP、RAR、7Z、TAR.GZ,最大 35MB),别人在详情页一键下载;只放链接不带附件也可以。
工具按大家的收藏热度排序,好用的自然会被顶上来。发布后可在详情页或卡片菜单里编辑、下架。
写笔记时勾上“隐藏”,这篇就只存在于你自己的账号里:不进列表、不进搜索、不上首页精选,也不会出现在任何公开的页面,链接发给别人同样打不开。
适合放密码、草稿、日记这类只给自己看的内容;想公开,去“发布”打开它,把“隐藏”的勾去掉再保存,之后编辑会默认保持原状态,不会悄悄变回公开。
不想公开、只想临时给人看:点“分享”生成一条带密码和有效期的链接,到期自动失效,你也能随时撤销。
你的内容会同时保存在多个副本上,系统定期做备份与完整性校验,再配合异地容灾机制:就算某台机器出问题,数据也不会丢,可以长期放心存放;特别重要的资料,仍建议你另外再留一份备份。
全站跑在容器化、模块化的现代架构上,更新、部署、回滚都很快,扩展性和稳定性都按长期运营的标准来设计(Built for reliability, designed to scale)。
这个网站最早只是一个人的笔记仓库,后来慢慢长成现在的知识中枢。设计上很克制——没有广告、没有追踪、没有推荐算法,只是干干净净地存放一些东西;既然做好了,就公开出来,万一有人用得上呢。
不做大而全,不做平台梦,保持简单、保持克制、保持好奇。所有内容都由用户贡献、由用户维护:不会突然冒出付费墙,不会在角落塞广告位,也不会把你的数据卖给第三方。
产品会持续迭代,站内日志页记录着每一次改动,改了什么都有迹可循;想了解这个站是怎么一步步走到今天的,翻翻日志就能看到来龙去脉。
如果在这里看到涉嫌违规的内容,点对应卡片右侧的“举报”按钮就能提交,我们会尽快核实处理;也谢谢你花一点时间,一起把这里维护干净。
趋势
如何用 shadcn/ui 构建生产级 Card 组件
Card 组件可能是 Web 开发里最常见的 UI 模式了。你在房产列表 App、SaaS 分析仪表盘、电商商品页、后台管理面板里到处都能看到它们。但想要构建一个 hover 状态干净利落、支持暗色模式、可访问性好、并且各种屏幕尺寸下都能正常显示的 Card,可不仅仅是把内容包进一个 <div> 那么简单。你需要一个一致的组件结构、可靠的设计系统,以及经过深思熟虑的 Tailwind 模式。
在这篇文章里,我会带你用 shadcn/ui 和 Shadcn Space 里的 Base UI 原语,构建四种生产级的 Card 组件。每个 Card 都针对一个真实的、开发者日常会遇到的 UI 模式。
学完之后,你会得到:
- 一个 预览卡(Preview Card),带有分组 hover 图片效果、覆盖箭头图标和房产详情布局
- 一个 分析卡(Analytics Card),带有类型化的 metric 属性、条件徽章颜色和装饰性背景图片
- 一个 统计卡(Statistics Card),带有响应式四列电商统计网格和图标徽章
- 一个 电商产品变体卡(Ecommerce Product Variant Card),包含尺寸选择、心愿单切换、购物袋按钮和购买按钮上的涟漪动画
目录
- 前置要求
- 为什么用 shadcn/ui?
- Shadcn Space 是什么?
- 你要构建什么
- 如何设置 CLI 注册表
- 如何构建预览卡(card-02)
- 如何构建分析卡(card-05)
- 如何构建统计卡(card-06)
- 如何构建电商产品变体卡(card-17)
- 快速参考表
- 关键概念总结
- 结语
- 资源
前置要求
开始之前,确保你已经准备好以下内容:
- 安装了 Node.js 18 或更高版本
- 有一个已搭建好的 Next.js 或 React 项目
- 你的项目中已经初始化了 shadcn/ui(运行
npx shadcn@latest init) - Tailwind CSS 已配置好
- 具备 React 和 TypeScript 的基础知识
如果你还没有初始化 shadcn/ui,请先在项目根目录运行 npx shadcn@latest init 并按提示操作,然后再继续。
为什么用 shadcn/ui?
shadcn/ui 是一套基于 Radix UI、Base UI 构建的可访问、开源 React 组件集合,并使用 Tailwind CSS 进行样式设计。它的工作方式与传统组件库不同。你不是安装一个包,而是通过 CLI 将组件源文件直接复制到你的项目中。这意味着你拥有每一行代码的所有权。你可以阅读它、编辑它,而且组件永远不会因为你无法控制的库更新而损坏。
一些关键优势:
- 默认可访问:基于 Radix UI 和 Base UI 原语构建
- 完全基于 Tailwind:没有外部 CSS 文件,没有特异性冲突
- 零锁定:组件位于你的
components/文件夹中,而不是node_modules里 - 随处可用:Next.js、Vite、Astro、Remix 和其他 React 框架
你将在本教程中使用的 Card、Badge、Button 和 Separator 组件都来自 shadcn/ui 的基础安装。
Shadcn Space 是什么?
Shadcn Space 是一个开源的注册表,提供了基于 shadcn/ui 构建的生产级组件和 UI 块。它在默认的 shadcn/ui 组件集基础上进行了扩展,增加了从常见模式到高度吸引人的布局的各种变体。
与默认的 shadcn/ui Card 组件的关键区别在于,Shadcn Space 的卡片是为特定的布局模式设计的。你开箱即用就能获得更多的结构。Shadcn Space 中的每个组件都同时支持 Radix UI 和 Base UI 原语。你还可以使用“复制提示”(Copy Prompt)功能。本教程使用的是 Base UI 版本。
安装方式与任何 shadcn/ui 组件相同,只需一个 CLI 命令,源文件就会放到你的项目中。你可以在 Shadcn 卡片组件库 中浏览完整的卡片集合。
你要构建什么
以下是你要构建的四张卡片及其具体功能的概览:
预览卡(card-02)
- 大图,带有 hover 亮度和缩放动画
- 仅在 hover 时显示的箭头图标
- 物业名称和位置
- 青绿色系的价格徽章
- 带有床、浴室和面积图标的设施行
分析卡(card-05)
- 类型化的 TypeScript 属性,带有内置的默认数据集
- 两个由垂直分隔符分隔的指标列
- 基于正/负趋势的条件徽章颜色
- 固定在右下角的装饰性背景图片
统计卡(card-06)
- 四列响应式网格,在移动设备上堆叠显示
- 每个指标使用 Iconify Solar 图标集
- 带有趋势方向图标的徽章
- 最后一列的边框分隔线自动移除
电商产品变体卡(card-17)
- 带有 3D 投影和 hover 缩放的产品图片
- 支持暗色模式的心形心愿单切换
- 带有高亮状态的尺寸选择器
- 点击时填充的购物袋图标切换
- 带有 CSS 涟漪动画的“立即购买”按钮
- 带有序数后缀格式的动态交货日期
如何设置 CLI 注册表
在运行任何安装命令之前,你需要先在 components.json 文件中注册 Shadcn Space 注册表。打开项目根目录下的 components.json,添加 registries 字段:
{
"registries": {
"@shadcn-space": {
"url": "https://shadcnspace.com/r/{name}.json"
}
}
}
这告诉 shadcn CLI 在哪里可以找到以 @shadcn-space/ 为前缀的组件。如果没有这一步,本教程中的所有安装命令都会失败。
添加注册表后,你的完整 components.json 应该看起来像这样:
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils"
},
"registries": {
"@shadcn-space": {
"url": "https://shadcnspace.com/r/{name}.json"
}
}
}
关于 CLI 如何与第三方注册表配合使用的完整指南,请访问 入门指南。你也可以观看 视频教程,如果你更喜欢跟着视频学习的话。
如何构建预览卡(card-02)
预览卡是做什么的
预览卡专为房产列表、酒店页面或任何需要大图配合下方支持性内容的设计而打造。当用户将鼠标悬停在卡片上时,图片会变暗并放大。一个箭头图标会出现在角落。图片下方会显示标题、位置、价格徽章和设施行。
如何安装预览卡
根据你的包管理器运行以下命令之一:
npm:
npx shadcn@latest add @shadcn-space/card-02
pnpm:
pnpm dlx shadcn@latest add @shadcn-space/card-02
Yarn:
yarn dlx shadcn@latest add @shadcn-space/card-02
Bun:
bunx --bun shadcn@latest add @shadcn-space/card-02
CLI 会将组件复制到你的项目中的以下位置:
components/
shadcn-space/
card/
Card-02.tsx
组件代码
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { ArrowRight, Bath, BedDouble, Expand } from "lucide-react";
const PreviewCard = () => (
<Card className="relative gap-0 py-0 rounded-2xl group hover:shadow-3xl duration-300">
<div className="overflow-hidden rounded-t-2xl">
<a href="#">
<div className="w-full h-72">
<img
src="https://images.shadcnspace.com/assets/card/property-cover-1.jpg"
alt="Serenity Residential Home"
width={440}
height={300}
className="w-full h-full object-cover rounded-t-2xl group-hover:brightness-50 group-hover:scale-125 transition duration-300 delay-75"
/>
</div>
</a>
<div className="absolute top-6 right-6 hidden p-4 bg-white rounded-full group-hover:block">
<ArrowRight className="text-card-foreground" />
</div>
</div>
<div className="p-6">
<div className="flex justify-between gap-5 mb-6">
<div>
<a href="#">
<h3 className="text-xl font-medium duration-300 group-hover:text-primary">
Serenity Residential Home
</h3>
</a>
<p className="text-base font-normal text-muted-foreground">
15 S Aurora Ave, Miami
</p>
</div>
<Badge className="px-5 py-4 text-base font-normal rounded-full bg-teal-500/10 text-teal-500">
$570,000
</Badge>
</div>
<div className="flex items-center gap-6">
<div className="flex items-center gap-2">
<BedDouble className="w-5 h-5 text-muted-foreground" />
<span className="text-base text-muted-foreground">3 Beds</span>
</div>
<div className="flex items-center gap-2">
<Bath className="w-5 h-5 text-muted-foreground" />
<span className="text-base text-muted-foreground">2 Baths</span>
</div>
<div className="flex items-center gap-2">
<Expand className="w-5 h-5 text-muted-foreground" />
<span className="text-base text-muted-foreground">1,500 sqft</span>
</div>
</div>
</div>
</Card>
);
export default PreviewCard;
深入理解代码
让我带你拆解一下这个组件,看看每个部分是怎么工作的,以及为什么要这么写。
外层 Card 容器:我们用了 group 类,这是 Tailwind 的一个分组功能。它允许父元素上的 hover 状态影响子元素。比如当鼠标悬停在整个卡片上时,图片会变暗并缩放,箭头图标会显示,标题颜色也会变化。hover:shadow-3xl 提供了 hover 时的阴影效果,让卡片有“浮起来”的感觉。
图片区域:图片被包裹在一个 overflow-hidden 的 div 里,这是为了防止缩放后的图片溢出边界。group-hover:brightness-50 让图片变暗到 50% 亮度,group-hover:scale-125 让它放大到 125%。transition duration-300 delay-75 控制动画持续 300 毫秒,延迟 75 毫秒开始。这个延迟很重要——它让动画感觉更自然,而不是一上来就猛冲。
箭头图标:默认是 hidden,只有 hover 时才显示。absolute top-6 right-6 把它定位在图片区域的右上角。白色背景和圆角让它看起来像一个悬浮的按钮。这里有个小细节:图标容器用了 p-4,这意味着点击区域比图标本身大,提高了可用性。
内容区域:价格徽章用了 bg-teal-500/10 和 text-teal-500,这是一个半透明背景加实色文字的组合,看起来很现代。设施图标使用了 Lucide React 图标库的 BedDouble、Bath 和 Expand 图标。每个图标都配有文字说明,并且用 flex items-center gap-2 来对齐。
如何使用这个组件
在你的页面中引入并使用它:
import PreviewCard from "@/components/shadcn-space/card/Card-02";
export default function PropertyPage() {
return (
<div className="max-w-md mx-auto p-4">
<PreviewCard />
</div>
);
}
实时预览
你可以在这里查看 预览卡的实时演示。
如何构建分析卡(card-05)
分析卡是做什么的
分析卡用于展示两个关键指标的对比,比如本月 vs 上月的收入或用户数。它包含类型化的 TypeScript 属性、条件徽章颜色、垂直分隔符,以及一个装饰性的背景图片。
如何安装分析卡
运行以下命令之一:
npm:
npx shadcn@latest add @shadcn-space/card-05
pnpm:
pnpm dlx shadcn@latest add @shadcn-space/card-05
Yarn:
yarn dlx shadcn@latest add @shadcn-space/card-05
Bun:
bunx --bun shadcn@latest add @shadcn-space/card-05
组件代码
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { Separator } from "@/components/ui/separator";
import { ArrowDown, ArrowUp } from "lucide-react";
interface Metric {
label: string;
value: string;
trend: number;
}
interface AnalyticsCardProps {
metrics?: [Metric, Metric];
}
const defaultMetrics: [Metric, Metric] = [
{ label: "Revenue", value: "$45,231", trend: 20.1 },
{ label: "Subscribers", value: "+2350", trend: -4.5 },
];
const AnalyticsCard = ({ metrics = defaultMetrics }: AnalyticsCardProps) => {
return (
<Card className="p-6 relative overflow-hidden">
<div className="flex items-center justify-between gap-8">
{metrics.map((metric, index) => (
<div key={index} className="flex items-center gap-8">
<div className="space-y-1">
<p className="text-sm text-muted-foreground">{metric.label}</p>
<p className="text-2xl font-bold">{metric.value}</p>
<Badge
variant={metric.trend >= 0 ? "default" : "destructive"}
className="gap-1"
>
{metric.trend >= 0 ? (
<ArrowUp className="w-3 h-3" />
) : (
<ArrowDown className="w-3 h-3" />
)}
{Math.abs(metric.trend)}%
</Badge>
</div>
{index === 0 && <Separator orientation="vertical" className="h-20" />}
</div>
))}
</div>
<img
src="https://images.shadcnspace.com/assets/card/pattern-1.svg"
alt=""
className="absolute -bottom-6 -right-6 opacity-10 pointer-events-none"
width={150}
height={150}
/>
</Card>
);
};
export default AnalyticsCard;
深入理解代码
这个组件展示了 TypeScript 在 React 组件中的强大之处。我们来看看关键部分。
类型定义:Metric 接口定义了每个指标的结构:label(标签)、value(值)和 trend(趋势,一个正负数)。AnalyticsCardProps 接口定义了一个可选的 metrics 属性,它是一个包含两个 Metric 对象的元组。如果用户没有传入自定义数据,组件会使用 defaultMetrics。
条件徽章颜色:Badge 的 variant 属性根据 trend 的正负值动态设置为 "default" 或 "destructive"。在 shadcn/ui 的默认主题中,default 通常是绿色,destructive 是红色。这样用户一眼就能看出趋势是上升还是下降。
趋势箭头图标:我们根据 trend 的正负值条件渲染 ArrowUp 或 ArrowDown 图标。注意这里用了 Math.abs(metric.trend) 来显示绝对值,所以趋势值始终显示为正数,但箭头指示了方向。
垂直分隔符:Separator 组件只在第一个指标后面显示(index === 0)。orientation="vertical" 让它变成一条竖线,h-20 控制它的高度。这个分隔符在视觉上清晰地区分了两个指标。
装饰性背景图片:<img> 标签被定位在卡片的右下角(-bottom-6 -right-6),opacity-10 让它几乎透明,pointer-events-none 确保它不会干扰用户交互。这是一个很常见的设计技巧:用微弱的背景图案增加视觉层次感,而不分散注意力。
如何使用这个组件
import AnalyticsCard from "@/components/shadcn-space/card/Card-05";
export default function DashboardPage() {
return (
<div className="max-w-2xl mx-auto p-4">
<AnalyticsCard />
{/* 或者传入自定义数据 */}
<AnalyticsCard
metrics={[
{ label: "Page Views", value: "12,847", trend: 8.3 },
{ label: "Bounce Rate", value: "32.1%", trend: -2.1 },
]}
/>
</div>
);
}
实时预览
你可以在这里查看 分析卡的实时演示。
如何构建统计卡(card-06)
统计卡是做什么的
统计卡用于电商仪表盘,以网格形式展示多个关键指标,比如总收入、订单数、客户数和转化率。每个指标都有一个对应的图标、数值和趋势徽章。
如何安装统计卡
运行以下命令之一:
npm:
npx shadcn@latest add @shadcn-space/card-06
pnpm:
pnpm dlx shadcn@latest add @shadcn-space/card-06
Yarn:
yarn dlx shadcn@latest add @shadcn-space/card-06
Bun:
bunx --bun shadcn@latest add @shadcn-space/card-06
组件代码
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { ArrowUp, ArrowDown } from "lucide-react";
interface Stat {
label: string;
value: string;
trend: number;
icon: React.ReactNode;
}
interface StatisticsCardProps {
stats?: Stat[];
}
const defaultStats: Stat[] = [
{
label: "Total Revenue",
value: "$45,231",
trend: 20.1,
icon: (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M11.5 1L18 10H5l6.5-9zm0 22L5 14h13l-6.5 9z"/>
</svg>
),
},
{
label: "Orders",
value: "+1,234",
trend: -4.5,
icon: (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-7 14l-5-5 1.41-1.41L12 14.17l6.59-6.59L20 9l-8 8z"/>
</svg>
),
},
{
label: "Customers",
value: "+5,678",
trend: 12.3,
icon: (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/>
</svg>
),
},
{
label: "Conversion Rate",
value: "3.24%",
trend: -1.2,
icon: (
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<path fill="currentColor" d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/>
</svg>
),
},
];
const StatisticsCard = ({ stats = defaultStats }: StatisticsCardProps) => {
return (
<Card className="p-6">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-6">
{stats.map((stat, index) => (
<div key={index} className="flex flex-col gap-4">
<div className="flex items-center justify-between">
<div className="p-2 rounded-lg bg-muted">
{stat.icon}
</div>
<Badge
variant={stat.trend >= 0 ? "default" : "destructive"}
className="gap-1"
>
{stat.trend >= 0 ? (
<ArrowUp className="w-3 h-3" />
) : (
<ArrowDown className="w-3 h-3" />
)}
{Math.abs(stat.trend)}%
</Badge>
</div>
<div>
<p className="text-sm text-muted-foreground">{stat.label}</p>
<p className="text-2xl font-bold">{stat.value}</p>
</div>
{index < stats.length - 1 && (
<div className="hidden lg:block border-r border-border h-full" />
)}
</div>
))}
</div>
</Card>
);
};
export default StatisticsCard;
深入理解代码
这个组件的关键在于它的响应式网格布局和自动分隔符管理。
响应式网格:grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 实现了从单列到两列再到四列的平滑过渡。在手机上,每个指标占一整行;在平板尺寸上,变成两列;在大屏幕上,四列并排显示。
图标系统:这里使用了内联 SVG 图标,而不是外部图标库。这样做的好处是无需安装额外的依赖,而且 SVG 是“当前颜色”(currentColor)的,会自动继承父元素的文字颜色。如果你更喜欢使用 Iconify 或其他图标库,完全可以替换掉这些 SVG。
条件徽章:和之前的分析卡一样,我们根据 trend 的正负值动态设置徽章的变体和箭头方向。
自动分隔符移除:注意最后这部分代码:
{index < stats.length - 1 && (
<div className="hidden lg:block border-r border-border h-full" />
)}
这确保了最后一个指标后面不会显示分隔线。hidden lg:block 意味着分隔线只在桌面端显示,在移动端会被隐藏,避免了在小屏幕上出现拥挤的竖线。
如何使用这个组件
import StatisticsCard from "@/components/shadcn-space/card/Card-06";
export default function DashboardPage() {
return (
<div className="max-w-4xl mx-auto p-4">
<StatisticsCard />
</div>
);
}
实时预览
你可以在这里查看 统计卡的实时演示。
如何构建电商产品变体卡(card-17)
电商产品变体卡是做什么的
这是最复杂的一张卡片,专为电商产品详情页设计。它包含产品图片(带有 3D 投影和 hover 缩放)、心愿单切换按钮、尺寸选择器、购物袋图标和“立即购买”按钮(带有涟漪动画),以及动态计算的交货日期。
如何安装电商产品变体卡
运行以下命令之一:
npm:
npx shadcn@latest add @shadcn-space/c