@moontra/moonui-pro 2.0.22 → 2.1.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.mjs +215 -214
- package/package.json +4 -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/advanced-chart/advanced-chart.test.tsx +281 -0
- package/src/components/advanced-chart/index.tsx +412 -0
- package/src/components/advanced-forms/index.tsx +431 -0
- package/src/components/animated-button/index.tsx +202 -0
- package/src/components/calendar/event-dialog.tsx +372 -0
- package/src/components/calendar/index.tsx +557 -0
- package/src/components/color-picker/index.tsx +434 -0
- package/src/components/dashboard/index.tsx +334 -0
- package/src/components/data-table/data-table.test.tsx +187 -0
- package/src/components/data-table/index.tsx +368 -0
- package/src/components/draggable-list/index.tsx +100 -0
- package/src/components/enhanced/button.tsx +360 -0
- package/src/components/enhanced/card.tsx +272 -0
- package/src/components/enhanced/dialog.tsx +248 -0
- package/src/components/enhanced/index.ts +3 -0
- package/src/components/error-boundary/index.tsx +111 -0
- package/src/components/file-upload/file-upload.test.tsx +242 -0
- package/src/components/file-upload/index.tsx +362 -0
- package/src/components/floating-action-button/index.tsx +209 -0
- package/src/components/github-stars/index.tsx +414 -0
- package/src/components/health-check/index.tsx +441 -0
- package/src/components/hover-card-3d/index.tsx +170 -0
- package/src/components/index.ts +76 -0
- package/src/components/kanban/index.tsx +436 -0
- package/src/components/lazy-component/index.tsx +342 -0
- package/src/components/magnetic-button/index.tsx +170 -0
- package/src/components/memory-efficient-data/index.tsx +352 -0
- package/src/components/optimized-image/index.tsx +427 -0
- package/src/components/performance-debugger/index.tsx +591 -0
- package/src/components/performance-monitor/index.tsx +775 -0
- package/src/components/pinch-zoom/index.tsx +172 -0
- package/src/components/rich-text-editor/index-old-backup.tsx +443 -0
- package/src/components/rich-text-editor/index.tsx +1537 -0
- package/src/components/rich-text-editor/slash-commands-extension.ts +220 -0
- package/src/components/rich-text-editor/slash-commands.css +35 -0
- package/src/components/rich-text-editor/table-styles.css +65 -0
- package/src/components/spotlight-card/index.tsx +194 -0
- package/src/components/swipeable-card/index.tsx +100 -0
- package/src/components/timeline/index.tsx +333 -0
- package/src/components/ui/animated-button.tsx +185 -0
- package/src/components/ui/avatar.tsx +135 -0
- package/src/components/ui/badge.tsx +225 -0
- package/src/components/ui/button.tsx +221 -0
- package/src/components/ui/card.tsx +141 -0
- package/src/components/ui/checkbox.tsx +256 -0
- package/src/components/ui/color-picker.tsx +95 -0
- package/src/components/ui/dialog.tsx +332 -0
- package/src/components/ui/dropdown-menu.tsx +200 -0
- package/src/components/ui/hover-card-3d.tsx +103 -0
- package/src/components/ui/index.ts +33 -0
- package/src/components/ui/input.tsx +219 -0
- package/src/components/ui/label.tsx +26 -0
- package/src/components/ui/magnetic-button.tsx +129 -0
- package/src/components/ui/popover.tsx +183 -0
- package/src/components/ui/select.tsx +273 -0
- package/src/components/ui/separator.tsx +140 -0
- package/src/components/ui/slider.tsx +351 -0
- package/src/components/ui/spotlight-card.tsx +119 -0
- package/src/components/ui/switch.tsx +83 -0
- package/src/components/ui/tabs.tsx +195 -0
- package/src/components/ui/textarea.tsx +25 -0
- package/src/components/ui/toast.tsx +313 -0
- package/src/components/ui/tooltip.tsx +152 -0
- package/src/components/virtual-list/index.tsx +369 -0
- package/src/hooks/use-chart.ts +205 -0
- package/src/hooks/use-data-table.ts +182 -0
- package/src/hooks/use-docs-pro-access.ts +13 -0
- package/src/hooks/use-license-check.ts +65 -0
- package/src/hooks/use-subscription.ts +19 -0
- package/src/index.ts +14 -0
- package/src/lib/micro-interactions.ts +255 -0
- package/src/lib/utils.ts +6 -0
- package/src/patterns/login-form/index.tsx +276 -0
- package/src/patterns/login-form/types.ts +67 -0
- package/src/setupTests.ts +41 -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/types/moonui.d.ts +22 -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
- package/src/utils/chart-helpers.ts +257 -0
- package/src/utils/cn.ts +69 -0
- package/src/utils/data-processing.ts +151 -0
- package/src/utils/license-guard.tsx +177 -0
- package/src/utils/license-validator.tsx +183 -0
- package/src/utils/package-guard.ts +60 -0
|
@@ -0,0 +1,414 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import React, { useState, useEffect } from "react"
|
|
4
|
+
import { motion, AnimatePresence } from "framer-motion"
|
|
5
|
+
import { Card, CardContent } from "../ui/card"
|
|
6
|
+
import { Button } from "../ui/button"
|
|
7
|
+
import { Badge } from "../ui/badge"
|
|
8
|
+
import { Skeleton } from "@moontra/moonui"
|
|
9
|
+
import { cn } from "../../lib/utils"
|
|
10
|
+
import { Star, GitFork, Eye, Users, ExternalLink, Github, Lock, Sparkles, RefreshCw } from "lucide-react"
|
|
11
|
+
import { useSubscription } from "../../hooks/use-subscription"
|
|
12
|
+
|
|
13
|
+
export interface GitHubRepository {
|
|
14
|
+
id: number
|
|
15
|
+
name: string
|
|
16
|
+
full_name: string
|
|
17
|
+
description: string | null
|
|
18
|
+
html_url: string
|
|
19
|
+
homepage: string | null
|
|
20
|
+
stargazers_count: number
|
|
21
|
+
watchers_count: number
|
|
22
|
+
forks_count: number
|
|
23
|
+
language: string | null
|
|
24
|
+
topics: string[]
|
|
25
|
+
created_at: string
|
|
26
|
+
updated_at: string
|
|
27
|
+
owner: {
|
|
28
|
+
login: string
|
|
29
|
+
avatar_url: string
|
|
30
|
+
html_url: string
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface GitHubStarsProps {
|
|
35
|
+
username: string
|
|
36
|
+
repositories?: string[]
|
|
37
|
+
showDescription?: boolean
|
|
38
|
+
showTopics?: boolean
|
|
39
|
+
showStats?: boolean
|
|
40
|
+
showOwner?: boolean
|
|
41
|
+
sortBy?: "stars" | "forks" | "updated" | "created"
|
|
42
|
+
layout?: "grid" | "list"
|
|
43
|
+
maxItems?: number
|
|
44
|
+
autoRefresh?: boolean
|
|
45
|
+
refreshInterval?: number
|
|
46
|
+
className?: string
|
|
47
|
+
onRepositoryClick?: (repo: GitHubRepository) => void
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const GitHubStarsInternal: React.FC<GitHubStarsProps> = ({
|
|
51
|
+
username,
|
|
52
|
+
repositories,
|
|
53
|
+
showDescription = true,
|
|
54
|
+
showTopics = true,
|
|
55
|
+
showStats = true,
|
|
56
|
+
showOwner = true,
|
|
57
|
+
sortBy = "stars",
|
|
58
|
+
layout = "grid",
|
|
59
|
+
maxItems = 6,
|
|
60
|
+
autoRefresh = false,
|
|
61
|
+
refreshInterval = 300000, // 5 minutes
|
|
62
|
+
className,
|
|
63
|
+
onRepositoryClick
|
|
64
|
+
}) => {
|
|
65
|
+
const [repos, setRepos] = useState<GitHubRepository[]>([])
|
|
66
|
+
const [loading, setLoading] = useState(true)
|
|
67
|
+
const [error, setError] = useState<string | null>(null)
|
|
68
|
+
const [lastUpdated, setLastUpdated] = useState<Date | null>(null)
|
|
69
|
+
|
|
70
|
+
const fetchRepositories = async () => {
|
|
71
|
+
try {
|
|
72
|
+
setLoading(true)
|
|
73
|
+
setError(null)
|
|
74
|
+
|
|
75
|
+
let url = `https://api.github.com/users/${username}/repos?sort=${sortBy}&per_page=100`
|
|
76
|
+
|
|
77
|
+
const response = await fetch(url)
|
|
78
|
+
if (!response.ok) {
|
|
79
|
+
throw new Error(`GitHub API error: ${response.status}`)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let data: GitHubRepository[] = await response.json()
|
|
83
|
+
|
|
84
|
+
// Filter specific repositories if provided
|
|
85
|
+
if (repositories && repositories.length > 0) {
|
|
86
|
+
data = data.filter(repo => repositories.includes(repo.name))
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Sort repositories
|
|
90
|
+
data.sort((a, b) => {
|
|
91
|
+
switch (sortBy) {
|
|
92
|
+
case "stars":
|
|
93
|
+
return b.stargazers_count - a.stargazers_count
|
|
94
|
+
case "forks":
|
|
95
|
+
return b.forks_count - a.forks_count
|
|
96
|
+
case "updated":
|
|
97
|
+
return new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()
|
|
98
|
+
case "created":
|
|
99
|
+
return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()
|
|
100
|
+
default:
|
|
101
|
+
return 0
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
// Limit results
|
|
106
|
+
if (maxItems) {
|
|
107
|
+
data = data.slice(0, maxItems)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
setRepos(data)
|
|
111
|
+
setLastUpdated(new Date())
|
|
112
|
+
} catch (err) {
|
|
113
|
+
setError(err instanceof Error ? err.message : "Failed to fetch repositories")
|
|
114
|
+
} finally {
|
|
115
|
+
setLoading(false)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
fetchRepositories()
|
|
121
|
+
}, [username, repositories, sortBy, maxItems])
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
if (!autoRefresh) return
|
|
125
|
+
|
|
126
|
+
const interval = setInterval(fetchRepositories, refreshInterval)
|
|
127
|
+
return () => clearInterval(interval)
|
|
128
|
+
}, [autoRefresh, refreshInterval])
|
|
129
|
+
|
|
130
|
+
const formatNumber = (num: number): string => {
|
|
131
|
+
if (num >= 1000) {
|
|
132
|
+
return (num / 1000).toFixed(1) + "k"
|
|
133
|
+
}
|
|
134
|
+
return num.toString()
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const formatDate = (dateString: string): string => {
|
|
138
|
+
const date = new Date(dateString)
|
|
139
|
+
return date.toLocaleDateString("en-US", {
|
|
140
|
+
year: "numeric",
|
|
141
|
+
month: "short",
|
|
142
|
+
day: "numeric"
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const getLanguageColor = (language: string | null): string => {
|
|
147
|
+
const colors: Record<string, string> = {
|
|
148
|
+
JavaScript: "#f7df1e",
|
|
149
|
+
TypeScript: "#3178c6",
|
|
150
|
+
Python: "#3776ab",
|
|
151
|
+
Java: "#ed8b00",
|
|
152
|
+
"C++": "#00599c",
|
|
153
|
+
"C#": "#239120",
|
|
154
|
+
Go: "#00add8",
|
|
155
|
+
Rust: "#000000",
|
|
156
|
+
Swift: "#fa7343",
|
|
157
|
+
Kotlin: "#7f52ff",
|
|
158
|
+
PHP: "#777bb4",
|
|
159
|
+
Ruby: "#cc342d",
|
|
160
|
+
HTML: "#e34f26",
|
|
161
|
+
CSS: "#1572b6",
|
|
162
|
+
Vue: "#4fc08d",
|
|
163
|
+
React: "#61dafb"
|
|
164
|
+
}
|
|
165
|
+
return colors[language || ""] || "#6b7280"
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (loading) {
|
|
169
|
+
return (
|
|
170
|
+
<Card className={cn("w-full", className)}>
|
|
171
|
+
<CardContent className="p-6">
|
|
172
|
+
<div className="space-y-4">
|
|
173
|
+
<div className="flex items-center justify-between">
|
|
174
|
+
<Skeleton className="h-6 w-48" />
|
|
175
|
+
<Skeleton className="h-8 w-20" />
|
|
176
|
+
</div>
|
|
177
|
+
<div className={cn(
|
|
178
|
+
layout === "grid"
|
|
179
|
+
? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
|
180
|
+
: "space-y-4"
|
|
181
|
+
)}>
|
|
182
|
+
{Array.from({ length: maxItems || 6 }).map((_, index) => (
|
|
183
|
+
<Card key={index}>
|
|
184
|
+
<CardContent className="p-4">
|
|
185
|
+
<div className="space-y-3">
|
|
186
|
+
<Skeleton className="h-5 w-3/4" />
|
|
187
|
+
<Skeleton className="h-4 w-full" />
|
|
188
|
+
<Skeleton className="h-4 w-2/3" />
|
|
189
|
+
<div className="flex gap-2">
|
|
190
|
+
<Skeleton className="h-6 w-16" />
|
|
191
|
+
<Skeleton className="h-6 w-16" />
|
|
192
|
+
<Skeleton className="h-6 w-16" />
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</CardContent>
|
|
196
|
+
</Card>
|
|
197
|
+
))}
|
|
198
|
+
</div>
|
|
199
|
+
</div>
|
|
200
|
+
</CardContent>
|
|
201
|
+
</Card>
|
|
202
|
+
)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (error) {
|
|
206
|
+
return (
|
|
207
|
+
<Card className={cn("w-full", className)}>
|
|
208
|
+
<CardContent className="p-6 text-center">
|
|
209
|
+
<div className="space-y-4">
|
|
210
|
+
<div className="text-destructive">
|
|
211
|
+
<Github className="h-12 w-12 mx-auto mb-2" />
|
|
212
|
+
<h3 className="font-semibold">Failed to load repositories</h3>
|
|
213
|
+
<p className="text-sm text-muted-foreground">{error}</p>
|
|
214
|
+
</div>
|
|
215
|
+
<Button onClick={fetchRepositories} variant="outline">
|
|
216
|
+
<RefreshCw className="h-4 w-4 mr-2" />
|
|
217
|
+
Try Again
|
|
218
|
+
</Button>
|
|
219
|
+
</div>
|
|
220
|
+
</CardContent>
|
|
221
|
+
</Card>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<Card className={cn("w-full", className)}>
|
|
227
|
+
<CardContent className="p-6">
|
|
228
|
+
<div className="space-y-6">
|
|
229
|
+
{/* Header */}
|
|
230
|
+
<div className="flex items-center justify-between">
|
|
231
|
+
<div className="flex items-center gap-3">
|
|
232
|
+
<Github className="h-6 w-6" />
|
|
233
|
+
<div>
|
|
234
|
+
<h3 className="font-semibold text-lg">{username}'s Repositories</h3>
|
|
235
|
+
{lastUpdated && (
|
|
236
|
+
<p className="text-sm text-muted-foreground">
|
|
237
|
+
Last updated: {lastUpdated.toLocaleTimeString()}
|
|
238
|
+
</p>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
<div className="flex items-center gap-2">
|
|
244
|
+
<Badge variant="outline">
|
|
245
|
+
{repos.length} repos
|
|
246
|
+
</Badge>
|
|
247
|
+
{autoRefresh && (
|
|
248
|
+
<Badge variant="secondary">
|
|
249
|
+
Auto-refresh
|
|
250
|
+
</Badge>
|
|
251
|
+
)}
|
|
252
|
+
<Button onClick={fetchRepositories} variant="outline" size="sm">
|
|
253
|
+
<RefreshCw className="h-4 w-4" />
|
|
254
|
+
</Button>
|
|
255
|
+
</div>
|
|
256
|
+
</div>
|
|
257
|
+
|
|
258
|
+
{/* Repository Grid/List */}
|
|
259
|
+
<div className={cn(
|
|
260
|
+
layout === "grid"
|
|
261
|
+
? "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"
|
|
262
|
+
: "space-y-4"
|
|
263
|
+
)}>
|
|
264
|
+
<AnimatePresence>
|
|
265
|
+
{repos.map((repo, index) => (
|
|
266
|
+
<motion.div
|
|
267
|
+
key={repo.id}
|
|
268
|
+
initial={{ opacity: 0, y: 20 }}
|
|
269
|
+
animate={{ opacity: 1, y: 0 }}
|
|
270
|
+
exit={{ opacity: 0, y: -20 }}
|
|
271
|
+
transition={{ delay: index * 0.1 }}
|
|
272
|
+
>
|
|
273
|
+
<Card
|
|
274
|
+
className="h-full hover:shadow-md transition-shadow cursor-pointer group"
|
|
275
|
+
onClick={() => onRepositoryClick?.(repo)}
|
|
276
|
+
>
|
|
277
|
+
<CardContent className="p-4">
|
|
278
|
+
<div className="space-y-3">
|
|
279
|
+
{/* Repository Name */}
|
|
280
|
+
<div className="flex items-start justify-between">
|
|
281
|
+
<div className="flex-1 min-w-0">
|
|
282
|
+
<h4 className="font-semibold text-sm group-hover:text-primary transition-colors">
|
|
283
|
+
{repo.name}
|
|
284
|
+
</h4>
|
|
285
|
+
{showOwner && (
|
|
286
|
+
<p className="text-xs text-muted-foreground truncate">
|
|
287
|
+
{repo.owner.login}
|
|
288
|
+
</p>
|
|
289
|
+
)}
|
|
290
|
+
</div>
|
|
291
|
+
<Button
|
|
292
|
+
variant="ghost"
|
|
293
|
+
size="sm"
|
|
294
|
+
className="opacity-0 group-hover:opacity-100 transition-opacity p-1 h-auto"
|
|
295
|
+
onClick={(e) => {
|
|
296
|
+
e.stopPropagation()
|
|
297
|
+
window.open(repo.html_url, '_blank')
|
|
298
|
+
}}
|
|
299
|
+
>
|
|
300
|
+
<ExternalLink className="h-3 w-3" />
|
|
301
|
+
</Button>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
{/* Description */}
|
|
305
|
+
{showDescription && repo.description && (
|
|
306
|
+
<p className="text-sm text-muted-foreground line-clamp-2">
|
|
307
|
+
{repo.description}
|
|
308
|
+
</p>
|
|
309
|
+
)}
|
|
310
|
+
|
|
311
|
+
{/* Topics */}
|
|
312
|
+
{showTopics && repo.topics.length > 0 && (
|
|
313
|
+
<div className="flex flex-wrap gap-1">
|
|
314
|
+
{repo.topics.slice(0, 3).map((topic) => (
|
|
315
|
+
<Badge key={topic} variant="secondary" className="text-xs">
|
|
316
|
+
{topic}
|
|
317
|
+
</Badge>
|
|
318
|
+
))}
|
|
319
|
+
{repo.topics.length > 3 && (
|
|
320
|
+
<Badge variant="outline" className="text-xs">
|
|
321
|
+
+{repo.topics.length - 3}
|
|
322
|
+
</Badge>
|
|
323
|
+
)}
|
|
324
|
+
</div>
|
|
325
|
+
)}
|
|
326
|
+
|
|
327
|
+
{/* Stats */}
|
|
328
|
+
{showStats && (
|
|
329
|
+
<div className="flex items-center gap-4 text-sm text-muted-foreground">
|
|
330
|
+
{repo.language && (
|
|
331
|
+
<div className="flex items-center gap-1">
|
|
332
|
+
<div
|
|
333
|
+
className="w-3 h-3 rounded-full"
|
|
334
|
+
style={{ backgroundColor: getLanguageColor(repo.language) }}
|
|
335
|
+
/>
|
|
336
|
+
<span className="text-xs">{repo.language}</span>
|
|
337
|
+
</div>
|
|
338
|
+
)}
|
|
339
|
+
|
|
340
|
+
<div className="flex items-center gap-1">
|
|
341
|
+
<Star className="h-3 w-3" />
|
|
342
|
+
<span className="text-xs">{formatNumber(repo.stargazers_count)}</span>
|
|
343
|
+
</div>
|
|
344
|
+
|
|
345
|
+
<div className="flex items-center gap-1">
|
|
346
|
+
<GitFork className="h-3 w-3" />
|
|
347
|
+
<span className="text-xs">{formatNumber(repo.forks_count)}</span>
|
|
348
|
+
</div>
|
|
349
|
+
</div>
|
|
350
|
+
)}
|
|
351
|
+
|
|
352
|
+
{/* Updated Date */}
|
|
353
|
+
<div className="text-xs text-muted-foreground">
|
|
354
|
+
Updated {formatDate(repo.updated_at)}
|
|
355
|
+
</div>
|
|
356
|
+
</div>
|
|
357
|
+
</CardContent>
|
|
358
|
+
</Card>
|
|
359
|
+
</motion.div>
|
|
360
|
+
))}
|
|
361
|
+
</AnimatePresence>
|
|
362
|
+
</div>
|
|
363
|
+
|
|
364
|
+
{repos.length === 0 && (
|
|
365
|
+
<div className="text-center py-8">
|
|
366
|
+
<Github className="h-12 w-12 mx-auto mb-4 text-muted-foreground" />
|
|
367
|
+
<p className="text-muted-foreground">No repositories found</p>
|
|
368
|
+
</div>
|
|
369
|
+
)}
|
|
370
|
+
</div>
|
|
371
|
+
</CardContent>
|
|
372
|
+
</Card>
|
|
373
|
+
)
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
export const GitHubStars: React.FC<GitHubStarsProps> = ({ className, ...props }) => {
|
|
377
|
+
// Check if we're in docs mode or have pro access
|
|
378
|
+
const docsProAccess = { hasAccess: true } // Pro access assumed in package
|
|
379
|
+
const { hasProAccess, isLoading } = useSubscription()
|
|
380
|
+
|
|
381
|
+
// In docs mode, always show the component
|
|
382
|
+
const canShowComponent = docsProAccess.isDocsMode || hasProAccess
|
|
383
|
+
|
|
384
|
+
// If not in docs mode and no pro access, show upgrade prompt
|
|
385
|
+
if (!docsProAccess.isDocsMode && !isLoading && !hasProAccess) {
|
|
386
|
+
return (
|
|
387
|
+
<Card className={cn("w-fit", className)}>
|
|
388
|
+
<CardContent className="py-6 text-center">
|
|
389
|
+
<div className="space-y-4">
|
|
390
|
+
<div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
|
|
391
|
+
<Lock className="h-6 w-6 text-purple-600 dark:text-purple-400" />
|
|
392
|
+
</div>
|
|
393
|
+
<div>
|
|
394
|
+
<h3 className="font-semibold text-sm mb-2">Pro Feature</h3>
|
|
395
|
+
<p className="text-muted-foreground text-xs mb-4">
|
|
396
|
+
GitHub Stars is available exclusively to MoonUI Pro subscribers.
|
|
397
|
+
</p>
|
|
398
|
+
<a href="/pricing">
|
|
399
|
+
<Button size="sm">
|
|
400
|
+
<Sparkles className="mr-2 h-4 w-4" />
|
|
401
|
+
Upgrade to Pro
|
|
402
|
+
</Button>
|
|
403
|
+
</a>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
</CardContent>
|
|
407
|
+
</Card>
|
|
408
|
+
)
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
return <GitHubStarsInternal className={className} {...props} />
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export type { GitHubRepository, GitHubStarsProps }
|