@moontra/moonui 2.0.8 → 2.0.9
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/package.json +9 -2
- package/src/__tests__/use-intersection-observer.test.tsx +216 -0
- package/src/__tests__/use-local-storage.test.tsx +174 -0
- package/src/__tests__/use-pro-access.test.tsx +183 -0
- package/src/components/ui/__tests__/accordion.test.tsx +571 -0
- package/src/components/ui/__tests__/alert.test.tsx +484 -0
- package/src/components/ui/__tests__/aspect-ratio.test.tsx +492 -0
- package/src/components/ui/__tests__/avatar.test.tsx +382 -0
- package/src/components/ui/__tests__/badge.test.tsx +364 -0
- package/src/components/ui/__tests__/breadcrumb.test.tsx +687 -0
- package/src/components/ui/__tests__/button.test.tsx +91 -0
- package/src/components/ui/__tests__/card.test.tsx +104 -0
- package/src/components/ui/__tests__/checkbox.test.tsx +591 -0
- package/src/components/ui/__tests__/collapsible.test.tsx +592 -0
- package/src/components/ui/__tests__/color-picker.test.tsx +365 -0
- package/src/components/ui/__tests__/command.test.tsx +677 -0
- package/src/components/ui/__tests__/data-table.test.tsx +256 -0
- package/src/components/ui/__tests__/date-picker.test.tsx +320 -0
- package/src/components/ui/__tests__/dialog.test.tsx +764 -0
- package/src/components/ui/__tests__/input.test.tsx +318 -0
- package/src/components/ui/__tests__/label.test.tsx +103 -0
- package/src/components/ui/__tests__/popover.test.tsx +637 -0
- package/src/components/ui/__tests__/progress.test.tsx +382 -0
- package/src/components/ui/__tests__/radio-group.test.tsx +555 -0
- package/src/components/ui/__tests__/select.test.tsx +705 -0
- package/src/components/ui/__tests__/skeleton.test.tsx +253 -0
- package/src/components/ui/__tests__/slider.test.tsx +493 -0
- package/src/components/ui/__tests__/switch.test.tsx +372 -0
- package/src/components/ui/__tests__/table.test.tsx +824 -0
- package/src/components/ui/__tests__/tabs.test.tsx +887 -0
- package/src/components/ui/__tests__/toast.test.tsx +458 -0
- package/src/components/ui/__tests__/tooltip.test.tsx +583 -0
- package/src/components/ui/accordion.tsx +63 -0
- package/src/components/ui/alert.tsx +130 -0
- package/src/components/ui/aspect-ratio.tsx +72 -0
- package/src/components/ui/avatar.tsx +135 -0
- package/src/components/ui/badge.tsx +225 -0
- package/src/components/ui/breadcrumb.tsx +207 -0
- package/src/components/ui/button.stories.tsx +162 -0
- package/src/components/ui/button.tsx +221 -0
- package/src/components/ui/calendar.tsx +262 -0
- package/src/components/ui/card.stories.tsx +208 -0
- package/src/components/ui/card.tsx +141 -0
- package/src/components/ui/checkbox.tsx +256 -0
- package/src/components/ui/collapsible.tsx +129 -0
- package/src/components/ui/color-picker.tsx +664 -0
- package/src/components/ui/command.tsx +218 -0
- package/src/components/ui/data-table.stories.tsx +509 -0
- package/src/components/ui/data-table.tsx +623 -0
- package/src/components/ui/date-picker.stories.tsx +321 -0
- package/src/components/ui/date-picker.tsx +603 -0
- package/src/components/ui/dialog.tsx +332 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/file-upload.tsx +400 -0
- package/src/components/ui/github-stars.tsx +201 -0
- package/src/components/ui/index.ts +12 -0
- package/src/components/ui/input.stories.tsx +255 -0
- package/src/components/ui/input.tsx +219 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/locked-component.tsx +215 -0
- package/src/components/ui/moon-logo.tsx +97 -0
- package/src/components/ui/pagination.tsx +116 -0
- package/src/components/ui/popover.tsx +183 -0
- package/src/components/ui/progress.tsx +182 -0
- package/src/components/ui/radio-group.tsx +243 -0
- package/src/components/ui/select.tsx +273 -0
- package/src/components/ui/separator.tsx +140 -0
- package/src/components/ui/simple-editor.tsx +652 -0
- package/src/components/ui/skeleton.tsx +351 -0
- package/src/components/ui/slider.tsx +351 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/table.tsx +322 -0
- package/src/components/ui/tabs.tsx +195 -0
- package/src/components/ui/textarea.tsx +46 -0
- package/src/components/ui/toast.tsx +313 -0
- package/src/components/ui/toggle.tsx +47 -0
- package/src/components/ui/tooltip.tsx +152 -0
- package/src/docs/theme-system.md +1194 -0
- package/src/index.tsx +39 -0
- package/src/lib/micro-interactions.ts +255 -0
- package/src/lib/theme.tsx +398 -0
- package/src/lib/utils.ts +69 -0
- package/src/styles/design-system.css +365 -0
- package/src/styles/index.css +4 -0
- package/src/styles/tailwind.css +6 -0
- package/src/styles/tokens.css +453 -0
- package/src/use-intersection-observer.tsx +154 -0
- package/src/use-local-storage.tsx +71 -0
- package/src/use-paddle.ts +138 -0
- package/src/use-performance-optimizer.ts +379 -0
- package/src/use-pro-access.ts +141 -0
- package/src/use-scroll-animation.ts +221 -0
- package/src/use-subscription.ts +37 -0
- package/src/use-toast.ts +32 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
// Locked Component UI
|
|
2
|
+
// Pro componentlerin locked state'ini gösteren wrapper component
|
|
3
|
+
|
|
4
|
+
import React, { useState } from 'react'
|
|
5
|
+
import { cn } from '../../lib/utils'
|
|
6
|
+
import { Button } from './button'
|
|
7
|
+
import { Badge } from './badge'
|
|
8
|
+
import { Lock, Crown, Zap } from 'lucide-react'
|
|
9
|
+
import Link from 'next/link'
|
|
10
|
+
import { useComponentAccess } from '../../use-pro-access'
|
|
11
|
+
|
|
12
|
+
interface LockedComponentProps {
|
|
13
|
+
children: React.ReactNode
|
|
14
|
+
componentName: string
|
|
15
|
+
className?: string
|
|
16
|
+
showPreview?: boolean
|
|
17
|
+
previewDuration?: number // ms
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function LockedComponent({
|
|
21
|
+
children,
|
|
22
|
+
componentName,
|
|
23
|
+
className,
|
|
24
|
+
showPreview = true,
|
|
25
|
+
previewDuration = 2000
|
|
26
|
+
}: LockedComponentProps) {
|
|
27
|
+
const [isPreviewActive, setIsPreviewActive] = useState(false)
|
|
28
|
+
const [previewTimeout, setPreviewTimeout] = useState<NodeJS.Timeout | null>(null)
|
|
29
|
+
|
|
30
|
+
const handleMouseEnter = () => {
|
|
31
|
+
if (!showPreview) return
|
|
32
|
+
|
|
33
|
+
setIsPreviewActive(true)
|
|
34
|
+
|
|
35
|
+
// Clear existing timeout
|
|
36
|
+
if (previewTimeout) {
|
|
37
|
+
clearTimeout(previewTimeout)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Set new timeout
|
|
41
|
+
const timeout = setTimeout(() => {
|
|
42
|
+
setIsPreviewActive(false)
|
|
43
|
+
}, previewDuration)
|
|
44
|
+
|
|
45
|
+
setPreviewTimeout(timeout)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const handleMouseLeave = () => {
|
|
49
|
+
if (previewTimeout) {
|
|
50
|
+
clearTimeout(previewTimeout)
|
|
51
|
+
setPreviewTimeout(null)
|
|
52
|
+
}
|
|
53
|
+
setIsPreviewActive(false)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
className={cn(
|
|
59
|
+
"relative group cursor-pointer transition-all duration-300",
|
|
60
|
+
className
|
|
61
|
+
)}
|
|
62
|
+
onMouseEnter={handleMouseEnter}
|
|
63
|
+
onMouseLeave={handleMouseLeave}
|
|
64
|
+
>
|
|
65
|
+
{/* Component Content */}
|
|
66
|
+
<div
|
|
67
|
+
className={cn(
|
|
68
|
+
"transition-all duration-300",
|
|
69
|
+
!isPreviewActive && "blur-sm grayscale-[0.3] opacity-60"
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{children}
|
|
73
|
+
</div>
|
|
74
|
+
|
|
75
|
+
{/* Overlay */}
|
|
76
|
+
<div
|
|
77
|
+
className={cn(
|
|
78
|
+
"absolute inset-0 bg-gradient-to-br from-amber-500/10 via-transparent to-purple-500/10",
|
|
79
|
+
"border-2 border-dashed border-amber-400/30 rounded-lg",
|
|
80
|
+
"flex items-center justify-center",
|
|
81
|
+
"transition-all duration-300",
|
|
82
|
+
isPreviewActive ? "opacity-0" : "opacity-100"
|
|
83
|
+
)}
|
|
84
|
+
>
|
|
85
|
+
<div className="text-center space-y-3 p-6">
|
|
86
|
+
{/* Pro Badge */}
|
|
87
|
+
<div className="flex justify-center">
|
|
88
|
+
<Badge
|
|
89
|
+
variant="secondary"
|
|
90
|
+
className="bg-gradient-to-r from-amber-500 to-orange-500 text-white border-0 px-3 py-1"
|
|
91
|
+
>
|
|
92
|
+
<Crown className="w-3 h-3 mr-1" />
|
|
93
|
+
PRO ONLY
|
|
94
|
+
</Badge>
|
|
95
|
+
</div>
|
|
96
|
+
|
|
97
|
+
{/* Lock Icon */}
|
|
98
|
+
<div className="flex justify-center">
|
|
99
|
+
<div className="p-3 rounded-full bg-amber-100 dark:bg-amber-900/30">
|
|
100
|
+
<Lock className="w-6 h-6 text-amber-600 dark:text-amber-400" />
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
{/* Component Name */}
|
|
105
|
+
<h3 className="font-semibold text-gray-900 dark:text-gray-100">
|
|
106
|
+
{componentName}
|
|
107
|
+
</h3>
|
|
108
|
+
|
|
109
|
+
{/* Description */}
|
|
110
|
+
<p className="text-sm text-gray-600 dark:text-gray-400 max-w-xs">
|
|
111
|
+
This premium component is available with Pro subscription
|
|
112
|
+
</p>
|
|
113
|
+
|
|
114
|
+
{/* Upgrade Button */}
|
|
115
|
+
<Link href="/pricing">
|
|
116
|
+
<Button
|
|
117
|
+
size="sm"
|
|
118
|
+
className="bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-600 hover:to-orange-600 border-0"
|
|
119
|
+
>
|
|
120
|
+
<Zap className="w-4 h-4 mr-2" />
|
|
121
|
+
Upgrade to Pro
|
|
122
|
+
</Button>
|
|
123
|
+
</Link>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
{/* Preview Hint */}
|
|
128
|
+
{showPreview && !isPreviewActive && (
|
|
129
|
+
<div className="absolute top-2 right-2 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
|
|
130
|
+
<div className="bg-black/80 text-white text-xs px-2 py-1 rounded">
|
|
131
|
+
Hover to preview
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
)}
|
|
135
|
+
</div>
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Pro Component Wrapper - Otomatik erişim kontrolü ile
|
|
140
|
+
interface ProComponentWrapperProps {
|
|
141
|
+
children: React.ReactNode
|
|
142
|
+
componentId: string
|
|
143
|
+
componentName?: string
|
|
144
|
+
className?: string
|
|
145
|
+
fallback?: React.ReactNode
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function ProComponentWrapper({
|
|
149
|
+
children,
|
|
150
|
+
componentId,
|
|
151
|
+
componentName,
|
|
152
|
+
className,
|
|
153
|
+
fallback
|
|
154
|
+
}: ProComponentWrapperProps) {
|
|
155
|
+
const { canUse, isLocked, isLoading } = useComponentAccess(componentId)
|
|
156
|
+
|
|
157
|
+
// Loading state
|
|
158
|
+
if (isLoading) {
|
|
159
|
+
return (
|
|
160
|
+
<div className={cn("animate-pulse bg-gray-200 dark:bg-gray-800 rounded-lg h-32", className)}>
|
|
161
|
+
<div className="flex items-center justify-center h-full">
|
|
162
|
+
<div className="text-sm text-gray-500">Loading...</div>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
)
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// Unlocked - show actual component
|
|
169
|
+
if (canUse) {
|
|
170
|
+
return <div className={className}>{children}</div>
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Locked - show locked state
|
|
174
|
+
if (isLocked) {
|
|
175
|
+
return (
|
|
176
|
+
<LockedComponent
|
|
177
|
+
componentName={componentName || componentId}
|
|
178
|
+
className={className}
|
|
179
|
+
>
|
|
180
|
+
{fallback || children}
|
|
181
|
+
</LockedComponent>
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Default fallback
|
|
186
|
+
return <div className={className}>{children}</div>
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Pro Badge Component
|
|
190
|
+
export function ProBadge({ className }: { className?: string }) {
|
|
191
|
+
return (
|
|
192
|
+
<Badge
|
|
193
|
+
variant="secondary"
|
|
194
|
+
className={cn(
|
|
195
|
+
"bg-gradient-to-r from-amber-500 to-orange-500 text-white border-0 text-xs",
|
|
196
|
+
className
|
|
197
|
+
)}
|
|
198
|
+
>
|
|
199
|
+
<Crown className="w-3 h-3 mr-1" />
|
|
200
|
+
PRO
|
|
201
|
+
</Badge>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Free Badge Component
|
|
206
|
+
export function FreeBadge({ className }: { className?: string }) {
|
|
207
|
+
return (
|
|
208
|
+
<Badge
|
|
209
|
+
variant="outline"
|
|
210
|
+
className={cn("border-green-500 text-green-600 dark:text-green-400 text-xs", className)}
|
|
211
|
+
>
|
|
212
|
+
FREE
|
|
213
|
+
</Badge>
|
|
214
|
+
)
|
|
215
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../lib/utils"
|
|
5
|
+
|
|
6
|
+
interface MoonLogoProps extends React.SVGProps<SVGSVGElement> {
|
|
7
|
+
variant?: "default" | "monochrome" | "gradient"
|
|
8
|
+
showText?: boolean
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function MoonLogo({
|
|
12
|
+
className,
|
|
13
|
+
variant = "default",
|
|
14
|
+
showText = true,
|
|
15
|
+
...props
|
|
16
|
+
}: MoonLogoProps) {
|
|
17
|
+
const logoId = React.useId()
|
|
18
|
+
const gradientId = `moon-gradient-${logoId}`
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<div className={cn("flex items-center gap-2", className)}>
|
|
22
|
+
{/* Moon Icon */}
|
|
23
|
+
<svg
|
|
24
|
+
width="32"
|
|
25
|
+
height="32"
|
|
26
|
+
viewBox="0 0 32 32"
|
|
27
|
+
fill="none"
|
|
28
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
29
|
+
className="flex-shrink-0"
|
|
30
|
+
{...props}
|
|
31
|
+
>
|
|
32
|
+
{variant === "gradient" && (
|
|
33
|
+
<defs>
|
|
34
|
+
<linearGradient id={gradientId} x1="0%" y1="0%" x2="100%" y2="100%">
|
|
35
|
+
<stop offset="0%" stopColor="#3B82F6" />
|
|
36
|
+
<stop offset="50%" stopColor="#8B5CF6" />
|
|
37
|
+
<stop offset="100%" stopColor="#EC4899" />
|
|
38
|
+
</linearGradient>
|
|
39
|
+
</defs>
|
|
40
|
+
)}
|
|
41
|
+
|
|
42
|
+
{/* Moon Circle */}
|
|
43
|
+
<circle
|
|
44
|
+
cx="16"
|
|
45
|
+
cy="16"
|
|
46
|
+
r="14"
|
|
47
|
+
fill={variant === "gradient" ? `url(#${gradientId})` : "currentColor"}
|
|
48
|
+
className={variant === "default" ? "fill-primary" : ""}
|
|
49
|
+
/>
|
|
50
|
+
|
|
51
|
+
{/* Crescent cutout */}
|
|
52
|
+
<circle
|
|
53
|
+
cx="22"
|
|
54
|
+
cy="10"
|
|
55
|
+
r="10"
|
|
56
|
+
fill="white"
|
|
57
|
+
className="dark:fill-background"
|
|
58
|
+
/>
|
|
59
|
+
</svg>
|
|
60
|
+
|
|
61
|
+
{/* Text */}
|
|
62
|
+
{showText && (
|
|
63
|
+
<span className="text-xl font-bold">
|
|
64
|
+
<span className="text-foreground">Moon</span>
|
|
65
|
+
<span className="text-primary">UI</span>
|
|
66
|
+
</span>
|
|
67
|
+
)}
|
|
68
|
+
</div>
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function MoonLogoIcon({
|
|
73
|
+
className,
|
|
74
|
+
variant = "default",
|
|
75
|
+
...props
|
|
76
|
+
}: Omit<MoonLogoProps, "showText">) {
|
|
77
|
+
return <MoonLogo showText={false} className={className} variant={variant} {...props} />
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function MoonLogoAnimated({
|
|
81
|
+
className,
|
|
82
|
+
variant = "default",
|
|
83
|
+
showText = true,
|
|
84
|
+
...props
|
|
85
|
+
}: MoonLogoProps) {
|
|
86
|
+
return (
|
|
87
|
+
<MoonLogo
|
|
88
|
+
className={cn(
|
|
89
|
+
"transition-all duration-300 hover:scale-105",
|
|
90
|
+
className
|
|
91
|
+
)}
|
|
92
|
+
variant={variant}
|
|
93
|
+
showText={showText}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
)
|
|
97
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { ChevronLeft, ChevronRight, MoreHorizontal } from "lucide-react"
|
|
3
|
+
import { cn } from "../../lib/utils"
|
|
4
|
+
import { ButtonProps, buttonVariants } from "./button"
|
|
5
|
+
|
|
6
|
+
const Pagination = ({ className, ...props }: React.ComponentProps<"nav">) => (
|
|
7
|
+
<nav
|
|
8
|
+
role="navigation"
|
|
9
|
+
aria-label="pagination"
|
|
10
|
+
className={cn("mx-auto flex w-full justify-center", className)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
)
|
|
14
|
+
Pagination.displayName = "Pagination"
|
|
15
|
+
|
|
16
|
+
const PaginationContent = React.forwardRef<
|
|
17
|
+
HTMLUListElement,
|
|
18
|
+
React.ComponentProps<"ul">
|
|
19
|
+
>(({ className, ...props }, ref) => (
|
|
20
|
+
<ul
|
|
21
|
+
ref={ref}
|
|
22
|
+
className={cn("flex flex-row items-center gap-1", className)}
|
|
23
|
+
{...props}
|
|
24
|
+
/>
|
|
25
|
+
))
|
|
26
|
+
PaginationContent.displayName = "PaginationContent"
|
|
27
|
+
|
|
28
|
+
const PaginationItem = React.forwardRef<
|
|
29
|
+
HTMLLIElement,
|
|
30
|
+
React.ComponentProps<"li">
|
|
31
|
+
>(({ className, ...props }, ref) => (
|
|
32
|
+
<li ref={ref} className={cn("", className)} {...props} />
|
|
33
|
+
))
|
|
34
|
+
PaginationItem.displayName = "PaginationItem"
|
|
35
|
+
|
|
36
|
+
type PaginationLinkProps = {
|
|
37
|
+
isActive?: boolean
|
|
38
|
+
} & Pick<ButtonProps, "size"> &
|
|
39
|
+
React.ComponentProps<"a">
|
|
40
|
+
|
|
41
|
+
const PaginationLink = ({
|
|
42
|
+
className,
|
|
43
|
+
isActive,
|
|
44
|
+
size = "icon",
|
|
45
|
+
...props
|
|
46
|
+
}: PaginationLinkProps) => (
|
|
47
|
+
<a
|
|
48
|
+
aria-current={isActive ? "page" : undefined}
|
|
49
|
+
className={cn(
|
|
50
|
+
buttonVariants({
|
|
51
|
+
variant: isActive ? "outline" : "ghost",
|
|
52
|
+
size,
|
|
53
|
+
}),
|
|
54
|
+
className
|
|
55
|
+
)}
|
|
56
|
+
{...props}
|
|
57
|
+
/>
|
|
58
|
+
)
|
|
59
|
+
PaginationLink.displayName = "PaginationLink"
|
|
60
|
+
|
|
61
|
+
const PaginationPrevious = ({
|
|
62
|
+
className,
|
|
63
|
+
...props
|
|
64
|
+
}: React.ComponentProps<typeof PaginationLink>) => (
|
|
65
|
+
<PaginationLink
|
|
66
|
+
aria-label="Go to previous page"
|
|
67
|
+
size="default"
|
|
68
|
+
className={cn("gap-1 pl-2.5", className)}
|
|
69
|
+
{...props}
|
|
70
|
+
>
|
|
71
|
+
<ChevronLeft className="h-4 w-4" />
|
|
72
|
+
<span>Previous</span>
|
|
73
|
+
</PaginationLink>
|
|
74
|
+
)
|
|
75
|
+
PaginationPrevious.displayName = "PaginationPrevious"
|
|
76
|
+
|
|
77
|
+
const PaginationNext = ({
|
|
78
|
+
className,
|
|
79
|
+
...props
|
|
80
|
+
}: React.ComponentProps<typeof PaginationLink>) => (
|
|
81
|
+
<PaginationLink
|
|
82
|
+
aria-label="Go to next page"
|
|
83
|
+
size="default"
|
|
84
|
+
className={cn("gap-1 pr-2.5", className)}
|
|
85
|
+
{...props}
|
|
86
|
+
>
|
|
87
|
+
<span>Next</span>
|
|
88
|
+
<ChevronRight className="h-4 w-4" />
|
|
89
|
+
</PaginationLink>
|
|
90
|
+
)
|
|
91
|
+
PaginationNext.displayName = "PaginationNext"
|
|
92
|
+
|
|
93
|
+
const PaginationEllipsis = ({
|
|
94
|
+
className,
|
|
95
|
+
...props
|
|
96
|
+
}: React.ComponentProps<"span">) => (
|
|
97
|
+
<span
|
|
98
|
+
aria-hidden
|
|
99
|
+
className={cn("flex h-9 w-9 items-center justify-center", className)}
|
|
100
|
+
{...props}
|
|
101
|
+
>
|
|
102
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
103
|
+
<span className="sr-only">More pages</span>
|
|
104
|
+
</span>
|
|
105
|
+
)
|
|
106
|
+
PaginationEllipsis.displayName = "PaginationEllipsis"
|
|
107
|
+
|
|
108
|
+
export {
|
|
109
|
+
Pagination,
|
|
110
|
+
PaginationContent,
|
|
111
|
+
PaginationEllipsis,
|
|
112
|
+
PaginationItem,
|
|
113
|
+
PaginationLink,
|
|
114
|
+
PaginationNext,
|
|
115
|
+
PaginationPrevious,
|
|
116
|
+
}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import * as PopoverPrimitive from "@radix-ui/react-popover";
|
|
5
|
+
import { cva, type VariantProps } from "class-variance-authority";
|
|
6
|
+
|
|
7
|
+
import { cn } from "../../lib/utils";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Popover Bileşeni
|
|
11
|
+
*
|
|
12
|
+
* Tıklanabilir bir öğeden açılan, tema sistemiyle tam entegre bir içerik bileşeni.
|
|
13
|
+
* Filtreler, ayarlar ve diğer içerikler için kullanışlı ve erişilebilir bir arayüz sağlar.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const popoverContentVariants = cva(
|
|
17
|
+
"z-50 w-72 rounded-md border border-border bg-background p-4 shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
18
|
+
{
|
|
19
|
+
variants: {
|
|
20
|
+
variant: {
|
|
21
|
+
default: "",
|
|
22
|
+
destructive: "border-destructive bg-destructive/5",
|
|
23
|
+
outline: "border-border bg-transparent",
|
|
24
|
+
subtle: "border-transparent bg-muted/50",
|
|
25
|
+
},
|
|
26
|
+
size: {
|
|
27
|
+
sm: "w-48 p-3",
|
|
28
|
+
default: "w-72 p-4",
|
|
29
|
+
lg: "w-96 p-5",
|
|
30
|
+
},
|
|
31
|
+
side: {
|
|
32
|
+
top: "data-[side=top]:slide-in-from-bottom-2",
|
|
33
|
+
right: "data-[side=right]:slide-in-from-left-2",
|
|
34
|
+
bottom: "data-[side=bottom]:slide-in-from-top-2",
|
|
35
|
+
left: "data-[side=left]:slide-in-from-right-2",
|
|
36
|
+
},
|
|
37
|
+
position: {
|
|
38
|
+
pointerEventsNone: "pointer-events-none",
|
|
39
|
+
default: "",
|
|
40
|
+
},
|
|
41
|
+
radius: {
|
|
42
|
+
none: "rounded-none",
|
|
43
|
+
sm: "rounded-sm",
|
|
44
|
+
default: "rounded-md",
|
|
45
|
+
lg: "rounded-lg",
|
|
46
|
+
full: "rounded-full",
|
|
47
|
+
},
|
|
48
|
+
shadow: {
|
|
49
|
+
none: "shadow-none",
|
|
50
|
+
sm: "shadow-sm",
|
|
51
|
+
default: "shadow-md",
|
|
52
|
+
md: "shadow-md",
|
|
53
|
+
lg: "shadow-lg",
|
|
54
|
+
xl: "shadow-xl",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
defaultVariants: {
|
|
58
|
+
variant: "default",
|
|
59
|
+
size: "default",
|
|
60
|
+
radius: "default",
|
|
61
|
+
shadow: "default",
|
|
62
|
+
},
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
const Popover = PopoverPrimitive.Root;
|
|
67
|
+
const PopoverTrigger = PopoverPrimitive.Trigger;
|
|
68
|
+
const PopoverAnchor = PopoverPrimitive.Anchor;
|
|
69
|
+
|
|
70
|
+
export interface PopoverContentProps
|
|
71
|
+
extends Omit<React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>, 'side'>,
|
|
72
|
+
VariantProps<typeof popoverContentVariants> {
|
|
73
|
+
/**
|
|
74
|
+
* Popover'ın arka plan bulanıklığı etkin mi
|
|
75
|
+
*/
|
|
76
|
+
backdrop?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Popover'a tıklandığında kapanıp kapanmayacağı
|
|
79
|
+
*/
|
|
80
|
+
closeOnInteractOutside?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Popover açıkken arka planın karartılması
|
|
83
|
+
*/
|
|
84
|
+
overlayBackdrop?: boolean;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const PopoverContent = React.forwardRef<
|
|
88
|
+
React.ElementRef<typeof PopoverPrimitive.Content>,
|
|
89
|
+
PopoverContentProps
|
|
90
|
+
>(({
|
|
91
|
+
className,
|
|
92
|
+
variant,
|
|
93
|
+
size,
|
|
94
|
+
side,
|
|
95
|
+
position,
|
|
96
|
+
radius,
|
|
97
|
+
shadow,
|
|
98
|
+
backdrop = false,
|
|
99
|
+
closeOnInteractOutside = true,
|
|
100
|
+
overlayBackdrop = false,
|
|
101
|
+
sideOffset = 4,
|
|
102
|
+
...props
|
|
103
|
+
}, ref) => (
|
|
104
|
+
<>
|
|
105
|
+
{overlayBackdrop && (
|
|
106
|
+
<div className="fixed inset-0 z-40 bg-overlay opacity-30" />
|
|
107
|
+
)}
|
|
108
|
+
<PopoverPrimitive.Content
|
|
109
|
+
ref={ref}
|
|
110
|
+
sideOffset={sideOffset}
|
|
111
|
+
collisionPadding={8}
|
|
112
|
+
onInteractOutside={(e) => {
|
|
113
|
+
if (!closeOnInteractOutside) {
|
|
114
|
+
e.preventDefault();
|
|
115
|
+
}
|
|
116
|
+
}}
|
|
117
|
+
className={cn(
|
|
118
|
+
popoverContentVariants({
|
|
119
|
+
variant,
|
|
120
|
+
size,
|
|
121
|
+
side,
|
|
122
|
+
position,
|
|
123
|
+
radius,
|
|
124
|
+
shadow
|
|
125
|
+
}),
|
|
126
|
+
backdrop && "backdrop-blur-md bg-opacity-80",
|
|
127
|
+
className
|
|
128
|
+
)}
|
|
129
|
+
{...props}
|
|
130
|
+
/>
|
|
131
|
+
</>
|
|
132
|
+
));
|
|
133
|
+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* PopoverClose bileşeni
|
|
137
|
+
*/
|
|
138
|
+
const PopoverClose = PopoverPrimitive.Close;
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Popover için bölüm ayırıcı
|
|
142
|
+
*/
|
|
143
|
+
const PopoverSeparator = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
144
|
+
<div
|
|
145
|
+
className={cn("my-2 h-px bg-border", className)}
|
|
146
|
+
{...props}
|
|
147
|
+
/>
|
|
148
|
+
);
|
|
149
|
+
PopoverSeparator.displayName = "PopoverSeparator";
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Popover başlık bileşeni
|
|
153
|
+
*/
|
|
154
|
+
const PopoverHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
155
|
+
<div
|
|
156
|
+
className={cn("-mx-4 -mt-4 mb-3 px-4 pt-4 pb-3 border-b border-border", className)}
|
|
157
|
+
{...props}
|
|
158
|
+
/>
|
|
159
|
+
);
|
|
160
|
+
PopoverHeader.displayName = "PopoverHeader";
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Popover footer bileşeni
|
|
164
|
+
*/
|
|
165
|
+
const PopoverFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
|
166
|
+
<div
|
|
167
|
+
className={cn("-mx-4 -mb-4 mt-3 px-4 pt-3 pb-4 border-t border-border", className)}
|
|
168
|
+
{...props}
|
|
169
|
+
/>
|
|
170
|
+
);
|
|
171
|
+
PopoverFooter.displayName = "PopoverFooter";
|
|
172
|
+
|
|
173
|
+
export {
|
|
174
|
+
Popover,
|
|
175
|
+
PopoverTrigger,
|
|
176
|
+
PopoverContent,
|
|
177
|
+
PopoverAnchor,
|
|
178
|
+
PopoverClose,
|
|
179
|
+
PopoverSeparator,
|
|
180
|
+
PopoverHeader,
|
|
181
|
+
PopoverFooter,
|
|
182
|
+
popoverContentVariants,
|
|
183
|
+
};
|