@moontra/moonui-pro 2.20.2 → 2.20.4

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 (153) hide show
  1. package/package.json +8 -3
  2. package/plugin/index.d.ts +86 -0
  3. package/plugin/index.js +308 -0
  4. package/scripts/postinstall.js +191 -23
  5. package/src/components/advanced-chart/index.tsx +0 -1246
  6. package/src/components/advanced-forms/index.tsx +0 -585
  7. package/src/components/animated-button/index.tsx +0 -385
  8. package/src/components/calendar/event-dialog.tsx +0 -377
  9. package/src/components/calendar/index.tsx +0 -1220
  10. package/src/components/calendar-pro/index.tsx +0 -1697
  11. package/src/components/color-picker/index.tsx +0 -432
  12. package/src/components/credit-card-input/index.tsx +0 -406
  13. package/src/components/dashboard/dashboard-grid.tsx +0 -480
  14. package/src/components/dashboard/demo.tsx +0 -425
  15. package/src/components/dashboard/index.tsx +0 -1046
  16. package/src/components/dashboard/time-range-picker.tsx +0 -336
  17. package/src/components/dashboard/types.ts +0 -225
  18. package/src/components/dashboard/widgets/activity-feed.tsx +0 -349
  19. package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
  20. package/src/components/dashboard/widgets/comparison-widget.tsx +0 -177
  21. package/src/components/dashboard/widgets/index.ts +0 -5
  22. package/src/components/dashboard/widgets/metric-card.tsx +0 -363
  23. package/src/components/dashboard/widgets/progress-widget.tsx +0 -113
  24. package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
  25. package/src/components/data-table/data-table-column-toggle.tsx +0 -169
  26. package/src/components/data-table/data-table-export.ts +0 -156
  27. package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
  28. package/src/components/data-table/index.tsx +0 -845
  29. package/src/components/draggable-list/index.tsx +0 -100
  30. package/src/components/error-boundary/index.tsx +0 -232
  31. package/src/components/file-upload/index.tsx +0 -1660
  32. package/src/components/floating-action-button/index.tsx +0 -206
  33. package/src/components/form-wizard/form-wizard-context.tsx +0 -335
  34. package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
  35. package/src/components/form-wizard/form-wizard-progress.tsx +0 -329
  36. package/src/components/form-wizard/form-wizard-step.tsx +0 -111
  37. package/src/components/form-wizard/index.tsx +0 -102
  38. package/src/components/form-wizard/types.ts +0 -77
  39. package/src/components/gesture-drawer/index.tsx +0 -551
  40. package/src/components/github-stars/github-api.ts +0 -426
  41. package/src/components/github-stars/hooks.ts +0 -517
  42. package/src/components/github-stars/index.tsx +0 -375
  43. package/src/components/github-stars/types.ts +0 -148
  44. package/src/components/github-stars/variants.tsx +0 -515
  45. package/src/components/health-check/index.tsx +0 -439
  46. package/src/components/hover-card-3d/index.tsx +0 -529
  47. package/src/components/index.ts +0 -130
  48. package/src/components/internal/index.ts +0 -78
  49. package/src/components/kanban/add-card-modal.tsx +0 -502
  50. package/src/components/kanban/card-detail-modal.tsx +0 -761
  51. package/src/components/kanban/index.ts +0 -13
  52. package/src/components/kanban/kanban.tsx +0 -1689
  53. package/src/components/kanban/types.ts +0 -168
  54. package/src/components/lazy-component/index.tsx +0 -823
  55. package/src/components/license-error/index.tsx +0 -31
  56. package/src/components/magnetic-button/index.tsx +0 -216
  57. package/src/components/memory-efficient-data/index.tsx +0 -1018
  58. package/src/components/moonui-quiz-form/index.tsx +0 -817
  59. package/src/components/navbar/index.tsx +0 -781
  60. package/src/components/optimized-image/index.tsx +0 -425
  61. package/src/components/performance-debugger/index.tsx +0 -613
  62. package/src/components/performance-monitor/index.tsx +0 -808
  63. package/src/components/phone-number-input/index.tsx +0 -343
  64. package/src/components/phone-number-input/phone-number-input-simple.tsx +0 -167
  65. package/src/components/pinch-zoom/index.tsx +0 -566
  66. package/src/components/quiz-form/index.tsx +0 -479
  67. package/src/components/rich-text-editor/index.tsx +0 -2322
  68. package/src/components/rich-text-editor/slash-commands-extension.ts +0 -230
  69. package/src/components/rich-text-editor/slash-commands.css +0 -35
  70. package/src/components/rich-text-editor/table-styles.css +0 -65
  71. package/src/components/sidebar/index.tsx +0 -884
  72. package/src/components/spotlight-card/index.tsx +0 -191
  73. package/src/components/swipeable-card/index.tsx +0 -100
  74. package/src/components/timeline/index.tsx +0 -1183
  75. package/src/components/ui/accordion.tsx +0 -581
  76. package/src/components/ui/alert-dialog.tsx +0 -141
  77. package/src/components/ui/alert.tsx +0 -141
  78. package/src/components/ui/aspect-ratio.tsx +0 -245
  79. package/src/components/ui/avatar.tsx +0 -155
  80. package/src/components/ui/badge.tsx +0 -230
  81. package/src/components/ui/breadcrumb.tsx +0 -216
  82. package/src/components/ui/button.tsx +0 -228
  83. package/src/components/ui/calendar.tsx +0 -387
  84. package/src/components/ui/card.tsx +0 -216
  85. package/src/components/ui/checkbox.tsx +0 -259
  86. package/src/components/ui/collapsible.tsx +0 -631
  87. package/src/components/ui/color-picker.tsx +0 -97
  88. package/src/components/ui/command.tsx +0 -948
  89. package/src/components/ui/dialog.tsx +0 -752
  90. package/src/components/ui/dropdown-menu.tsx +0 -706
  91. package/src/components/ui/gesture-drawer.tsx +0 -11
  92. package/src/components/ui/hover-card.tsx +0 -29
  93. package/src/components/ui/index.ts +0 -222
  94. package/src/components/ui/input.tsx +0 -224
  95. package/src/components/ui/label.tsx +0 -29
  96. package/src/components/ui/lightbox.tsx +0 -606
  97. package/src/components/ui/magnetic-button.tsx +0 -129
  98. package/src/components/ui/media-gallery.tsx +0 -611
  99. package/src/components/ui/navigation-menu.tsx +0 -130
  100. package/src/components/ui/pagination.tsx +0 -125
  101. package/src/components/ui/popover.tsx +0 -185
  102. package/src/components/ui/progress.tsx +0 -30
  103. package/src/components/ui/radio-group.tsx +0 -257
  104. package/src/components/ui/scroll-area.tsx +0 -47
  105. package/src/components/ui/select.tsx +0 -378
  106. package/src/components/ui/separator.tsx +0 -145
  107. package/src/components/ui/sheet.tsx +0 -139
  108. package/src/components/ui/skeleton.tsx +0 -20
  109. package/src/components/ui/slider.tsx +0 -354
  110. package/src/components/ui/spotlight-card.tsx +0 -119
  111. package/src/components/ui/switch.tsx +0 -86
  112. package/src/components/ui/table.tsx +0 -331
  113. package/src/components/ui/tabs-pro.tsx +0 -542
  114. package/src/components/ui/tabs.tsx +0 -54
  115. package/src/components/ui/textarea.tsx +0 -28
  116. package/src/components/ui/toast.tsx +0 -317
  117. package/src/components/ui/toggle.tsx +0 -119
  118. package/src/components/ui/tooltip.tsx +0 -151
  119. package/src/components/virtual-list/index.tsx +0 -668
  120. package/src/hooks/use-chart.ts +0 -205
  121. package/src/hooks/use-data-table.ts +0 -182
  122. package/src/hooks/use-docs-pro-access.ts +0 -13
  123. package/src/hooks/use-license-check.ts +0 -65
  124. package/src/hooks/use-subscription.ts +0 -19
  125. package/src/hooks/use-toast.ts +0 -15
  126. package/src/index.ts +0 -22
  127. package/src/lib/ai-providers.ts +0 -377
  128. package/src/lib/component-metadata.ts +0 -18
  129. package/src/lib/micro-interactions.ts +0 -255
  130. package/src/lib/paddle.ts +0 -17
  131. package/src/lib/utils.ts +0 -6
  132. package/src/patterns/login-form/index.tsx +0 -276
  133. package/src/patterns/login-form/types.ts +0 -67
  134. package/src/setupTests.ts +0 -41
  135. package/src/styles/advanced-chart.css +0 -239
  136. package/src/styles/calendar.css +0 -35
  137. package/src/styles/design-system.css +0 -363
  138. package/src/styles/index.css +0 -681
  139. package/src/styles/tailwind.css +0 -7
  140. package/src/styles/tokens.css +0 -455
  141. package/src/types/next-auth.d.ts +0 -21
  142. package/src/use-intersection-observer.tsx +0 -154
  143. package/src/use-local-storage.tsx +0 -71
  144. package/src/use-paddle.ts +0 -138
  145. package/src/use-performance-optimizer.ts +0 -389
  146. package/src/use-pro-access.ts +0 -141
  147. package/src/use-scroll-animation.ts +0 -219
  148. package/src/use-subscription.ts +0 -37
  149. package/src/use-toast.ts +0 -32
  150. package/src/utils/chart-helpers.ts +0 -357
  151. package/src/utils/cn.ts +0 -6
  152. package/src/utils/data-processing.ts +0 -151
  153. package/src/utils/license-validator.tsx +0 -183
@@ -1,613 +0,0 @@
1
- "use client"
2
-
3
- import React, { useState, useEffect, useRef, useCallback } from "react"
4
- import { motion, AnimatePresence } from "framer-motion"
5
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../ui/card"
6
- import { Button } from "../ui/button"
7
- import { MoonUIBadgePro as Badge } from "../ui/badge"
8
- import { Progress } from "../ui/progress"
9
- import { Tabs, TabsContent, TabsList, TabsTrigger } from "../ui/tabs"
10
- import { cn } from "../../lib/utils"
11
- import {
12
- Activity,
13
- Zap,
14
- Clock,
15
- Eye,
16
- EyeOff,
17
- Download,
18
- RefreshCw,
19
- AlertTriangle,
20
- CheckCircle,
21
- TrendingUp,
22
- TrendingDown,
23
- Lock,
24
- Sparkles,
25
- Cpu,
26
- MemoryStick,
27
- Network,
28
- HardDrive
29
- } from "lucide-react"
30
- import { useSubscription } from "../../hooks/use-subscription"
31
-
32
- interface PerformanceMetric {
33
- name: string
34
- value: number
35
- unit: string
36
- threshold?: {
37
- good: number
38
- needs_improvement: number
39
- }
40
- description?: string
41
- }
42
-
43
- interface PerformanceEntry {
44
- timestamp: number
45
- metrics: PerformanceMetric[]
46
- url: string
47
- userAgent: string
48
- }
49
-
50
- interface PerformanceDebuggerProps {
51
- autoCapture?: boolean
52
- captureInterval?: number
53
- maxEntries?: number
54
- showRealTime?: boolean
55
- showWebVitals?: boolean
56
- showResourceTiming?: boolean
57
- showNavigationTiming?: boolean
58
- onMetricChange?: (metrics: PerformanceMetric[]) => void
59
- className?: string
60
- }
61
-
62
- const PerformanceDebuggerInternal: React.FC<PerformanceDebuggerProps> = ({
63
- autoCapture = true,
64
- captureInterval = 5000,
65
- maxEntries = 50,
66
- showRealTime = true,
67
- showWebVitals = true,
68
- showResourceTiming = true,
69
- showNavigationTiming = true,
70
- onMetricChange,
71
- className
72
- }) => {
73
- const [entries, setEntries] = useState<PerformanceEntry[]>([])
74
- const [currentMetrics, setCurrentMetrics] = useState<PerformanceMetric[]>([])
75
- const [isCapturing, setIsCapturing] = useState(autoCapture)
76
- const [isVisible, setIsVisible] = useState(true)
77
- const intervalRef = useRef<NodeJS.Timeout | undefined>(undefined)
78
-
79
- // Core Web Vitals thresholds
80
- const webVitalsThresholds = {
81
- FCP: { good: 1800, needs_improvement: 3000 },
82
- LCP: { good: 2500, needs_improvement: 4000 },
83
- FID: { good: 100, needs_improvement: 300 },
84
- CLS: { good: 0.1, needs_improvement: 0.25 },
85
- INP: { good: 200, needs_improvement: 500 },
86
- TTFB: { good: 800, needs_improvement: 1800 }
87
- }
88
-
89
- // Get performance metrics
90
- const captureMetrics = useCallback(() => {
91
- const metrics: PerformanceMetric[] = []
92
-
93
- // Navigation Timing
94
- if (showNavigationTiming && 'performance' in window) {
95
- const nav = performance.getEntriesByType('navigation')[0] as PerformanceNavigationTiming
96
- if (nav) {
97
- metrics.push(
98
- {
99
- name: 'DNS Lookup',
100
- value: nav.domainLookupEnd - nav.domainLookupStart,
101
- unit: 'ms',
102
- description: 'Time to resolve domain name'
103
- },
104
- {
105
- name: 'TCP Connection',
106
- value: nav.connectEnd - nav.connectStart,
107
- unit: 'ms',
108
- description: 'Time to establish TCP connection'
109
- },
110
- {
111
- name: 'Request/Response',
112
- value: nav.responseEnd - nav.requestStart,
113
- unit: 'ms',
114
- description: 'Time to get first byte and complete response'
115
- },
116
- {
117
- name: 'DOM Processing',
118
- value: nav.domComplete - (nav.domInteractive || nav.fetchStart),
119
- unit: 'ms',
120
- description: 'Time to process DOM'
121
- },
122
- {
123
- name: 'Load Complete',
124
- value: nav.loadEventEnd - nav.loadEventStart,
125
- unit: 'ms',
126
- description: 'Time to fire load event'
127
- }
128
- )
129
- }
130
- }
131
-
132
- // Web Vitals (simulated - in real app you'd use web-vitals library)
133
- if (showWebVitals) {
134
- const paintEntries = performance.getEntriesByType('paint')
135
- const fcpEntry = paintEntries.find(entry => entry.name === 'first-contentful-paint')
136
-
137
- if (fcpEntry) {
138
- metrics.push({
139
- name: 'FCP',
140
- value: fcpEntry.startTime,
141
- unit: 'ms',
142
- threshold: webVitalsThresholds.FCP,
143
- description: 'First Contentful Paint'
144
- })
145
- }
146
-
147
- // Simulated LCP (in real app, use PerformanceObserver)
148
- metrics.push({
149
- name: 'LCP',
150
- value: Math.random() * 4000 + 1000,
151
- unit: 'ms',
152
- threshold: webVitalsThresholds.LCP,
153
- description: 'Largest Contentful Paint'
154
- })
155
-
156
- // Simulated CLS
157
- metrics.push({
158
- name: 'CLS',
159
- value: Math.random() * 0.3,
160
- unit: '',
161
- threshold: webVitalsThresholds.CLS,
162
- description: 'Cumulative Layout Shift'
163
- })
164
- }
165
-
166
- // Memory usage (if available)
167
- if ('memory' in performance) {
168
- const memory = (performance as any).memory
169
- metrics.push(
170
- {
171
- name: 'JS Heap Used',
172
- value: memory.usedJSHeapSize / 1024 / 1024,
173
- unit: 'MB',
174
- description: 'JavaScript heap memory in use'
175
- },
176
- {
177
- name: 'JS Heap Total',
178
- value: memory.totalJSHeapSize / 1024 / 1024,
179
- unit: 'MB',
180
- description: 'Total JavaScript heap memory'
181
- },
182
- {
183
- name: 'JS Heap Limit',
184
- value: memory.jsHeapSizeLimit / 1024 / 1024,
185
- unit: 'MB',
186
- description: 'JavaScript heap memory limit'
187
- }
188
- )
189
- }
190
-
191
- // Resource timing
192
- if (showResourceTiming) {
193
- const resources = performance.getEntriesByType('resource')
194
- const totalSize = resources.reduce((acc, resource) => {
195
- return acc + ((resource as any).transferSize || 0)
196
- }, 0)
197
-
198
- metrics.push({
199
- name: 'Resources Loaded',
200
- value: resources.length,
201
- unit: 'count',
202
- description: 'Total number of resources loaded'
203
- })
204
-
205
- if (totalSize > 0) {
206
- metrics.push({
207
- name: 'Total Transfer Size',
208
- value: totalSize / 1024,
209
- unit: 'KB',
210
- description: 'Total size of transferred resources'
211
- })
212
- }
213
- }
214
-
215
- // Current performance scores (simulated)
216
- metrics.push(
217
- {
218
- name: 'Performance Score',
219
- value: Math.random() * 40 + 60,
220
- unit: '/100',
221
- threshold: { good: 90, needs_improvement: 50 },
222
- description: 'Overall performance score'
223
- },
224
- {
225
- name: 'CPU Usage',
226
- value: Math.random() * 50 + 20,
227
- unit: '%',
228
- threshold: { good: 30, needs_improvement: 70 },
229
- description: 'Current CPU usage'
230
- }
231
- )
232
-
233
- return metrics
234
- }, [showNavigationTiming, showWebVitals, showResourceTiming])
235
-
236
- // Capture performance data
237
- const capture = useCallback(() => {
238
- const metrics = captureMetrics()
239
- const entry: PerformanceEntry = {
240
- timestamp: Date.now(),
241
- metrics,
242
- url: window.location.href,
243
- userAgent: navigator.userAgent
244
- }
245
-
246
- setEntries(prev => [entry, ...prev.slice(0, maxEntries - 1)])
247
- setCurrentMetrics(metrics)
248
- onMetricChange?.(metrics)
249
- }, [captureMetrics, maxEntries, onMetricChange])
250
-
251
- // Auto capture
252
- useEffect(() => {
253
- if (isCapturing && showRealTime) {
254
- capture() // Initial capture
255
- intervalRef.current = setInterval(capture, captureInterval)
256
- } else {
257
- if (intervalRef.current) {
258
- clearInterval(intervalRef.current)
259
- }
260
- }
261
-
262
- return () => {
263
- if (intervalRef.current) {
264
- clearInterval(intervalRef.current)
265
- }
266
- }
267
- }, [isCapturing, showRealTime, capture, captureInterval])
268
-
269
- // Initial capture on mount
270
- useEffect(() => {
271
- capture()
272
- }, [])
273
-
274
- const getMetricStatus = (metric: PerformanceMetric): 'good' | 'needs_improvement' | 'poor' => {
275
- if (!metric.threshold) return 'good'
276
-
277
- if (metric.value <= metric.threshold.good) return 'good'
278
- if (metric.value <= metric.threshold.needs_improvement) return 'needs_improvement'
279
- return 'poor'
280
- }
281
-
282
- const getStatusColor = (status: string) => {
283
- switch (status) {
284
- case 'good': return 'text-green-500'
285
- case 'needs_improvement': return 'text-yellow-500'
286
- case 'poor': return 'text-red-500'
287
- default: return 'text-muted-foreground'
288
- }
289
- }
290
-
291
- const getStatusIcon = (status: string) => {
292
- switch (status) {
293
- case 'good': return <CheckCircle className="h-4 w-4 text-green-500" />
294
- case 'needs_improvement': return <AlertTriangle className="h-4 w-4 text-yellow-500" />
295
- case 'poor': return <AlertTriangle className="h-4 w-4 text-red-500" />
296
- default: return <Activity className="h-4 w-4 text-muted-foreground" />
297
- }
298
- }
299
-
300
- const exportData = () => {
301
- const data = {
302
- timestamp: new Date().toISOString(),
303
- entries,
304
- currentMetrics
305
- }
306
-
307
- const blob = new Blob([JSON.stringify(data, null, 2)], {
308
- type: 'application/json'
309
- })
310
-
311
- const url = URL.createObjectURL(blob)
312
- const link = document.createElement('a')
313
- link.href = url
314
- link.download = `performance-debug-${Date.now()}.json`
315
- document.body.appendChild(link)
316
- link.click()
317
- document.body.removeChild(link)
318
- URL.revokeObjectURL(url)
319
- }
320
-
321
- const clearData = () => {
322
- setEntries([])
323
- setCurrentMetrics([])
324
- }
325
-
326
- const formatValue = (value: number, unit: string) => {
327
- const formatted = unit === 'ms' || unit === 'MB' || unit === 'KB'
328
- ? value.toFixed(1)
329
- : unit === '%' || unit === '/100'
330
- ? Math.round(value)
331
- : value.toString()
332
-
333
- return `${formatted}${unit}`
334
- }
335
-
336
- if (!isVisible) {
337
- return (
338
- <Button
339
- variant="outline"
340
- size="sm"
341
- onClick={() => setIsVisible(true)}
342
- className="fixed bottom-4 right-4 z-50"
343
- >
344
- <Activity className="h-4 w-4 mr-2" />
345
- Performance
346
- </Button>
347
- )
348
- }
349
-
350
- return (
351
- <Card className={cn("w-full max-w-6xl", className)}>
352
- <CardHeader className="pb-6">
353
- <div className="flex items-center justify-between">
354
- <div>
355
- <CardTitle className="flex items-center gap-2">
356
- <Zap className="h-5 w-5" />
357
- Performance Debugger
358
- </CardTitle>
359
- <CardDescription>
360
- Real-time performance monitoring and web vitals tracking
361
- </CardDescription>
362
- </div>
363
-
364
- <div className="flex items-center gap-2">
365
- <div className={cn(
366
- "inline-flex items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium",
367
- isCapturing
368
- ? "border border-border bg-background text-foreground"
369
- : "bg-secondary text-secondary-foreground"
370
- )}>
371
- {isCapturing ? (
372
- <Activity className="h-3 w-3 animate-pulse" />
373
- ) : (
374
- <Clock className="h-3 w-3" />
375
- )}
376
- <span>{isCapturing ? "Live" : "Paused"}</span>
377
- </div>
378
-
379
- <div className="flex items-center gap-1">
380
- <Button
381
- variant="outline"
382
- size="icon"
383
- className="h-7 w-7"
384
- onClick={() => setIsCapturing(!isCapturing)}
385
- >
386
- {isCapturing ? (
387
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
388
- <rect x="6" y="4" width="4" height="16"></rect>
389
- <rect x="14" y="4" width="4" height="16"></rect>
390
- </svg>
391
- ) : (
392
- <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
393
- <polygon points="5 3 19 12 5 21 5 3"></polygon>
394
- </svg>
395
- )}
396
- </Button>
397
-
398
- <Button
399
- variant="outline"
400
- size="icon"
401
- className="h-7 w-7"
402
- onClick={capture}
403
- >
404
- <RefreshCw className="h-3.5 w-3.5" />
405
- </Button>
406
-
407
- <Button
408
- variant="outline"
409
- size="icon"
410
- className="h-7 w-7"
411
- onClick={exportData}
412
- >
413
- <Download className="h-3.5 w-3.5" />
414
- </Button>
415
-
416
- <Button
417
- variant="ghost"
418
- size="icon"
419
- className="h-7 w-7"
420
- onClick={() => setIsVisible(false)}
421
- >
422
- <EyeOff className="h-3.5 w-3.5" />
423
- </Button>
424
- </div>
425
- </div>
426
- </div>
427
- </CardHeader>
428
-
429
- <CardContent>
430
- <Tabs defaultValue="current" className="w-full mt-2">
431
- <TabsList className="grid w-full grid-cols-3">
432
- <TabsTrigger value="current">Current Metrics</TabsTrigger>
433
- <TabsTrigger value="history">History</TabsTrigger>
434
- <TabsTrigger value="vitals">Web Vitals</TabsTrigger>
435
- </TabsList>
436
-
437
- <TabsContent value="current" className="space-y-4">
438
- <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
439
- <AnimatePresence>
440
- {currentMetrics.map((metric, index) => {
441
- const status = getMetricStatus(metric)
442
- return (
443
- <motion.div
444
- key={metric.name}
445
- initial={{ opacity: 0, y: 20 }}
446
- animate={{ opacity: 1, y: 0 }}
447
- exit={{ opacity: 0, y: -20 }}
448
- transition={{ delay: index * 0.05 }}
449
- >
450
- <Card>
451
- <CardContent className="p-4">
452
- <div className="flex items-center justify-between mb-2">
453
- <div className="flex items-center gap-2">
454
- {getStatusIcon(status)}
455
- <span className="font-medium text-sm">{metric.name}</span>
456
- </div>
457
- <span className={cn("font-bold", getStatusColor(status))}>
458
- {formatValue(metric.value, metric.unit)}
459
- </span>
460
- </div>
461
-
462
- {metric.threshold && (
463
- <div className="space-y-1">
464
- <Progress
465
- value={Math.min((metric.value / (metric.threshold.needs_improvement * 2)) * 100, 100)}
466
- className="h-2"
467
- />
468
- <div className="text-xs text-muted-foreground">
469
- Good: &lt;{metric.threshold.good}{metric.unit} |
470
- Needs improvement: &lt;{metric.threshold.needs_improvement}{metric.unit}
471
- </div>
472
- </div>
473
- )}
474
-
475
- {metric.description && (
476
- <p className="text-xs text-muted-foreground mt-2">
477
- {metric.description}
478
- </p>
479
- )}
480
- </CardContent>
481
- </Card>
482
- </motion.div>
483
- )
484
- })}
485
- </AnimatePresence>
486
- </div>
487
- </TabsContent>
488
-
489
- <TabsContent value="history" className="space-y-4">
490
- <div className="flex items-center justify-between">
491
- <div className="text-sm text-muted-foreground">
492
- {entries.length} entries captured
493
- </div>
494
- <Button variant="outline" size="sm" onClick={clearData}>
495
- Clear History
496
- </Button>
497
- </div>
498
-
499
- <div className="space-y-2 max-h-96 overflow-y-auto">
500
- {entries.map((entry, index) => (
501
- <Card key={entry.timestamp}>
502
- <CardContent className="p-4">
503
- <div className="flex items-center justify-between mb-2">
504
- <span className="text-sm font-medium">
505
- {new Date(entry.timestamp).toLocaleTimeString()}
506
- </span>
507
- <Badge variant="outline" className="text-xs">
508
- {entry.metrics.length} metrics
509
- </Badge>
510
- </div>
511
-
512
- <div className="grid grid-cols-2 md:grid-cols-4 gap-2 text-xs">
513
- {entry.metrics.slice(0, 4).map((metric) => (
514
- <div key={metric.name} className="flex justify-between">
515
- <span className="text-muted-foreground">{metric.name}:</span>
516
- <span className={getStatusColor(getMetricStatus(metric))}>
517
- {formatValue(metric.value, metric.unit)}
518
- </span>
519
- </div>
520
- ))}
521
- </div>
522
- </CardContent>
523
- </Card>
524
- ))}
525
- </div>
526
- </TabsContent>
527
-
528
- <TabsContent value="vitals" className="space-y-4">
529
- <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
530
- {currentMetrics
531
- .filter(metric => ['FCP', 'LCP', 'CLS', 'FID', 'INP', 'TTFB'].includes(metric.name))
532
- .map((metric) => {
533
- const status = getMetricStatus(metric)
534
- return (
535
- <Card key={metric.name}>
536
- <CardContent className="p-6">
537
- <div className="flex items-center justify-between mb-4">
538
- <div>
539
- <h3 className="font-semibold">{metric.name}</h3>
540
- <p className="text-sm text-muted-foreground">
541
- {metric.description}
542
- </p>
543
- </div>
544
- {getStatusIcon(status)}
545
- </div>
546
-
547
- <div className="text-2xl font-bold mb-2 text-center">
548
- <span className={getStatusColor(status)}>
549
- {formatValue(metric.value, metric.unit)}
550
- </span>
551
- </div>
552
-
553
- {metric.threshold && (
554
- <div className="space-y-2">
555
- <Progress
556
- value={Math.min((metric.value / (metric.threshold.needs_improvement * 2)) * 100, 100)}
557
- className="h-3"
558
- />
559
- <div className="flex justify-between text-xs text-muted-foreground">
560
- <span>Good: &lt;{metric.threshold.good}{metric.unit}</span>
561
- <span>Poor: &gt;{metric.threshold.needs_improvement}{metric.unit}</span>
562
- </div>
563
- </div>
564
- )}
565
- </CardContent>
566
- </Card>
567
- )
568
- })}
569
- </div>
570
- </TabsContent>
571
- </Tabs>
572
- </CardContent>
573
- </Card>
574
- )
575
- }
576
-
577
- export const PerformanceDebugger: React.FC<PerformanceDebuggerProps> = ({ className, ...props }) => {
578
- // Check if we're in docs mode or have pro access
579
- const { hasProAccess, isLoading } = useSubscription()
580
-
581
- // In docs mode, always show the component
582
-
583
- // If not in docs mode and no pro access, show upgrade prompt
584
- if (!isLoading && !hasProAccess) {
585
- return (
586
- <Card className={cn("w-fit", className)}>
587
- <CardContent className="py-6 text-center">
588
- <div className="space-y-4">
589
- <div className="rounded-full bg-purple-100 dark:bg-purple-900/30 p-3 w-fit mx-auto">
590
- <Lock className="h-6 w-6 text-purple-600 dark:text-purple-400" />
591
- </div>
592
- <div>
593
- <h3 className="font-semibold text-sm mb-2">Pro Feature</h3>
594
- <p className="text-muted-foreground text-xs mb-4">
595
- Performance Debugger is available exclusively to MoonUI Pro subscribers.
596
- </p>
597
- <a href="/pricing">
598
- <Button size="sm">
599
- <Sparkles className="mr-2 h-4 w-4" />
600
- Upgrade to Pro
601
- </Button>
602
- </a>
603
- </div>
604
- </div>
605
- </CardContent>
606
- </Card>
607
- )
608
- }
609
-
610
- return <PerformanceDebuggerInternal className={className} {...props} />
611
- }
612
-
613
- export type { PerformanceMetric, PerformanceEntry, PerformanceDebuggerProps }