返回 AiToEarn
card.tsx
1 /**
2 * Card - 卡片组件
3 * 支持两种 API:
4 * 1. 简化 API:<Card title="标题" extra={<Button />}>内容</Card>
5 * 2. shadcn/ui 标准 API:<Card><CardHeader><CardTitle>标题</CardTitle></CardHeader><CardContent>内容</CardContent></Card>
6 */
7
8 'use client'
9
10 import * as React from 'react'
11 import { cn } from '@/utils/className'
12
13 // ==================== shadcn/ui 标准子组件 ====================
14
15 const Card = React.forwardRef<
16 HTMLDivElement,
17 React.HTMLAttributes<HTMLDivElement>
18 >(({ className, ...props }, ref) => (
19 <div
20 ref={ref}
21 className={cn(
22 'rounded-lg border bg-card text-card-foreground shadow-sm',
23 className,
24 )}
25 {...props}
26 />
27 ))
28 Card.displayName = 'Card'
29
30 const CardHeader = React.forwardRef<
31 HTMLDivElement,
32 React.HTMLAttributes<HTMLDivElement>
33 >(({ className, ...props }, ref) => (
34 <div
35 ref={ref}
36 className={cn('flex flex-col space-y-1.5 p-6', className)}
37 {...props}
38 />
39 ))
40 CardHeader.displayName = 'CardHeader'
41
42 const CardTitle = React.forwardRef<
43 HTMLParagraphElement,
44 React.HTMLAttributes<HTMLHeadingElement>
45 >(({ className, ...props }, ref) => (
46 <h3
47 ref={ref}
48 className={cn(
49 'text-2xl font-semibold leading-none tracking-tight',
50 className,
51 )}
52 {...props}
53 />
54 ))
55 CardTitle.displayName = 'CardTitle'
56
57 const CardDescription = React.forwardRef<
58 HTMLParagraphElement,
59 React.HTMLAttributes<HTMLParagraphElement>
60 >(({ className, ...props }, ref) => (
61 <p
62 ref={ref}
63 className={cn('text-sm text-muted-foreground', className)}
64 {...props}
65 />
66 ))
67 CardDescription.displayName = 'CardDescription'
68
69 const CardContent = React.forwardRef<
70 HTMLDivElement,
71 React.HTMLAttributes<HTMLDivElement>
72 >(({ className, ...props }, ref) => (
73 <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />
74 ))
75 CardContent.displayName = 'CardContent'
76
77 const CardFooter = React.forwardRef<
78 HTMLDivElement,
79 React.HTMLAttributes<HTMLDivElement>
80 >(({ className, ...props }, ref) => (
81 <div
82 ref={ref}
83 className={cn('flex items-center p-6 pt-0', className)}
84 {...props}
85 />
86 ))
87 CardFooter.displayName = 'CardFooter'
88
89 // ==================== 简化 API 组件(兼容旧代码) ====================
90
91 interface SimpleCardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'title'> {
92 /** 标题 */
93 title?: React.ReactNode
94 /** 额外内容 */
95 extra?: React.ReactNode
96 }
97
98 function SimpleCard({ className, title, extra, children, ...props }: SimpleCardProps) {
99 return (
100 <div
101 className={cn('rounded-lg border bg-card text-card-foreground shadow-sm', className)}
102 {...props}
103 >
104 {(title || extra) && (
105 <div className="flex items-center justify-between p-6 pb-4">
106 {title && <h3 className="text-lg font-semibold">{title}</h3>}
107 {extra && <div>{extra}</div>}
108 </div>
109 )}
110 <div className={cn('p-6', !title && !extra && 'p-6')}>{children}</div>
111 </div>
112 )
113 }
114
115 export { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, SimpleCard }
116
116 lines Plain Text