@catalystsoftware/ui 1.0.4 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/tailwind.config.js +261 -3821
- package/dist/components/catalyst-ui/buttons/burger.tsx +207 -0
- package/dist/components/catalyst-ui/core/data-display/timeline.tsx +210 -0
- package/dist/components/catalyst-ui/core/feedback/alert.tsx +491 -0
- package/dist/components/catalyst-ui/core/feedback/spinner-1.tsx +65 -0
- package/dist/components/catalyst-ui/core/feedback/toast.tsx +1857 -0
- package/dist/components/catalyst-ui/core/navigation/menu.tsx +164 -0
- package/dist/components/catalyst-ui/forms/toggle-class.tsx +176 -0
- package/dist/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +419 -0
- package/dist/components/catalyst-ui/hooks/use-counter.tsx +13 -0
- package/dist/components/catalyst-ui/hooks/use-event-listener.tsx +23 -0
- package/dist/components/catalyst-ui/hooks/use-export-markdown.tsx +47 -0
- package/dist/components/catalyst-ui/hooks/use-focus.tsx +17 -0
- package/dist/components/catalyst-ui/hooks/use-interval.tsx +23 -0
- package/dist/components/catalyst-ui/hooks/use-is-client.tsx +16 -0
- package/dist/components/catalyst-ui/hooks/use-media-query.tsx +19 -0
- package/dist/components/catalyst-ui/hooks/use-mobile.tsx +19 -0
- package/dist/components/catalyst-ui/hooks/use-resize-observer.tsx +81 -0
- package/dist/components/catalyst-ui/hooks/use-timeout.tsx +21 -0
- package/dist/components/catalyst-ui/hooks/use-timer.tsx +209 -0
- package/dist/components/catalyst-ui/hooks/use-toggle.tsx +12 -0
- package/dist/components/catalyst-ui/media/image.tsx +13 -0
- package/dist/components/catalyst-ui/overlays/dual-sidebar.tsx +4142 -0
- package/dist/components/catalyst-ui/overlays/sidebar-original.tsx +726 -0
- package/dist/components/catalyst-ui/primitives/accordion.tsx +250 -0
- package/dist/components/catalyst-ui/primitives/alert-dialog.tsx +126 -0
- package/dist/components/catalyst-ui/primitives/aspect-ratio.tsx +9 -0
- package/dist/components/catalyst-ui/primitives/avatar.tsx +296 -0
- package/dist/components/catalyst-ui/primitives/badge.tsx +57 -0
- package/dist/components/catalyst-ui/primitives/breadcrumb.tsx +101 -0
- package/dist/components/catalyst-ui/primitives/button.tsx +265 -0
- package/dist/components/catalyst-ui/primitives/calendar-v4.tsx +208 -0
- package/dist/components/catalyst-ui/primitives/calendar.tsx +295 -0
- package/dist/components/catalyst-ui/primitives/card.tsx +618 -0
- package/dist/components/catalyst-ui/primitives/carousel.tsx +238 -0
- package/dist/components/catalyst-ui/primitives/chart.tsx +347 -0
- package/dist/components/catalyst-ui/primitives/checkbox.tsx +225 -0
- package/dist/components/catalyst-ui/primitives/collapsible.tsx +212 -0
- package/dist/components/catalyst-ui/primitives/command.tsx +393 -0
- package/dist/components/catalyst-ui/primitives/context-menu.tsx +236 -0
- package/dist/components/catalyst-ui/primitives/dialog.tsx +471 -0
- package/dist/components/catalyst-ui/primitives/drawer.tsx +761 -0
- package/dist/components/catalyst-ui/primitives/dropdown-menu.tsx +290 -0
- package/dist/components/catalyst-ui/primitives/empty.tsx +104 -0
- package/dist/components/catalyst-ui/primitives/field.tsx +244 -0
- package/dist/components/catalyst-ui/primitives/hover-card.tsx +124 -0
- package/dist/components/catalyst-ui/primitives/input-otp.tsx +76 -0
- package/dist/components/catalyst-ui/primitives/input.tsx +64 -0
- package/dist/components/catalyst-ui/primitives/item.tsx +196 -0
- package/dist/components/catalyst-ui/primitives/kbd.tsx +75 -0
- package/dist/components/catalyst-ui/primitives/label.tsx +24 -0
- package/dist/components/catalyst-ui/primitives/navigation-menu.tsx +150 -0
- package/dist/components/catalyst-ui/primitives/pagination.tsx +198 -0
- package/dist/components/catalyst-ui/primitives/popover.tsx +232 -0
- package/dist/components/catalyst-ui/primitives/progress.tsx +34 -0
- package/dist/components/catalyst-ui/primitives/radio-group.tsx +43 -0
- package/dist/components/catalyst-ui/primitives/resizable.tsx +56 -0
- package/dist/components/catalyst-ui/primitives/select.tsx +155 -0
- package/dist/components/catalyst-ui/primitives/separator.tsx +74 -0
- package/dist/components/catalyst-ui/primitives/sheet.tsx +126 -0
- package/dist/components/catalyst-ui/primitives/skeleton.tsx +15 -0
- package/dist/components/catalyst-ui/primitives/slider.tsx +27 -0
- package/dist/components/catalyst-ui/primitives/switch.tsx +187 -0
- package/dist/components/catalyst-ui/primitives/tabs.tsx +335 -0
- package/dist/components/catalyst-ui/primitives/textarea.tsx +24 -0
- package/dist/components/catalyst-ui/primitives/toggle-group.tsx +55 -0
- package/dist/components/catalyst-ui/primitives/toggle.tsx +42 -0
- package/dist/components/catalyst-ui/primitives/tooltip.tsx +116 -0
- package/dist/components/catalyst-ui/utils/basic-auth.tsx +40 -0
- package/dist/components/catalyst-ui/utils/context-storage.tsx +19 -0
- package/dist/components/catalyst-ui/utils/cors-middleware.tsx +71 -0
- package/dist/components/catalyst-ui/utils/deferred-content.tsx +595 -0
- package/dist/components/catalyst-ui/utils/honeypot-middleware.tsx +38 -0
- package/dist/components/catalyst-ui/utils/incId.tsx +75 -0
- package/dist/components/catalyst-ui/utils/jwk-auth.tsx +36 -0
- package/dist/components/catalyst-ui/utils/request-id.tsx +14 -0
- package/dist/components/catalyst-ui/utils/secure-headers.tsx +37 -0
- package/dist/components/catalyst-ui/utils/server-timing.tsx +23 -0
- package/dist/components/catalyst-ui/utils/utils.ts +43 -0
- package/dist/components/catalyst-ui/utils/with-cookie.tsx +43 -0
- package/dist/components/catalyst-ui/x/accordian-x.tsx +428 -0
- package/dist/components/catalyst-ui/x/alert-x.tsx +413 -0
- package/dist/components/catalyst-ui/x/animated-text-x.tsx +2242 -0
- package/dist/components/catalyst-ui/x/avatar-x.tsx +515 -0
- package/dist/components/catalyst-ui/x/badge-x.tsx +670 -0
- package/dist/components/catalyst-ui/x/button-X.tsx +2857 -0
- package/dist/components/catalyst-ui/x/button-group-x.tsx +847 -0
- package/dist/components/catalyst-ui/x/calendar-x.tsx +1910 -0
- package/dist/components/catalyst-ui/x/card-x.tsx +2597 -0
- package/dist/components/catalyst-ui/x/checkbox-x.tsx +656 -0
- package/dist/components/catalyst-ui/x/collapsible-x.tsx +1360 -0
- package/dist/components/catalyst-ui/x/combobox-x.tsx +911 -0
- package/dist/components/catalyst-ui/x/data-table-x.tsx +1753 -0
- package/dist/components/catalyst-ui/x/date-picker-x.tsx +648 -0
- package/dist/components/catalyst-ui/x/dialog-x.tsx +659 -0
- package/dist/components/catalyst-ui/x/dropdown-menu-x.tsx +612 -0
- package/dist/components/catalyst-ui/x/hover-card-x.tsx +375 -0
- package/dist/components/catalyst-ui/x/icon-x.tsx +840 -0
- package/dist/components/catalyst-ui/x/input-mask-x.tsx +981 -0
- package/dist/components/catalyst-ui/x/input-otp-x.tsx +659 -0
- package/dist/components/catalyst-ui/x/loader-x.tsx +1757 -0
- package/dist/components/catalyst-ui/x/pagination-x.tsx +622 -0
- package/dist/components/catalyst-ui/x/popover-x.tsx +744 -0
- package/dist/components/catalyst-ui/x/radio-group-x.tsx +499 -0
- package/dist/components/catalyst-ui/x/select-x.tsx +1127 -0
- package/dist/components/catalyst-ui/x/sheet-x.tsx +668 -0
- package/dist/components/catalyst-ui/x/switch-x.tsx +681 -0
- package/dist/components/catalyst-ui/x/table-x.tsx +574 -0
- package/dist/components/catalyst-ui/x/tabs-x.tsx +839 -0
- package/dist/components/catalyst-ui/x/textarea-x.tsx +1263 -0
- package/dist/components/catalyst-ui/x/tooltip-x.tsx +396 -0
- package/dist/components/catalyst-ui/x/tracker-x.tsx +560 -0
- package/dist/data/bg-data.tsx +901 -0
- package/dist/data/buttons-data.tsx +2327 -0
- package/dist/data/charts-data.tsx +102 -0
- package/dist/data/chat-data.tsx +83 -0
- package/dist/data/code-data.tsx +1040 -0
- package/dist/data/comboboxes-data.tsx +1843 -0
- package/dist/data/command-data.tsx +1381 -0
- package/dist/data/core-data.tsx +15953 -0
- package/dist/data/crm-data.tsx +47 -0
- package/dist/data/data.tsx +159 -0
- package/dist/data/date-and-time-data.tsx +554 -0
- package/dist/data/dependencies.tsx +7 -0
- package/dist/data/ecommerce-data.tsx +1387 -0
- package/dist/data/forms-data.tsx +7890 -0
- package/dist/data/hooks-data.tsx +5487 -0
- package/dist/data/index.ts +34 -0
- package/dist/data/inputs-data.tsx +557 -0
- package/dist/data/interactive-data.tsx +5394 -0
- package/dist/data/lofi-data.tsx +18295 -0
- package/dist/data/marketing-data.tsx +2546 -0
- package/dist/data/media-data.tsx +1510 -0
- package/dist/data/motion-data.tsx +5801 -0
- package/dist/data/overlay-data.tsx +4136 -0
- package/dist/data/pdf-data.tsx +124 -0
- package/dist/data/pos-data.tsx +213 -0
- package/dist/data/postcss.config.js +6 -0
- package/dist/data/primitive-data.tsx +5170 -0
- package/dist/data/prompt-data.tsx +1226 -0
- package/dist/data/requiredLibs.ts +4 -0
- package/dist/data/sandbox-data.tsx +1 -0
- package/dist/data/sidebars-data.tsx +5421 -0
- package/dist/data/stacks-data.tsx +32 -0
- package/dist/data/table-data.tsx +706 -0
- package/dist/data/tailwind.config.js +270 -0
- package/dist/data/tailwind.config.ngin.js +3830 -0
- package/dist/data/tailwind.css +431 -0
- package/dist/data/tools-data.tsx +6910 -0
- package/dist/data/typography-data.tsx +2050 -0
- package/dist/data/utils-data.tsx +6500 -0
- package/dist/data/x-data.tsx +1171 -0
- package/dist/data.tsx +159 -0
- package/package.json +1 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -362
|
@@ -0,0 +1,2597 @@
|
|
|
1
|
+
import React, { useState, useEffect, useRef, createContext } from 'react'
|
|
2
|
+
import { cn } from '~/components/catalyst-ui'
|
|
3
|
+
import {
|
|
4
|
+
Card,
|
|
5
|
+
CardHeader,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardFooter,
|
|
8
|
+
CardTitle,
|
|
9
|
+
CardDescription,
|
|
10
|
+
CardAction,
|
|
11
|
+
CardImage,
|
|
12
|
+
CardHeart,
|
|
13
|
+
CardProduct,
|
|
14
|
+
cardVariants,
|
|
15
|
+
cardHeaderVariants,
|
|
16
|
+
cardTitleVariants,
|
|
17
|
+
cardDescriptionVariants,
|
|
18
|
+
cardContentVariants,
|
|
19
|
+
cardFooterVariants,
|
|
20
|
+
cardActionVariants,
|
|
21
|
+
} from '~/components/catalyst-ui/primitives/card'
|
|
22
|
+
import { Avatar, AvatarImage, AvatarFallback } from '~/components/catalyst-ui'
|
|
23
|
+
import { Button } from '~/components/catalyst-ui'
|
|
24
|
+
import { Badge } from '~/components/catalyst-ui'
|
|
25
|
+
import { Tabs, TabsList, TabsTrigger, TabsContent } from '~/components/catalyst-ui'
|
|
26
|
+
import type { LucideIcon } from 'lucide-react'
|
|
27
|
+
import {
|
|
28
|
+
XIcon,
|
|
29
|
+
HeartIcon,
|
|
30
|
+
MessageCircleIcon,
|
|
31
|
+
RepeatIcon,
|
|
32
|
+
SendIcon,
|
|
33
|
+
BadgeCheckIcon,
|
|
34
|
+
UserPlusIcon,
|
|
35
|
+
EllipsisIcon,
|
|
36
|
+
StarIcon,
|
|
37
|
+
CircleFadingPlusIcon
|
|
38
|
+
} from 'lucide-react'
|
|
39
|
+
import {
|
|
40
|
+
DropdownMenu,
|
|
41
|
+
DropdownMenuContent,
|
|
42
|
+
DropdownMenuGroup,
|
|
43
|
+
DropdownMenuItem,
|
|
44
|
+
DropdownMenuTrigger,
|
|
45
|
+
} from '~/components/catalyst-ui'
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* ★ ━━━━ ☆ ━━━━ CardX ━━━━ ☆ ━━━━ ★
|
|
49
|
+
* type CardXType =
|
|
50
|
+
* | 'default' | 'spotlight' | '3d' | 'closable' | 'tweet' | 'product' // Interactive & Social
|
|
51
|
+
* | 'productTop' | 'productBottom' | 'productLeft' | 'productRight' // Product Layouts
|
|
52
|
+
* | 'testimonial' | 'overlay' | 'horizontal' | 'topImage' | 'bottomImage' // Content Display
|
|
53
|
+
* | 'meeting' | 'invite' // Functional
|
|
54
|
+
*
|
|
55
|
+
* ★ ━━━━ ☆ ━━━━ USAGE ━━━━ ☆ ━━━━ ★
|
|
56
|
+
*
|
|
57
|
+
* ★ ━━━━━━━━━ Default Card ━━━━━━━━━ ★
|
|
58
|
+
* ```jsx
|
|
59
|
+
* <CardX className="max-w-md">
|
|
60
|
+
* <CardXHeader>
|
|
61
|
+
* <CardXTitle>Card Title</CardXTitle>
|
|
62
|
+
* <CardXDescription>Card description goes here</CardXDescription>
|
|
63
|
+
* </CardXHeader>
|
|
64
|
+
* <CardXContent>
|
|
65
|
+
* This is the default card content. You can put any content here.
|
|
66
|
+
* </CardXContent>
|
|
67
|
+
* <CardXFooter>
|
|
68
|
+
* <Button>Action</Button>
|
|
69
|
+
* </CardXFooter>
|
|
70
|
+
* </CardX>
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* ★ ━━━━━━━━━ Spotlight Card ━━━━━━━━━ ★
|
|
74
|
+
* ```jsx
|
|
75
|
+
* <CardX card="spotlight">
|
|
76
|
+
* <CardXHeader>
|
|
77
|
+
* <CardXTitle>Spotlight Card</CardXTitle>
|
|
78
|
+
* <CardXDescription>Hover to see the effect</CardXDescription>
|
|
79
|
+
* </CardXHeader>
|
|
80
|
+
* <CardXContent>
|
|
81
|
+
* This card has a beautiful spotlight effect that follows your cursor.
|
|
82
|
+
* </CardXContent>
|
|
83
|
+
* </CardX>
|
|
84
|
+
* ```
|
|
85
|
+
*
|
|
86
|
+
* ★ ━━━━━━━━━ 3D Card ━━━━━━━━━ ★
|
|
87
|
+
* ```jsx
|
|
88
|
+
* <div className="card-3d-wrapper">
|
|
89
|
+
* <CardX card="3d" className="max-w-md">
|
|
90
|
+
* <CardXHeader>
|
|
91
|
+
* <CardXTitle>3D Interactive Card</CardXTitle>
|
|
92
|
+
* <CardXDescription>Hover to see 3D effect</CardXDescription>
|
|
93
|
+
* </CardXHeader>
|
|
94
|
+
* <CardXContent image="https://example.com/image.jpg">
|
|
95
|
+
* This card tilts in 3D when you hover over it.
|
|
96
|
+
* </CardXContent>
|
|
97
|
+
* </CardX>
|
|
98
|
+
* </div>
|
|
99
|
+
* ```
|
|
100
|
+
*
|
|
101
|
+
* ★ ━━━━━━━━━ Closable Card ━━━━━━━━━ ★
|
|
102
|
+
* ```jsx
|
|
103
|
+
* {closableActive && (
|
|
104
|
+
* <CardX card="closable" className="max-w-md">
|
|
105
|
+
* <CardXHeader onClose={() => setClosableActive(false)}>
|
|
106
|
+
* Important Notice
|
|
107
|
+
* </CardXHeader>
|
|
108
|
+
* <CardXContent actionText="Got it">
|
|
109
|
+
* This is an important message that can be dismissed.
|
|
110
|
+
* </CardXContent>
|
|
111
|
+
* </CardX>
|
|
112
|
+
* )}
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* ★ ━━━━━━━━━ Tweet Card ━━━━━━━━━ ★
|
|
116
|
+
* ```jsx
|
|
117
|
+
* <CardX card="tweet" className="max-w-md">
|
|
118
|
+
* <CardXHeader
|
|
119
|
+
* avatar="https://example.com/avatar.jpg"
|
|
120
|
+
* name="John Doe"
|
|
121
|
+
* handle="johndoe"
|
|
122
|
+
* verified={true}
|
|
123
|
+
* />
|
|
124
|
+
* <CardXContent image="https://example.com/image.jpg">
|
|
125
|
+
* Just shipped a new feature! Check it out and let me know what you think. 🚀
|
|
126
|
+
* </CardXContent>
|
|
127
|
+
* <CardXFooter
|
|
128
|
+
* state={tweetState}
|
|
129
|
+
* setState={setTweetState}
|
|
130
|
+
* likes="124"
|
|
131
|
+
* comments="32"
|
|
132
|
+
* retweets="18"
|
|
133
|
+
* shares="7"
|
|
134
|
+
* />
|
|
135
|
+
* </CardX>
|
|
136
|
+
*
|
|
137
|
+
* // Tweet state management
|
|
138
|
+
* const [tweetState, setTweetState] = useState({
|
|
139
|
+
* liked: false,
|
|
140
|
+
* commented: false,
|
|
141
|
+
* retweeted: false,
|
|
142
|
+
* shared: false
|
|
143
|
+
* });
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* ★ ━━━━━━━━━ Product Card ━━━━━━━━━ ★
|
|
147
|
+
* ```jsx
|
|
148
|
+
* <CardX card="product" className="max-w-md border-none">
|
|
149
|
+
* <CardXProduct src="https://example.com/product.jpg" liked={productLiked} setLiked={setProductLiked}>
|
|
150
|
+
* <Card className="border-none">
|
|
151
|
+
* <CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
152
|
+
* <CardXContent>
|
|
153
|
+
* Crossing hardwood comfort with off-court flair.
|
|
154
|
+
* </CardXContent>
|
|
155
|
+
* <CardXFooter price1="Price" price2="$129.99" buttonLabel="Add to cart" onAddToCart={() => console.log('Added')} />
|
|
156
|
+
* </Card>
|
|
157
|
+
* </CardXProduct>
|
|
158
|
+
* </CardX>
|
|
159
|
+
* ```
|
|
160
|
+
*
|
|
161
|
+
* ★ ━━━━━━━━━ Product Card Layouts ━━━━━━━━━ ★
|
|
162
|
+
* ```jsx
|
|
163
|
+
* // Product Top Image
|
|
164
|
+
* <CardX card="productTop" className="border-none">
|
|
165
|
+
* <CardXProduct src="https://example.com/product.jpg" liked={productLiked} setLiked={setProductLiked}>
|
|
166
|
+
* <Card className="border-none">
|
|
167
|
+
* <CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
168
|
+
* <CardXContent>Premium materials and timeless design.</CardXContent>
|
|
169
|
+
* <CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
170
|
+
* </Card>
|
|
171
|
+
* </CardXProduct>
|
|
172
|
+
* </CardX>
|
|
173
|
+
*
|
|
174
|
+
* // Product Bottom Image
|
|
175
|
+
* <CardX card="productBottom" className="border-none">
|
|
176
|
+
* <CardXProduct src="https://example.com/product.jpg" liked={productLiked} setLiked={setProductLiked}>
|
|
177
|
+
* <Card className="border-none">
|
|
178
|
+
* <CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
179
|
+
* <CardXContent>Premium materials and timeless design.</CardXContent>
|
|
180
|
+
* <CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
181
|
+
* </Card>
|
|
182
|
+
* </CardXProduct>
|
|
183
|
+
* </CardX>
|
|
184
|
+
*
|
|
185
|
+
* // Product Left Image
|
|
186
|
+
* <CardX card="productLeft" className="border-none">
|
|
187
|
+
* <CardXProduct src="https://example.com/product.jpg" liked={productLiked} setLiked={setProductLiked}>
|
|
188
|
+
* <Card className="border-none">
|
|
189
|
+
* <CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
190
|
+
* <CardXContent>Premium materials and timeless design.</CardXContent>
|
|
191
|
+
* <CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
192
|
+
* </Card>
|
|
193
|
+
* </CardXProduct>
|
|
194
|
+
* </CardX>
|
|
195
|
+
*
|
|
196
|
+
* // Product Right Image
|
|
197
|
+
* <CardX card="productRight" className="border-none">
|
|
198
|
+
* <CardXProduct src="https://example.com/product.jpg" liked={productLiked} setLiked={setProductLiked}>
|
|
199
|
+
* <Card className="border-none">
|
|
200
|
+
* <CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
201
|
+
* <CardXContent>Premium materials and timeless design.</CardXContent>
|
|
202
|
+
* <CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
203
|
+
* </Card>
|
|
204
|
+
* </CardXProduct>
|
|
205
|
+
* </CardX>
|
|
206
|
+
* ```
|
|
207
|
+
*
|
|
208
|
+
* ★ ━━━━━━━━━ Testimonial Card ━━━━━━━━━ ★
|
|
209
|
+
* ```jsx
|
|
210
|
+
* <CardX card="testimonial" className="max-w-md">
|
|
211
|
+
* <CardXContent>
|
|
212
|
+
* "This product has completely transformed how I work. The attention to detail is incredible!"
|
|
213
|
+
* </CardXContent>
|
|
214
|
+
* <CardXFooter
|
|
215
|
+
* avatar="https://example.com/avatar.jpg"
|
|
216
|
+
* name="Sarah Johnson"
|
|
217
|
+
* handle="sarahj"
|
|
218
|
+
* rating={5}
|
|
219
|
+
* />
|
|
220
|
+
* </CardX>
|
|
221
|
+
* ```
|
|
222
|
+
*
|
|
223
|
+
* ★ ━━━━━━━━━ Overlay Card ━━━━━━━━━ ★
|
|
224
|
+
* ```jsx
|
|
225
|
+
* <CardX card="overlay">
|
|
226
|
+
* <CardXHeader>Stunning Destination</CardXHeader>
|
|
227
|
+
* <CardXContent image="https://example.com/image.jpg">
|
|
228
|
+
* Discover the beauty of nature in this breathtaking location.
|
|
229
|
+
* </CardXContent>
|
|
230
|
+
* </CardX>
|
|
231
|
+
* ```
|
|
232
|
+
*
|
|
233
|
+
* ★ ━━━━━━━━━ Horizontal Card ━━━━━━━━━ ★
|
|
234
|
+
* ```jsx
|
|
235
|
+
* <CardX card="horizontal" className="max-w-2xl">
|
|
236
|
+
* <CardXContent
|
|
237
|
+
* title="Featured Article"
|
|
238
|
+
* description="Learn about the latest trends"
|
|
239
|
+
* actionText="Read More"
|
|
240
|
+
* >
|
|
241
|
+
* <img
|
|
242
|
+
* src="https://example.com/image.jpg"
|
|
243
|
+
* alt="Article"
|
|
244
|
+
* className="h-full w-full rounded-l-xl object-cover"
|
|
245
|
+
* />
|
|
246
|
+
* </CardXContent>
|
|
247
|
+
* </CardX>
|
|
248
|
+
* ```
|
|
249
|
+
*
|
|
250
|
+
* ★ ━━━━━━━━━ Top Image Card ━━━━━━━━━ ★
|
|
251
|
+
* ```jsx
|
|
252
|
+
* <CardX card="topImage" className="max-w-md">
|
|
253
|
+
* <CardXContent image="https://example.com/image.jpg" />
|
|
254
|
+
* <CardXHeader>
|
|
255
|
+
* <CardXTitle>Beautiful Landscape</CardXTitle>
|
|
256
|
+
* <CardXDescription>Explore the wonders of nature</CardXDescription>
|
|
257
|
+
* </CardXHeader>
|
|
258
|
+
* <CardXFooter showActions onClick={() => console.log('explore')} onClick2={() => console.log('download')} />
|
|
259
|
+
* </CardX>
|
|
260
|
+
* ```
|
|
261
|
+
*
|
|
262
|
+
* ★ ━━━━━━━━━ Bottom Image Card ━━━━━━━━━ ★
|
|
263
|
+
* ```jsx
|
|
264
|
+
* <CardX card="bottomImage" className="max-w-md">
|
|
265
|
+
* <CardXHeader>
|
|
266
|
+
* <CardXTitle>Amazing View</CardXTitle>
|
|
267
|
+
* <CardXDescription>Experience the beauty</CardXDescription>
|
|
268
|
+
* </CardXHeader>
|
|
269
|
+
* <CardXContent image="https://example.com/image.jpg" />
|
|
270
|
+
* </CardX>
|
|
271
|
+
* ```
|
|
272
|
+
*
|
|
273
|
+
* ★ ━━━━━━━━━ Meeting Card ━━━━━━━━━ ★
|
|
274
|
+
* ```jsx
|
|
275
|
+
* <CardX card="meeting" className="max-w-md">
|
|
276
|
+
* <CardXHeader>
|
|
277
|
+
* <CardXTitle>Team Meeting</CardXTitle>
|
|
278
|
+
* <CardXDescription>Wednesday, 2:00 PM</CardXDescription>
|
|
279
|
+
* </CardXHeader>
|
|
280
|
+
* <CardXContent
|
|
281
|
+
* items={[
|
|
282
|
+
* 'Review Q4 goals',
|
|
283
|
+
* 'Discuss new project timeline',
|
|
284
|
+
* 'Team feedback session'
|
|
285
|
+
* ]}
|
|
286
|
+
* >
|
|
287
|
+
* Join us for our weekly sync to align on priorities.
|
|
288
|
+
* </CardXContent>
|
|
289
|
+
* <CardXFooter
|
|
290
|
+
* avatars={[
|
|
291
|
+
* { src: 'https://example.com/avatar1.jpg', name: 'John', fallback: 'JD' },
|
|
292
|
+
* { src: 'https://example.com/avatar2.jpg', name: 'Sarah', fallback: 'SJ' }
|
|
293
|
+
* ]}
|
|
294
|
+
* />
|
|
295
|
+
* </CardX>
|
|
296
|
+
* ```
|
|
297
|
+
*
|
|
298
|
+
* ★ ━━━━━━━━━ Invite Card ━━━━━━━━━ ★
|
|
299
|
+
* ```jsx
|
|
300
|
+
* <CardX card="invite" className="max-w-md">
|
|
301
|
+
* <CardXHeader>
|
|
302
|
+
* <CardXTitle>Team Members</CardXTitle>
|
|
303
|
+
* <CardXDescription>Manage your team</CardXDescription>
|
|
304
|
+
* </CardXHeader>
|
|
305
|
+
* <CardXContent
|
|
306
|
+
* showInvite
|
|
307
|
+
* members={[
|
|
308
|
+
* { avatar: 'https://example.com/avatar1.jpg', name: 'John Doe', role: 'Developer', fallback: 'JD' },
|
|
309
|
+
* { avatar: 'https://example.com/avatar2.jpg', name: 'Sarah Smith', role: 'Designer', fallback: 'SS' }
|
|
310
|
+
* ]}
|
|
311
|
+
* />
|
|
312
|
+
* </CardX>
|
|
313
|
+
* ```
|
|
314
|
+
*
|
|
315
|
+
* ★ ━━━━━━━━━ Card Groups ━━━━━━━━━ ★
|
|
316
|
+
* ```jsx
|
|
317
|
+
* // Horizontal Card Group (Default)
|
|
318
|
+
* <CardXGroup>
|
|
319
|
+
* <CardX>
|
|
320
|
+
* <CardXHeader>
|
|
321
|
+
* <CardXTitle>Card 1</CardXTitle>
|
|
322
|
+
* </CardXHeader>
|
|
323
|
+
* <CardXContent>First card content</CardXContent>
|
|
324
|
+
* </CardX>
|
|
325
|
+
* <CardX>
|
|
326
|
+
* <CardXHeader>
|
|
327
|
+
* <CardXTitle>Card 2</CardXTitle>
|
|
328
|
+
* </CardXHeader>
|
|
329
|
+
* <CardXContent>Second card content</CardXContent>
|
|
330
|
+
* </CardX>
|
|
331
|
+
* <CardX>
|
|
332
|
+
* <CardXHeader>
|
|
333
|
+
* <CardXTitle>Card 3</CardXTitle>
|
|
334
|
+
* </CardXHeader>
|
|
335
|
+
* <CardXContent>Third card content</CardXContent>
|
|
336
|
+
* </CardX>
|
|
337
|
+
* </CardXGroup>
|
|
338
|
+
*
|
|
339
|
+
* // Vertical Card Group
|
|
340
|
+
* <CardXGroup variant="vertical" className="max-w-md">
|
|
341
|
+
* <CardX>
|
|
342
|
+
* <CardXHeader>
|
|
343
|
+
* <CardXTitle>First Card</CardXTitle>
|
|
344
|
+
* </CardXHeader>
|
|
345
|
+
* <CardXContent>Content for first card</CardXContent>
|
|
346
|
+
* </CardX>
|
|
347
|
+
* <CardX>
|
|
348
|
+
* <CardXHeader>
|
|
349
|
+
* <CardXTitle>Second Card</CardXTitle>
|
|
350
|
+
* </CardXHeader>
|
|
351
|
+
* <CardXContent>Content for second card</CardXContent>
|
|
352
|
+
* </CardX>
|
|
353
|
+
* <CardX>
|
|
354
|
+
* <CardXHeader>
|
|
355
|
+
* <CardXTitle>Third Card</CardXTitle>
|
|
356
|
+
* </CardXHeader>
|
|
357
|
+
* <CardXContent>Content for third card</CardXContent>
|
|
358
|
+
* </CardX>
|
|
359
|
+
* </CardXGroup>
|
|
360
|
+
* ```
|
|
361
|
+
*
|
|
362
|
+
* ★ ━━━━━━━━━ Props ━━━━━━━━━ ★
|
|
363
|
+
*
|
|
364
|
+
* CardX Props:
|
|
365
|
+
* - `card`: CardXType - Specifies which variant to use
|
|
366
|
+
* - `className`: string - Additional CSS classes
|
|
367
|
+
*
|
|
368
|
+
* CardXHeader Props (for tweet variant):
|
|
369
|
+
* - `avatar`: string - Avatar image URL
|
|
370
|
+
* - `name`: string - Display name
|
|
371
|
+
* - `handle`: string - Twitter handle
|
|
372
|
+
* - `verified`: boolean - Show verified badge
|
|
373
|
+
*
|
|
374
|
+
* CardXHeader Props (for product variant):
|
|
375
|
+
* - `title`: string - Product title
|
|
376
|
+
* - `info1`: string - Product info 1 (e.g., size)
|
|
377
|
+
* - `info2`: string - Product info 2 (e.g., color)
|
|
378
|
+
*
|
|
379
|
+
* CardXContent Props:
|
|
380
|
+
* - `image`: string - Image URL to display
|
|
381
|
+
* - `actionText`: string - Call to action text (for closable card)
|
|
382
|
+
* - `items`: string[] - Bullet point items (for meeting card)
|
|
383
|
+
* - `showInvite`: boolean - Show invite UI (for invite card)
|
|
384
|
+
* - `members`: Array<{ avatar: string, name: string, role: string, fallback: string }> - Team members
|
|
385
|
+
*
|
|
386
|
+
* CardXFooter Props (for tweet variant):
|
|
387
|
+
* - `state`: { liked: boolean, commented: boolean, retweeted: boolean, shared: boolean }
|
|
388
|
+
* - `setState`: (state) => void - State update function
|
|
389
|
+
* - `likes`: string - Number of likes
|
|
390
|
+
* - `comments`: string - Number of comments
|
|
391
|
+
* - `retweets`: string - Number of retweets
|
|
392
|
+
* - `shares`: string - Number of shares
|
|
393
|
+
*
|
|
394
|
+
* CardXFooter Props (for testimonial variant):
|
|
395
|
+
* - `avatar`: string - Reviewer avatar
|
|
396
|
+
* - `name`: string - Reviewer name
|
|
397
|
+
* - `handle`: string - Reviewer handle
|
|
398
|
+
* - `rating`: number - Star rating 1-5
|
|
399
|
+
*
|
|
400
|
+
* CardXFooter Props (for product variant):
|
|
401
|
+
* - `price1`: string - Price label
|
|
402
|
+
* - `price2`: string - Price amount
|
|
403
|
+
* - `buttonLabel`: string - Button text
|
|
404
|
+
* - `onAddToCart`: () => void - Add to cart callback
|
|
405
|
+
*
|
|
406
|
+
* CardXFooter Props (for meeting variant):
|
|
407
|
+
* - `avatars`: Array<{ src: string, name: string, fallback: string }> - Avatar list
|
|
408
|
+
*
|
|
409
|
+
* CardXFooter Props (for general use):
|
|
410
|
+
* - `showActions`: boolean - Show action buttons
|
|
411
|
+
* - `onClick`: () => void - Primary action callback
|
|
412
|
+
* - `onClick2`: () => void - Secondary action callback
|
|
413
|
+
*
|
|
414
|
+
* CardXProduct Props:
|
|
415
|
+
* - `src`: string - Product image URL
|
|
416
|
+
* - `liked`: boolean - Whether product is liked
|
|
417
|
+
* - `setLiked`: (liked: boolean) => void - Like state update
|
|
418
|
+
* - `children`: ReactNode - Product content card
|
|
419
|
+
*
|
|
420
|
+
* CardXGroup Props:
|
|
421
|
+
* - `variant`: 'horizontal' | 'vertical' - Group layout direction
|
|
422
|
+
* - `className`: string - Additional CSS classes
|
|
423
|
+
* - `children`: ReactNode - CardX components
|
|
424
|
+
*
|
|
425
|
+
*/
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
// #endregion ===========================================================================
|
|
429
|
+
// TYPE DEFINITIONS
|
|
430
|
+
// #region ===========================================================================
|
|
431
|
+
type CardType =
|
|
432
|
+
| 'default'
|
|
433
|
+
| 'spotlight'
|
|
434
|
+
| '3d'
|
|
435
|
+
| 'closable'
|
|
436
|
+
| 'tweet'
|
|
437
|
+
| 'product'
|
|
438
|
+
| 'productTop'
|
|
439
|
+
| 'productBottom'
|
|
440
|
+
| 'productLeft'
|
|
441
|
+
| 'productRight'
|
|
442
|
+
| 'testimonial'
|
|
443
|
+
| 'overlay'
|
|
444
|
+
| 'horizontal'
|
|
445
|
+
| 'topImage'
|
|
446
|
+
| 'bottomImage'
|
|
447
|
+
| 'meeting'
|
|
448
|
+
| 'invite'
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
interface CardContextValue {
|
|
452
|
+
variant?: string
|
|
453
|
+
size?: string
|
|
454
|
+
align?: string
|
|
455
|
+
card?: CardType
|
|
456
|
+
padding?: string
|
|
457
|
+
spacing?: string
|
|
458
|
+
position?: string
|
|
459
|
+
weight?: string
|
|
460
|
+
interactive?: boolean
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const CardContext = createContext<CardContextValue>({})
|
|
464
|
+
|
|
465
|
+
const useCardContext = () => useContext(CardContext)
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
// #endregion ===========================================================================
|
|
469
|
+
// CONTEXT
|
|
470
|
+
// #region ===========================================================================
|
|
471
|
+
const CardXContext = React.createContext<CardType>('default')
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
interface CardContextValue {
|
|
475
|
+
variant?: string
|
|
476
|
+
size?: string
|
|
477
|
+
interactive?: boolean
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
// #endregion ===========================================================================
|
|
482
|
+
// CARDX PARENT WRAPPER
|
|
483
|
+
// #region ===========================================================================
|
|
484
|
+
export function CardX({ card = 'default', variant, size, interactive, align, weight, spacing, padding, layout, justify, gap, className, children, ...props }: any) {
|
|
485
|
+
const contextValue: CardContextValue = { card, variant, size, interactive, align, weight, spacing, padding, position, layout, justify, gap, }
|
|
486
|
+
switch (card) {
|
|
487
|
+
case 'spotlight':
|
|
488
|
+
return (
|
|
489
|
+
<CardXContext.Provider value={card}>
|
|
490
|
+
<CardContext.Provider value={contextValue}>
|
|
491
|
+
<div className='h-max w-max'>
|
|
492
|
+
<div className='spotlight-card group bg-border relative overflow-hidden rounded-xl p-px transition-all duration-300 ease-in-out'>
|
|
493
|
+
<Card className={cn(cardVariants({ variant, size, interactive, align }), 'group-hover:bg-card/90 max-w-80 border-none transition-all duration-300 ease-in-out group-hover:backdrop-blur-[20px]', className)} {...props} >
|
|
494
|
+
{children}
|
|
495
|
+
</Card>
|
|
496
|
+
<div className='blob absolute top-0 left-0 size-20 rounded-full bg-sky-600/60 opacity-0 blur-2xl transition-all duration-300 ease-in-out dark:bg-sky-400/60' />
|
|
497
|
+
<div className='fake-blob absolute top-0 left-0 size-20 rounded-full' />
|
|
498
|
+
</div>
|
|
499
|
+
</div>
|
|
500
|
+
</CardContext.Provider>
|
|
501
|
+
</CardXContext.Provider>
|
|
502
|
+
)
|
|
503
|
+
|
|
504
|
+
case 'overlay':
|
|
505
|
+
return (
|
|
506
|
+
<CardXContext.Provider value={card}>
|
|
507
|
+
<CardContext.Provider value={contextValue}>
|
|
508
|
+
<Card className={cn(cardVariants({ variant, size, interactive, align }), 'before:bg-primary/70 relative max-w-md py-0 before:absolute before:size-full before:rounded-xl', className)} {...props} >
|
|
509
|
+
{children}
|
|
510
|
+
</Card>
|
|
511
|
+
</CardContext.Provider>
|
|
512
|
+
</CardXContext.Provider>
|
|
513
|
+
)
|
|
514
|
+
|
|
515
|
+
default:
|
|
516
|
+
return (
|
|
517
|
+
<CardXContext.Provider value={card}>
|
|
518
|
+
<CardContext.Provider value={contextValue}>
|
|
519
|
+
<Card className={cn(cardVariants({ variant, size, interactive, align }), className)} {...props} >
|
|
520
|
+
{children}
|
|
521
|
+
</Card>
|
|
522
|
+
</CardContext.Provider>
|
|
523
|
+
</CardXContext.Provider>
|
|
524
|
+
)
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// #endregion ===========================================================================
|
|
529
|
+
// CARDX HEADER - STRUCTURAL VARIANTS
|
|
530
|
+
// #region ===========================================================================
|
|
531
|
+
export function CardXHeader({ children, ...props }: any) {
|
|
532
|
+
const { card, spacing, align } = useCardContext()
|
|
533
|
+
|
|
534
|
+
switch (card) {
|
|
535
|
+
case 'product':
|
|
536
|
+
case 'productTop':
|
|
537
|
+
case 'productBottom':
|
|
538
|
+
case 'productLeft':
|
|
539
|
+
case 'productRight':
|
|
540
|
+
return (
|
|
541
|
+
<CardHeader className={cn(cardHeaderVariants({ spacing, align }), props.className)}>
|
|
542
|
+
<CardTitle>{props.title}</CardTitle>
|
|
543
|
+
<CardDescription className='flex items-center gap-2'>
|
|
544
|
+
{props.info1 && <Badge variant='outline' className='rounded-sm'>{props.info1}</Badge>}
|
|
545
|
+
{props.info2 && <Badge variant='outline' className='rounded-sm'>{props.info2}</Badge>}
|
|
546
|
+
{children}
|
|
547
|
+
</CardDescription>
|
|
548
|
+
</CardHeader>
|
|
549
|
+
)
|
|
550
|
+
case 'tweet':
|
|
551
|
+
return (
|
|
552
|
+
<CardHeader className={cn(cardHeaderVariants({ spacing, align, }), 'flex-row items-center justify-between gap-3', props.className)}>
|
|
553
|
+
<div className='flex items-center gap-3'>
|
|
554
|
+
<Avatar className='ring-ring ring-2'>
|
|
555
|
+
<AvatarImage src={props.avatar} alt={props.name} />
|
|
556
|
+
<AvatarFallback className='text-xs'>{props.name?.[0]}</AvatarFallback>
|
|
557
|
+
</Avatar>
|
|
558
|
+
<div className='flex flex-col gap-0.5'>
|
|
559
|
+
<CardTitle className='flex items-center gap-1 text-sm'>
|
|
560
|
+
{props.name} {props.verified && <BadgeCheckIcon className='size-4 fill-sky-600 stroke-white dark:fill-sky-400' />}
|
|
561
|
+
</CardTitle>
|
|
562
|
+
<CardDescription>@{props.handle}</CardDescription>
|
|
563
|
+
</div>
|
|
564
|
+
</div>
|
|
565
|
+
<CardXAction />
|
|
566
|
+
</CardHeader>
|
|
567
|
+
)
|
|
568
|
+
|
|
569
|
+
case 'closable':
|
|
570
|
+
return (
|
|
571
|
+
<CardHeader className={cn(cardHeaderVariants({ spacing, align, }), 'relative', props.className)}>
|
|
572
|
+
<Button
|
|
573
|
+
variant='ghost'
|
|
574
|
+
size='icon'
|
|
575
|
+
onClick={props.onClose}
|
|
576
|
+
className='absolute top-2 right-2 rounded-full'
|
|
577
|
+
>
|
|
578
|
+
<XIcon />
|
|
579
|
+
<span className='sr-only'>Close</span>
|
|
580
|
+
</Button>
|
|
581
|
+
<CardTitle className='text-center'>{children}</CardTitle>
|
|
582
|
+
</CardHeader>
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
case 'overlay':
|
|
586
|
+
return (
|
|
587
|
+
<CardHeader className={cn(cardHeaderVariants({ spacing, align, }), 'text-primary-foreground w-full pt-6 absolute', props.className)}>
|
|
588
|
+
<CardTitle>{children}</CardTitle>
|
|
589
|
+
</CardHeader>
|
|
590
|
+
)
|
|
591
|
+
|
|
592
|
+
default:
|
|
593
|
+
return (
|
|
594
|
+
<CardHeader
|
|
595
|
+
className={cn(
|
|
596
|
+
cardHeaderVariants({
|
|
597
|
+
spacing,
|
|
598
|
+
align: align || (context.variant === 'default' ? 'left' : undefined)
|
|
599
|
+
}),
|
|
600
|
+
props.className
|
|
601
|
+
)}
|
|
602
|
+
{...props}
|
|
603
|
+
/>
|
|
604
|
+
)
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
// #endregion ===========================================================================
|
|
609
|
+
// CARDX TITLE - PASSTHROUGH
|
|
610
|
+
// #region ===========================================================================
|
|
611
|
+
export function CardXTitle({ ...props }: any) {
|
|
612
|
+
const { card, size, weight } = useCardContext()
|
|
613
|
+
switch (card) {
|
|
614
|
+
default:
|
|
615
|
+
return (
|
|
616
|
+
<CardTitle
|
|
617
|
+
className={cn(cardTitleVariants({ size, weight }), className)}
|
|
618
|
+
{...props}
|
|
619
|
+
/>
|
|
620
|
+
)
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
// #endregion ===========================================================================
|
|
625
|
+
// CARDX DESCRIPTION - PASSTHROUGH
|
|
626
|
+
// #region ===========================================================================
|
|
627
|
+
export function CardXDescription({ ...props }: any) {
|
|
628
|
+
const { card, size, } = useCardContext()
|
|
629
|
+
|
|
630
|
+
switch (card) {
|
|
631
|
+
default:
|
|
632
|
+
return (
|
|
633
|
+
<CardDescription
|
|
634
|
+
className={cn(cardDescriptionVariants({ size }), props.className)}
|
|
635
|
+
{...props}
|
|
636
|
+
/>
|
|
637
|
+
)
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// #endregion ===========================================================================
|
|
642
|
+
// CARDX ACTION - PASSTHROUGH
|
|
643
|
+
// #region ===========================================================================
|
|
644
|
+
export function CardXAction({ onClick, items, ...props }: any) {
|
|
645
|
+
const { card, position } = useCardContext()
|
|
646
|
+
switch (card) {
|
|
647
|
+
case 'tweet':
|
|
648
|
+
return (
|
|
649
|
+
<div className='flex items-center gap-2'>
|
|
650
|
+
<Button variant='outline' size='sm' onClick={onClick}>
|
|
651
|
+
<UserPlusIcon />
|
|
652
|
+
Follow
|
|
653
|
+
</Button>
|
|
654
|
+
<DropdownMenu>
|
|
655
|
+
<DropdownMenuTrigger asChild>
|
|
656
|
+
<Button variant='ghost' size='icon' aria-label='Toggle menu'>
|
|
657
|
+
<EllipsisIcon />
|
|
658
|
+
</Button>
|
|
659
|
+
</DropdownMenuTrigger>
|
|
660
|
+
<DropdownMenuContent className="w-56" align="start">
|
|
661
|
+
<DropdownMenuGroup>
|
|
662
|
+
{items?.map((item: any, index: number) => (
|
|
663
|
+
<DropdownMenuItem key={index} onSelect={item.onSelect}>
|
|
664
|
+
{item.name}
|
|
665
|
+
</DropdownMenuItem>
|
|
666
|
+
))}
|
|
667
|
+
</DropdownMenuGroup>
|
|
668
|
+
</DropdownMenuContent>
|
|
669
|
+
</DropdownMenu>
|
|
670
|
+
</div>
|
|
671
|
+
)
|
|
672
|
+
default:
|
|
673
|
+
return (
|
|
674
|
+
<CardAction
|
|
675
|
+
data-slot="card-action"
|
|
676
|
+
className={cn(cardActionVariants({ position }), props.className)}
|
|
677
|
+
{...props}
|
|
678
|
+
/>
|
|
679
|
+
)
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
// #endregion ===========================================================================
|
|
684
|
+
// CARDX CONTENT - STRUCTURAL VARIANTS
|
|
685
|
+
// #region ===========================================================================
|
|
686
|
+
export function CardXContent({ children, ...props }: any) {
|
|
687
|
+
const { card, padding, spacing } = useCardContext()
|
|
688
|
+
const cardRef = useRef<HTMLDivElement>(null)
|
|
689
|
+
const imageRef = useRef<HTMLImageElement>(null)
|
|
690
|
+
const animationFrameRef = useRef<number | undefined>(undefined)
|
|
691
|
+
const lastMousePosition = useRef({ x: 0, y: 0 })
|
|
692
|
+
// Spotlight effect
|
|
693
|
+
useEffect(() => {
|
|
694
|
+
if (card !== 'spotlight') return
|
|
695
|
+
|
|
696
|
+
const all = document.querySelectorAll('.spotlight-card')
|
|
697
|
+
|
|
698
|
+
const handleMouseMove = (ev: MouseEvent) => {
|
|
699
|
+
all.forEach(e => {
|
|
700
|
+
const blob = e.querySelector('.blob') as HTMLElement
|
|
701
|
+
const fblob = e.querySelector('.fake-blob') as HTMLElement
|
|
702
|
+
|
|
703
|
+
if (!blob || !fblob) return
|
|
704
|
+
|
|
705
|
+
const rec = fblob.getBoundingClientRect()
|
|
706
|
+
blob.style.opacity = '1'
|
|
707
|
+
|
|
708
|
+
blob.animate(
|
|
709
|
+
[
|
|
710
|
+
{
|
|
711
|
+
transform: `translate(${ev.clientX - rec.left - rec.width / 2
|
|
712
|
+
}px, ${ev.clientY - rec.top - rec.height / 2}px)`
|
|
713
|
+
}
|
|
714
|
+
],
|
|
715
|
+
{
|
|
716
|
+
duration: 300,
|
|
717
|
+
fill: 'forwards'
|
|
718
|
+
}
|
|
719
|
+
)
|
|
720
|
+
})
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
window.addEventListener('mousemove', handleMouseMove)
|
|
724
|
+
return () => window.removeEventListener('mousemove', handleMouseMove)
|
|
725
|
+
}, [card])
|
|
726
|
+
|
|
727
|
+
// 3D effect
|
|
728
|
+
useEffect(() => {
|
|
729
|
+
if (card !== '3d') return
|
|
730
|
+
|
|
731
|
+
const card = cardRef.current?.closest('.card-3d-wrapper') as HTMLElement
|
|
732
|
+
const image = imageRef.current
|
|
733
|
+
|
|
734
|
+
if (!card || !image) return
|
|
735
|
+
|
|
736
|
+
let rect: DOMRect
|
|
737
|
+
let centerX: number
|
|
738
|
+
let centerY: number
|
|
739
|
+
|
|
740
|
+
const updateCardTransform = (mouseX: number, mouseY: number) => {
|
|
741
|
+
if (!rect) {
|
|
742
|
+
rect = card.getBoundingClientRect()
|
|
743
|
+
centerX = rect.left + rect.width / 2
|
|
744
|
+
centerY = rect.top + rect.height / 2
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
const relativeX = mouseX - centerX
|
|
748
|
+
const relativeY = mouseY - centerY
|
|
749
|
+
|
|
750
|
+
const cardTransform: CardTransform = {
|
|
751
|
+
rotateX: -relativeY * 0.035,
|
|
752
|
+
rotateY: relativeX * 0.035,
|
|
753
|
+
scale: 1.025
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
const imageTransform: CardTransform = {
|
|
757
|
+
rotateX: -relativeY * 0.025,
|
|
758
|
+
rotateY: relativeX * 0.025,
|
|
759
|
+
scale: 1.05
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
return { cardTransform, imageTransform }
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const animate = () => {
|
|
766
|
+
const { cardTransform, imageTransform } = updateCardTransform(
|
|
767
|
+
lastMousePosition.current.x,
|
|
768
|
+
lastMousePosition.current.y
|
|
769
|
+
)
|
|
770
|
+
|
|
771
|
+
card.style.transform = `perspective(1000px) rotateX(${cardTransform.rotateX}deg) rotateY(${cardTransform.rotateY}deg) scale3d(${cardTransform.scale}, ${cardTransform.scale}, ${cardTransform.scale})`
|
|
772
|
+
card.style.boxShadow = '0 10px 35px rgba(0, 0, 0, 0.2)'
|
|
773
|
+
|
|
774
|
+
image.style.transform = `perspective(1000px) rotateX(${imageTransform.rotateX}deg) rotateY(${imageTransform.rotateY}deg) scale3d(${imageTransform.scale}, ${imageTransform.scale}, ${imageTransform.scale})`
|
|
775
|
+
|
|
776
|
+
animationFrameRef.current = requestAnimationFrame(animate)
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
const handleMouseMove = (e: MouseEvent) => {
|
|
780
|
+
lastMousePosition.current = { x: e.clientX, y: e.clientY }
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
const handleMouseEnter = () => {
|
|
784
|
+
card.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease'
|
|
785
|
+
image.style.transition = 'transform 0.2s ease'
|
|
786
|
+
animate()
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
const handleMouseLeave = () => {
|
|
790
|
+
if (animationFrameRef.current) {
|
|
791
|
+
cancelAnimationFrame(animationFrameRef.current)
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
|
|
795
|
+
card.style.boxShadow = 'none'
|
|
796
|
+
card.style.transition = 'transform 0.5s ease, box-shadow 0.5s ease'
|
|
797
|
+
|
|
798
|
+
image.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
|
|
799
|
+
image.style.transition = 'transform 0.5s ease'
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
card.addEventListener('mouseenter', handleMouseEnter)
|
|
803
|
+
card.addEventListener('mousemove', handleMouseMove)
|
|
804
|
+
card.addEventListener('mouseleave', handleMouseLeave)
|
|
805
|
+
|
|
806
|
+
return () => {
|
|
807
|
+
if (animationFrameRef.current) {
|
|
808
|
+
cancelAnimationFrame(animationFrameRef.current)
|
|
809
|
+
}
|
|
810
|
+
card.removeEventListener('mouseenter', handleMouseEnter)
|
|
811
|
+
card.removeEventListener('mousemove', handleMouseMove)
|
|
812
|
+
card.removeEventListener('mouseleave', handleMouseLeave)
|
|
813
|
+
}
|
|
814
|
+
}, [card])
|
|
815
|
+
|
|
816
|
+
switch (card) {
|
|
817
|
+
case '3d':
|
|
818
|
+
return (
|
|
819
|
+
<CardContent ref={cardRef} className={cn(cardContentVariants({ padding, spacing: 'loose' }), props.className)}>
|
|
820
|
+
<img
|
|
821
|
+
ref={imageRef}
|
|
822
|
+
src={props.image}
|
|
823
|
+
alt={props.imageAlt || 'Banner'}
|
|
824
|
+
className='aspect-video w-full rounded-md object-cover'
|
|
825
|
+
width={500}
|
|
826
|
+
height={500}
|
|
827
|
+
/>
|
|
828
|
+
{children}
|
|
829
|
+
</CardContent>
|
|
830
|
+
)
|
|
831
|
+
|
|
832
|
+
case 'tweet':
|
|
833
|
+
return (
|
|
834
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing: 'loose' }), 'text-sm', props.className)}>
|
|
835
|
+
{props.image && (
|
|
836
|
+
<img
|
|
837
|
+
src={props.image}
|
|
838
|
+
alt='Banner'
|
|
839
|
+
className='aspect-video w-full rounded-md object-cover'
|
|
840
|
+
/>
|
|
841
|
+
)}
|
|
842
|
+
{children}
|
|
843
|
+
</CardContent>
|
|
844
|
+
)
|
|
845
|
+
|
|
846
|
+
case 'closable':
|
|
847
|
+
return (
|
|
848
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'flex flex-col gap-4 text-center', props.className)}>
|
|
849
|
+
{children}
|
|
850
|
+
{props.actionText && <Button>{props.actionText}</Button>}
|
|
851
|
+
</CardContent>
|
|
852
|
+
)
|
|
853
|
+
|
|
854
|
+
case 'testimonial':
|
|
855
|
+
return (
|
|
856
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), props.className)}>
|
|
857
|
+
{children}
|
|
858
|
+
</CardContent>
|
|
859
|
+
)
|
|
860
|
+
|
|
861
|
+
case 'overlay':
|
|
862
|
+
return (
|
|
863
|
+
<>
|
|
864
|
+
<CardContent className='px-0' >
|
|
865
|
+
<img
|
|
866
|
+
src={props.image}
|
|
867
|
+
alt='Banner'
|
|
868
|
+
className='h-70 w-112 rounded-xl'
|
|
869
|
+
/>
|
|
870
|
+
</CardContent>
|
|
871
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'text-primary-foreground/80 absolute', props.className)}>
|
|
872
|
+
{children}
|
|
873
|
+
</CardContent>
|
|
874
|
+
</>
|
|
875
|
+
)
|
|
876
|
+
|
|
877
|
+
case 'horizontal':
|
|
878
|
+
return (
|
|
879
|
+
<div className='flex items-center'>
|
|
880
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'grow-1 px-0', props.className)} >
|
|
881
|
+
{children}
|
|
882
|
+
</CardContent>
|
|
883
|
+
<div className='sm:min-w-54'>
|
|
884
|
+
<CardHeader className='pt-6'>
|
|
885
|
+
<CardTitle>{props.title}</CardTitle>
|
|
886
|
+
<CardDescription>{props.description}</CardDescription>
|
|
887
|
+
</CardHeader>
|
|
888
|
+
{props.actionText && (
|
|
889
|
+
<CardFooter className='gap-3 py-6'>
|
|
890
|
+
<Button className='bg-transparent bg-gradient-to-br from-purple-500 to-pink-500 text-white focus-visible:ring-pink-600/20'>
|
|
891
|
+
{props.actionText}
|
|
892
|
+
</Button>
|
|
893
|
+
</CardFooter>
|
|
894
|
+
)}
|
|
895
|
+
</div>
|
|
896
|
+
</div>
|
|
897
|
+
)
|
|
898
|
+
|
|
899
|
+
case 'topImage':
|
|
900
|
+
return (
|
|
901
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'px-0', props.className)} {...props} >
|
|
902
|
+
<img
|
|
903
|
+
src={props.image}
|
|
904
|
+
alt='Banner'
|
|
905
|
+
className='aspect-video h-70 rounded-t-xl object-cover'
|
|
906
|
+
/>
|
|
907
|
+
</CardContent>
|
|
908
|
+
)
|
|
909
|
+
|
|
910
|
+
case 'bottomImage':
|
|
911
|
+
return (
|
|
912
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'px-0', props.className)} {...props} >
|
|
913
|
+
<img
|
|
914
|
+
src={props.image}
|
|
915
|
+
alt='Banner'
|
|
916
|
+
className='aspect-video h-70 rounded-b-xl object-cover'
|
|
917
|
+
/>
|
|
918
|
+
</CardContent>
|
|
919
|
+
)
|
|
920
|
+
|
|
921
|
+
case 'meeting':
|
|
922
|
+
return (
|
|
923
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'text-sm', props.className)}>
|
|
924
|
+
<p>{props.children}</p>
|
|
925
|
+
{props.items && (
|
|
926
|
+
<ol className='mt-4 flex list-decimal flex-col gap-2 pl-6'>
|
|
927
|
+
{props.items.map((item: string, i: number) => (
|
|
928
|
+
<li key={i}>{item}</li>
|
|
929
|
+
))}
|
|
930
|
+
</ol>
|
|
931
|
+
)}
|
|
932
|
+
</CardContent>
|
|
933
|
+
)
|
|
934
|
+
|
|
935
|
+
case 'invite':
|
|
936
|
+
return (
|
|
937
|
+
<CardContent className={cn(cardContentVariants({ padding, spacing }), 'grid gap-4 sm:grid-cols-2', props.className)}>
|
|
938
|
+
{props.showInvite && (
|
|
939
|
+
<div className='flex items-center gap-4'>
|
|
940
|
+
<CircleFadingPlusIcon />
|
|
941
|
+
<span className='text-sm font-semibold'>Invite Member</span>
|
|
942
|
+
</div>
|
|
943
|
+
)}
|
|
944
|
+
{props.members?.map((member: any, i: number) => (
|
|
945
|
+
<div key={i} className='flex items-center gap-4'>
|
|
946
|
+
<Avatar>
|
|
947
|
+
<AvatarImage src={member.avatar} alt={member.name} />
|
|
948
|
+
<AvatarFallback className='text-xs'>{member.fallback}</AvatarFallback>
|
|
949
|
+
</Avatar>
|
|
950
|
+
<div className='flex flex-col'>
|
|
951
|
+
<span className='text-sm font-semibold'>{member.name}</span>
|
|
952
|
+
<span className='text-muted-foreground text-sm'>{member.role}</span>
|
|
953
|
+
</div>
|
|
954
|
+
</div>
|
|
955
|
+
))}
|
|
956
|
+
</CardContent>
|
|
957
|
+
)
|
|
958
|
+
|
|
959
|
+
default:
|
|
960
|
+
return <CardContent className={cn(cardContentVariants({ padding, spacing }), props.className)} {...props} />
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
// #endregion ===========================================================================
|
|
965
|
+
// CARDX FOOTER - STRUCTURAL VARIANTS
|
|
966
|
+
// #region ===========================================================================
|
|
967
|
+
export function CardXFooter({ state = {
|
|
968
|
+
liked: false,
|
|
969
|
+
commented: false,
|
|
970
|
+
retweeted: false,
|
|
971
|
+
shared: false
|
|
972
|
+
},
|
|
973
|
+
setState,
|
|
974
|
+
className,
|
|
975
|
+
children,
|
|
976
|
+
...props
|
|
977
|
+
}: any) {
|
|
978
|
+
const { card, layout, justify, align, gap, } = useCardContext()
|
|
979
|
+
/**const [state, setState] = useState({
|
|
980
|
+
liked: false,
|
|
981
|
+
commented: false,
|
|
982
|
+
retweeted: false,
|
|
983
|
+
shared: false
|
|
984
|
+
})
|
|
985
|
+
|
|
986
|
+
// Pass to CardXFooter
|
|
987
|
+
<CardXFooter
|
|
988
|
+
state={tweetState}
|
|
989
|
+
setState={setTweetState}
|
|
990
|
+
/> */
|
|
991
|
+
switch (card) {
|
|
992
|
+
case 'product':
|
|
993
|
+
case 'productTop':
|
|
994
|
+
case 'productBottom':
|
|
995
|
+
case 'productLeft':
|
|
996
|
+
case 'productRight':
|
|
997
|
+
return (
|
|
998
|
+
<CardFooter className={cn(cardFooterVariants({ layout, justify: justify || 'between', align, gap: gap || 'md' }), 'max-sm:flex-col max-sm:items-stretch', props.className)}>
|
|
999
|
+
<div className='flex flex-col'>
|
|
1000
|
+
<span className='text-sm font-medium uppercase'>{props.price1 || 'Price'}</span>
|
|
1001
|
+
<span className='text-xl font-semibold'>{props.price2}</span>
|
|
1002
|
+
</div>
|
|
1003
|
+
{children}
|
|
1004
|
+
{props.buttonLabel && <Button size='lg' onClick={props.onAddToCart}>{props.buttonLabel}</Button>}
|
|
1005
|
+
</CardFooter>
|
|
1006
|
+
)
|
|
1007
|
+
case 'tweet':
|
|
1008
|
+
return (
|
|
1009
|
+
<CardFooter className={cn(cardFooterVariants({ layout, justify, align, gap: gap || 'sm' }), props.className)}>
|
|
1010
|
+
<Button variant='ghost' size='sm' onClick={() => setState((prev) => ({
|
|
1011
|
+
...prev,
|
|
1012
|
+
liked: !prev.liked
|
|
1013
|
+
}))}>
|
|
1014
|
+
<HeartIcon className={cn(props.state?.liked && 'fill-destructive stroke-destructive')} />
|
|
1015
|
+
{state.likes || '0'}
|
|
1016
|
+
</Button>
|
|
1017
|
+
<Button variant='ghost' size='sm' onClick={() => setState((prev) => ({
|
|
1018
|
+
...prev,
|
|
1019
|
+
commented: !prev.commented
|
|
1020
|
+
}))}>
|
|
1021
|
+
<MessageCircleIcon />
|
|
1022
|
+
{state.comments || '0'}
|
|
1023
|
+
</Button>
|
|
1024
|
+
<Button variant='ghost' size='sm' onClick={() => setState((prev) => ({
|
|
1025
|
+
...prev,
|
|
1026
|
+
retweeted: !prev.retweeted
|
|
1027
|
+
}))}>
|
|
1028
|
+
<RepeatIcon />
|
|
1029
|
+
{state.retweets || '0'}
|
|
1030
|
+
</Button>
|
|
1031
|
+
<Button variant='ghost' size='sm' onClick={() => setState((prev) => ({
|
|
1032
|
+
...prev,
|
|
1033
|
+
shared: !prev.shared
|
|
1034
|
+
}))}>
|
|
1035
|
+
<SendIcon />
|
|
1036
|
+
{state.shares || '0'}
|
|
1037
|
+
</Button>
|
|
1038
|
+
</CardFooter>
|
|
1039
|
+
)
|
|
1040
|
+
|
|
1041
|
+
case 'testimonial':
|
|
1042
|
+
return (
|
|
1043
|
+
<CardFooter className={cn(cardFooterVariants({ layout, justify: justify || 'between', align, gap }), 'max-sm:flex-col max-sm:items-stretch', props.className)}>
|
|
1044
|
+
<div className='flex items-center gap-3'>
|
|
1045
|
+
<Avatar className='ring-ring ring-2'>
|
|
1046
|
+
<AvatarImage src={props.avatar} alt={props.name} />
|
|
1047
|
+
<AvatarFallback className='text-xs'>{props.name?.[0]}</AvatarFallback>
|
|
1048
|
+
</Avatar>
|
|
1049
|
+
<div className='flex flex-col gap-0.5'>
|
|
1050
|
+
<CardTitle className='flex items-center gap-1 text-sm'>{props.name}</CardTitle>
|
|
1051
|
+
<CardDescription>@{props.handle}</CardDescription>
|
|
1052
|
+
</div>
|
|
1053
|
+
</div>
|
|
1054
|
+
<div className='flex items-center gap-1'>
|
|
1055
|
+
{[...Array(5)].map((_, i) => (
|
|
1056
|
+
<StarIcon
|
|
1057
|
+
key={i}
|
|
1058
|
+
className={cn(
|
|
1059
|
+
'size-5',
|
|
1060
|
+
i < (props.rating || 5)
|
|
1061
|
+
? 'fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400'
|
|
1062
|
+
: 'stroke-amber-500 dark:stroke-amber-400'
|
|
1063
|
+
)}
|
|
1064
|
+
/>
|
|
1065
|
+
))}
|
|
1066
|
+
</div>
|
|
1067
|
+
</CardFooter>
|
|
1068
|
+
)
|
|
1069
|
+
|
|
1070
|
+
case 'topImage':
|
|
1071
|
+
if (!props.showActions) return null
|
|
1072
|
+
return (
|
|
1073
|
+
<CardFooter className={cn(cardFooterVariants({ layout, justify, align, gap }), 'max-sm:flex-col max-sm:items-stretch', props.className)}>
|
|
1074
|
+
<Button onClick={props.onClick}>Explore More</Button>
|
|
1075
|
+
<Button onClick={props.onClick2} variant='outline'>Download Now</Button>
|
|
1076
|
+
</CardFooter>
|
|
1077
|
+
)
|
|
1078
|
+
|
|
1079
|
+
case 'meeting':
|
|
1080
|
+
if (!props.avatars) return null
|
|
1081
|
+
return (
|
|
1082
|
+
<CardFooter className={cn(cardFooterVariants({ layout, justify, align, gap }), props.className)}>
|
|
1083
|
+
<div className='flex -space-x-2 hover:space-x-1'>
|
|
1084
|
+
{props.avatars.map((avatar: any, index: number) => (
|
|
1085
|
+
<Avatar key={index} className='ring-background ring-2 transition-all duration-300 ease-in-out'>
|
|
1086
|
+
<AvatarImage src={avatar.src} alt={avatar.name} />
|
|
1087
|
+
<AvatarFallback className='text-xs'>{avatar.fallback}</AvatarFallback>
|
|
1088
|
+
</Avatar>
|
|
1089
|
+
))}
|
|
1090
|
+
</div>
|
|
1091
|
+
</CardFooter>
|
|
1092
|
+
)
|
|
1093
|
+
case 'product':
|
|
1094
|
+
case 'productTop':
|
|
1095
|
+
case 'productBottom':
|
|
1096
|
+
case 'productLeft':
|
|
1097
|
+
case 'productRight':
|
|
1098
|
+
break;
|
|
1099
|
+
default:
|
|
1100
|
+
return <CardFooter className={cn(cardFooterVariants({ layout, justify, align, gap }), className)} {...props} />
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// #endregion ===========================================================================
|
|
1105
|
+
// CARDX IMAGE - STRUCTURAL VARIANTS
|
|
1106
|
+
// #region ===========================================================================
|
|
1107
|
+
export function CardXImage({ ...props }: any) {
|
|
1108
|
+
const { card, } = useCardContext()
|
|
1109
|
+
|
|
1110
|
+
switch (card) {
|
|
1111
|
+
default:
|
|
1112
|
+
return <CardImage {...props} />
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
// #endregion ===========================================================================
|
|
1117
|
+
// CARDX HEART - STRUCTURAL VARIANTS
|
|
1118
|
+
// #region ===========================================================================
|
|
1119
|
+
export function CardXHeart({ filled, ...props }: any) {
|
|
1120
|
+
const [liked, setLiked] = useState(filled || false)
|
|
1121
|
+
const { card, } = useCardContext()
|
|
1122
|
+
|
|
1123
|
+
switch (card) {
|
|
1124
|
+
case 'product':
|
|
1125
|
+
return (
|
|
1126
|
+
<Button
|
|
1127
|
+
size='icon'
|
|
1128
|
+
onClick={() => setLiked(!liked)}
|
|
1129
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
1130
|
+
>
|
|
1131
|
+
<CardHeart filled={liked} className={cn('h-4 w-4', liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
1132
|
+
<span className='sr-only'>Like</span>
|
|
1133
|
+
</Button>
|
|
1134
|
+
)
|
|
1135
|
+
|
|
1136
|
+
default:
|
|
1137
|
+
return <CardHeart {...props} />
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
// #endregion ===========================================================================
|
|
1142
|
+
// CARDX PRODUCT - STRUCTURAL VARIANTS
|
|
1143
|
+
// #region ===========================================================================
|
|
1144
|
+
export function CardXProduct({ variant, filled, ...props }: any) {
|
|
1145
|
+
const { card, } = useCardContext()
|
|
1146
|
+
switch (card) {
|
|
1147
|
+
case 'productTop':
|
|
1148
|
+
return (
|
|
1149
|
+
<div className='relative max-w-md rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 pt-0 shadow-lg'>
|
|
1150
|
+
<div className='flex h-60 items-center justify-center'>
|
|
1151
|
+
<img src={props.src} alt='product' className='w-75' />
|
|
1152
|
+
</div>
|
|
1153
|
+
<Button
|
|
1154
|
+
size='icon'
|
|
1155
|
+
onClick={() => props.setLiked(!props.liked)}
|
|
1156
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
1157
|
+
>
|
|
1158
|
+
<HeartIcon className={cn(props.liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
1159
|
+
<span className='sr-only'>Like</span>
|
|
1160
|
+
</Button>
|
|
1161
|
+
{props.children}
|
|
1162
|
+
</div>
|
|
1163
|
+
)
|
|
1164
|
+
case 'productBottom':
|
|
1165
|
+
return (
|
|
1166
|
+
<div className='relative max-w-md rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 pt-0 shadow-lg'>
|
|
1167
|
+
{props.children}
|
|
1168
|
+
<div className='flex h-60 items-center justify-center'>
|
|
1169
|
+
<img src={props.src} alt='product' className='w-75' />
|
|
1170
|
+
</div>
|
|
1171
|
+
<Button
|
|
1172
|
+
size='icon'
|
|
1173
|
+
onClick={() => props.setLiked(!props.liked)}
|
|
1174
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
1175
|
+
>
|
|
1176
|
+
<HeartIcon className={cn(props.liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
1177
|
+
<span className='sr-only'>Like</span>
|
|
1178
|
+
</Button>
|
|
1179
|
+
</div>
|
|
1180
|
+
)
|
|
1181
|
+
case 'productLeft':
|
|
1182
|
+
return (
|
|
1183
|
+
<div className='relative flex items-center max-w-md rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 pt-0 shadow-lg'>
|
|
1184
|
+
|
|
1185
|
+
<div className='flex h-60 items-center justify-center'>
|
|
1186
|
+
<img src={props.src} alt='product' className='w-75' />
|
|
1187
|
+
</div>
|
|
1188
|
+
<Button
|
|
1189
|
+
size='icon'
|
|
1190
|
+
onClick={() => props.setLiked(!props.liked)}
|
|
1191
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
1192
|
+
>
|
|
1193
|
+
<HeartIcon className={cn(props.liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
1194
|
+
<span className='sr-only'>Like</span>
|
|
1195
|
+
</Button>
|
|
1196
|
+
{props.children}
|
|
1197
|
+
</div>
|
|
1198
|
+
)
|
|
1199
|
+
case 'productRight':
|
|
1200
|
+
return (
|
|
1201
|
+
<div className='relative flex items-center max-w-md rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 pt-0 shadow-lg'>
|
|
1202
|
+
{props.children}
|
|
1203
|
+
<div className='flex h-60 items-center justify-center'>
|
|
1204
|
+
<img src={props.src} alt='product' className='w-75' />
|
|
1205
|
+
</div>
|
|
1206
|
+
<Button
|
|
1207
|
+
size='icon'
|
|
1208
|
+
onClick={() => props.setLiked(!props.liked)}
|
|
1209
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
1210
|
+
>
|
|
1211
|
+
<HeartIcon className={cn(props.liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
1212
|
+
<span className='sr-only'>Like</span>
|
|
1213
|
+
</Button>
|
|
1214
|
+
</div>
|
|
1215
|
+
)
|
|
1216
|
+
default:
|
|
1217
|
+
return <CardHeart {...props} />
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
|
|
1222
|
+
export function CardXGroup({ variant, className, children }: any) {
|
|
1223
|
+
switch (variant) {
|
|
1224
|
+
case 'vertical':
|
|
1225
|
+
return (
|
|
1226
|
+
<div className={cn('flex flex-col *:rounded-none *:shadow-none *:not-last:border-b-0 *:first:rounded-t-xl *:last:rounded-b-xl', className)}>
|
|
1227
|
+
{children}
|
|
1228
|
+
</div>
|
|
1229
|
+
)
|
|
1230
|
+
default:
|
|
1231
|
+
return (
|
|
1232
|
+
<div className={cn('flex *:rounded-none *:shadow-none max-xl:flex-col max-xl:*:not-last:border-b-0 max-xl:*:first:rounded-t-xl max-xl:*:last:rounded-b-xl xl:*:not-last:border-r-0 xl:*:first:rounded-l-xl xl:*:last:rounded-r-xl', className)}>
|
|
1233
|
+
{children}
|
|
1234
|
+
</div>
|
|
1235
|
+
)
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
// #endregion ===========================================================================
|
|
1240
|
+
// DEMO COMPONENT
|
|
1241
|
+
// #region ===========================================================================
|
|
1242
|
+
export function CardXDemo() {
|
|
1243
|
+
const [closableActive, setClosableActive] = useState(true)
|
|
1244
|
+
const [tweetState, setTweetState] = useState({
|
|
1245
|
+
liked: false,
|
|
1246
|
+
commented: false,
|
|
1247
|
+
retweeted: false,
|
|
1248
|
+
shared: false
|
|
1249
|
+
})
|
|
1250
|
+
const [productLiked, setProductLiked] = useState(false)
|
|
1251
|
+
|
|
1252
|
+
return (
|
|
1253
|
+
<div className="space-y-12 p-6 max-w-5xl mx-auto">
|
|
1254
|
+
{/* Default */}
|
|
1255
|
+
<div>
|
|
1256
|
+
<h3 className="text-lg font-semibold mb-4">Default</h3>
|
|
1257
|
+
<CardX className="max-w-md">
|
|
1258
|
+
<CardXHeader>
|
|
1259
|
+
<CardXTitle>Card Title</CardXTitle>
|
|
1260
|
+
<CardXDescription>Card description goes here</CardXDescription>
|
|
1261
|
+
</CardXHeader>
|
|
1262
|
+
<CardXContent>
|
|
1263
|
+
This is the default card content. You can put any content here.
|
|
1264
|
+
</CardXContent>
|
|
1265
|
+
<CardXFooter>
|
|
1266
|
+
<Button>Action</Button>
|
|
1267
|
+
</CardXFooter>
|
|
1268
|
+
</CardX>
|
|
1269
|
+
</div>
|
|
1270
|
+
|
|
1271
|
+
{/* Spotlight */}
|
|
1272
|
+
<div>
|
|
1273
|
+
<h3 className="text-lg font-semibold mb-4">Spotlight</h3>
|
|
1274
|
+
<CardX card="spotlight">
|
|
1275
|
+
<CardXHeader>
|
|
1276
|
+
<CardXTitle>Spotlight Card</CardXTitle>
|
|
1277
|
+
<CardXDescription>Hover to see the effect</CardXDescription>
|
|
1278
|
+
</CardXHeader>
|
|
1279
|
+
<CardXContent>
|
|
1280
|
+
This card has a beautiful spotlight effect that follows your cursor.
|
|
1281
|
+
</CardXContent>
|
|
1282
|
+
</CardX>
|
|
1283
|
+
</div>
|
|
1284
|
+
|
|
1285
|
+
{/* 3D */}
|
|
1286
|
+
<div>
|
|
1287
|
+
<h3 className="text-lg font-semibold mb-4">3D Card</h3>
|
|
1288
|
+
<div className="card-3d-wrapper">
|
|
1289
|
+
<CardX card="3d" className="max-w-md">
|
|
1290
|
+
<CardXHeader>
|
|
1291
|
+
<CardXTitle>3D Interactive Card</CardXTitle>
|
|
1292
|
+
<CardXDescription>Hover to see 3D effect</CardXDescription>
|
|
1293
|
+
</CardXHeader>
|
|
1294
|
+
<CardXContent image="https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=500&h=300&fit=crop">
|
|
1295
|
+
This card tilts in 3D when you hover over it.
|
|
1296
|
+
</CardXContent>
|
|
1297
|
+
</CardX>
|
|
1298
|
+
</div>
|
|
1299
|
+
</div>
|
|
1300
|
+
|
|
1301
|
+
{/* Closable */}
|
|
1302
|
+
<div>
|
|
1303
|
+
<h3 className="text-lg font-semibold mb-4">Closable</h3>
|
|
1304
|
+
{closableActive && (
|
|
1305
|
+
<CardX card="closable" className="max-w-md">
|
|
1306
|
+
<CardXHeader onClose={() => setClosableActive(false)}>
|
|
1307
|
+
Important Notice
|
|
1308
|
+
</CardXHeader>
|
|
1309
|
+
<CardXContent actionText="Got it">
|
|
1310
|
+
This is an important message that can be dismissed.
|
|
1311
|
+
</CardXContent>
|
|
1312
|
+
</CardX>
|
|
1313
|
+
)}
|
|
1314
|
+
</div>
|
|
1315
|
+
|
|
1316
|
+
{/* Tweet */}
|
|
1317
|
+
<div>
|
|
1318
|
+
<h3 className="text-lg font-semibold mb-4">Tweet Card</h3>
|
|
1319
|
+
<CardX card="tweet" className="max-w-md">
|
|
1320
|
+
<CardXHeader
|
|
1321
|
+
avatar="https://avatar.vercel.sh/john"
|
|
1322
|
+
name="John Doe"
|
|
1323
|
+
handle="johndoe"
|
|
1324
|
+
verified={true}
|
|
1325
|
+
/>
|
|
1326
|
+
<CardXContent image="https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=500&h=300&fit=crop">
|
|
1327
|
+
Just shipped a new feature! Check it out and let me know what you think. 🚀
|
|
1328
|
+
</CardXContent>
|
|
1329
|
+
<CardXFooter
|
|
1330
|
+
state={tweetState}
|
|
1331
|
+
setState={setTweetState}
|
|
1332
|
+
likes="124"
|
|
1333
|
+
comments="32"
|
|
1334
|
+
retweets="18"
|
|
1335
|
+
shares="7"
|
|
1336
|
+
/>
|
|
1337
|
+
</CardX>
|
|
1338
|
+
</div>
|
|
1339
|
+
|
|
1340
|
+
{/* Product */}
|
|
1341
|
+
<div>
|
|
1342
|
+
<h3 className="text-lg font-semibold mb-4">Product Card</h3>
|
|
1343
|
+
<CardX card="product" className="max-w-md border-none">
|
|
1344
|
+
<CardXProduct src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&fit=crop" liked={productLiked} setLiked={setProductLiked}>
|
|
1345
|
+
<Card className="border-none">
|
|
1346
|
+
<CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
1347
|
+
<CardXContent>
|
|
1348
|
+
Crossing hardwood comfort with off-court flair. '80s-Inspired construction, bold details and nothin'-but-net style.
|
|
1349
|
+
</CardXContent>
|
|
1350
|
+
<CardXFooter price1="Price" price2="$129.99" buttonLabel="Add to cart" onAddToCart={() => console.log('Added')} />
|
|
1351
|
+
</Card>
|
|
1352
|
+
</CardXProduct>
|
|
1353
|
+
</CardX>
|
|
1354
|
+
</div>
|
|
1355
|
+
|
|
1356
|
+
{/* Product Top */}
|
|
1357
|
+
<div>
|
|
1358
|
+
<h3 className="text-lg font-semibold mb-4">Product Top</h3>
|
|
1359
|
+
<CardX card="productTop" className="border-none">
|
|
1360
|
+
<CardXProduct src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&fit=crop" liked={productLiked} setLiked={setProductLiked}>
|
|
1361
|
+
<Card className="border-none">
|
|
1362
|
+
<CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
1363
|
+
<CardXContent>
|
|
1364
|
+
Premium materials and timeless design.
|
|
1365
|
+
</CardXContent>
|
|
1366
|
+
<CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
1367
|
+
</Card>
|
|
1368
|
+
</CardXProduct>
|
|
1369
|
+
</CardX>
|
|
1370
|
+
</div>
|
|
1371
|
+
|
|
1372
|
+
{/* Product Bottom */}
|
|
1373
|
+
<div>
|
|
1374
|
+
<h3 className="text-lg font-semibold mb-4">Product Bottom</h3>
|
|
1375
|
+
<CardX card="productBottom" className="border-none">
|
|
1376
|
+
<CardXProduct src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&fit=crop" liked={productLiked} setLiked={setProductLiked}>
|
|
1377
|
+
<Card className="border-none">
|
|
1378
|
+
<CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
1379
|
+
<CardXContent>
|
|
1380
|
+
Premium materials and timeless design.
|
|
1381
|
+
</CardXContent>
|
|
1382
|
+
<CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
1383
|
+
</Card>
|
|
1384
|
+
</CardXProduct>
|
|
1385
|
+
</CardX>
|
|
1386
|
+
</div>
|
|
1387
|
+
|
|
1388
|
+
{/* Product Left */}
|
|
1389
|
+
<div>
|
|
1390
|
+
<h3 className="text-lg font-semibold mb-4">Product Left</h3>
|
|
1391
|
+
<CardX card="productLeft" className="border-none">
|
|
1392
|
+
<CardXProduct src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&fit=crop" liked={productLiked} setLiked={setProductLiked}>
|
|
1393
|
+
<Card className="border-none">
|
|
1394
|
+
<CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
1395
|
+
<CardXContent>
|
|
1396
|
+
Premium materials and timeless design.
|
|
1397
|
+
</CardXContent>
|
|
1398
|
+
<CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
1399
|
+
</Card>
|
|
1400
|
+
</CardXProduct>
|
|
1401
|
+
</CardX>
|
|
1402
|
+
</div>
|
|
1403
|
+
|
|
1404
|
+
{/* Product Right */}
|
|
1405
|
+
<div>
|
|
1406
|
+
<h3 className="text-lg font-semibold mb-4">Product Right</h3>
|
|
1407
|
+
<CardX card="productRight" className="border-none">
|
|
1408
|
+
<CardXProduct src="https://images.unsplash.com/photo-1542291026-7eec264c27ff?w=300&fit=crop" liked={productLiked} setLiked={setProductLiked}>
|
|
1409
|
+
<Card className="border-none">
|
|
1410
|
+
<CardXHeader title="Nike Air Max" info1="EU42" info2="Black/White" />
|
|
1411
|
+
<CardXContent>
|
|
1412
|
+
Premium materials and timeless design.
|
|
1413
|
+
</CardXContent>
|
|
1414
|
+
<CardXFooter price2="$129.99" buttonLabel="Buy Now" />
|
|
1415
|
+
</Card>
|
|
1416
|
+
</CardXProduct>
|
|
1417
|
+
</CardX>
|
|
1418
|
+
</div>
|
|
1419
|
+
|
|
1420
|
+
{/* Testimonial */}
|
|
1421
|
+
<div>
|
|
1422
|
+
<h3 className="text-lg font-semibold mb-4">Testimonial</h3>
|
|
1423
|
+
<CardX card="testimonial" className="max-w-md">
|
|
1424
|
+
<CardXContent>
|
|
1425
|
+
"This product has completely transformed how I work. The attention to detail is incredible!"
|
|
1426
|
+
</CardXContent>
|
|
1427
|
+
<CardXFooter
|
|
1428
|
+
avatar="https://avatar.vercel.sh/sarah"
|
|
1429
|
+
name="Sarah Johnson"
|
|
1430
|
+
handle="sarahj"
|
|
1431
|
+
rating={5}
|
|
1432
|
+
/>
|
|
1433
|
+
</CardX>
|
|
1434
|
+
</div>
|
|
1435
|
+
|
|
1436
|
+
{/* Overlay */}
|
|
1437
|
+
<div>
|
|
1438
|
+
<h3 className="text-lg font-semibold mb-4">Overlay</h3>
|
|
1439
|
+
<CardX card="overlay">
|
|
1440
|
+
<CardXHeader>Stunning Destination</CardXHeader>
|
|
1441
|
+
<CardXContent image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=500&h=300&fit=crop">
|
|
1442
|
+
Discover the beauty of nature in this breathtaking location.
|
|
1443
|
+
</CardXContent>
|
|
1444
|
+
</CardX>
|
|
1445
|
+
</div>
|
|
1446
|
+
|
|
1447
|
+
{/* Horizontal */}
|
|
1448
|
+
<div>
|
|
1449
|
+
<h3 className="text-lg font-semibold mb-4">Horizontal</h3>
|
|
1450
|
+
<CardX card="horizontal" className="max-w-2xl">
|
|
1451
|
+
<CardXContent
|
|
1452
|
+
title="Featured Article"
|
|
1453
|
+
description="Learn about the latest trends"
|
|
1454
|
+
actionText="Read More"
|
|
1455
|
+
>
|
|
1456
|
+
<img
|
|
1457
|
+
src="https://images.unsplash.com/photo-1498050108023-c5249f4df085?w=300&h=200&fit=crop"
|
|
1458
|
+
alt="Article"
|
|
1459
|
+
className="h-full w-full rounded-l-xl object-cover"
|
|
1460
|
+
/>
|
|
1461
|
+
</CardXContent>
|
|
1462
|
+
</CardX>
|
|
1463
|
+
</div>
|
|
1464
|
+
|
|
1465
|
+
{/* Top Image */}
|
|
1466
|
+
<div>
|
|
1467
|
+
<h3 className="text-lg font-semibold mb-4">Top Image</h3>
|
|
1468
|
+
<CardX card="topImage" className="max-w-md">
|
|
1469
|
+
<CardXContent image="https://images.unsplash.com/photo-1682687220742-aba13b6e50ba?w=500&h=300&fit=crop" />
|
|
1470
|
+
<CardXHeader>
|
|
1471
|
+
<CardXTitle>Beautiful Landscape</CardXTitle>
|
|
1472
|
+
<CardXDescription>Explore the wonders of nature</CardXDescription>
|
|
1473
|
+
</CardXHeader>
|
|
1474
|
+
<CardXFooter showActions onClick={() => console.log('explore')} onClick2={() => console.log('download')} />
|
|
1475
|
+
</CardX>
|
|
1476
|
+
</div>
|
|
1477
|
+
|
|
1478
|
+
{/* Bottom Image */}
|
|
1479
|
+
<div>
|
|
1480
|
+
<h3 className="text-lg font-semibold mb-4">Bottom Image</h3>
|
|
1481
|
+
<CardX card="bottomImage" className="max-w-md">
|
|
1482
|
+
<CardXHeader>
|
|
1483
|
+
<CardXTitle>Amazing View</CardXTitle>
|
|
1484
|
+
<CardXDescription>Experience the beauty</CardXDescription>
|
|
1485
|
+
</CardXHeader>
|
|
1486
|
+
<CardXContent image="https://images.unsplash.com/photo-1506905925346-21bda4d32df4?w=500&h=300&fit=crop" />
|
|
1487
|
+
</CardX>
|
|
1488
|
+
</div>
|
|
1489
|
+
|
|
1490
|
+
{/* Meeting */}
|
|
1491
|
+
<div>
|
|
1492
|
+
<h3 className="text-lg font-semibold mb-4">Meeting</h3>
|
|
1493
|
+
<CardX card="meeting" className="max-w-md">
|
|
1494
|
+
<CardXHeader>
|
|
1495
|
+
<CardXTitle>Team Meeting</CardXTitle>
|
|
1496
|
+
<CardXDescription>Wednesday, 2:00 PM</CardXDescription>
|
|
1497
|
+
</CardXHeader>
|
|
1498
|
+
<CardXContent
|
|
1499
|
+
items={[
|
|
1500
|
+
'Review Q4 goals',
|
|
1501
|
+
'Discuss new project timeline',
|
|
1502
|
+
'Team feedback session'
|
|
1503
|
+
]}
|
|
1504
|
+
>
|
|
1505
|
+
Join us for our weekly sync to align on priorities.
|
|
1506
|
+
</CardXContent>
|
|
1507
|
+
<CardXFooter
|
|
1508
|
+
avatars={[
|
|
1509
|
+
{ src: 'https://avatar.vercel.sh/john', name: 'John', fallback: 'JD' },
|
|
1510
|
+
{ src: 'https://avatar.vercel.sh/sarah', name: 'Sarah', fallback: 'SJ' },
|
|
1511
|
+
{ src: 'https://avatar.vercel.sh/mike', name: 'Mike', fallback: 'MW' }
|
|
1512
|
+
]}
|
|
1513
|
+
/>
|
|
1514
|
+
</CardX>
|
|
1515
|
+
</div>
|
|
1516
|
+
|
|
1517
|
+
{/* Invite */}
|
|
1518
|
+
<div>
|
|
1519
|
+
<h3 className="text-lg font-semibold mb-4">Invite</h3>
|
|
1520
|
+
<CardX card="invite" className="max-w-md">
|
|
1521
|
+
<CardXHeader>
|
|
1522
|
+
<CardXTitle>Team Members</CardXTitle>
|
|
1523
|
+
<CardXDescription>Manage your team</CardXDescription>
|
|
1524
|
+
</CardXHeader>
|
|
1525
|
+
<CardXContent
|
|
1526
|
+
showInvite
|
|
1527
|
+
members={[
|
|
1528
|
+
{ avatar: 'https://avatar.vercel.sh/john', name: 'John Doe', role: 'Developer', fallback: 'JD' },
|
|
1529
|
+
{ avatar: 'https://avatar.vercel.sh/sarah', name: 'Sarah Smith', role: 'Designer', fallback: 'SS' },
|
|
1530
|
+
{ avatar: 'https://avatar.vercel.sh/mike', name: 'Mike Wilson', role: 'Manager', fallback: 'MW' }
|
|
1531
|
+
]}
|
|
1532
|
+
/>
|
|
1533
|
+
</CardX>
|
|
1534
|
+
</div>
|
|
1535
|
+
|
|
1536
|
+
{/* Card Group Vertical */}
|
|
1537
|
+
<div>
|
|
1538
|
+
<h3 className="text-lg font-semibold mb-4">Card Group - Vertical</h3>
|
|
1539
|
+
<CardXGroup variant="vertical" className="max-w-md">
|
|
1540
|
+
<CardX>
|
|
1541
|
+
<CardXHeader>
|
|
1542
|
+
<CardXTitle>First Card</CardXTitle>
|
|
1543
|
+
</CardXHeader>
|
|
1544
|
+
<CardXContent>Content for first card</CardXContent>
|
|
1545
|
+
</CardX>
|
|
1546
|
+
<CardX>
|
|
1547
|
+
<CardXHeader>
|
|
1548
|
+
<CardXTitle>Second Card</CardXTitle>
|
|
1549
|
+
</CardXHeader>
|
|
1550
|
+
<CardXContent>Content for second card</CardXContent>
|
|
1551
|
+
</CardX>
|
|
1552
|
+
<CardX>
|
|
1553
|
+
<CardXHeader>
|
|
1554
|
+
<CardXTitle>Third Card</CardXTitle>
|
|
1555
|
+
</CardXHeader>
|
|
1556
|
+
<CardXContent>Content for third card</CardXContent>
|
|
1557
|
+
</CardX>
|
|
1558
|
+
</CardXGroup>
|
|
1559
|
+
</div>
|
|
1560
|
+
|
|
1561
|
+
{/* Card Group Horizontal */}
|
|
1562
|
+
<div>
|
|
1563
|
+
<h3 className="text-lg font-semibold mb-4">Card Group - Horizontal</h3>
|
|
1564
|
+
<CardXGroup>
|
|
1565
|
+
<CardX>
|
|
1566
|
+
<CardXHeader>
|
|
1567
|
+
<CardXTitle>Card 1</CardXTitle>
|
|
1568
|
+
</CardXHeader>
|
|
1569
|
+
<CardXContent>First card content</CardXContent>
|
|
1570
|
+
</CardX>
|
|
1571
|
+
<CardX>
|
|
1572
|
+
<CardXHeader>
|
|
1573
|
+
<CardXTitle>Card 2</CardXTitle>
|
|
1574
|
+
</CardXHeader>
|
|
1575
|
+
<CardXContent>Second card content</CardXContent>
|
|
1576
|
+
</CardX>
|
|
1577
|
+
<CardX>
|
|
1578
|
+
<CardXHeader>
|
|
1579
|
+
<CardXTitle>Card 3</CardXTitle>
|
|
1580
|
+
</CardXHeader>
|
|
1581
|
+
<CardXContent>Third card content</CardXContent>
|
|
1582
|
+
</CardX>
|
|
1583
|
+
</CardXGroup>
|
|
1584
|
+
</div>
|
|
1585
|
+
</div>
|
|
1586
|
+
)
|
|
1587
|
+
}
|
|
1588
|
+
export function CardXDemo1() {
|
|
1589
|
+
const [closableVisible, setClosableVisible] = useState(true)
|
|
1590
|
+
|
|
1591
|
+
const avatars = [
|
|
1592
|
+
{ src: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-1.png', name: 'User 1', fallback: 'U1' },
|
|
1593
|
+
{ src: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-2.png', name: 'User 2', fallback: 'U2' },
|
|
1594
|
+
{ src: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-3.png', name: 'User 3', fallback: 'U3' },
|
|
1595
|
+
]
|
|
1596
|
+
|
|
1597
|
+
const members = [
|
|
1598
|
+
{ name: 'Jimmy Anderson', role: 'UI Designer', avatar: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png', fallback: 'JA' },
|
|
1599
|
+
{ name: 'Dean Ambrose', role: 'UX Designer', avatar: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-2.png', fallback: 'DA' },
|
|
1600
|
+
{ name: 'Anita John', role: 'Branding', avatar: 'https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-3.png', fallback: 'AJ' },
|
|
1601
|
+
]
|
|
1602
|
+
|
|
1603
|
+
const dropdownItems = [
|
|
1604
|
+
{ name: 'View Profile', onSelect: () => console.log('View Profile') },
|
|
1605
|
+
{ name: 'Mute', onSelect: () => console.log('Mute') },
|
|
1606
|
+
{ name: 'Block', onSelect: () => console.log('Block') },
|
|
1607
|
+
{ name: 'Report', onSelect: () => console.log('Report') },
|
|
1608
|
+
]
|
|
1609
|
+
|
|
1610
|
+
return (
|
|
1611
|
+
<div className='space-y-12 p-6 max-w-4xl mx-auto'>
|
|
1612
|
+
<div>
|
|
1613
|
+
<h3 className='text-lg font-semibold mb-4'>Default Card</h3>
|
|
1614
|
+
<CardX className='max-w-md'>
|
|
1615
|
+
<CardXHeader>
|
|
1616
|
+
<CardXTitle>Default Card</CardXTitle>
|
|
1617
|
+
<CardXDescription>This is the standard card layout</CardXDescription>
|
|
1618
|
+
</CardXHeader>
|
|
1619
|
+
<CardXContent>
|
|
1620
|
+
Basic card content goes here with no special variants applied.
|
|
1621
|
+
</CardXContent>
|
|
1622
|
+
<CardXFooter>
|
|
1623
|
+
<Button>Action</Button>
|
|
1624
|
+
</CardXFooter>
|
|
1625
|
+
</CardX>
|
|
1626
|
+
</div>
|
|
1627
|
+
|
|
1628
|
+
<div>
|
|
1629
|
+
<h3 className='text-lg font-semibold mb-4'>Spotlight Card</h3>
|
|
1630
|
+
<CardX card='spotlight'>
|
|
1631
|
+
<CardXHeader>
|
|
1632
|
+
<CardXTitle>Hover for the Glow-Up</CardXTitle>
|
|
1633
|
+
</CardXHeader>
|
|
1634
|
+
<CardXContent>
|
|
1635
|
+
Glide your cursor here and watch magic unfold — an experience designed just for you.
|
|
1636
|
+
</CardXContent>
|
|
1637
|
+
</CardX>
|
|
1638
|
+
</div>
|
|
1639
|
+
|
|
1640
|
+
<div>
|
|
1641
|
+
<h3 className='text-lg font-semibold mb-4'>3D Hover Card</h3>
|
|
1642
|
+
<div className='card-3d-wrapper'>
|
|
1643
|
+
<CardX card='3d' className='max-w-md'>
|
|
1644
|
+
<CardXHeader>
|
|
1645
|
+
<CardXTitle>Dynamic 3D Hover Card</CardXTitle>
|
|
1646
|
+
</CardXHeader>
|
|
1647
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-10.png?width=350&format=auto'>
|
|
1648
|
+
Experience interactive depth and motion with this sleek 3D hover effect.
|
|
1649
|
+
</CardXContent>
|
|
1650
|
+
</CardX>
|
|
1651
|
+
</div>
|
|
1652
|
+
</div>
|
|
1653
|
+
|
|
1654
|
+
{closableVisible && (
|
|
1655
|
+
<div>
|
|
1656
|
+
<h3 className='text-lg font-semibold mb-4'>Closable Card</h3>
|
|
1657
|
+
<CardX card='closable' className='max-w-lg shadow-none'>
|
|
1658
|
+
<CardXHeader onClose={() => setClosableVisible(false)}>
|
|
1659
|
+
Have a project in mind
|
|
1660
|
+
</CardXHeader>
|
|
1661
|
+
<CardXContent actionText='Contact Our Team'>
|
|
1662
|
+
Let's discuss! Our Assistant team is excited to hear about your projects, ideas and questions.
|
|
1663
|
+
</CardXContent>
|
|
1664
|
+
</CardX>
|
|
1665
|
+
</div>
|
|
1666
|
+
)}
|
|
1667
|
+
|
|
1668
|
+
<div>
|
|
1669
|
+
<h3 className='text-lg font-semibold mb-4'>Tweet Card</h3>
|
|
1670
|
+
<CardX card='tweet' className='max-w-md'>
|
|
1671
|
+
<CardXHeader
|
|
1672
|
+
name='Philip George'
|
|
1673
|
+
handle='philip20'
|
|
1674
|
+
verified
|
|
1675
|
+
showFollow
|
|
1676
|
+
avatar='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png'
|
|
1677
|
+
/>
|
|
1678
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-6.png?width=350&format=auto'>
|
|
1679
|
+
Lost in the colors of the night 🌌✨ Sometimes the blur reveals more than clarity. #AbstractVibes #Dreamscape
|
|
1680
|
+
</CardXContent>
|
|
1681
|
+
<CardXFooter likes='2.1K' comments='1.4K' retweets='669' shares='1.1K' />
|
|
1682
|
+
</CardX>
|
|
1683
|
+
</div>
|
|
1684
|
+
|
|
1685
|
+
<div>
|
|
1686
|
+
<h3 className='text-lg font-semibold mb-4'>Product Card</h3>
|
|
1687
|
+
<CardX card='product' className='max-w-md border-none'>
|
|
1688
|
+
<div className='relative rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 shadow-lg'>
|
|
1689
|
+
<div className='flex h-60 items-center justify-center'>
|
|
1690
|
+
<img
|
|
1691
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'
|
|
1692
|
+
alt='Nike Jordan Air Rev'
|
|
1693
|
+
className='w-75'
|
|
1694
|
+
/>
|
|
1695
|
+
</div>
|
|
1696
|
+
<CardXHeart />
|
|
1697
|
+
<Card className='border-none'>
|
|
1698
|
+
<CardXHeader>
|
|
1699
|
+
<CardXTitle>Nike Jordan Air Rev</CardXTitle>
|
|
1700
|
+
<CardXDescription className='flex items-center gap-2'>
|
|
1701
|
+
<Badge variant='outline' className='rounded-sm'>EU38</Badge>
|
|
1702
|
+
<Badge variant='outline' className='rounded-sm'>Black and White</Badge>
|
|
1703
|
+
</CardXDescription>
|
|
1704
|
+
</CardXHeader>
|
|
1705
|
+
<CardXContent>
|
|
1706
|
+
Crossing hardwood comfort with off-court flair. '80s-Inspired construction, bold details and nothin'-but-net style.
|
|
1707
|
+
</CardXContent>
|
|
1708
|
+
<CardXFooter className='justify-between gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
1709
|
+
<div className='flex flex-col'>
|
|
1710
|
+
<span className='text-sm font-medium uppercase'>Price</span>
|
|
1711
|
+
<span className='text-xl font-semibold'>$69.99</span>
|
|
1712
|
+
</div>
|
|
1713
|
+
<Button size='lg'>Add to cart</Button>
|
|
1714
|
+
</CardXFooter>
|
|
1715
|
+
</Card>
|
|
1716
|
+
</div>
|
|
1717
|
+
</CardX>
|
|
1718
|
+
</div>
|
|
1719
|
+
|
|
1720
|
+
<div>
|
|
1721
|
+
<h3 className='text-lg font-semibold mb-4'>Product Card - Top Image</h3>
|
|
1722
|
+
<CardXProduct card='productTop' src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'>
|
|
1723
|
+
<Card className='border-none'>
|
|
1724
|
+
<CardXHeader>
|
|
1725
|
+
<CardXTitle>Premium Sneakers</CardXTitle>
|
|
1726
|
+
<CardXDescription>Limited Edition</CardXDescription>
|
|
1727
|
+
</CardXHeader>
|
|
1728
|
+
<CardXContent>
|
|
1729
|
+
Top-quality materials and craftsmanship.
|
|
1730
|
+
</CardXContent>
|
|
1731
|
+
<CardXFooter className='justify-between'>
|
|
1732
|
+
<span className='text-xl font-semibold'>$129.99</span>
|
|
1733
|
+
<Button>Buy Now</Button>
|
|
1734
|
+
</CardXFooter>
|
|
1735
|
+
</Card>
|
|
1736
|
+
</CardXProduct>
|
|
1737
|
+
</div>
|
|
1738
|
+
|
|
1739
|
+
<div>
|
|
1740
|
+
<h3 className='text-lg font-semibold mb-4'>Product Card - Bottom Image</h3>
|
|
1741
|
+
<CardXProduct card='productBottom' src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'>
|
|
1742
|
+
<Card className='border-none'>
|
|
1743
|
+
<CardXHeader>
|
|
1744
|
+
<CardXTitle>Sport Edition</CardXTitle>
|
|
1745
|
+
<CardXDescription>Performance Ready</CardXDescription>
|
|
1746
|
+
</CardXHeader>
|
|
1747
|
+
<CardXContent>
|
|
1748
|
+
Designed for maximum comfort and style.
|
|
1749
|
+
</CardXContent>
|
|
1750
|
+
<CardXFooter className='justify-between'>
|
|
1751
|
+
<span className='text-xl font-semibold'>$99.99</span>
|
|
1752
|
+
<Button>Add to Cart</Button>
|
|
1753
|
+
</CardXFooter>
|
|
1754
|
+
</Card>
|
|
1755
|
+
</CardXProduct>
|
|
1756
|
+
</div>
|
|
1757
|
+
|
|
1758
|
+
<div>
|
|
1759
|
+
<h3 className='text-lg font-semibold mb-4'>Product Card - Left Image</h3>
|
|
1760
|
+
<CardXProduct card='productLeft' src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'>
|
|
1761
|
+
<Card className='border-none'>
|
|
1762
|
+
<CardXHeader>
|
|
1763
|
+
<CardXTitle>Classic Style</CardXTitle>
|
|
1764
|
+
<CardXDescription>Timeless Design</CardXDescription>
|
|
1765
|
+
</CardXHeader>
|
|
1766
|
+
<CardXContent>
|
|
1767
|
+
Perfect for everyday wear.
|
|
1768
|
+
</CardXContent>
|
|
1769
|
+
<CardXFooter className='justify-between'>
|
|
1770
|
+
<span className='text-xl font-semibold'>$89.99</span>
|
|
1771
|
+
<Button>Shop Now</Button>
|
|
1772
|
+
</CardXFooter>
|
|
1773
|
+
</Card>
|
|
1774
|
+
</CardXProduct>
|
|
1775
|
+
</div>
|
|
1776
|
+
|
|
1777
|
+
<div>
|
|
1778
|
+
<h3 className='text-lg font-semibold mb-4'>Product Card - Right Image</h3>
|
|
1779
|
+
<CardXProduct card='productRight' src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'>
|
|
1780
|
+
<Card className='border-none'>
|
|
1781
|
+
<CardXHeader>
|
|
1782
|
+
<CardXTitle>Modern Collection</CardXTitle>
|
|
1783
|
+
<CardXDescription>Latest Release</CardXDescription>
|
|
1784
|
+
</CardXHeader>
|
|
1785
|
+
<CardXContent>
|
|
1786
|
+
Contemporary design meets comfort.
|
|
1787
|
+
</CardXContent>
|
|
1788
|
+
<CardXFooter className='justify-between'>
|
|
1789
|
+
<span className='text-xl font-semibold'>$119.99</span>
|
|
1790
|
+
<Button>Purchase</Button>
|
|
1791
|
+
</CardXFooter>
|
|
1792
|
+
</Card>
|
|
1793
|
+
</CardXProduct>
|
|
1794
|
+
</div>
|
|
1795
|
+
|
|
1796
|
+
<div>
|
|
1797
|
+
<h3 className='text-lg font-semibold mb-4'>Testimonial Card</h3>
|
|
1798
|
+
<CardX card='testimonial' className='max-w-md border-none'>
|
|
1799
|
+
<CardXContent>
|
|
1800
|
+
Incredible time-saver! shadcn/studio has made UI development a breeze. The pre build components are not only visually appealing but also highly customizable.
|
|
1801
|
+
</CardXContent>
|
|
1802
|
+
<CardXFooter
|
|
1803
|
+
name='Sam Green'
|
|
1804
|
+
handle='SamG11'
|
|
1805
|
+
avatar='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png'
|
|
1806
|
+
rating={4}
|
|
1807
|
+
/>
|
|
1808
|
+
</CardX>
|
|
1809
|
+
</div>
|
|
1810
|
+
|
|
1811
|
+
<div>
|
|
1812
|
+
<h3 className='text-lg font-semibold mb-4'>Overlay Card</h3>
|
|
1813
|
+
<CardX card='overlay'>
|
|
1814
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-8.png?widht=448&height=280&format=auto'>
|
|
1815
|
+
Step into a world where imagination takes the lead and every pixel tells a story.
|
|
1816
|
+
</CardXContent>
|
|
1817
|
+
<CardXHeader>Creative Catalyst</CardXHeader>
|
|
1818
|
+
</CardX>
|
|
1819
|
+
</div>
|
|
1820
|
+
|
|
1821
|
+
<div>
|
|
1822
|
+
<h3 className='text-lg font-semibold mb-4'>Horizontal Card</h3>
|
|
1823
|
+
<CardX card='horizontal' className='max-w-lg py-0 sm:flex-row sm:gap-0'>
|
|
1824
|
+
<CardXContent
|
|
1825
|
+
title='Dreamy Colorwave Gradient'
|
|
1826
|
+
description='A smooth blend of vibrant pinks, purples, and blues for a magical touch.'
|
|
1827
|
+
image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-3.png'
|
|
1828
|
+
actionText='Explore More'
|
|
1829
|
+
>
|
|
1830
|
+
<img
|
|
1831
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-3.png'
|
|
1832
|
+
alt='Banner'
|
|
1833
|
+
className='size-full rounded-l-xl'
|
|
1834
|
+
/>
|
|
1835
|
+
</CardXContent>
|
|
1836
|
+
</CardX>
|
|
1837
|
+
</div>
|
|
1838
|
+
|
|
1839
|
+
<div>
|
|
1840
|
+
<h3 className='text-lg font-semibold mb-4'>Top Image Card</h3>
|
|
1841
|
+
<CardX card='topImage' className='max-w-md pt-0'>
|
|
1842
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-2.png?height=280&format=auto' />
|
|
1843
|
+
<CardXHeader>
|
|
1844
|
+
<CardXTitle>Ethereal Swirl Gradient</CardXTitle>
|
|
1845
|
+
<CardXDescription>Smooth, flowing gradients blending rich reds and blues in an abstract swirl.</CardXDescription>
|
|
1846
|
+
</CardXHeader>
|
|
1847
|
+
<CardXFooter showActions />
|
|
1848
|
+
</CardX>
|
|
1849
|
+
</div>
|
|
1850
|
+
|
|
1851
|
+
<div>
|
|
1852
|
+
<h3 className='text-lg font-semibold mb-4'>Bottom Image Card</h3>
|
|
1853
|
+
<CardX card='bottomImage' className='max-w-md pb-0'>
|
|
1854
|
+
<CardXHeader>
|
|
1855
|
+
<CardXTitle>Fluid Gradient Flow</CardXTitle>
|
|
1856
|
+
<CardXDescription>A vibrant and abstract background with smooth gradient curves.</CardXDescription>
|
|
1857
|
+
</CardXHeader>
|
|
1858
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-1.png?height=280&format=auto' />
|
|
1859
|
+
</CardX>
|
|
1860
|
+
</div>
|
|
1861
|
+
|
|
1862
|
+
<div>
|
|
1863
|
+
<h3 className='text-lg font-semibold mb-4'>Meeting Notes Card</h3>
|
|
1864
|
+
<CardX card='meeting' className='max-w-md'>
|
|
1865
|
+
<CardXHeader>
|
|
1866
|
+
<CardXTitle>Meeting Notes</CardXTitle>
|
|
1867
|
+
<CardXDescription>Transcript from the meeting with the client.</CardXDescription>
|
|
1868
|
+
</CardXHeader>
|
|
1869
|
+
<CardXContent items={[
|
|
1870
|
+
'New analytics widgets for daily/weekly metrics',
|
|
1871
|
+
'Simplified navigation menu',
|
|
1872
|
+
'Dark mode support',
|
|
1873
|
+
'Timeline: 6 weeks',
|
|
1874
|
+
'Follow-up meeting scheduled for next Tuesday'
|
|
1875
|
+
]}>
|
|
1876
|
+
Client requested dashboard redesign with focus on mobile responsiveness.
|
|
1877
|
+
</CardXContent>
|
|
1878
|
+
<CardXFooter avatars={avatars} />
|
|
1879
|
+
</CardX>
|
|
1880
|
+
</div>
|
|
1881
|
+
|
|
1882
|
+
<div>
|
|
1883
|
+
<h3 className='text-lg font-semibold mb-4'>Invite Card</h3>
|
|
1884
|
+
<CardX card='invite' className='w-full max-w-lg'>
|
|
1885
|
+
<CardXHeader>
|
|
1886
|
+
<CardXTitle>Team Members</CardXTitle>
|
|
1887
|
+
</CardXHeader>
|
|
1888
|
+
<CardXContent showInvite members={members} />
|
|
1889
|
+
</CardX>
|
|
1890
|
+
</div>
|
|
1891
|
+
|
|
1892
|
+
<div>
|
|
1893
|
+
<h3 className='text-lg font-semibold mb-4'>Card Group - Horizontal (Default)</h3>
|
|
1894
|
+
<CardXGroup>
|
|
1895
|
+
<CardX card='topImage' className='overflow-hidden pt-0'>
|
|
1896
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-7.png?width=368&format=auto' />
|
|
1897
|
+
<CardXHeader>
|
|
1898
|
+
<CardXTitle>Mystical Blue Swirl</CardXTitle>
|
|
1899
|
+
<CardXDescription>
|
|
1900
|
+
Dive into the depths of an enchanting swirl where vibrant blues and soft pinks merge seamlessly.
|
|
1901
|
+
</CardXDescription>
|
|
1902
|
+
</CardXHeader>
|
|
1903
|
+
<CardXFooter showActions />
|
|
1904
|
+
</CardX>
|
|
1905
|
+
<CardX card='topImage' className='overflow-hidden pt-0'>
|
|
1906
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-4.png?width=368&format=auto' />
|
|
1907
|
+
<CardXHeader>
|
|
1908
|
+
<CardXTitle>Fiery Sunset Gradient</CardXTitle>
|
|
1909
|
+
<CardXDescription>
|
|
1910
|
+
Experience the warmth of a radiant sunset with flowing gradients of red, orange, and yellow.
|
|
1911
|
+
</CardXDescription>
|
|
1912
|
+
</CardXHeader>
|
|
1913
|
+
<CardXFooter showActions />
|
|
1914
|
+
</CardX>
|
|
1915
|
+
<CardX card='topImage' className='overflow-hidden pt-0'>
|
|
1916
|
+
<CardXContent image='https://cdn.shadcnstudio.com/ss-assets/components/card/image-5.png?width=368&format=auto' />
|
|
1917
|
+
<CardXHeader>
|
|
1918
|
+
<CardXTitle>Cosmic Blue Waves</CardXTitle>
|
|
1919
|
+
<CardXDescription>
|
|
1920
|
+
Explore the mysteries of the cosmos with deep, swirling waves of blue and purple.
|
|
1921
|
+
</CardXDescription>
|
|
1922
|
+
</CardXHeader>
|
|
1923
|
+
<CardXFooter showActions />
|
|
1924
|
+
</CardX>
|
|
1925
|
+
</CardXGroup>
|
|
1926
|
+
</div>
|
|
1927
|
+
|
|
1928
|
+
<div>
|
|
1929
|
+
<h3 className='text-lg font-semibold mb-4'>Card Group - Vertical</h3>
|
|
1930
|
+
<CardXGroup variant='vertical'>
|
|
1931
|
+
<CardX className='max-w-md'>
|
|
1932
|
+
<CardXHeader>
|
|
1933
|
+
<CardXTitle>First Card</CardXTitle>
|
|
1934
|
+
<CardXDescription>First item in vertical stack</CardXDescription>
|
|
1935
|
+
</CardXHeader>
|
|
1936
|
+
<CardXContent>Content for the first card</CardXContent>
|
|
1937
|
+
</CardX>
|
|
1938
|
+
<CardX className='max-w-md'>
|
|
1939
|
+
<CardXHeader>
|
|
1940
|
+
<CardXTitle>Second Card</CardXTitle>
|
|
1941
|
+
<CardXDescription>Second item in vertical stack</CardXDescription>
|
|
1942
|
+
</CardXHeader>
|
|
1943
|
+
<CardXContent>Content for the second card</CardXContent>
|
|
1944
|
+
</CardX>
|
|
1945
|
+
<CardX className='max-w-md'>
|
|
1946
|
+
<CardXHeader>
|
|
1947
|
+
<CardXTitle>Third Card</CardXTitle>
|
|
1948
|
+
<CardXDescription>Third item in vertical stack</CardXDescription>
|
|
1949
|
+
</CardXHeader>
|
|
1950
|
+
<CardXContent>Content for the third card</CardXContent>
|
|
1951
|
+
</CardX>
|
|
1952
|
+
</CardXGroup>
|
|
1953
|
+
</div>
|
|
1954
|
+
</div>
|
|
1955
|
+
)
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
|
|
1959
|
+
|
|
1960
|
+
const CardMeetingNotesDemo = () => {
|
|
1961
|
+
return (
|
|
1962
|
+
<Card className='max-w-md'>
|
|
1963
|
+
<CardHeader>
|
|
1964
|
+
<CardTitle>Meeting Notes</CardTitle>
|
|
1965
|
+
<CardDescription>Transcript from the meeting with the client.</CardDescription>
|
|
1966
|
+
</CardHeader>
|
|
1967
|
+
<CardContent className='text-sm'>
|
|
1968
|
+
<p>Client requested dashboard redesign with focus on mobile responsiveness.</p>
|
|
1969
|
+
<ol className='mt-4 flex list-decimal flex-col gap-2 pl-6'>
|
|
1970
|
+
<li>New analytics widgets for daily/weekly metrics</li>
|
|
1971
|
+
<li>Simplified navigation menu</li>
|
|
1972
|
+
<li>Dark mode support</li>
|
|
1973
|
+
<li>Timeline: 6 weeks</li>
|
|
1974
|
+
<li>Follow-up meeting scheduled for next Tuesday</li>
|
|
1975
|
+
</ol>
|
|
1976
|
+
</CardContent>
|
|
1977
|
+
<CardFooter>
|
|
1978
|
+
<div className='flex -space-x-2 hover:space-x-1'>
|
|
1979
|
+
{avatars.map((avatar, index) => (
|
|
1980
|
+
<Avatar key={index} className='ring-background ring-2 transition-all duration-300 ease-in-out'>
|
|
1981
|
+
<AvatarImage src={avatar.src} alt={avatar.name} />
|
|
1982
|
+
<AvatarFallback className='text-xs'>{avatar.fallback}</AvatarFallback>
|
|
1983
|
+
</Avatar>
|
|
1984
|
+
))}
|
|
1985
|
+
</div>
|
|
1986
|
+
</CardFooter>
|
|
1987
|
+
</Card>
|
|
1988
|
+
)
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
const CardInviteCardDemo = () => {
|
|
1992
|
+
return (
|
|
1993
|
+
<Card className='w-full max-w-lg'>
|
|
1994
|
+
<CardHeader>
|
|
1995
|
+
<CardTitle>Meeting Notes</CardTitle>
|
|
1996
|
+
</CardHeader>
|
|
1997
|
+
<CardContent className='grid gap-4 sm:grid-cols-2'>
|
|
1998
|
+
<div className='flex items-center gap-4'>
|
|
1999
|
+
<CircleFadingPlusIcon />
|
|
2000
|
+
<span className='text-sm font-semibold'>Invite Member </span>
|
|
2001
|
+
</div>
|
|
2002
|
+
<div className='flex items-center gap-4'>
|
|
2003
|
+
<Avatar>
|
|
2004
|
+
<AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png' alt='Hallie Richards' />
|
|
2005
|
+
<AvatarFallback className='text-xs'>JA</AvatarFallback>
|
|
2006
|
+
</Avatar>
|
|
2007
|
+
<div className='flex flex-col'>
|
|
2008
|
+
<span className='text-sm font-semibold'>Jimmy Androson </span>
|
|
2009
|
+
<span className='text-muted-foreground text-sm'>UI Designer</span>
|
|
2010
|
+
</div>
|
|
2011
|
+
</div>
|
|
2012
|
+
<div className='flex items-center gap-4'>
|
|
2013
|
+
<Avatar>
|
|
2014
|
+
<AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-2.png' alt='Hallie Richards' />
|
|
2015
|
+
<AvatarFallback className='text-xs'>DA</AvatarFallback>
|
|
2016
|
+
</Avatar>
|
|
2017
|
+
<div className='flex flex-col'>
|
|
2018
|
+
<span className='text-sm font-semibold'>Dean Ambrose </span>
|
|
2019
|
+
<span className='text-muted-foreground text-sm'>UX Designer</span>
|
|
2020
|
+
</div>
|
|
2021
|
+
</div>
|
|
2022
|
+
<div className='flex items-center gap-4'>
|
|
2023
|
+
<Avatar>
|
|
2024
|
+
<AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-3.png' alt='Hallie Richards' />
|
|
2025
|
+
<AvatarFallback className='text-xs'>HR</AvatarFallback>
|
|
2026
|
+
</Avatar>
|
|
2027
|
+
<div className='flex flex-col'>
|
|
2028
|
+
<span className='text-sm font-semibold'>Anita John</span>
|
|
2029
|
+
<span className='text-muted-foreground text-sm'>Branding</span>
|
|
2030
|
+
</div>
|
|
2031
|
+
</div>
|
|
2032
|
+
<div></div>
|
|
2033
|
+
<div></div>
|
|
2034
|
+
</CardContent>
|
|
2035
|
+
</Card>
|
|
2036
|
+
)
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
const CardBottomImageDemo = () => {
|
|
2040
|
+
return (
|
|
2041
|
+
<Card className='max-w-md pb-0'>
|
|
2042
|
+
<CardHeader>
|
|
2043
|
+
<CardTitle>Fluid Gradient Flow</CardTitle>
|
|
2044
|
+
<CardDescription>A vibrant and abstract background with smooth gradient curves.</CardDescription>
|
|
2045
|
+
</CardHeader>
|
|
2046
|
+
<CardContent className='px-0'>
|
|
2047
|
+
<img
|
|
2048
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-1.png?height=280&format=auto'
|
|
2049
|
+
alt='Banner'
|
|
2050
|
+
className='aspect-video h-70 rounded-b-xl object-cover'
|
|
2051
|
+
/>
|
|
2052
|
+
</CardContent>
|
|
2053
|
+
</Card>
|
|
2054
|
+
)
|
|
2055
|
+
}
|
|
2056
|
+
|
|
2057
|
+
const CardTopImageDemo = () => {
|
|
2058
|
+
return (
|
|
2059
|
+
<Card className='max-w-md pt-0'>
|
|
2060
|
+
<CardContent className='px-0'>
|
|
2061
|
+
<img
|
|
2062
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-2.png?height=280&format=auto'
|
|
2063
|
+
alt='Banner'
|
|
2064
|
+
className='aspect-video h-70 rounded-t-xl object-cover'
|
|
2065
|
+
/>
|
|
2066
|
+
</CardContent>
|
|
2067
|
+
<CardHeader>
|
|
2068
|
+
<CardTitle>Ethereal Swirl Gradient</CardTitle>
|
|
2069
|
+
<CardDescription>Smooth, flowing gradients blending rich reds and blues in an abstract swirl.</CardDescription>
|
|
2070
|
+
</CardHeader>
|
|
2071
|
+
<CardFooter className='gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2072
|
+
<Button>Explore More</Button>
|
|
2073
|
+
<Button variant={'outline'}>Download Now</Button>
|
|
2074
|
+
</CardFooter>
|
|
2075
|
+
</Card>
|
|
2076
|
+
)
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
const CardHorizontalDemo = () => {
|
|
2080
|
+
return (
|
|
2081
|
+
<Card className='max-w-lg py-0 sm:flex-row sm:gap-0'>
|
|
2082
|
+
<CardContent className='grow-1 px-0'>
|
|
2083
|
+
<img
|
|
2084
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-3.png'
|
|
2085
|
+
alt='Banner'
|
|
2086
|
+
className='size-full rounded-l-xl'
|
|
2087
|
+
/>
|
|
2088
|
+
</CardContent>
|
|
2089
|
+
<div className='sm:min-w-54'>
|
|
2090
|
+
<CardHeader className='pt-6'>
|
|
2091
|
+
<CardTitle>Dreamy Colorwave Gradient</CardTitle>
|
|
2092
|
+
<CardDescription>A smooth blend of vibrant pinks, purples, and blues for a magical touch.</CardDescription>
|
|
2093
|
+
</CardHeader>
|
|
2094
|
+
<CardFooter className='gap-3 py-6'>
|
|
2095
|
+
<Button className='bg-transparent bg-gradient-to-br from-purple-500 to-pink-500 text-white focus-visible:ring-pink-600/20'>
|
|
2096
|
+
Explore More
|
|
2097
|
+
</Button>
|
|
2098
|
+
</CardFooter>
|
|
2099
|
+
</div>
|
|
2100
|
+
</Card>
|
|
2101
|
+
)
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
const CardOverlayDemo = () => {
|
|
2105
|
+
return (
|
|
2106
|
+
<Card className='before:bg-primary/70 relative max-w-md py-0 before:absolute before:size-full before:rounded-xl'>
|
|
2107
|
+
<CardContent className='px-0'>
|
|
2108
|
+
<img
|
|
2109
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-8.png?widht=448&height=280&format=auto'
|
|
2110
|
+
alt='Banner'
|
|
2111
|
+
className='h-70 w-112 rounded-xl'
|
|
2112
|
+
/>
|
|
2113
|
+
</CardContent>
|
|
2114
|
+
<div className='absolute'>
|
|
2115
|
+
<CardHeader className='text-primary-foreground w-full pt-6'>
|
|
2116
|
+
<CardTitle>Creative Catalyst</CardTitle>
|
|
2117
|
+
</CardHeader>
|
|
2118
|
+
<CardContent className='text-primary-foreground/80'>
|
|
2119
|
+
Step into a world where imagination takes the lead and every pixel tells a story. This is a space designed to
|
|
2120
|
+
unleash your creative potential without boundaries or time constraints. Explore bold ideas, experiment with
|
|
2121
|
+
vibrant concepts, and craft visuals that inspire and captivate.
|
|
2122
|
+
</CardContent>
|
|
2123
|
+
</div>
|
|
2124
|
+
</Card>
|
|
2125
|
+
)
|
|
2126
|
+
}
|
|
2127
|
+
|
|
2128
|
+
const CardSoftDemo = () => {
|
|
2129
|
+
return (
|
|
2130
|
+
<Card className='bg-primary/20 max-w-md gap-0'>
|
|
2131
|
+
<CardHeader>
|
|
2132
|
+
<CardTitle>Design Throwdown</CardTitle>
|
|
2133
|
+
</CardHeader>
|
|
2134
|
+
<CardContent>
|
|
2135
|
+
Where passion, pressure, and pixels collide—push your creativity to the edge and show what you are made of.
|
|
2136
|
+
</CardContent>
|
|
2137
|
+
</Card>
|
|
2138
|
+
)
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
const CardOutlineDemo = () => {
|
|
2142
|
+
return (
|
|
2143
|
+
<Card className='border-primary max-w-md gap-0 bg-transparent shadow-none'>
|
|
2144
|
+
<CardHeader>
|
|
2145
|
+
<CardTitle>Creative Clash</CardTitle>
|
|
2146
|
+
</CardHeader>
|
|
2147
|
+
<CardContent>
|
|
2148
|
+
Step into a space where design skills are tested, ideas come alive, and only the boldest concepts win the
|
|
2149
|
+
spotlight.
|
|
2150
|
+
</CardContent>
|
|
2151
|
+
</Card>
|
|
2152
|
+
)
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
const CardWithTabsDemo = () => {
|
|
2156
|
+
return (
|
|
2157
|
+
<Card className='w-max'>
|
|
2158
|
+
<CardContent>
|
|
2159
|
+
<Tabs defaultValue={tabs[0].value} className='w-full max-w-sm'>
|
|
2160
|
+
<TabsList className='bg-background w-full justify-start rounded-none border-b p-0'>
|
|
2161
|
+
{tabs.map(tab => (
|
|
2162
|
+
<TabsTrigger
|
|
2163
|
+
key={tab.value}
|
|
2164
|
+
value={tab.value}
|
|
2165
|
+
className='bg-background data-[state=active]:border-b-primary h-full rounded-none border-b-2 border-transparent data-[state=active]:shadow-none'
|
|
2166
|
+
>
|
|
2167
|
+
{tab.name}
|
|
2168
|
+
</TabsTrigger>
|
|
2169
|
+
))}
|
|
2170
|
+
</TabsList>
|
|
2171
|
+
{tabs.map(tab => (
|
|
2172
|
+
<TabsContent key={tab.value} value={tab.value}>
|
|
2173
|
+
<p className='text-muted-foreground p-4 text-sm'>{tab.content}</p>
|
|
2174
|
+
</TabsContent>
|
|
2175
|
+
))}
|
|
2176
|
+
</Tabs>
|
|
2177
|
+
</CardContent>
|
|
2178
|
+
</Card>
|
|
2179
|
+
)
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2182
|
+
const CardTweetDemo = () => {
|
|
2183
|
+
const [liked, setLiked] = useState<boolean>(true)
|
|
2184
|
+
|
|
2185
|
+
return (
|
|
2186
|
+
<Card className='max-w-md'>
|
|
2187
|
+
<CardHeader className='flex items-center justify-between gap-3'>
|
|
2188
|
+
<div className='flex items-center gap-3'>
|
|
2189
|
+
<Avatar className='ring-ring ring-2'>
|
|
2190
|
+
<AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png' alt='Hallie Richards' />
|
|
2191
|
+
<AvatarFallback className='text-xs'>PG</AvatarFallback>
|
|
2192
|
+
</Avatar>
|
|
2193
|
+
<div className='flex flex-col gap-0.5'>
|
|
2194
|
+
<CardTitle className='flex items-center gap-1 text-sm'>
|
|
2195
|
+
Philip George <BadgeCheckIcon className='size-4 fill-sky-600 stroke-white dark:fill-sky-400' />
|
|
2196
|
+
</CardTitle>
|
|
2197
|
+
<CardDescription>@philip20</CardDescription>
|
|
2198
|
+
</div>
|
|
2199
|
+
</div>
|
|
2200
|
+
<div className='flex items-center gap-2'>
|
|
2201
|
+
<Button variant='outline' size='sm'>
|
|
2202
|
+
<UserPlusIcon />
|
|
2203
|
+
Follow
|
|
2204
|
+
</Button>
|
|
2205
|
+
<Button variant='ghost' size='icon' aria-label='Toggle menu'>
|
|
2206
|
+
<EllipsisIcon />
|
|
2207
|
+
</Button>
|
|
2208
|
+
</div>
|
|
2209
|
+
</CardHeader>
|
|
2210
|
+
<CardContent className='space-y-6 text-sm'>
|
|
2211
|
+
<img
|
|
2212
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-6.png?width=350&format=auto'
|
|
2213
|
+
alt='Banner'
|
|
2214
|
+
className='aspect-video w-full rounded-md object-cover'
|
|
2215
|
+
/>
|
|
2216
|
+
<p>
|
|
2217
|
+
Lost in the colors of the night 🌌✨ Sometimes the blur reveals more than clarity.{' '}
|
|
2218
|
+
<a href='#' className='text-sky-600 dark:text-sky-400'>
|
|
2219
|
+
#AbstractVibes
|
|
2220
|
+
</a>{' '}
|
|
2221
|
+
<a href='#' className='text-sky-600 dark:text-sky-400'>
|
|
2222
|
+
#Dreamscape
|
|
2223
|
+
</a>{' '}
|
|
2224
|
+
<a href='#' className='text-sky-600 dark:text-sky-400'>
|
|
2225
|
+
#VisualPoetry
|
|
2226
|
+
</a>
|
|
2227
|
+
</p>
|
|
2228
|
+
</CardContent>
|
|
2229
|
+
<CardFooter className='flex items-center gap-1'>
|
|
2230
|
+
<Button variant='ghost' size='sm' onClick={() => setLiked(!liked)}>
|
|
2231
|
+
<HeartIcon className={cn(liked && 'fill-destructive stroke-destructive')} />
|
|
2232
|
+
2.1K
|
|
2233
|
+
</Button>
|
|
2234
|
+
<Button variant='ghost' size='sm'>
|
|
2235
|
+
<MessageCircleIcon />
|
|
2236
|
+
1.4K
|
|
2237
|
+
</Button>
|
|
2238
|
+
<Button variant='ghost' size='sm'>
|
|
2239
|
+
<RepeatIcon />
|
|
2240
|
+
669
|
|
2241
|
+
</Button>
|
|
2242
|
+
<Button variant='ghost' size='sm'>
|
|
2243
|
+
<SendIcon />
|
|
2244
|
+
1.1K
|
|
2245
|
+
</Button>
|
|
2246
|
+
</CardFooter>
|
|
2247
|
+
</Card>
|
|
2248
|
+
)
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
const CardProductDemo = () => {
|
|
2252
|
+
const [liked, setLiked] = useState<boolean>(false)
|
|
2253
|
+
|
|
2254
|
+
return (
|
|
2255
|
+
<div className='relative max-w-md rounded-xl bg-gradient-to-r from-neutral-600 to-violet-300 pt-0 shadow-lg'>
|
|
2256
|
+
<div className='flex h-60 items-center justify-center'>
|
|
2257
|
+
<img
|
|
2258
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-11.png?width=300&format=auto'
|
|
2259
|
+
alt='Shoes'
|
|
2260
|
+
className='w-75'
|
|
2261
|
+
/>
|
|
2262
|
+
</div>
|
|
2263
|
+
<Button
|
|
2264
|
+
size='icon'
|
|
2265
|
+
onClick={() => setLiked(!liked)}
|
|
2266
|
+
className='bg-primary/10 hover:bg-primary/20 absolute top-4 right-4 rounded-full'
|
|
2267
|
+
>
|
|
2268
|
+
<HeartIcon className={cn(liked ? 'fill-destructive stroke-destructive' : 'stroke-white')} />
|
|
2269
|
+
<span className='sr-only'>Like</span>
|
|
2270
|
+
</Button>
|
|
2271
|
+
<Card className='border-none'>
|
|
2272
|
+
<CardHeader>
|
|
2273
|
+
<CardTitle>Nike Jordan Air Rev</CardTitle>
|
|
2274
|
+
<CardDescription className='flex items-center gap-2'>
|
|
2275
|
+
<Badge variant='outline' className='rounded-sm'>
|
|
2276
|
+
EU38
|
|
2277
|
+
</Badge>
|
|
2278
|
+
<Badge variant='outline' className='rounded-sm'>
|
|
2279
|
+
Black and White
|
|
2280
|
+
</Badge>
|
|
2281
|
+
</CardDescription>
|
|
2282
|
+
</CardHeader>
|
|
2283
|
+
<CardContent>
|
|
2284
|
+
<p>
|
|
2285
|
+
Crossing hardwood comfort with off-court flair. '80s-Inspired construction, bold details and
|
|
2286
|
+
nothin'-but-net style.
|
|
2287
|
+
</p>
|
|
2288
|
+
</CardContent>
|
|
2289
|
+
<CardFooter className='justify-between gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2290
|
+
<div className='flex flex-col'>
|
|
2291
|
+
<span className='text-sm font-medium uppercase'>Price</span>
|
|
2292
|
+
<span className='text-xl font-semibold'>$69.99</span>
|
|
2293
|
+
</div>
|
|
2294
|
+
<Button size='lg'>Add to cart</Button>
|
|
2295
|
+
</CardFooter>
|
|
2296
|
+
</Card>
|
|
2297
|
+
</div>
|
|
2298
|
+
)
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
const CardTestimonialDemo = () => {
|
|
2302
|
+
return (
|
|
2303
|
+
<Card className='max-w-md border-none'>
|
|
2304
|
+
<CardContent>
|
|
2305
|
+
<p>
|
|
2306
|
+
Incredible time-saver! shadcn/studio has made UI development a breeze. The pre build components are not only{' '}
|
|
2307
|
+
<span className='bg-primary/10'>visually appealing but also highly customizable</span>, fitting seamlessly
|
|
2308
|
+
into my projects. With a wide array of options to choose from, I can easily match.
|
|
2309
|
+
</p>
|
|
2310
|
+
</CardContent>
|
|
2311
|
+
<CardFooter className='justify-between gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2312
|
+
<div className='flex items-center gap-3'>
|
|
2313
|
+
<Avatar className='ring-ring ring-2'>
|
|
2314
|
+
<AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png' alt='Hallie Richards' />
|
|
2315
|
+
<AvatarFallback className='text-xs'>SG</AvatarFallback>
|
|
2316
|
+
</Avatar>
|
|
2317
|
+
<div className='flex flex-col gap-0.5'>
|
|
2318
|
+
<CardTitle className='flex items-center gap-1 text-sm'>Sam Green</CardTitle>
|
|
2319
|
+
<CardDescription>@SamG11</CardDescription>
|
|
2320
|
+
</div>
|
|
2321
|
+
</div>
|
|
2322
|
+
<div className='flex items-center gap-1'>
|
|
2323
|
+
<StarIcon className='size-5 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400'></StarIcon>
|
|
2324
|
+
<StarIcon className='size-5 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400'></StarIcon>
|
|
2325
|
+
<StarIcon className='size-5 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400'></StarIcon>
|
|
2326
|
+
<StarIcon className='size-5 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400'></StarIcon>
|
|
2327
|
+
<StarIcon className='size-5 stroke-amber-500 dark:stroke-amber-400'></StarIcon>
|
|
2328
|
+
</div>
|
|
2329
|
+
</CardFooter>
|
|
2330
|
+
</Card>
|
|
2331
|
+
)
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
const CardActionDemo = () => {
|
|
2335
|
+
const [isActive, setIsActive] = useState(true)
|
|
2336
|
+
|
|
2337
|
+
if (!isActive) return null
|
|
2338
|
+
|
|
2339
|
+
return (
|
|
2340
|
+
<Card className='relative max-w-lg shadow-none'>
|
|
2341
|
+
<Button
|
|
2342
|
+
variant='ghost'
|
|
2343
|
+
size='icon'
|
|
2344
|
+
onClick={() => setIsActive(false)}
|
|
2345
|
+
className='absolute top-2 right-2 rounded-full'
|
|
2346
|
+
>
|
|
2347
|
+
<XIcon />
|
|
2348
|
+
<span className='sr-only'>Close</span>
|
|
2349
|
+
</Button>
|
|
2350
|
+
<CardHeader>
|
|
2351
|
+
<CardTitle className='text-center'>Have a project in mind</CardTitle>
|
|
2352
|
+
</CardHeader>
|
|
2353
|
+
<CardContent className='flex flex-col gap-4 text-center'>
|
|
2354
|
+
<p>Let's discuss! Our Assistant team is excited to hear about your projects, ideas and questions. </p>
|
|
2355
|
+
<Button>Contact Our Team</Button>
|
|
2356
|
+
</CardContent>
|
|
2357
|
+
</Card>
|
|
2358
|
+
)
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
const CardGroupDemo = () => {
|
|
2362
|
+
return (
|
|
2363
|
+
<div className='flex *:rounded-none *:shadow-none max-xl:flex-col max-xl:*:not-last:border-b-0 max-xl:*:first:rounded-t-xl max-xl:*:last:rounded-b-xl xl:*:not-last:border-r-0 xl:*:first:rounded-l-xl xl:*:last:rounded-r-xl'>
|
|
2364
|
+
<Card className='overflow-hidden pt-0'>
|
|
2365
|
+
<CardContent className='px-0'>
|
|
2366
|
+
<img
|
|
2367
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-7.png?width=368&format=auto'
|
|
2368
|
+
alt='Banner'
|
|
2369
|
+
className='aspect-video w-92 object-cover'
|
|
2370
|
+
/>
|
|
2371
|
+
</CardContent>
|
|
2372
|
+
<CardHeader>
|
|
2373
|
+
<CardTitle>Mystical Blue Swirl</CardTitle>
|
|
2374
|
+
<CardDescription>
|
|
2375
|
+
Dive into the depths of an enchanting swirl where vibrant blues and soft pinks merge seamlessly, creating a
|
|
2376
|
+
mesmerizing flow of colors.
|
|
2377
|
+
</CardDescription>
|
|
2378
|
+
</CardHeader>
|
|
2379
|
+
<CardFooter className='gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2380
|
+
<Button>Explore More</Button>
|
|
2381
|
+
<Button variant={'outline'}>Download Now</Button>
|
|
2382
|
+
</CardFooter>
|
|
2383
|
+
</Card>
|
|
2384
|
+
<Card className='overflow-hidden pt-0'>
|
|
2385
|
+
<CardContent className='px-0'>
|
|
2386
|
+
<img
|
|
2387
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-4.png?width=368&format=auto'
|
|
2388
|
+
alt='Banner'
|
|
2389
|
+
className='aspect-video w-92 object-cover'
|
|
2390
|
+
/>
|
|
2391
|
+
</CardContent>
|
|
2392
|
+
<CardHeader>
|
|
2393
|
+
<CardTitle>Fiery Sunset Gradient</CardTitle>
|
|
2394
|
+
<CardDescription>
|
|
2395
|
+
Experience the warmth of a radiant sunset with flowing gradients of red, orange, and yellow blending
|
|
2396
|
+
effortlessly in an abstract glow.
|
|
2397
|
+
</CardDescription>
|
|
2398
|
+
</CardHeader>
|
|
2399
|
+
<CardFooter className='gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2400
|
+
<Button>Explore More</Button>
|
|
2401
|
+
<Button variant={'outline'}>Download Now</Button>
|
|
2402
|
+
</CardFooter>
|
|
2403
|
+
</Card>
|
|
2404
|
+
<Card className='overflow-hidden pt-0'>
|
|
2405
|
+
<CardContent className='px-0'>
|
|
2406
|
+
<img
|
|
2407
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-5.png?width=368&format=auto'
|
|
2408
|
+
alt='Banner'
|
|
2409
|
+
className='aspect-video w-92 object-cover'
|
|
2410
|
+
/>
|
|
2411
|
+
</CardContent>
|
|
2412
|
+
<CardHeader>
|
|
2413
|
+
<CardTitle>Cosmic Blue Waves</CardTitle>
|
|
2414
|
+
<CardDescription>
|
|
2415
|
+
Explore the mysteries of the cosmos with deep, swirling waves of blue and purple, evoking a sense of depth
|
|
2416
|
+
and infinite space.
|
|
2417
|
+
</CardDescription>
|
|
2418
|
+
</CardHeader>
|
|
2419
|
+
<CardFooter className='gap-3 max-sm:flex-col max-sm:items-stretch'>
|
|
2420
|
+
<Button>Explore More</Button>
|
|
2421
|
+
<Button variant={'outline'}>Download Now</Button>
|
|
2422
|
+
</CardFooter>
|
|
2423
|
+
</Card>
|
|
2424
|
+
</div>
|
|
2425
|
+
)
|
|
2426
|
+
}
|
|
2427
|
+
|
|
2428
|
+
const CardSpotlightDemo = () => {
|
|
2429
|
+
useEffect(() => {
|
|
2430
|
+
const all = document.querySelectorAll('.spotlight-card')
|
|
2431
|
+
|
|
2432
|
+
const handleMouseMove = (ev: MouseEvent) => {
|
|
2433
|
+
all.forEach(e => {
|
|
2434
|
+
const blob = e.querySelector('.blob') as HTMLElement
|
|
2435
|
+
const fblob = e.querySelector('.fake-blob') as HTMLElement
|
|
2436
|
+
|
|
2437
|
+
if (!blob || !fblob) return
|
|
2438
|
+
|
|
2439
|
+
const rec = fblob.getBoundingClientRect()
|
|
2440
|
+
|
|
2441
|
+
blob.style.opacity = '1'
|
|
2442
|
+
|
|
2443
|
+
blob.animate(
|
|
2444
|
+
[
|
|
2445
|
+
{
|
|
2446
|
+
transform: `translate(${ev.clientX - rec.left - rec.width / 2
|
|
2447
|
+
}px, ${ev.clientY - rec.top - rec.height / 2}px)`
|
|
2448
|
+
}
|
|
2449
|
+
],
|
|
2450
|
+
{
|
|
2451
|
+
duration: 300,
|
|
2452
|
+
fill: 'forwards'
|
|
2453
|
+
}
|
|
2454
|
+
)
|
|
2455
|
+
})
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
window.addEventListener('mousemove', handleMouseMove)
|
|
2459
|
+
|
|
2460
|
+
return () => {
|
|
2461
|
+
window.removeEventListener('mousemove', handleMouseMove)
|
|
2462
|
+
}
|
|
2463
|
+
}, [])
|
|
2464
|
+
|
|
2465
|
+
return (
|
|
2466
|
+
<div className='h-max w-max'>
|
|
2467
|
+
<div className='spotlight-card group bg-border relative overflow-hidden rounded-xl p-px transition-all duration-300 ease-in-out'>
|
|
2468
|
+
<Card className='group-hover:bg-card/90 max-w-80 border-none transition-all duration-300 ease-in-out group-hover:backdrop-blur-[20px]'>
|
|
2469
|
+
<CardHeader>
|
|
2470
|
+
<CardTitle>Hover for the Glow-Up</CardTitle>
|
|
2471
|
+
</CardHeader>
|
|
2472
|
+
<CardContent>
|
|
2473
|
+
Glide your cursor here and watch magic unfold — an experience designed just for you.
|
|
2474
|
+
</CardContent>
|
|
2475
|
+
</Card>
|
|
2476
|
+
<div className='blob absolute top-0 left-0 size-20 rounded-full bg-sky-600/60 opacity-0 blur-2xl transition-all duration-300 ease-in-out dark:bg-sky-400/60' />
|
|
2477
|
+
<div className='fake-blob absolute top-0 left-0 size-20 rounded-full' />
|
|
2478
|
+
</div>
|
|
2479
|
+
</div>
|
|
2480
|
+
)
|
|
2481
|
+
}
|
|
2482
|
+
|
|
2483
|
+
const Card3dDemo = () => {
|
|
2484
|
+
const cardRef = useRef<HTMLDivElement>(null)
|
|
2485
|
+
const imageRef = useRef<HTMLImageElement>(null)
|
|
2486
|
+
const animationFrameRef = useRef<number | undefined>(undefined)
|
|
2487
|
+
const lastMousePosition = useRef({ x: 0, y: 0 })
|
|
2488
|
+
|
|
2489
|
+
useEffect(() => {
|
|
2490
|
+
const card = cardRef.current
|
|
2491
|
+
const image = imageRef.current
|
|
2492
|
+
|
|
2493
|
+
if (!card || !image) return
|
|
2494
|
+
|
|
2495
|
+
let rect: DOMRect
|
|
2496
|
+
let centerX: number
|
|
2497
|
+
let centerY: number
|
|
2498
|
+
|
|
2499
|
+
const updateCardTransform = (mouseX: number, mouseY: number) => {
|
|
2500
|
+
if (!rect) {
|
|
2501
|
+
rect = card.getBoundingClientRect()
|
|
2502
|
+
centerX = rect.left + rect.width / 2
|
|
2503
|
+
centerY = rect.top + rect.height / 2
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
const relativeX = mouseX - centerX
|
|
2507
|
+
const relativeY = mouseY - centerY
|
|
2508
|
+
|
|
2509
|
+
const cardTransform: CardTransform = {
|
|
2510
|
+
rotateX: -relativeY * 0.035,
|
|
2511
|
+
rotateY: relativeX * 0.035,
|
|
2512
|
+
scale: 1.025
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
const imageTransform: CardTransform = {
|
|
2516
|
+
rotateX: -relativeY * 0.025,
|
|
2517
|
+
rotateY: relativeX * 0.025,
|
|
2518
|
+
scale: 1.05
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2521
|
+
return { cardTransform, imageTransform }
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
const animate = () => {
|
|
2525
|
+
const { cardTransform, imageTransform } = updateCardTransform(
|
|
2526
|
+
lastMousePosition.current.x,
|
|
2527
|
+
lastMousePosition.current.y
|
|
2528
|
+
)
|
|
2529
|
+
|
|
2530
|
+
card.style.transform = `perspective(1000px) rotateX(${cardTransform.rotateX}deg) rotateY(${cardTransform.rotateY}deg) scale3d(${cardTransform.scale}, ${cardTransform.scale}, ${cardTransform.scale})`
|
|
2531
|
+
card.style.boxShadow = '0 10px 35px rgba(0, 0, 0, 0.2)'
|
|
2532
|
+
|
|
2533
|
+
image.style.transform = `perspective(1000px) rotateX(${imageTransform.rotateX}deg) rotateY(${imageTransform.rotateY}deg) scale3d(${imageTransform.scale}, ${imageTransform.scale}, ${imageTransform.scale})`
|
|
2534
|
+
|
|
2535
|
+
animationFrameRef.current = requestAnimationFrame(animate)
|
|
2536
|
+
}
|
|
2537
|
+
|
|
2538
|
+
const handleMouseMove = (e: MouseEvent) => {
|
|
2539
|
+
lastMousePosition.current = { x: e.clientX, y: e.clientY }
|
|
2540
|
+
}
|
|
2541
|
+
|
|
2542
|
+
const handleMouseEnter = () => {
|
|
2543
|
+
card.style.transition = 'transform 0.2s ease, box-shadow 0.2s ease'
|
|
2544
|
+
image.style.transition = 'transform 0.2s ease'
|
|
2545
|
+
animate()
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
const handleMouseLeave = () => {
|
|
2549
|
+
if (animationFrameRef.current) {
|
|
2550
|
+
cancelAnimationFrame(animationFrameRef.current)
|
|
2551
|
+
}
|
|
2552
|
+
|
|
2553
|
+
card.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
|
|
2554
|
+
card.style.boxShadow = 'none'
|
|
2555
|
+
card.style.transition = 'transform 0.5s ease, box-shadow 0.5s ease'
|
|
2556
|
+
|
|
2557
|
+
image.style.transform = 'perspective(1000px) rotateX(0) rotateY(0) scale3d(1, 1, 1)'
|
|
2558
|
+
image.style.transition = 'transform 0.5s ease'
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
card.addEventListener('mouseenter', handleMouseEnter)
|
|
2562
|
+
card.addEventListener('mousemove', handleMouseMove)
|
|
2563
|
+
card.addEventListener('mouseleave', handleMouseLeave)
|
|
2564
|
+
|
|
2565
|
+
return () => {
|
|
2566
|
+
if (animationFrameRef.current) {
|
|
2567
|
+
cancelAnimationFrame(animationFrameRef.current)
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
card.removeEventListener('mouseenter', handleMouseEnter)
|
|
2571
|
+
card.removeEventListener('mousemove', handleMouseMove)
|
|
2572
|
+
card.removeEventListener('mouseleave', handleMouseLeave)
|
|
2573
|
+
}
|
|
2574
|
+
}, [])
|
|
2575
|
+
|
|
2576
|
+
return (
|
|
2577
|
+
<Card ref={cardRef} className='max-w-md'>
|
|
2578
|
+
<CardHeader>
|
|
2579
|
+
<CardTitle>Dynamic 3D Hover Card</CardTitle>
|
|
2580
|
+
</CardHeader>
|
|
2581
|
+
<CardContent className='space-y-6 text-sm'>
|
|
2582
|
+
<img
|
|
2583
|
+
ref={imageRef}
|
|
2584
|
+
src='https://cdn.shadcnstudio.com/ss-assets/components/card/image-10.png?width=350&format=auto'
|
|
2585
|
+
alt='Banner'
|
|
2586
|
+
className='aspect-video w-full rounded-md object-cover'
|
|
2587
|
+
width={500}
|
|
2588
|
+
height={500}
|
|
2589
|
+
/>
|
|
2590
|
+
<p>
|
|
2591
|
+
Experience interactive depth and motion with this sleek 3D hover effect. Move your cursor to see it come
|
|
2592
|
+
alive!
|
|
2593
|
+
</p>
|
|
2594
|
+
</CardContent>
|
|
2595
|
+
</Card>
|
|
2596
|
+
)
|
|
2597
|
+
}
|