@catalystsoftware/ui 1.0.5 → 1.0.6

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.
Files changed (155) hide show
  1. package/dist/data/data.tsx +29 -29
  2. package/dist/data/tailwind.config.js +3821 -261
  3. package/dist/data.tsx +29 -29
  4. package/package.json +4 -3
  5. package/components/catalyst-ui/buttons/burger.tsx +0 -207
  6. package/components/catalyst-ui/core/data-display/timeline.tsx +0 -210
  7. package/components/catalyst-ui/core/feedback/alert.tsx +0 -491
  8. package/components/catalyst-ui/core/feedback/spinner-1.tsx +0 -65
  9. package/components/catalyst-ui/core/feedback/toast.tsx +0 -1857
  10. package/components/catalyst-ui/core/navigation/menu.tsx +0 -164
  11. package/components/catalyst-ui/forms/toggle-class.tsx +0 -176
  12. package/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +0 -419
  13. package/components/catalyst-ui/hooks/use-counter.tsx +0 -13
  14. package/components/catalyst-ui/hooks/use-event-listener.tsx +0 -23
  15. package/components/catalyst-ui/hooks/use-export-markdown.tsx +0 -47
  16. package/components/catalyst-ui/hooks/use-focus.tsx +0 -17
  17. package/components/catalyst-ui/hooks/use-interval.tsx +0 -23
  18. package/components/catalyst-ui/hooks/use-is-client.tsx +0 -16
  19. package/components/catalyst-ui/hooks/use-media-query.tsx +0 -19
  20. package/components/catalyst-ui/hooks/use-mobile.tsx +0 -19
  21. package/components/catalyst-ui/hooks/use-resize-observer.tsx +0 -81
  22. package/components/catalyst-ui/hooks/use-timeout.tsx +0 -21
  23. package/components/catalyst-ui/hooks/use-timer.tsx +0 -209
  24. package/components/catalyst-ui/hooks/use-toggle.tsx +0 -12
  25. package/components/catalyst-ui/media/image.tsx +0 -13
  26. package/components/catalyst-ui/overlays/dual-sidebar.tsx +0 -4142
  27. package/components/catalyst-ui/overlays/sidebar-original.tsx +0 -726
  28. package/components/catalyst-ui/primitives/accordion.tsx +0 -250
  29. package/components/catalyst-ui/primitives/alert-dialog.tsx +0 -126
  30. package/components/catalyst-ui/primitives/aspect-ratio.tsx +0 -9
  31. package/components/catalyst-ui/primitives/avatar.tsx +0 -296
  32. package/components/catalyst-ui/primitives/badge.tsx +0 -57
  33. package/components/catalyst-ui/primitives/breadcrumb.tsx +0 -101
  34. package/components/catalyst-ui/primitives/button.tsx +0 -265
  35. package/components/catalyst-ui/primitives/calendar-v4.tsx +0 -208
  36. package/components/catalyst-ui/primitives/calendar.tsx +0 -295
  37. package/components/catalyst-ui/primitives/card.tsx +0 -618
  38. package/components/catalyst-ui/primitives/carousel.tsx +0 -238
  39. package/components/catalyst-ui/primitives/chart.tsx +0 -347
  40. package/components/catalyst-ui/primitives/checkbox.tsx +0 -225
  41. package/components/catalyst-ui/primitives/collapsible.tsx +0 -212
  42. package/components/catalyst-ui/primitives/command.tsx +0 -393
  43. package/components/catalyst-ui/primitives/context-menu.tsx +0 -236
  44. package/components/catalyst-ui/primitives/dialog.tsx +0 -471
  45. package/components/catalyst-ui/primitives/drawer.tsx +0 -761
  46. package/components/catalyst-ui/primitives/dropdown-menu.tsx +0 -290
  47. package/components/catalyst-ui/primitives/empty.tsx +0 -104
  48. package/components/catalyst-ui/primitives/field.tsx +0 -244
  49. package/components/catalyst-ui/primitives/hover-card.tsx +0 -124
  50. package/components/catalyst-ui/primitives/input-otp.tsx +0 -76
  51. package/components/catalyst-ui/primitives/input.tsx +0 -64
  52. package/components/catalyst-ui/primitives/item.tsx +0 -196
  53. package/components/catalyst-ui/primitives/kbd.tsx +0 -75
  54. package/components/catalyst-ui/primitives/label.tsx +0 -24
  55. package/components/catalyst-ui/primitives/navigation-menu.tsx +0 -150
  56. package/components/catalyst-ui/primitives/pagination.tsx +0 -198
  57. package/components/catalyst-ui/primitives/popover.tsx +0 -232
  58. package/components/catalyst-ui/primitives/progress.tsx +0 -34
  59. package/components/catalyst-ui/primitives/radio-group.tsx +0 -43
  60. package/components/catalyst-ui/primitives/resizable.tsx +0 -56
  61. package/components/catalyst-ui/primitives/select.tsx +0 -155
  62. package/components/catalyst-ui/primitives/separator.tsx +0 -74
  63. package/components/catalyst-ui/primitives/sheet.tsx +0 -126
  64. package/components/catalyst-ui/primitives/skeleton.tsx +0 -15
  65. package/components/catalyst-ui/primitives/slider.tsx +0 -27
  66. package/components/catalyst-ui/primitives/switch.tsx +0 -187
  67. package/components/catalyst-ui/primitives/tabs.tsx +0 -335
  68. package/components/catalyst-ui/primitives/textarea.tsx +0 -24
  69. package/components/catalyst-ui/primitives/toggle-group.tsx +0 -55
  70. package/components/catalyst-ui/primitives/toggle.tsx +0 -42
  71. package/components/catalyst-ui/primitives/tooltip.tsx +0 -116
  72. package/components/catalyst-ui/utils/basic-auth.tsx +0 -40
  73. package/components/catalyst-ui/utils/context-storage.tsx +0 -19
  74. package/components/catalyst-ui/utils/cors-middleware.tsx +0 -71
  75. package/components/catalyst-ui/utils/deferred-content.tsx +0 -595
  76. package/components/catalyst-ui/utils/honeypot-middleware.tsx +0 -38
  77. package/components/catalyst-ui/utils/incId.tsx +0 -75
  78. package/components/catalyst-ui/utils/jwk-auth.tsx +0 -36
  79. package/components/catalyst-ui/utils/request-id.tsx +0 -14
  80. package/components/catalyst-ui/utils/secure-headers.tsx +0 -37
  81. package/components/catalyst-ui/utils/server-timing.tsx +0 -23
  82. package/components/catalyst-ui/utils/utils.ts +0 -43
  83. package/components/catalyst-ui/utils/with-cookie.tsx +0 -43
  84. package/components/catalyst-ui/x/accordian-x.tsx +0 -428
  85. package/components/catalyst-ui/x/alert-x.tsx +0 -413
  86. package/components/catalyst-ui/x/animated-text-x.tsx +0 -2242
  87. package/components/catalyst-ui/x/avatar-x.tsx +0 -515
  88. package/components/catalyst-ui/x/badge-x.tsx +0 -670
  89. package/components/catalyst-ui/x/button-X.tsx +0 -2857
  90. package/components/catalyst-ui/x/button-group-x.tsx +0 -847
  91. package/components/catalyst-ui/x/calendar-x.tsx +0 -1910
  92. package/components/catalyst-ui/x/card-x.tsx +0 -2597
  93. package/components/catalyst-ui/x/checkbox-x.tsx +0 -656
  94. package/components/catalyst-ui/x/collapsible-x.tsx +0 -1360
  95. package/components/catalyst-ui/x/combobox-x.tsx +0 -911
  96. package/components/catalyst-ui/x/data-table-x.tsx +0 -1753
  97. package/components/catalyst-ui/x/date-picker-x.tsx +0 -648
  98. package/components/catalyst-ui/x/dialog-x.tsx +0 -659
  99. package/components/catalyst-ui/x/dropdown-menu-x.tsx +0 -612
  100. package/components/catalyst-ui/x/hover-card-x.tsx +0 -375
  101. package/components/catalyst-ui/x/icon-x.tsx +0 -840
  102. package/components/catalyst-ui/x/input-mask-x.tsx +0 -981
  103. package/components/catalyst-ui/x/input-otp-x.tsx +0 -659
  104. package/components/catalyst-ui/x/loader-x.tsx +0 -1757
  105. package/components/catalyst-ui/x/pagination-x.tsx +0 -622
  106. package/components/catalyst-ui/x/popover-x.tsx +0 -744
  107. package/components/catalyst-ui/x/radio-group-x.tsx +0 -499
  108. package/components/catalyst-ui/x/select-x.tsx +0 -1127
  109. package/components/catalyst-ui/x/sheet-x.tsx +0 -668
  110. package/components/catalyst-ui/x/switch-x.tsx +0 -681
  111. package/components/catalyst-ui/x/table-x.tsx +0 -574
  112. package/components/catalyst-ui/x/tabs-x.tsx +0 -839
  113. package/components/catalyst-ui/x/textarea-x.tsx +0 -1263
  114. package/components/catalyst-ui/x/tooltip-x.tsx +0 -396
  115. package/components/catalyst-ui/x/tracker-x.tsx +0 -560
  116. package/data/bg-data.tsx +0 -901
  117. package/data/buttons-data.tsx +0 -2327
  118. package/data/charts-data.tsx +0 -102
  119. package/data/chat-data.tsx +0 -83
  120. package/data/code-data.tsx +0 -1040
  121. package/data/comboboxes-data.tsx +0 -1843
  122. package/data/command-data.tsx +0 -1381
  123. package/data/core-data.tsx +0 -15953
  124. package/data/crm-data.tsx +0 -47
  125. package/data/data.tsx +0 -159
  126. package/data/date-and-time-data.tsx +0 -554
  127. package/data/dependencies.tsx +0 -7
  128. package/data/ecommerce-data.tsx +0 -1387
  129. package/data/forms-data.tsx +0 -7890
  130. package/data/hooks-data.tsx +0 -5487
  131. package/data/index.ts +0 -34
  132. package/data/inputs-data.tsx +0 -557
  133. package/data/interactive-data.tsx +0 -5394
  134. package/data/lofi-data.tsx +0 -18295
  135. package/data/marketing-data.tsx +0 -2546
  136. package/data/media-data.tsx +0 -1510
  137. package/data/motion-data.tsx +0 -5801
  138. package/data/overlay-data.tsx +0 -4136
  139. package/data/pdf-data.tsx +0 -124
  140. package/data/pos-data.tsx +0 -213
  141. package/data/postcss.config.js +0 -6
  142. package/data/primitive-data.tsx +0 -5170
  143. package/data/prompt-data.tsx +0 -1226
  144. package/data/requiredLibs.ts +0 -4
  145. package/data/sandbox-data.tsx +0 -1
  146. package/data/sidebars-data.tsx +0 -5421
  147. package/data/stacks-data.tsx +0 -32
  148. package/data/table-data.tsx +0 -706
  149. package/data/tailwind.config.js +0 -270
  150. package/data/tailwind.config.ngin.js +0 -3830
  151. package/data/tailwind.css +0 -431
  152. package/data/tools-data.tsx +0 -6910
  153. package/data/typography-data.tsx +0 -2050
  154. package/data/utils-data.tsx +0 -6500
  155. package/data/x-data.tsx +0 -1171
@@ -1,744 +0,0 @@
1
- /**
2
-
3
-
4
-
5
-
6
-
7
-
8
- export function PopoverX({ popover = 'default', children, ...props }: any) {
9
- switch (popover) {
10
- case 'Closable':
11
- break
12
- default:
13
- break;
14
- }
15
- }
16
-
17
- const PopoverRatingsDemo = () => {
18
- const totalReviews = Object.values(ratings).reduce((acc, count) => acc + count, 0)
19
- const totalRating = Object.entries(ratings).reduce((acc, [star, count]) => acc + Number(star) * count, 0)
20
- const averageRating = Number((totalRating / totalReviews || 0).toFixed(2))
21
-
22
- return (
23
- <Popover>
24
- <PopoverTrigger asChild>
25
- <Button variant='outline' size='icon'>
26
- <StarIcon />
27
- <span className='sr-only'>Ratings & reviews</span>
28
- </Button>
29
- </PopoverTrigger>
30
- <PopoverContent className='w-80'>
31
- <div className='grid gap-4'>
32
- <div className='space-y-1'>
33
- <div className='flex items-center gap-1'>
34
- <span className='text-xl font-semibold'>{averageRating}</span>
35
- <StarIcon className='size-5 fill-amber-500 stroke-amber-500 dark:fill-amber-400 dark:stroke-amber-400' />
36
- </div>
37
- <div className='text-sm font-medium'>Total {totalReviews} reviews</div>
38
- <p className='text-muted-foreground text-sm'>All reviews are from genuine customers.</p>
39
- </div>
40
- <div className='grid'>
41
- <div className='flex items-center justify-between'>
42
- <Badge variant='secondary' className='rounded-sm'>
43
- +6 this week
44
- </Badge>
45
- <a href='#' className='text-sm hover:underline'>
46
- See all
47
- </a>
48
- </div>
49
- <Separator className='my-2' />
50
- <ul className='space-y-2'>
51
- {Object.entries(ratings)
52
- .reverse()
53
- .map(([star, count]) => (
54
- <li key={star} className='flex items-center gap-2'>
55
- <span className='shrink-0 text-sm'>{star} star</span>
56
- <Progress value={(count / totalReviews) * 100} className='w-full' />
57
- <span className='shrink-0 text-sm'>{count.toString()}</span>
58
- </li>
59
- ))}
60
- </ul>
61
- </div>
62
- </div>
63
- </PopoverContent>
64
- </Popover>
65
- )
66
- }
67
-
68
- const PopoverDimensionsDemo = () => {
69
- return (
70
- <Popover>
71
- <PopoverTrigger asChild>
72
- <Button variant='outline' size='icon'>
73
- <PencilRulerIcon />
74
- <span className='sr-only'>Dimensions</span>
75
- </Button>
76
- </PopoverTrigger>
77
- <PopoverContent className='w-80'>
78
- <div className='grid gap-4'>
79
- <div className='space-y-2'>
80
- <h4 className='leading-none font-medium'>Dimensions</h4>
81
- <p className='text-muted-foreground text-sm'>Set the dimensions for the layer.</p>
82
- </div>
83
- <div className='grid gap-2'>
84
- <div className='grid grid-cols-3 items-center gap-4'>
85
- <Label htmlFor='width'>Width</Label>
86
- <Input id='width' defaultValue='100%' className='col-span-2 h-8' />
87
- </div>
88
- <div className='grid grid-cols-3 items-center gap-4'>
89
- <Label htmlFor='maxWidth'>Max. width</Label>
90
- <Input id='maxWidth' defaultValue='300px' className='col-span-2 h-8' />
91
- </div>
92
- <div className='grid grid-cols-3 items-center gap-4'>
93
- <Label htmlFor='height'>Height</Label>
94
- <Input id='height' defaultValue='25px' className='col-span-2 h-8' />
95
- </div>
96
- <div className='grid grid-cols-3 items-center gap-4'>
97
- <Label htmlFor='maxHeight'>Max. height</Label>
98
- <Input id='maxHeight' defaultValue='none' className='col-span-2 h-8' />
99
- </div>
100
- </div>
101
- </div>
102
- </PopoverContent>
103
- </Popover>
104
- )
105
- }
106
-
107
- const PopoverPricingDemo = () => {
108
- return (
109
- <Popover>
110
- <PopoverTrigger asChild>
111
- <Button variant='outline' size='icon'>
112
- <DollarSignIcon />
113
- <span className='sr-only'>Pricing details</span>
114
- </Button>
115
- </PopoverTrigger>
116
- <PopoverContent className='w-80'>
117
- <div className='grid gap-2.5'>
118
- <div className='flex items-center justify-between'>
119
- <span className='text-lg font-semibold'>Enterprise Plan</span>
120
- <span className='text-sm font-medium'>$49.99/month</span>
121
- </div>
122
- <p className='text-sm'>
123
- Get unlimited access to all features including AI-powered analytics, custom branding, priority support, and
124
- advanced team collaboration tools.
125
- </p>
126
- <div className='flex items-center gap-2'>
127
- <Badge variant='destructive' className='rounded-sm px-1.5 py-px text-xs'>
128
- Limited Offer
129
- </Badge>
130
- <span className='text-muted-foreground text-xs'>20% discount on annual plan</span>
131
- </div>
132
- </div>
133
- </PopoverContent>
134
- </Popover>
135
- )
136
- }
137
-
138
- const PopoverVolumeDemo = () => {
139
- const [value, setValue] = useState([45])
140
-
141
- return (
142
- <Popover>
143
- <PopoverTrigger asChild>
144
- <Button variant='outline' size='icon'>
145
- <Volume2Icon />
146
- <span className='sr-only'>Volume control</span>
147
- </Button>
148
- </PopoverTrigger>
149
- <PopoverContent className='w-80'>
150
- <div className='space-y-3'>
151
- <div className='flex items-center justify-between gap-2'>
152
- <Label className='leading-5'>Volume</Label>
153
- <output className='text-sm font-medium tabular-nums'>{value[0]}</output>
154
- </div>
155
- <div className='flex items-center gap-2'>
156
- <VolumeXIcon className='size-4 shrink-0 opacity-60' />
157
- <Slider value={value} onValueChange={setValue} aria-label='Volume slider' />
158
- <Volume2Icon className='size-4 shrink-0 opacity-60' />
159
- </div>
160
- </div>
161
- </PopoverContent>
162
- </Popover>
163
- )
164
- }
165
-
166
- const PopoverAboutDemo = () => {
167
- return (
168
- <Popover>
169
- <PopoverTrigger asChild>
170
- <Button variant='outline' size='icon'>
171
- <InfoIcon />
172
- <span className='sr-only'>About Shadcn Studio</span>
173
- </Button>
174
- </PopoverTrigger>
175
- <PopoverContent className='w-80'>
176
- <div className='grid gap-4'>
177
- <div className='space-y-1.5 text-center'>
178
- <div className='text-lg font-semibold'>About Shadcn Studio</div>
179
- <p className='text-muted-foreground text-sm'>
180
- Welcome to Shadcn Studio — your toolkit for building sleek, customizable UI components with ease!
181
- </p>
182
- </div>
183
- <Button size='sm' asChild>
184
- <a
185
- href='https://shadcnstudio.com/docs/getting-started/introduction'
186
- target='_blank'
187
- rel='noopener noreferrer'
188
- >
189
- Learn More
190
- </a>
191
- </Button>
192
- </div>
193
- </PopoverContent>
194
- </Popover>
195
- )
196
- }
197
-
198
- const PopoverDownloadDemo = () => {
199
- const [isPaused, setIsPaused] = useState(false)
200
- const [isCanceled, setIsCanceled] = useState(false)
201
- const [value, setValue] = useState(0)
202
- const [open, setOpen] = useState(false)
203
- const [hasStarted, setHasStarted] = useState(false)
204
-
205
- useEffect(() => {
206
- if (open && !hasStarted && !isCanceled) {
207
- setHasStarted(true)
208
- }
209
- }, [open, hasStarted, isCanceled])
210
-
211
- useEffect(() => {
212
- if (!hasStarted || isPaused || isCanceled) return
213
-
214
- const timer = setInterval(() => {
215
- setValue(prev => {
216
- if (prev < 100) {
217
- return Math.min(100, prev + Math.floor(Math.random() * 10) + 1)
218
- } else {
219
- clearInterval(timer)
220
-
221
- return prev
222
- }
223
- })
224
- }, 500)
225
-
226
- return () => {
227
- clearInterval(timer)
228
- }
229
- }, [open, isPaused, isCanceled, hasStarted])
230
-
231
- const getText = () => {
232
- if (isCanceled) return 'Download Canceled'
233
- if (isPaused) return 'Download Paused'
234
- if (value === 100) return 'Download Complete'
235
-
236
- return 'Downloading File'
237
- }
238
-
239
- return (
240
- <Popover onOpenChange={setOpen} open={open}>
241
- <PopoverTrigger asChild>
242
- <Button variant='outline' size='icon'>
243
- <DownloadIcon />
244
- <span className='sr-only'>Download File</span>
245
- </Button>
246
- </PopoverTrigger>
247
- <PopoverContent className='w-80'>
248
- <div className='grid gap-4'>
249
- <div className='flex items-center gap-2'>
250
- <div className='relative flex size-6 items-center justify-center'>
251
- <span
252
- className={cn('border-primary absolute inset-0 rounded-full border border-dashed', {
253
- 'animate-spin [animation-duration:3s]': value < 100 && !isPaused && !isCanceled
254
- })}
255
- />
256
- <DownloadIcon className='z-1 size-3' />
257
- </div>
258
- <span className='flex-1 text-sm font-medium'>{getText()}</span>
259
- {!isCanceled && <span className='text-sm font-semibold'>{`${value}%`}</span>}
260
- </div>
261
- <Progress value={value} className='w-full' />
262
- <div className='grid grid-cols-2 gap-2'>
263
- <Button size='sm' onClick={() => setIsPaused(!isPaused)} disabled={value === 100 || isCanceled}>
264
- {isPaused ? 'Resume' : 'Pause'}
265
- </Button>
266
- <Button
267
- variant='secondary'
268
- size='sm'
269
- onClick={() => {
270
- if (value < 100) {
271
- setValue(0)
272
- setIsCanceled(true)
273
- setHasStarted(false)
274
- }
275
-
276
- setOpen(false)
277
- }}
278
- >
279
- Cancel
280
- </Button>
281
- </div>
282
- </div>
283
- </PopoverContent>
284
- </Popover>
285
- )
286
- }
287
-
288
- const PopoverDeleteFileDemo = () => {
289
- return (
290
- <Popover>
291
- <PopoverTrigger asChild>
292
- <Button variant='outline' size='icon'>
293
- <FileWarningIcon />
294
- <span className='sr-only'>Delete File</span>
295
- </Button>
296
- </PopoverTrigger>
297
- <PopoverContent className='w-80'>
298
- <div className='flex flex-col items-center gap-4'>
299
- <div className='flex aspect-square size-12 items-center justify-center rounded-full bg-red-500/10'>
300
- <FileWarningIcon className='text-destructive size-6' />
301
- </div>
302
- <div className='space-y-2 text-center'>
303
- <div className='font-semibold text-balance'>Are you sure you want to delete this file?</div>
304
- <p className='text-muted-foreground text-sm'>
305
- Deleting this file can affect your project and other files connection so keep in mind before making
306
- decision
307
- </p>
308
- </div>
309
- <div className='grid w-full grid-cols-2 gap-2'>
310
- <Button variant='secondary' size='sm'>
311
- Cancel
312
- </Button>
313
- <Button variant='destructive' size='sm'>
314
- Delete File
315
- </Button>
316
- </div>
317
- </div>
318
- </PopoverContent>
319
- </Popover>
320
- )
321
- }
322
-
323
- const PopoverFeedbackDemo = () => {
324
- return (
325
- <Popover>
326
- <PopoverTrigger asChild>
327
- <Button variant='outline' size='icon'>
328
- <MessageCircleIcon />
329
- <span className='sr-only'>Feedback</span>
330
- </Button>
331
- </PopoverTrigger>
332
- <PopoverContent className='w-80'>
333
- <div className='grid gap-2'>
334
- <div className='font-medium'>Feedback</div>
335
- <Textarea placeholder='Type your message here.' className='max-h-56' />
336
- <div className='grid w-full grid-cols-2 gap-2'>
337
- <Button size='sm'>Send</Button>
338
- <Button variant='secondary' size='sm'>
339
- Cancel
340
- </Button>
341
- </div>
342
- </div>
343
- </PopoverContent>
344
- </Popover>
345
- )
346
- }
347
-
348
- const PopoverFilterDemo = () => {
349
- const [selected, setSelected] = useState(['Most liked', 'Newest'])
350
- const [price, setPrice] = useState([450])
351
-
352
- return (
353
- <Popover>
354
- <PopoverTrigger asChild>
355
- <Button variant='outline' size='icon'>
356
- <FunnelPlusIcon />
357
- <span className='sr-only'>Filter</span>
358
- </Button>
359
- </PopoverTrigger>
360
- <PopoverContent>
361
- <div className='grid gap-4'>
362
- <div className='flex items-center justify-between gap-2'>
363
- <span className='font-medium'>Filter</span>
364
- <Button
365
- variant='secondary'
366
- className='h-7 rounded-full px-2 py-1 text-xs'
367
- onClick={() => {
368
- setSelected(['Most liked', 'Newest'])
369
- setPrice([450])
370
- }}
371
- >
372
- Reset all
373
- </Button>
374
- </div>
375
- <div className='flex flex-col gap-2'>
376
- {filters.map((label, index) => (
377
- <div key={index} className='flex items-center gap-2'>
378
- <Checkbox
379
- id={`filter-${index + 1}`}
380
- checked={selected.includes(label)}
381
- onCheckedChange={checked =>
382
- setSelected(checked ? [...selected, label] : selected.filter(item => item !== label))
383
- }
384
- />
385
- <Label htmlFor={`filter-${index + 1}`}>{label}</Label>
386
- </div>
387
- ))}
388
- </div>
389
- <div className='grid gap-3'>
390
- <Label>Price range</Label>
391
- <div className='space-y-2'>
392
- <Slider value={price} onValueChange={setPrice} step={50} max={1000} aria-label='Price range' />
393
- <span className='text-muted-foreground flex w-full items-center justify-between gap-1 text-xs font-medium'>
394
- <span>0</span>
395
- <span>500</span>
396
- <span>1000</span>
397
- </span>
398
- </div>
399
- </div>
400
- </div>
401
- </PopoverContent>
402
- </Popover>
403
- )
404
- }
405
-
406
- const useDebounce = (value: string, delay: number = 300) => {
407
- const [debouncedValue, setDebouncedValue] = useState(value)
408
-
409
- useEffect(() => {
410
- const timer = setTimeout(() => {
411
- setDebouncedValue(value)
412
- }, delay)
413
-
414
- return () => {
415
- clearTimeout(timer)
416
- }
417
- }, [value, delay])
418
-
419
- return debouncedValue
420
- }
421
-
422
- const PopoverSearchDemo = () => {
423
- const [inputValue, setInputValue] = useState('')
424
- const [isLoading, setIsLoading] = useState(false)
425
- const debouncedSearch = useDebounce(inputValue)
426
- const [filteredUsers, setFilteredUsers] = useState(users)
427
-
428
- // Handle loading state when input changes
429
- useEffect(() => {
430
- if (inputValue) {
431
- setIsLoading(true)
432
- } else {
433
- setIsLoading(false)
434
- }
435
- }, [inputValue])
436
-
437
- // Apply filtering after debounce and update loading state
438
- useEffect(() => {
439
- if (debouncedSearch.trim() === '') {
440
- setFilteredUsers(users)
441
- setIsLoading(false)
442
- } else {
443
- const searchTerm = debouncedSearch.toLowerCase()
444
-
445
- const filtered = users.filter(user => user.name.toLowerCase().includes(searchTerm))
446
-
447
- setFilteredUsers(filtered)
448
- setIsLoading(false)
449
- }
450
- }, [debouncedSearch])
451
-
452
- return (
453
- <Popover>
454
- <PopoverTrigger asChild>
455
- <Button variant='outline' size='icon'>
456
- <SearchIcon />
457
- <span className='sr-only'>Search users</span>
458
- </Button>
459
- </PopoverTrigger>
460
- <PopoverContent className='w-80'>
461
- <div className='grid gap-4'>
462
- <div className='relative'>
463
- <div className='text-muted-foreground pointer-events-none absolute inset-y-0 left-0 flex items-center justify-center pl-3 peer-disabled:opacity-50'>
464
- <SearchIcon className='size-4' />
465
- <span className='sr-only'>Search</span>
466
- </div>
467
- <Input
468
- type='search'
469
- placeholder='Search users'
470
- value={inputValue}
471
- onChange={e => setInputValue(e.target.value)}
472
- className='peer px-9 [&::-webkit-search-cancel-button]:appearance-none [&::-webkit-search-decoration]:appearance-none [&::-webkit-search-results-button]:appearance-none [&::-webkit-search-results-decoration]:appearance-none'
473
- />
474
- {isLoading && (
475
- <div className='text-muted-foreground pointer-events-none absolute inset-y-0 right-0 flex items-center justify-center pr-3 peer-disabled:opacity-50'>
476
- <LoaderCircleIcon className='size-4 animate-spin' />
477
- <span className='sr-only'>Loading...</span>
478
- </div>
479
- )}
480
- </div>
481
- <ul className='space-y-2'>
482
- {filteredUsers.length > 0 ? (
483
- filteredUsers.map((user, index) => (
484
- <li key={index} className='flex items-center gap-2'>
485
- <Avatar className='size-6'>
486
- <AvatarImage src={user.image} alt={user.name} />
487
- <AvatarFallback className='text-xs'>{user.fallback}</AvatarFallback>
488
- </Avatar>
489
- <div className='flex-1 text-sm font-medium'>{user.name}</div>
490
- {user.notifications && (
491
- <span className='text-muted-foreground text-xs'>{`${user.notifications} Notification${user.notifications > 1 ? 's' : ''}`}</span>
492
- )}
493
- </li>
494
- ))
495
- ) : (
496
- <li className='py-2 text-center text-sm'>No users found</li>
497
- )}
498
- </ul>
499
- </div>
500
- </PopoverContent>
501
- </Popover>
502
- )
503
- }
504
-
505
- const PopoverNotificationsDemo = () => {
506
- const [readMessages, setReadMessages] = useState([3])
507
-
508
- return (
509
- <Popover>
510
- <PopoverTrigger asChild>
511
- <Button variant='outline' size='icon'>
512
- <BellIcon />
513
- <span className='sr-only'>Notifications</span>
514
- </Button>
515
- </PopoverTrigger>
516
- <PopoverContent className='w-80 p-0'>
517
- <div className='grid'>
518
- <div className='flex items-center justify-between gap-2 px-4 py-2.5'>
519
- <span className='font-medium'>Notifications</span>
520
- <Button
521
- variant='secondary'
522
- className='h-7 rounded-full px-2 py-1 text-xs'
523
- onClick={() => setReadMessages(notifications.map(item => item.id))}
524
- >
525
- Mark as all read
526
- </Button>
527
- </div>
528
- <Separator className='' />
529
- <ul className='grid gap-4 p-2'>
530
- {notifications.map(item => (
531
- <li
532
- key={item.id}
533
- className='hover:bg-accent flex items-start gap-2 rounded-lg px-2 py-1.5'
534
- onClick={() => setReadMessages([...readMessages, item.id])}
535
- >
536
- <Avatar className='rounded-lg'>
537
- <AvatarImage src={item.image} alt={item.fallback} />
538
- <AvatarFallback className='rounded-lg text-xs'>{item.fallback}</AvatarFallback>
539
- </Avatar>
540
- <div className='flex-1 space-y-1'>
541
- <div className='text-sm font-medium'>{item.message}</div>
542
- <p className='text-muted-foreground text-xs'>{`${item.time} ago`}</p>
543
- </div>
544
- {!readMessages.includes(item.id) && (
545
- <CircleIcon className='fill-primary text-primary size-2 self-center' />
546
- )}
547
- </li>
548
- ))}
549
- </ul>
550
- </div>
551
- </PopoverContent>
552
- </Popover>
553
- )
554
- }
555
-
556
- const PopoverAboutHimalayasDemo = () => {
557
- return (
558
- <Popover>
559
- <PopoverTrigger asChild>
560
- <Button variant='outline' size='icon'>
561
- <MapPinIcon />
562
- <span className='sr-only'>About Himalayas</span>
563
- </Button>
564
- </PopoverTrigger>
565
- <PopoverContent className='w-85 p-0'>
566
- <div className='flex'>
567
- <div className='space-y-2 p-4'>
568
- <p className='font-medium'>About Himalayas</p>
569
- <p className='text-muted-foreground text-xs'>
570
- The Great Himalayan mountain ranges in the Indian sub-continent region.{' '}
571
- </p>
572
- <a
573
- href='https://en.wikipedia.org/wiki/Himalayas'
574
- target='_blank'
575
- rel='noopener noreferrer'
576
- className='flex w-fit text-xs hover:underline'
577
- >
578
- Read more
579
- <ChevronRightIcon className='size-4' />
580
- </a>
581
- </div>
582
- <img
583
- src='https://lp-cms-production.imgix.net/2021-01/GettyRF_450207051.jpg?height=136'
584
- alt='the himalayas'
585
- className='h-34 w-2/5 rounded-r-md object-cover'
586
- />
587
- </div>
588
- </PopoverContent>
589
- </Popover>
590
- )
591
- }
592
-
593
- const PopoverSlideInLeftDemo = () => {
594
- const [copied, setCopied] = useState<boolean>(false)
595
-
596
- const handleCopy = async () => {
597
- try {
598
- await navigator.clipboard.writeText('SUMMER25OFF')
599
- setCopied(true)
600
- setTimeout(() => setCopied(false), 1500)
601
- } catch (err) {
602
- console.error('Failed to copy text: ', err)
603
- }
604
- }
605
-
606
- return (
607
- <Popover>
608
- <PopoverTrigger asChild>
609
- <Button variant='outline'>Slide-in from left</Button>
610
- </PopoverTrigger>
611
- <PopoverContent className='data-[state=open]:slide-in-from-left-20 data-[state=closed]:slide-out-to-left-20 data-[state=open]:slide-in-from-top-0 data-[state=closed]:slide-out-to-top-0 data-[state=closed]:zoom-out-100 data-[state=open]:zoom-in-100 w-80 duration-400'>
612
- <div className='flex flex-col items-center gap-4'>
613
- <div className='space-y-1 text-center'>
614
- <div className='text-lg font-semibold'>Summer Sale Discount</div>
615
- <p className='text-sm'>Scan this code at checkout for 25% off</p>
616
- </div>
617
- <div className='aspect-square rounded-xl border p-2'>
618
- <img
619
- src='https://cdn.shadcnstudio.com/ss-assets/components/popover/qr-code.png?height=152'
620
- alt='Discount QR Code'
621
- className='size-38 rounded-md'
622
- />
623
- </div>
624
- <div className='flex w-full items-center gap-1.5'>
625
- <Separator className='flex-1' />
626
- <span className='text-muted-foreground text-xs'>or use coupon code</span>
627
- <Separator className='flex-1' />
628
- </div>
629
- <div className='flex w-full gap-2'>
630
- <Input
631
- type='text'
632
- placeholder='Discount code'
633
- defaultValue='SUMMER25OFF'
634
- className='disabled:bg-muted'
635
- disabled
636
- />
637
- <Button variant='outline' size='icon' className='relative' onClick={handleCopy}>
638
- <span className={cn('transition-all', copied ? 'scale-100 opacity-100' : 'scale-0 opacity-0')}>
639
- <CheckIcon className='stroke-green-600 dark:stroke-green-400' />
640
- </span>
641
- <span
642
- className={cn(
643
- 'absolute left-2.25 transition-all',
644
- copied ? 'scale-0 opacity-0' : 'scale-100 opacity-100'
645
- )}
646
- >
647
- <CopyIcon />
648
- </span>
649
- </Button>
650
- </div>
651
- </div>
652
- </PopoverContent>
653
- </Popover>
654
- )
655
- }
656
-
657
- const PopoverSlideInBottomDemo = () => {
658
- const id = useId()
659
-
660
- return (
661
- <Popover>
662
- <PopoverTrigger asChild>
663
- <Button variant='outline'>Slide-in from bottom</Button>
664
- </PopoverTrigger>
665
- <PopoverContent className='data-[state=open]:slide-in-from-bottom-20 data-[state=closed]:slide-out-to-bottom-20 data-[state=closed]:zoom-out-100 data-[state=open]:zoom-in-100 w-80 duration-400'>
666
- <div className='grid gap-4'>
667
- <div className='space-y-1'>
668
- <div className='font-medium'>Share to team members</div>
669
- <p className='text-muted-foreground text-sm'>
670
- Give your team members access to this project and start collaborating in real time
671
- </p>
672
- </div>
673
- <div className='w-full space-y-1.5'>
674
- <Label htmlFor={id} className='text-muted-foreground text-xs font-normal'>
675
- Email address
676
- </Label>
677
- <div className='flex gap-2'>
678
- <Input id={id} type='email' placeholder='example@xyz.com' className='h-8' />
679
- <Button type='submit' size='sm'>
680
- Share invite
681
- </Button>
682
- </div>
683
- </div>
684
- <div className='space-y-1.5'>
685
- <Label className='text-muted-foreground text-xs font-normal'>Team members</Label>
686
- <ul className='grid gap-2'>
687
- {members.map((member, index) => (
688
- <li key={index} className='flex items-center gap-3'>
689
- <Checkbox id={`member-${index + 1}`} />
690
- <Label htmlFor={`member-${index + 1}`} className='flex flex-1 items-center gap-2'>
691
- <div className='flex flex-1 items-center gap-2'>
692
- <Avatar className='size-6'>
693
- <AvatarImage src={member.image} alt={member.name} />
694
- <AvatarFallback className='text-xs'>{member.fallback}</AvatarFallback>
695
- </Avatar>
696
- <span className='text-sm font-medium'>{member.name}</span>
697
- </div>
698
- <span className='text-muted-foreground text-xs'>{member.designation}</span>
699
- </Label>
700
- </li>
701
- ))}
702
- </ul>
703
- </div>
704
- </div>
705
- </PopoverContent>
706
- </Popover>
707
- )
708
- }
709
-
710
- const PopoverZoomInDemo = () => {
711
- return (
712
- <Popover>
713
- <PopoverTrigger asChild>
714
- <Button variant='outline'>Zoom in</Button>
715
- </PopoverTrigger>
716
- <PopoverContent className='data-[state=open]:!zoom-in-0 data-[state=closed]:!zoom-out-0 origin-center duration-400'>
717
- <div className='grid gap-4'>
718
- <div className='flex flex-col items-center gap-2'>
719
- <Avatar className='size-20'>
720
- <AvatarImage src='https://cdn.shadcnstudio.com/ss-assets/avatar/avatar-5.png' alt='Howard Lloyd' />
721
- <AvatarFallback className='text-xs'>HL</AvatarFallback>
722
- </Avatar>
723
- <div className='flex flex-col items-center text-center'>
724
- <p className='text-lg font-semibold'>Howard Lloyd</p>
725
- <span className='text-sm'>@iamhoward</span>
726
- </div>
727
- </div>
728
- <div className='from-border/20 via-border to-border/20 mx-auto h-px w-45 bg-gradient-to-r' />
729
- <p className='text-center text-sm italic'>
730
- Product Manager @oliviasparks, passionate about building user-centric solutions that solve real problems.
731
- </p>
732
- <div className='flex justify-center gap-2 text-sm'>
733
- <div className='font-medium'>
734
- 512 <span className='text-muted-foreground font-normal'>followers</span>
735
- </div>
736
- <div className='font-medium'>
737
- 128 <span className='text-muted-foreground font-normal'>following</span>
738
- </div>
739
- </div>
740
- </div>
741
- </PopoverContent>
742
- </Popover>
743
- )
744
- } */