@moontra/moonui-pro 2.4.6 → 2.5.0
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/dist/index.d.ts +127 -25
- package/dist/index.mjs +2023 -186
- package/package.json +4 -1
- package/src/components/advanced-chart/index.tsx +11 -1
- package/src/components/dashboard/dashboard-grid.tsx +327 -0
- package/src/components/dashboard/demo.tsx +308 -0
- package/src/components/dashboard/index.tsx +683 -275
- package/src/components/dashboard/time-range-picker.tsx +267 -0
- package/src/components/dashboard/types.ts +222 -0
- package/src/components/dashboard/widgets/activity-feed.tsx +344 -0
- package/src/components/dashboard/widgets/chart-widget.tsx +418 -0
- package/src/components/dashboard/widgets/metric-card.tsx +343 -0
- package/src/components/index.ts +2 -2
- package/src/components/ui/calendar.tsx +65 -0
- package/src/components/ui/index.ts +12 -0
- package/src/components/ui/scroll-area.tsx +47 -0
- package/src/components/ui/sheet.tsx +139 -0
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React from 'react'
|
|
4
|
+
import { motion } from 'framer-motion'
|
|
5
|
+
import { Card } from '../../ui/card'
|
|
6
|
+
import { cn } from '../../../lib/utils'
|
|
7
|
+
import {
|
|
8
|
+
TrendingUp,
|
|
9
|
+
TrendingDown,
|
|
10
|
+
Minus,
|
|
11
|
+
ArrowUpRight,
|
|
12
|
+
ArrowDownRight,
|
|
13
|
+
MoreVertical,
|
|
14
|
+
Maximize2,
|
|
15
|
+
Download,
|
|
16
|
+
Share2
|
|
17
|
+
} from 'lucide-react'
|
|
18
|
+
import { MetricData } from '../types'
|
|
19
|
+
import { Button } from '../../ui/button'
|
|
20
|
+
import {
|
|
21
|
+
DropdownMenu,
|
|
22
|
+
DropdownMenuContent,
|
|
23
|
+
DropdownMenuItem,
|
|
24
|
+
DropdownMenuTrigger,
|
|
25
|
+
} from '../../ui/dropdown-menu'
|
|
26
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '../../ui/tooltip'
|
|
27
|
+
|
|
28
|
+
interface MetricCardProps {
|
|
29
|
+
data: MetricData
|
|
30
|
+
onClick?: () => void
|
|
31
|
+
onAction?: (action: string) => void
|
|
32
|
+
className?: string
|
|
33
|
+
showSparkline?: boolean
|
|
34
|
+
showForecast?: boolean
|
|
35
|
+
interactive?: boolean
|
|
36
|
+
glassmorphism?: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function MetricCard({
|
|
40
|
+
data,
|
|
41
|
+
onClick,
|
|
42
|
+
onAction,
|
|
43
|
+
className,
|
|
44
|
+
showSparkline = true,
|
|
45
|
+
showForecast = false,
|
|
46
|
+
interactive = true,
|
|
47
|
+
glassmorphism = false
|
|
48
|
+
}: MetricCardProps) {
|
|
49
|
+
const [isHovered, setIsHovered] = React.useState(false)
|
|
50
|
+
|
|
51
|
+
// Renk sınıfları
|
|
52
|
+
const colorClasses = {
|
|
53
|
+
primary: 'text-blue-600 dark:text-blue-400',
|
|
54
|
+
success: 'text-green-600 dark:text-green-400',
|
|
55
|
+
warning: 'text-yellow-600 dark:text-yellow-400',
|
|
56
|
+
danger: 'text-red-600 dark:text-red-400',
|
|
57
|
+
info: 'text-purple-600 dark:text-purple-400'
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Değişim renkleri
|
|
61
|
+
const getChangeColor = (type: 'increase' | 'decrease' | 'neutral') => {
|
|
62
|
+
switch (type) {
|
|
63
|
+
case 'increase':
|
|
64
|
+
return 'text-green-600 dark:text-green-400'
|
|
65
|
+
case 'decrease':
|
|
66
|
+
return 'text-red-600 dark:text-red-400'
|
|
67
|
+
default:
|
|
68
|
+
return 'text-gray-600 dark:text-gray-400'
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Değişim ikonu
|
|
73
|
+
const getChangeIcon = (type: 'increase' | 'decrease' | 'neutral') => {
|
|
74
|
+
switch (type) {
|
|
75
|
+
case 'increase':
|
|
76
|
+
return <ArrowUpRight className="h-4 w-4" />
|
|
77
|
+
case 'decrease':
|
|
78
|
+
return <ArrowDownRight className="h-4 w-4" />
|
|
79
|
+
default:
|
|
80
|
+
return <Minus className="h-4 w-4" />
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Sparkline çizimi
|
|
85
|
+
const renderSparkline = () => {
|
|
86
|
+
if (!data.sparkline || data.sparkline.length < 2) return null
|
|
87
|
+
|
|
88
|
+
const max = Math.max(...data.sparkline)
|
|
89
|
+
const min = Math.min(...data.sparkline)
|
|
90
|
+
const range = max - min || 1
|
|
91
|
+
|
|
92
|
+
const points = data.sparkline
|
|
93
|
+
.map((value, index) => {
|
|
94
|
+
const x = (index / (data.sparkline!.length - 1)) * 100
|
|
95
|
+
const y = 100 - ((value - min) / range) * 100
|
|
96
|
+
return `${x},${y}`
|
|
97
|
+
})
|
|
98
|
+
.join(' ')
|
|
99
|
+
|
|
100
|
+
const gradientId = `gradient-${data.id}`
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<motion.div
|
|
104
|
+
className="absolute bottom-0 left-0 right-0 h-16 overflow-hidden rounded-b-lg opacity-20"
|
|
105
|
+
initial={{ opacity: 0 }}
|
|
106
|
+
animate={{ opacity: isHovered ? 0.3 : 0.2 }}
|
|
107
|
+
transition={{ duration: 0.2 }}
|
|
108
|
+
>
|
|
109
|
+
<svg
|
|
110
|
+
className="w-full h-full"
|
|
111
|
+
viewBox="0 0 100 100"
|
|
112
|
+
preserveAspectRatio="none"
|
|
113
|
+
>
|
|
114
|
+
<defs>
|
|
115
|
+
<linearGradient id={gradientId} x1="0%" y1="0%" x2="0%" y2="100%">
|
|
116
|
+
<stop offset="0%" stopColor="currentColor" stopOpacity="0.3" />
|
|
117
|
+
<stop offset="100%" stopColor="currentColor" stopOpacity="0" />
|
|
118
|
+
</linearGradient>
|
|
119
|
+
</defs>
|
|
120
|
+
<polyline
|
|
121
|
+
fill="none"
|
|
122
|
+
stroke="currentColor"
|
|
123
|
+
strokeWidth="2"
|
|
124
|
+
points={points}
|
|
125
|
+
className={colorClasses[data.color || 'primary']}
|
|
126
|
+
/>
|
|
127
|
+
<polygon
|
|
128
|
+
fill={`url(#${gradientId})`}
|
|
129
|
+
points={`0,100 ${points} 100,100`}
|
|
130
|
+
className={colorClasses[data.color || 'primary']}
|
|
131
|
+
/>
|
|
132
|
+
</svg>
|
|
133
|
+
</motion.div>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// İlerleme barı (hedef varsa)
|
|
138
|
+
const renderProgress = () => {
|
|
139
|
+
if (!data.target) return null
|
|
140
|
+
|
|
141
|
+
const currentValue = typeof data.value === 'number' ? data.value : parseFloat(data.value as string)
|
|
142
|
+
const progress = (currentValue / data.target) * 100
|
|
143
|
+
|
|
144
|
+
return (
|
|
145
|
+
<motion.div
|
|
146
|
+
className="mt-3"
|
|
147
|
+
initial={{ opacity: 0, y: 10 }}
|
|
148
|
+
animate={{ opacity: 1, y: 0 }}
|
|
149
|
+
transition={{ delay: 0.1 }}
|
|
150
|
+
>
|
|
151
|
+
<div className="flex justify-between text-xs text-muted-foreground mb-1">
|
|
152
|
+
<span>Progress to target</span>
|
|
153
|
+
<span>{progress.toFixed(1)}%</span>
|
|
154
|
+
</div>
|
|
155
|
+
<div className="h-1.5 bg-muted rounded-full overflow-hidden">
|
|
156
|
+
<motion.div
|
|
157
|
+
className={cn(
|
|
158
|
+
"h-full rounded-full",
|
|
159
|
+
progress >= 100 ? 'bg-green-500' : 'bg-primary'
|
|
160
|
+
)}
|
|
161
|
+
initial={{ width: 0 }}
|
|
162
|
+
animate={{ width: `${Math.min(progress, 100)}%` }}
|
|
163
|
+
transition={{ duration: 0.5, ease: "easeOut" }}
|
|
164
|
+
/>
|
|
165
|
+
</div>
|
|
166
|
+
<div className="flex justify-between text-xs text-muted-foreground mt-1">
|
|
167
|
+
<span>{currentValue} {data.unit}</span>
|
|
168
|
+
<span>Target: {data.target} {data.unit}</span>
|
|
169
|
+
</div>
|
|
170
|
+
</motion.div>
|
|
171
|
+
)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Değer formatı
|
|
175
|
+
const formatValue = (value: string | number): string => {
|
|
176
|
+
if (typeof value === 'number') {
|
|
177
|
+
if (value >= 1000000) {
|
|
178
|
+
return (value / 1000000).toFixed(1) + 'M'
|
|
179
|
+
} else if (value >= 1000) {
|
|
180
|
+
return (value / 1000).toFixed(1) + 'K'
|
|
181
|
+
}
|
|
182
|
+
return value.toLocaleString()
|
|
183
|
+
}
|
|
184
|
+
return value.toString()
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Card variants
|
|
188
|
+
const cardVariants = {
|
|
189
|
+
initial: { opacity: 0, y: 20 },
|
|
190
|
+
animate: {
|
|
191
|
+
opacity: 1,
|
|
192
|
+
y: 0,
|
|
193
|
+
transition: { duration: 0.3, ease: "easeOut" }
|
|
194
|
+
},
|
|
195
|
+
hover: interactive ? {
|
|
196
|
+
y: -2,
|
|
197
|
+
transition: { duration: 0.2 }
|
|
198
|
+
} : {}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<motion.div
|
|
203
|
+
variants={cardVariants}
|
|
204
|
+
initial="initial"
|
|
205
|
+
animate="animate"
|
|
206
|
+
whileHover="hover"
|
|
207
|
+
onHoverStart={() => setIsHovered(true)}
|
|
208
|
+
onHoverEnd={() => setIsHovered(false)}
|
|
209
|
+
>
|
|
210
|
+
<Card
|
|
211
|
+
className={cn(
|
|
212
|
+
"relative overflow-hidden cursor-pointer transition-all duration-300",
|
|
213
|
+
interactive && "hover:shadow-lg hover:shadow-primary/5",
|
|
214
|
+
glassmorphism && "bg-background/60 backdrop-blur-md border-white/10",
|
|
215
|
+
className
|
|
216
|
+
)}
|
|
217
|
+
onClick={onClick}
|
|
218
|
+
>
|
|
219
|
+
{/* Açık arka plan efekti */}
|
|
220
|
+
{glassmorphism && (
|
|
221
|
+
<div className="absolute inset-0 bg-gradient-to-br from-primary/5 to-transparent" />
|
|
222
|
+
)}
|
|
223
|
+
|
|
224
|
+
{/* Üst bar */}
|
|
225
|
+
<div className="flex items-center justify-between p-4 pb-2">
|
|
226
|
+
<div className="flex items-center gap-3">
|
|
227
|
+
<motion.div
|
|
228
|
+
className={cn(
|
|
229
|
+
"p-2 rounded-lg",
|
|
230
|
+
glassmorphism ? "bg-white/10 backdrop-blur" : "bg-muted"
|
|
231
|
+
)}
|
|
232
|
+
whileHover={{ scale: 1.05 }}
|
|
233
|
+
whileTap={{ scale: 0.95 }}
|
|
234
|
+
>
|
|
235
|
+
<div className={cn("h-5 w-5", colorClasses[data.color || 'primary'])}>
|
|
236
|
+
{data.icon}
|
|
237
|
+
</div>
|
|
238
|
+
</motion.div>
|
|
239
|
+
<div>
|
|
240
|
+
<h3 className="text-sm font-medium text-muted-foreground">{data.title}</h3>
|
|
241
|
+
</div>
|
|
242
|
+
</div>
|
|
243
|
+
|
|
244
|
+
{/* Aksiyonlar */}
|
|
245
|
+
{interactive && (
|
|
246
|
+
<DropdownMenu>
|
|
247
|
+
<DropdownMenuTrigger asChild>
|
|
248
|
+
<Button
|
|
249
|
+
variant="ghost"
|
|
250
|
+
size="sm"
|
|
251
|
+
className="h-8 w-8 p-0"
|
|
252
|
+
onClick={(e) => e.stopPropagation()}
|
|
253
|
+
>
|
|
254
|
+
<MoreVertical className="h-4 w-4" />
|
|
255
|
+
</Button>
|
|
256
|
+
</DropdownMenuTrigger>
|
|
257
|
+
<DropdownMenuContent align="end">
|
|
258
|
+
<DropdownMenuItem onClick={() => onAction?.('fullscreen')}>
|
|
259
|
+
<Maximize2 className="mr-2 h-4 w-4" />
|
|
260
|
+
Fullscreen
|
|
261
|
+
</DropdownMenuItem>
|
|
262
|
+
<DropdownMenuItem onClick={() => onAction?.('export')}>
|
|
263
|
+
<Download className="mr-2 h-4 w-4" />
|
|
264
|
+
Export Data
|
|
265
|
+
</DropdownMenuItem>
|
|
266
|
+
<DropdownMenuItem onClick={() => onAction?.('share')}>
|
|
267
|
+
<Share2 className="mr-2 h-4 w-4" />
|
|
268
|
+
Share
|
|
269
|
+
</DropdownMenuItem>
|
|
270
|
+
</DropdownMenuContent>
|
|
271
|
+
</DropdownMenu>
|
|
272
|
+
)}
|
|
273
|
+
</div>
|
|
274
|
+
|
|
275
|
+
{/* Ana değer */}
|
|
276
|
+
<div className="px-4 pb-4">
|
|
277
|
+
<TooltipProvider>
|
|
278
|
+
<Tooltip>
|
|
279
|
+
<TooltipTrigger asChild>
|
|
280
|
+
<motion.div
|
|
281
|
+
className="text-3xl font-bold tracking-tight"
|
|
282
|
+
animate={{
|
|
283
|
+
scale: isHovered ? 1.02 : 1,
|
|
284
|
+
}}
|
|
285
|
+
transition={{ duration: 0.2 }}
|
|
286
|
+
>
|
|
287
|
+
{formatValue(data.value)}
|
|
288
|
+
{data.unit && <span className="text-lg ml-1 text-muted-foreground">{data.unit}</span>}
|
|
289
|
+
</motion.div>
|
|
290
|
+
</TooltipTrigger>
|
|
291
|
+
<TooltipContent>
|
|
292
|
+
<p>Exact value: {data.value} {data.unit}</p>
|
|
293
|
+
</TooltipContent>
|
|
294
|
+
</Tooltip>
|
|
295
|
+
</TooltipProvider>
|
|
296
|
+
|
|
297
|
+
{/* Değişim göstergesi */}
|
|
298
|
+
{data.change && (
|
|
299
|
+
<motion.div
|
|
300
|
+
className={cn(
|
|
301
|
+
"flex items-center gap-1 text-sm mt-2",
|
|
302
|
+
getChangeColor(data.change.type)
|
|
303
|
+
)}
|
|
304
|
+
initial={{ opacity: 0, x: -10 }}
|
|
305
|
+
animate={{ opacity: 1, x: 0 }}
|
|
306
|
+
transition={{ delay: 0.1 }}
|
|
307
|
+
>
|
|
308
|
+
{getChangeIcon(data.change.type)}
|
|
309
|
+
<span className="font-medium">
|
|
310
|
+
{data.change.type === 'neutral' ? '' : data.change.type === 'increase' ? '+' : '-'}
|
|
311
|
+
{Math.abs(data.change.value)}%
|
|
312
|
+
</span>
|
|
313
|
+
<span className="text-muted-foreground">
|
|
314
|
+
from {data.change.period}
|
|
315
|
+
</span>
|
|
316
|
+
</motion.div>
|
|
317
|
+
)}
|
|
318
|
+
|
|
319
|
+
{/* Tahmin */}
|
|
320
|
+
{showForecast && data.forecast && (
|
|
321
|
+
<motion.div
|
|
322
|
+
className="flex items-center gap-1 text-xs text-muted-foreground mt-1"
|
|
323
|
+
initial={{ opacity: 0 }}
|
|
324
|
+
animate={{ opacity: 1 }}
|
|
325
|
+
transition={{ delay: 0.2 }}
|
|
326
|
+
>
|
|
327
|
+
<TrendingUp className="h-3 w-3" />
|
|
328
|
+
<span>Forecast: {formatValue(data.forecast)} {data.unit}</span>
|
|
329
|
+
</motion.div>
|
|
330
|
+
)}
|
|
331
|
+
|
|
332
|
+
{/* İlerleme barı */}
|
|
333
|
+
{renderProgress()}
|
|
334
|
+
</div>
|
|
335
|
+
|
|
336
|
+
{/* Sparkline */}
|
|
337
|
+
{showSparkline && renderSparkline()}
|
|
338
|
+
</Card>
|
|
339
|
+
</motion.div>
|
|
340
|
+
)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
export default MetricCard
|
package/src/components/index.ts
CHANGED
|
@@ -24,8 +24,8 @@ export * from "./pinch-zoom"
|
|
|
24
24
|
// Spotlight Card
|
|
25
25
|
export * from "./spotlight-card"
|
|
26
26
|
|
|
27
|
-
// Calendar
|
|
28
|
-
export
|
|
27
|
+
// Calendar component (Advanced version with events)
|
|
28
|
+
export { Calendar as AdvancedCalendar } from "./calendar"
|
|
29
29
|
|
|
30
30
|
// Kanban
|
|
31
31
|
export * from "./kanban"
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ChevronLeft, ChevronRight } from "lucide-react"
|
|
5
|
+
import { DayPicker } from "react-day-picker"
|
|
6
|
+
import { cn } from "../../lib/utils"
|
|
7
|
+
import { buttonVariants } from "./button"
|
|
8
|
+
|
|
9
|
+
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
|
10
|
+
|
|
11
|
+
function Calendar({
|
|
12
|
+
className,
|
|
13
|
+
classNames,
|
|
14
|
+
showOutsideDays = true,
|
|
15
|
+
...props
|
|
16
|
+
}: CalendarProps) {
|
|
17
|
+
return (
|
|
18
|
+
<DayPicker
|
|
19
|
+
showOutsideDays={showOutsideDays}
|
|
20
|
+
className={cn("p-3", className)}
|
|
21
|
+
classNames={{
|
|
22
|
+
months: "flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0",
|
|
23
|
+
month: "space-y-4",
|
|
24
|
+
caption: "flex justify-center pt-1 relative items-center",
|
|
25
|
+
caption_label: "text-sm font-medium",
|
|
26
|
+
nav: "space-x-1 flex items-center",
|
|
27
|
+
nav_button: cn(
|
|
28
|
+
buttonVariants({ variant: "outline" }),
|
|
29
|
+
"h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100"
|
|
30
|
+
),
|
|
31
|
+
nav_button_previous: "absolute left-1",
|
|
32
|
+
nav_button_next: "absolute right-1",
|
|
33
|
+
table: "w-full border-collapse space-y-1",
|
|
34
|
+
head_row: "flex",
|
|
35
|
+
head_cell:
|
|
36
|
+
"text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]",
|
|
37
|
+
row: "flex w-full mt-2",
|
|
38
|
+
cell: "h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20",
|
|
39
|
+
day: cn(
|
|
40
|
+
buttonVariants({ variant: "ghost" }),
|
|
41
|
+
"h-9 w-9 p-0 font-normal aria-selected:opacity-100"
|
|
42
|
+
),
|
|
43
|
+
day_range_end: "day-range-end",
|
|
44
|
+
day_selected:
|
|
45
|
+
"bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
|
|
46
|
+
day_today: "bg-accent text-accent-foreground",
|
|
47
|
+
day_outside:
|
|
48
|
+
"day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30",
|
|
49
|
+
day_disabled: "text-muted-foreground opacity-50",
|
|
50
|
+
day_range_middle:
|
|
51
|
+
"aria-selected:bg-accent aria-selected:text-accent-foreground",
|
|
52
|
+
day_hidden: "invisible",
|
|
53
|
+
...classNames,
|
|
54
|
+
}}
|
|
55
|
+
components={{
|
|
56
|
+
// IconLeft: () => <ChevronLeft className="h-4 w-4" />,
|
|
57
|
+
// IconRight: () => <ChevronRight className="h-4 w-4" />,
|
|
58
|
+
}}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
Calendar.displayName = "Calendar"
|
|
64
|
+
|
|
65
|
+
export { Calendar }
|
|
@@ -34,6 +34,10 @@ export {
|
|
|
34
34
|
Button, buttonVariants
|
|
35
35
|
} from './button';
|
|
36
36
|
|
|
37
|
+
export {
|
|
38
|
+
Calendar
|
|
39
|
+
} from './calendar';
|
|
40
|
+
|
|
37
41
|
export {
|
|
38
42
|
MoonUICardPro, MoonUICardHeaderPro, MoonUICardFooterPro, MoonUICardTitlePro, MoonUICardDescriptionPro, MoonUICardContentPro,
|
|
39
43
|
Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent
|
|
@@ -99,6 +103,10 @@ export {
|
|
|
99
103
|
radioGroupItemVariants, RadioGroupContext, RadioGroup, RadioGroupItem, RadioLabel, RadioItemWithLabel
|
|
100
104
|
} from './radio-group';
|
|
101
105
|
|
|
106
|
+
export {
|
|
107
|
+
ScrollArea, ScrollBar
|
|
108
|
+
} from './scroll-area';
|
|
109
|
+
|
|
102
110
|
export {
|
|
103
111
|
MoonUISelectPro, MoonUISelectTriggerPro, MoonUISelectContentPro, MoonUISelectItemPro, MoonUISelectValuePro, MoonUISelectGroupPro, MoonUISelectLabelPro, MoonUISelectSeparatorPro,
|
|
104
112
|
Select, SelectTrigger, SelectContent, SelectItem, SelectValue, SelectGroup, SelectLabel, SelectSeparator
|
|
@@ -109,6 +117,10 @@ export {
|
|
|
109
117
|
Separator, separatorVariants
|
|
110
118
|
} from './separator';
|
|
111
119
|
|
|
120
|
+
export {
|
|
121
|
+
Sheet, SheetTrigger, SheetContent, SheetHeader, SheetFooter, SheetTitle, SheetDescription, SheetClose, SheetPortal, SheetOverlay
|
|
122
|
+
} from './sheet';
|
|
123
|
+
|
|
112
124
|
export {
|
|
113
125
|
MoonUISkeletonPro,
|
|
114
126
|
Skeleton
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area"
|
|
5
|
+
import { cn } from "../../lib/utils"
|
|
6
|
+
|
|
7
|
+
const ScrollArea = React.forwardRef<
|
|
8
|
+
React.ElementRef<typeof ScrollAreaPrimitive.Root>,
|
|
9
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.Root>
|
|
10
|
+
>(({ className, children, ...props }, ref) => (
|
|
11
|
+
<ScrollAreaPrimitive.Root
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={cn("relative overflow-hidden", className)}
|
|
14
|
+
{...props}
|
|
15
|
+
>
|
|
16
|
+
<ScrollAreaPrimitive.Viewport className="h-full w-full rounded-[inherit]">
|
|
17
|
+
{children}
|
|
18
|
+
</ScrollAreaPrimitive.Viewport>
|
|
19
|
+
<ScrollBar />
|
|
20
|
+
<ScrollAreaPrimitive.Corner />
|
|
21
|
+
</ScrollAreaPrimitive.Root>
|
|
22
|
+
))
|
|
23
|
+
ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName
|
|
24
|
+
|
|
25
|
+
const ScrollBar = React.forwardRef<
|
|
26
|
+
React.ElementRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>,
|
|
27
|
+
React.ComponentPropsWithoutRef<typeof ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
28
|
+
>(({ className, orientation = "vertical", ...props }, ref) => (
|
|
29
|
+
<ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
30
|
+
ref={ref}
|
|
31
|
+
orientation={orientation}
|
|
32
|
+
className={cn(
|
|
33
|
+
"flex touch-none select-none transition-colors",
|
|
34
|
+
orientation === "vertical" &&
|
|
35
|
+
"h-full w-2.5 border-l border-l-transparent p-[1px]",
|
|
36
|
+
orientation === "horizontal" &&
|
|
37
|
+
"h-2.5 flex-col border-t border-t-transparent p-[1px]",
|
|
38
|
+
className
|
|
39
|
+
)}
|
|
40
|
+
{...props}
|
|
41
|
+
>
|
|
42
|
+
<ScrollAreaPrimitive.ScrollAreaThumb className="relative flex-1 rounded-full bg-border" />
|
|
43
|
+
</ScrollAreaPrimitive.ScrollAreaScrollbar>
|
|
44
|
+
))
|
|
45
|
+
ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName
|
|
46
|
+
|
|
47
|
+
export { ScrollArea, ScrollBar }
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as SheetPrimitive from "@radix-ui/react-dialog"
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
6
|
+
import { X } from "lucide-react"
|
|
7
|
+
import { cn } from "../../lib/utils"
|
|
8
|
+
|
|
9
|
+
const Sheet = SheetPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const SheetTrigger = SheetPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const SheetClose = SheetPrimitive.Close
|
|
14
|
+
|
|
15
|
+
const SheetPortal = SheetPrimitive.Portal
|
|
16
|
+
|
|
17
|
+
const SheetOverlay = React.forwardRef<
|
|
18
|
+
React.ElementRef<typeof SheetPrimitive.Overlay>,
|
|
19
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Overlay>
|
|
20
|
+
>(({ className, ...props }, ref) => (
|
|
21
|
+
<SheetPrimitive.Overlay
|
|
22
|
+
className={cn(
|
|
23
|
+
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
24
|
+
className
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
ref={ref}
|
|
28
|
+
/>
|
|
29
|
+
))
|
|
30
|
+
SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
|
|
31
|
+
|
|
32
|
+
const sheetVariants = cva(
|
|
33
|
+
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500",
|
|
34
|
+
{
|
|
35
|
+
variants: {
|
|
36
|
+
side: {
|
|
37
|
+
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
|
|
38
|
+
bottom:
|
|
39
|
+
"inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
|
|
40
|
+
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
|
|
41
|
+
right:
|
|
42
|
+
"inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
defaultVariants: {
|
|
46
|
+
side: "right",
|
|
47
|
+
},
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
interface SheetContentProps
|
|
52
|
+
extends React.ComponentPropsWithoutRef<typeof SheetPrimitive.Content>,
|
|
53
|
+
VariantProps<typeof sheetVariants> {}
|
|
54
|
+
|
|
55
|
+
const SheetContent = React.forwardRef<
|
|
56
|
+
React.ElementRef<typeof SheetPrimitive.Content>,
|
|
57
|
+
SheetContentProps
|
|
58
|
+
>(({ side = "right", className, children, ...props }, ref) => (
|
|
59
|
+
<SheetPortal>
|
|
60
|
+
<SheetOverlay />
|
|
61
|
+
<SheetPrimitive.Content
|
|
62
|
+
ref={ref}
|
|
63
|
+
className={cn(sheetVariants({ side }), className)}
|
|
64
|
+
{...props}
|
|
65
|
+
>
|
|
66
|
+
{children}
|
|
67
|
+
<SheetPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-secondary">
|
|
68
|
+
<X className="h-4 w-4" />
|
|
69
|
+
<span className="sr-only">Close</span>
|
|
70
|
+
</SheetPrimitive.Close>
|
|
71
|
+
</SheetPrimitive.Content>
|
|
72
|
+
</SheetPortal>
|
|
73
|
+
))
|
|
74
|
+
SheetContent.displayName = SheetPrimitive.Content.displayName
|
|
75
|
+
|
|
76
|
+
const SheetHeader = ({
|
|
77
|
+
className,
|
|
78
|
+
...props
|
|
79
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
80
|
+
<div
|
|
81
|
+
className={cn(
|
|
82
|
+
"flex flex-col space-y-2 text-center sm:text-left",
|
|
83
|
+
className
|
|
84
|
+
)}
|
|
85
|
+
{...props}
|
|
86
|
+
/>
|
|
87
|
+
)
|
|
88
|
+
SheetHeader.displayName = "SheetHeader"
|
|
89
|
+
|
|
90
|
+
const SheetFooter = ({
|
|
91
|
+
className,
|
|
92
|
+
...props
|
|
93
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
94
|
+
<div
|
|
95
|
+
className={cn(
|
|
96
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
97
|
+
className
|
|
98
|
+
)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
SheetFooter.displayName = "SheetFooter"
|
|
103
|
+
|
|
104
|
+
const SheetTitle = React.forwardRef<
|
|
105
|
+
React.ElementRef<typeof SheetPrimitive.Title>,
|
|
106
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Title>
|
|
107
|
+
>(({ className, ...props }, ref) => (
|
|
108
|
+
<SheetPrimitive.Title
|
|
109
|
+
ref={ref}
|
|
110
|
+
className={cn("text-lg font-semibold text-foreground", className)}
|
|
111
|
+
{...props}
|
|
112
|
+
/>
|
|
113
|
+
))
|
|
114
|
+
SheetTitle.displayName = SheetPrimitive.Title.displayName
|
|
115
|
+
|
|
116
|
+
const SheetDescription = React.forwardRef<
|
|
117
|
+
React.ElementRef<typeof SheetPrimitive.Description>,
|
|
118
|
+
React.ComponentPropsWithoutRef<typeof SheetPrimitive.Description>
|
|
119
|
+
>(({ className, ...props }, ref) => (
|
|
120
|
+
<SheetPrimitive.Description
|
|
121
|
+
ref={ref}
|
|
122
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
123
|
+
{...props}
|
|
124
|
+
/>
|
|
125
|
+
))
|
|
126
|
+
SheetDescription.displayName = SheetPrimitive.Description.displayName
|
|
127
|
+
|
|
128
|
+
export {
|
|
129
|
+
Sheet,
|
|
130
|
+
SheetPortal,
|
|
131
|
+
SheetOverlay,
|
|
132
|
+
SheetTrigger,
|
|
133
|
+
SheetClose,
|
|
134
|
+
SheetContent,
|
|
135
|
+
SheetHeader,
|
|
136
|
+
SheetFooter,
|
|
137
|
+
SheetTitle,
|
|
138
|
+
SheetDescription,
|
|
139
|
+
}
|