@moontra/moonui-pro 2.20.1 → 2.20.3

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 (162) hide show
  1. package/dist/index.d.ts +691 -261
  2. package/dist/index.mjs +7418 -4934
  3. package/package.json +11 -5
  4. package/plugin/index.d.ts +86 -0
  5. package/plugin/index.js +308 -0
  6. package/scripts/postbuild.js +27 -0
  7. package/scripts/postinstall.js +176 -23
  8. package/src/__tests__/use-intersection-observer.test.tsx +0 -216
  9. package/src/__tests__/use-local-storage.test.tsx +0 -174
  10. package/src/__tests__/use-pro-access.test.tsx +0 -183
  11. package/src/components/advanced-chart/advanced-chart.test.tsx +0 -281
  12. package/src/components/advanced-chart/index.tsx +0 -1242
  13. package/src/components/advanced-forms/index.tsx +0 -426
  14. package/src/components/animated-button/index.tsx +0 -385
  15. package/src/components/calendar/event-dialog.tsx +0 -372
  16. package/src/components/calendar/index.tsx +0 -1073
  17. package/src/components/calendar-pro/index.tsx +0 -1697
  18. package/src/components/color-picker/index.tsx +0 -432
  19. package/src/components/credit-card-input/index.tsx +0 -406
  20. package/src/components/dashboard/dashboard-grid.tsx +0 -462
  21. package/src/components/dashboard/demo.tsx +0 -425
  22. package/src/components/dashboard/index.tsx +0 -1046
  23. package/src/components/dashboard/time-range-picker.tsx +0 -336
  24. package/src/components/dashboard/types.ts +0 -222
  25. package/src/components/dashboard/widgets/activity-feed.tsx +0 -344
  26. package/src/components/dashboard/widgets/chart-widget.tsx +0 -418
  27. package/src/components/dashboard/widgets/metric-card.tsx +0 -343
  28. package/src/components/data-table/data-table-bulk-actions.tsx +0 -204
  29. package/src/components/data-table/data-table-column-toggle.tsx +0 -169
  30. package/src/components/data-table/data-table-export.ts +0 -156
  31. package/src/components/data-table/data-table-filter-drawer.tsx +0 -448
  32. package/src/components/data-table/data-table.test.tsx +0 -187
  33. package/src/components/data-table/index.tsx +0 -845
  34. package/src/components/draggable-list/index.tsx +0 -100
  35. package/src/components/enhanced/badge.tsx +0 -191
  36. package/src/components/enhanced/button.tsx +0 -362
  37. package/src/components/enhanced/card.tsx +0 -266
  38. package/src/components/enhanced/dialog.tsx +0 -246
  39. package/src/components/enhanced/index.ts +0 -4
  40. package/src/components/error-boundary/index.tsx +0 -109
  41. package/src/components/file-upload/file-upload.test.tsx +0 -243
  42. package/src/components/file-upload/index.tsx +0 -1660
  43. package/src/components/floating-action-button/index.tsx +0 -206
  44. package/src/components/form-wizard/form-wizard-context.tsx +0 -307
  45. package/src/components/form-wizard/form-wizard-navigation.tsx +0 -118
  46. package/src/components/form-wizard/form-wizard-progress.tsx +0 -298
  47. package/src/components/form-wizard/form-wizard-step.tsx +0 -111
  48. package/src/components/form-wizard/index.tsx +0 -102
  49. package/src/components/form-wizard/types.ts +0 -76
  50. package/src/components/gesture-drawer/index.tsx +0 -551
  51. package/src/components/github-stars/github-api.ts +0 -426
  52. package/src/components/github-stars/hooks.ts +0 -516
  53. package/src/components/github-stars/index.tsx +0 -375
  54. package/src/components/github-stars/types.ts +0 -148
  55. package/src/components/github-stars/variants.tsx +0 -513
  56. package/src/components/health-check/index.tsx +0 -439
  57. package/src/components/hover-card-3d/index.tsx +0 -530
  58. package/src/components/index.ts +0 -128
  59. package/src/components/internal/index.ts +0 -78
  60. package/src/components/kanban/add-card-modal.tsx +0 -502
  61. package/src/components/kanban/card-detail-modal.tsx +0 -761
  62. package/src/components/kanban/index.ts +0 -13
  63. package/src/components/kanban/kanban.tsx +0 -1684
  64. package/src/components/kanban/types.ts +0 -168
  65. package/src/components/lazy-component/index.tsx +0 -823
  66. package/src/components/license-error/index.tsx +0 -29
  67. package/src/components/magnetic-button/index.tsx +0 -167
  68. package/src/components/memory-efficient-data/index.tsx +0 -1016
  69. package/src/components/moonui-quiz-form/index.tsx +0 -817
  70. package/src/components/optimized-image/index.tsx +0 -425
  71. package/src/components/performance-debugger/index.tsx +0 -589
  72. package/src/components/performance-monitor/index.tsx +0 -794
  73. package/src/components/phone-number-input/index.tsx +0 -338
  74. package/src/components/pinch-zoom/index.tsx +0 -566
  75. package/src/components/quiz-form/index.tsx +0 -479
  76. package/src/components/rich-text-editor/index-old-backup.tsx +0 -437
  77. package/src/components/rich-text-editor/index.tsx +0 -2324
  78. package/src/components/rich-text-editor/slash-commands-extension.ts +0 -220
  79. package/src/components/rich-text-editor/slash-commands.css +0 -35
  80. package/src/components/rich-text-editor/table-styles.css +0 -65
  81. package/src/components/sidebar/index.tsx +0 -865
  82. package/src/components/spotlight-card/index.tsx +0 -191
  83. package/src/components/swipeable-card/index.tsx +0 -100
  84. package/src/components/timeline/index.tsx +0 -1148
  85. package/src/components/ui/accordion.tsx +0 -73
  86. package/src/components/ui/alert-dialog.tsx +0 -141
  87. package/src/components/ui/alert.tsx +0 -141
  88. package/src/components/ui/aspect-ratio.tsx +0 -245
  89. package/src/components/ui/avatar.tsx +0 -153
  90. package/src/components/ui/badge.tsx +0 -228
  91. package/src/components/ui/breadcrumb.tsx +0 -214
  92. package/src/components/ui/button.tsx +0 -222
  93. package/src/components/ui/calendar.tsx +0 -387
  94. package/src/components/ui/card.tsx +0 -214
  95. package/src/components/ui/checkbox.tsx +0 -259
  96. package/src/components/ui/collapsible.tsx +0 -135
  97. package/src/components/ui/color-picker.tsx +0 -97
  98. package/src/components/ui/command.tsx +0 -225
  99. package/src/components/ui/dialog.tsx +0 -334
  100. package/src/components/ui/dropdown-menu.tsx +0 -218
  101. package/src/components/ui/gesture-drawer.tsx +0 -11
  102. package/src/components/ui/hover-card.tsx +0 -29
  103. package/src/components/ui/index.ts +0 -190
  104. package/src/components/ui/input.tsx +0 -222
  105. package/src/components/ui/label.tsx +0 -29
  106. package/src/components/ui/lightbox.tsx +0 -606
  107. package/src/components/ui/magnetic-button.tsx +0 -129
  108. package/src/components/ui/media-gallery.tsx +0 -612
  109. package/src/components/ui/pagination.tsx +0 -123
  110. package/src/components/ui/popover.tsx +0 -185
  111. package/src/components/ui/progress.tsx +0 -30
  112. package/src/components/ui/radio-group.tsx +0 -257
  113. package/src/components/ui/scroll-area.tsx +0 -47
  114. package/src/components/ui/select.tsx +0 -374
  115. package/src/components/ui/separator.tsx +0 -145
  116. package/src/components/ui/sheet.tsx +0 -139
  117. package/src/components/ui/skeleton.tsx +0 -20
  118. package/src/components/ui/slider.tsx +0 -354
  119. package/src/components/ui/spotlight-card.tsx +0 -119
  120. package/src/components/ui/switch.tsx +0 -86
  121. package/src/components/ui/table.tsx +0 -329
  122. package/src/components/ui/tabs.tsx +0 -198
  123. package/src/components/ui/textarea.tsx +0 -28
  124. package/src/components/ui/toast.tsx +0 -317
  125. package/src/components/ui/toggle.tsx +0 -119
  126. package/src/components/ui/tooltip.tsx +0 -151
  127. package/src/components/virtual-list/index.tsx +0 -668
  128. package/src/hooks/use-chart.ts +0 -205
  129. package/src/hooks/use-data-table.ts +0 -182
  130. package/src/hooks/use-docs-pro-access.ts +0 -13
  131. package/src/hooks/use-license-check.ts +0 -65
  132. package/src/hooks/use-subscription.ts +0 -19
  133. package/src/hooks/use-toast.ts +0 -15
  134. package/src/index.ts +0 -14
  135. package/src/lib/ai-providers.ts +0 -377
  136. package/src/lib/component-metadata.ts +0 -18
  137. package/src/lib/micro-interactions.ts +0 -255
  138. package/src/lib/paddle.ts +0 -17
  139. package/src/lib/utils.ts +0 -6
  140. package/src/patterns/login-form/index.tsx +0 -276
  141. package/src/patterns/login-form/types.ts +0 -67
  142. package/src/setupTests.ts +0 -41
  143. package/src/styles/advanced-chart.css +0 -239
  144. package/src/styles/calendar.css +0 -35
  145. package/src/styles/design-system.css +0 -363
  146. package/src/styles/index.css +0 -85
  147. package/src/styles/tailwind.css +0 -7
  148. package/src/styles/tokens.css +0 -455
  149. package/src/types/moonui.d.ts +0 -22
  150. package/src/types/next-auth.d.ts +0 -21
  151. package/src/use-intersection-observer.tsx +0 -154
  152. package/src/use-local-storage.tsx +0 -71
  153. package/src/use-paddle.ts +0 -138
  154. package/src/use-performance-optimizer.ts +0 -389
  155. package/src/use-pro-access.ts +0 -141
  156. package/src/use-scroll-animation.ts +0 -219
  157. package/src/use-subscription.ts +0 -37
  158. package/src/use-toast.ts +0 -32
  159. package/src/utils/chart-helpers.ts +0 -357
  160. package/src/utils/cn.ts +0 -6
  161. package/src/utils/data-processing.ts +0 -151
  162. package/src/utils/license-validator.tsx +0 -183
@@ -1,1046 +0,0 @@
1
- "use client"
2
-
3
- import React from 'react'
4
- import { motion, AnimatePresence } from 'framer-motion'
5
- import { Button } from '../ui/button'
6
- import { Badge } from '../ui/badge'
7
- import { Input } from '../ui/input'
8
- import { ScrollArea } from '../ui/scroll-area'
9
- import { Tabs, TabsContent, TabsList, TabsTrigger } from '../ui/tabs'
10
- import { Avatar, AvatarFallback, AvatarImage } from '../ui/avatar'
11
- import { Separator } from '../ui/separator'
12
- import {
13
- Activity,
14
- Download,
15
- Upload,
16
- Settings,
17
- Edit3,
18
- Save,
19
- X,
20
- Plus,
21
- RefreshCw,
22
- Share2,
23
- Filter,
24
- LayoutGrid,
25
- Palette,
26
- Search,
27
- Bell,
28
- Menu,
29
- ChevronRight,
30
- Sparkles,
31
- BarChart3,
32
- Users,
33
- DollarSign,
34
- TrendingUp,
35
- Calendar,
36
- Map,
37
- Table,
38
- Clock,
39
- Target,
40
- ArrowUpRight,
41
- CheckCircle,
42
- User,
43
- LogOut,
44
- Settings2,
45
- AlertCircle,
46
- Info,
47
- CheckCheck
48
- } from 'lucide-react'
49
- import { cn } from '../../lib/utils'
50
- import { DashboardGrid } from './dashboard-grid'
51
- import { TimeRangePicker } from './time-range-picker'
52
- import { MetricCard } from './widgets/metric-card'
53
- import { ChartWidget } from './widgets/chart-widget'
54
- import { ActivityFeed } from './widgets/activity-feed'
55
- import {
56
- Widget,
57
- DashboardConfig,
58
- DashboardTheme,
59
- TimeRange,
60
- MetricData,
61
- ChartData,
62
- ActivityItem,
63
- DashboardTemplate,
64
- WidgetType,
65
- DashboardNotification
66
- } from './types'
67
- import {
68
- DropdownMenu,
69
- DropdownMenuContent,
70
- DropdownMenuItem,
71
- DropdownMenuSeparator,
72
- DropdownMenuSub,
73
- DropdownMenuSubContent,
74
- DropdownMenuSubTrigger,
75
- DropdownMenuTrigger,
76
- } from '../ui/dropdown-menu'
77
- import {
78
- Dialog,
79
- DialogContent,
80
- DialogDescription,
81
- DialogHeader,
82
- DialogTitle,
83
- DialogTrigger,
84
- } from '../ui/dialog'
85
- import {
86
- Sheet,
87
- SheetContent,
88
- SheetDescription,
89
- SheetHeader,
90
- SheetTitle,
91
- SheetTrigger,
92
- } from '../ui/sheet'
93
-
94
- interface DashboardProps {
95
- config?: DashboardConfig
96
- widgets?: Widget[]
97
- templates?: DashboardTemplate[]
98
- onConfigChange?: (config: DashboardConfig) => void
99
- onWidgetAdd?: (widget: Omit<Widget, 'id'>) => void
100
- onWidgetRemove?: (widgetId: string) => void
101
- onWidgetUpdate?: (widgetId: string, updates: Partial<Widget>) => void
102
- onExport?: (format: 'json' | 'pdf' | 'png') => void
103
- onImport?: (file: File) => void
104
- className?: string
105
- showHeader?: boolean
106
- title?: string
107
- description?: string
108
- editable?: boolean
109
- realtime?: boolean
110
- glassmorphism?: boolean
111
-
112
- // Notification yönetimi
113
- notifications?: DashboardNotification[]
114
- onNotificationClick?: (notification: DashboardNotification) => void
115
- onNotificationMarkAsRead?: (notificationId: string) => void
116
- onNotificationMarkAllAsRead?: () => void
117
- onNotificationClear?: (notificationId: string) => void
118
- onNotificationClearAll?: () => void
119
-
120
- // User yönetimi
121
- user?: {
122
- name: string
123
- email?: string
124
- avatar?: string
125
- role?: string
126
- }
127
- userMenuItems?: Array<{
128
- id: string
129
- label: string
130
- icon?: React.ReactNode
131
- onClick?: () => void
132
- separator?: boolean
133
- }>
134
- onUserMenuClick?: () => void
135
- onProfileClick?: () => void
136
- onLogout?: () => void
137
-
138
- // Header actions
139
- onSearch?: (query: string) => void
140
- onThemeChange?: (theme: DashboardTheme) => void
141
- onMenuClick?: () => void
142
- onRefresh?: () => void
143
-
144
- // Custom header actions
145
- headerActions?: React.ReactNode
146
-
147
- // Time range yönetimi
148
- timeRange?: TimeRange
149
- onTimeRangeChange?: (range: TimeRange) => void
150
-
151
- // Custom branding
152
- logo?: React.ReactNode
153
- brandName?: string
154
- }
155
-
156
- // Dashboard template'leri
157
- const DASHBOARD_TEMPLATES: DashboardTemplate[] = [
158
- {
159
- id: 'analytics',
160
- name: 'Analytics Dashboard',
161
- description: 'Comprehensive analytics with metrics and charts',
162
- category: 'analytics',
163
- theme: 'analytics',
164
- widgets: [
165
- {
166
- type: 'metric',
167
- title: 'Total Revenue',
168
- size: { w: 3, h: 2 },
169
- position: { x: 0, y: 0 },
170
- data: {
171
- id: 'revenue',
172
- title: 'Total Revenue',
173
- value: 125430,
174
- change: { value: 12, type: 'increase', period: 'last month' },
175
- color: 'success',
176
- icon: <DollarSign className="h-4 w-4" />,
177
- sparkline: [100, 120, 115, 125, 130, 128, 132],
178
- unit: '$'
179
- }
180
- },
181
- {
182
- type: 'metric',
183
- title: 'Active Users',
184
- size: { w: 3, h: 2 },
185
- position: { x: 3, y: 0 },
186
- data: {
187
- id: 'users',
188
- title: 'Active Users',
189
- value: 2543,
190
- change: { value: 8, type: 'increase', period: 'last week' },
191
- color: 'primary',
192
- icon: <Users className="h-4 w-4" />,
193
- sparkline: [200, 220, 210, 230, 225, 240, 254]
194
- }
195
- },
196
- {
197
- type: 'chart',
198
- title: 'Revenue Trend',
199
- size: { w: 6, h: 4 },
200
- position: { x: 0, y: 2 },
201
- data: {
202
- type: 'area',
203
- data: [
204
- { name: 'Jan', revenue: 4000, profit: 2400 },
205
- { name: 'Feb', revenue: 3000, profit: 1398 },
206
- { name: 'Mar', revenue: 5000, profit: 3200 },
207
- { name: 'Apr', revenue: 4500, profit: 2900 },
208
- { name: 'May', revenue: 6000, profit: 3800 },
209
- { name: 'Jun', revenue: 5500, profit: 3400 }
210
- ]
211
- }
212
- },
213
- {
214
- type: 'activity',
215
- title: 'Recent Activity',
216
- size: { w: 3, h: 6 },
217
- position: { x: 9, y: 0 },
218
- data: {
219
- realtime: true,
220
- items: [
221
- {
222
- id: '1',
223
- type: 'success',
224
- title: 'completed a purchase',
225
- description: 'Order #12345 - $250.00',
226
- timestamp: new Date(Date.now() - 1000 * 60 * 5),
227
- user: { name: 'John Doe' }
228
- },
229
- {
230
- id: '2',
231
- type: 'info',
232
- title: 'signed up',
233
- description: 'New user registration',
234
- timestamp: new Date(Date.now() - 1000 * 60 * 15),
235
- user: { name: 'Jane Smith' }
236
- }
237
- ]
238
- }
239
- }
240
- ]
241
- },
242
- {
243
- id: 'sales',
244
- name: 'Sales Dashboard',
245
- description: 'Track sales performance and targets',
246
- category: 'sales',
247
- theme: 'sales',
248
- widgets: [
249
- // Sales-specific widgets
250
- ]
251
- },
252
- {
253
- id: 'monitoring',
254
- name: 'System Monitoring',
255
- description: 'Monitor system health and performance',
256
- category: 'operations',
257
- theme: 'monitoring',
258
- widgets: [
259
- // Monitoring widgets
260
- ]
261
- }
262
- ]
263
-
264
- // Widget türleri için ikonlar
265
- const WIDGET_TYPE_ICONS: Record<WidgetType, React.ReactNode> = {
266
- metric: <BarChart3 className="h-4 w-4" />,
267
- chart: <Activity className="h-4 w-4" />,
268
- table: <Table className="h-4 w-4" />,
269
- map: <Map className="h-4 w-4" />,
270
- activity: <Clock className="h-4 w-4" />,
271
- calendar: <Calendar className="h-4 w-4" />,
272
- progress: <Target className="h-4 w-4" />,
273
- comparison: <TrendingUp className="h-4 w-4" />
274
- }
275
-
276
- // Tema renkleri
277
- const THEME_COLORS: Record<DashboardTheme, string> = {
278
- analytics: 'from-blue-500/10 to-purple-500/10',
279
- sales: 'from-green-500/10 to-emerald-500/10',
280
- monitoring: 'from-orange-500/10 to-red-500/10',
281
- finance: 'from-indigo-500/10 to-blue-500/10',
282
- custom: 'from-gray-500/10 to-gray-600/10'
283
- }
284
-
285
- // Relative time formatter
286
- function formatRelativeTime(date: Date): string {
287
- const now = new Date();
288
- const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
289
-
290
- if (diffInSeconds < 60) return 'just now';
291
- if (diffInSeconds < 3600) return `${Math.floor(diffInSeconds / 60)}m ago`;
292
- if (diffInSeconds < 86400) return `${Math.floor(diffInSeconds / 3600)}h ago`;
293
- if (diffInSeconds < 604800) return `${Math.floor(diffInSeconds / 86400)}d ago`;
294
-
295
- return date.toLocaleDateString();
296
- }
297
-
298
- export function Dashboard({
299
- config,
300
- widgets: initialWidgets = [],
301
- templates = DASHBOARD_TEMPLATES,
302
- onConfigChange,
303
- onWidgetAdd,
304
- onWidgetRemove,
305
- onWidgetUpdate,
306
- onExport,
307
- onImport,
308
- className,
309
- showHeader = true,
310
- title = 'Dashboard',
311
- description = 'Real-time analytics and insights',
312
- editable = true,
313
- realtime = false,
314
- glassmorphism = true,
315
- notifications = [],
316
- onNotificationClick,
317
- onNotificationMarkAsRead,
318
- onNotificationMarkAllAsRead,
319
- onNotificationClear,
320
- onNotificationClearAll,
321
- user,
322
- userMenuItems,
323
- onUserMenuClick,
324
- onProfileClick,
325
- onLogout,
326
- onSearch,
327
- onThemeChange,
328
- onMenuClick,
329
- onRefresh,
330
- headerActions,
331
- timeRange: propTimeRange,
332
- onTimeRangeChange,
333
- logo,
334
- brandName
335
- }: DashboardProps) {
336
- // State yönetimi
337
- const [editMode, setEditMode] = React.useState(false)
338
- const [widgets, setWidgets] = React.useState<Widget[]>(initialWidgets)
339
- const [selectedTheme, setSelectedTheme] = React.useState<DashboardTheme>('analytics')
340
- const [timeRange, setTimeRange] = React.useState<TimeRange | undefined>(propTimeRange)
341
- const [searchQuery, setSearchQuery] = React.useState('')
342
- const [showWidgetLibrary, setShowWidgetLibrary] = React.useState(false)
343
- const [showTemplates, setShowTemplates] = React.useState(false)
344
- const [refreshing, setRefreshing] = React.useState(false)
345
- const [showNotifications, setShowNotifications] = React.useState(false)
346
-
347
- // initialWidgets değiştiğinde state'i güncelle
348
- React.useEffect(() => {
349
- setWidgets(initialWidgets)
350
- }, [initialWidgets])
351
-
352
- // propTimeRange değiştiğinde state'i güncelle
353
- React.useEffect(() => {
354
- if (propTimeRange) {
355
- setTimeRange(propTimeRange)
356
- }
357
- }, [propTimeRange])
358
-
359
- // WebSocket bağlantısı (real-time için)
360
- React.useEffect(() => {
361
- if (!realtime) return
362
-
363
- // Simüle edilmiş WebSocket bağlantısı
364
- const interval = setInterval(() => {
365
- // Widget'ları güncelle
366
- setWidgets(prev => prev.map(widget => {
367
- if (widget.type === 'metric' && widget.data) {
368
- const newValue = typeof widget.data.value === 'number'
369
- ? widget.data.value + Math.floor(Math.random() * 10 - 5)
370
- : widget.data.value
371
-
372
- return {
373
- ...widget,
374
- data: {
375
- ...widget.data,
376
- value: newValue,
377
- lastUpdated: new Date()
378
- }
379
- }
380
- }
381
- return widget
382
- }))
383
- }, 5000)
384
-
385
- return () => clearInterval(interval)
386
- }, [realtime])
387
-
388
- // Widget ekle
389
- const handleAddWidget = (type: WidgetType) => {
390
- const newWidget: Widget = {
391
- id: `widget-${Date.now()}`,
392
- type,
393
- title: `New ${type} Widget`,
394
- size: { w: 3, h: 3 },
395
- position: { x: 0, y: 0 },
396
- data: generateDefaultData(type)
397
- }
398
-
399
- setWidgets(prev => [...prev, newWidget])
400
- onWidgetAdd?.(newWidget)
401
- setShowWidgetLibrary(false)
402
- }
403
-
404
- // Template uygula
405
- const applyTemplate = (template: DashboardTemplate) => {
406
- const newWidgets = template.widgets.map((w, index) => ({
407
- ...w,
408
- id: `widget-${Date.now()}-${index}`,
409
- position: w.position || { x: (index * 3) % 12, y: Math.floor((index * 3) / 12) * 3 },
410
- size: w.size || { w: 3, h: 3 }
411
- }))
412
-
413
- setWidgets(newWidgets as Widget[])
414
- setSelectedTheme(template.theme)
415
- setShowTemplates(false)
416
- }
417
-
418
- // Varsayılan widget verisi oluştur
419
- const generateDefaultData = (type: WidgetType): any => {
420
- switch (type) {
421
- case 'metric':
422
- return {
423
- id: 'new-metric',
424
- title: 'New Metric',
425
- value: 0,
426
- icon: <BarChart3 className="h-4 w-4" />,
427
- color: 'primary'
428
- }
429
- case 'chart':
430
- return {
431
- type: 'line',
432
- data: [
433
- { name: 'Mon', value: 100 },
434
- { name: 'Tue', value: 120 },
435
- { name: 'Wed', value: 110 },
436
- { name: 'Thu', value: 130 },
437
- { name: 'Fri', value: 125 }
438
- ]
439
- }
440
- case 'activity':
441
- return {
442
- items: [],
443
- realtime: true
444
- }
445
- default:
446
- return {}
447
- }
448
- }
449
-
450
- // Widget kütüphanesi
451
- const WidgetLibrary = () => (
452
- <Sheet open={showWidgetLibrary} onOpenChange={setShowWidgetLibrary}>
453
- <SheetContent className={cn(
454
- "w-[400px] sm:w-[540px]",
455
- glassmorphism && "bg-background/95 backdrop-blur-md"
456
- )}>
457
- <SheetHeader>
458
- <SheetTitle>Widget Library</SheetTitle>
459
- <SheetDescription>
460
- Add widgets to customize your dashboard
461
- </SheetDescription>
462
- </SheetHeader>
463
-
464
- <div className="mt-6 space-y-4">
465
- <div className="relative">
466
- <Search className="absolute left-3 top-3 h-4 w-4 text-muted-foreground" />
467
- <Input
468
- placeholder="Search widgets..."
469
- value={searchQuery}
470
- onChange={(e) => {
471
- setSearchQuery(e.target.value);
472
- onSearch?.(e.target.value);
473
- }}
474
- className="pl-10"
475
- />
476
- </div>
477
-
478
- <ScrollArea className="h-[calc(100vh-200px)]">
479
- <div className="grid grid-cols-2 gap-4">
480
- {Object.entries(WIDGET_TYPE_ICONS)
481
- .filter(([type]) => type.toLowerCase().includes(searchQuery.toLowerCase()))
482
- .map(([type, icon]) => (
483
- <motion.div
484
- key={type}
485
- whileHover={{ scale: 1.02 }}
486
- whileTap={{ scale: 0.98 }}
487
- >
488
- <Button
489
- variant="outline"
490
- className="w-full h-24 flex-col gap-2"
491
- onClick={() => handleAddWidget(type as WidgetType)}
492
- >
493
- <div className="p-2 rounded-lg bg-muted">
494
- {icon}
495
- </div>
496
- <span className="capitalize text-sm">{type}</span>
497
- </Button>
498
- </motion.div>
499
- ))}
500
- </div>
501
- </ScrollArea>
502
- </div>
503
- </SheetContent>
504
- </Sheet>
505
- )
506
-
507
- // Template galerisi
508
- const TemplateGallery = () => (
509
- <Dialog open={showTemplates} onOpenChange={setShowTemplates}>
510
- <DialogContent className={cn(
511
- "max-w-4xl",
512
- glassmorphism && "bg-background/95 backdrop-blur-md"
513
- )}>
514
- <DialogHeader>
515
- <DialogTitle>Dashboard Templates</DialogTitle>
516
- <DialogDescription>
517
- Start with a pre-built template or create your own
518
- </DialogDescription>
519
- </DialogHeader>
520
-
521
- <Tabs defaultValue="all" className="mt-4">
522
- <TabsList>
523
- <TabsTrigger value="all">All Templates</TabsTrigger>
524
- <TabsTrigger value="analytics">Analytics</TabsTrigger>
525
- <TabsTrigger value="sales">Sales</TabsTrigger>
526
- <TabsTrigger value="operations">Operations</TabsTrigger>
527
- </TabsList>
528
-
529
- <TabsContent value="all" className="mt-4">
530
- <div className="grid grid-cols-3 gap-4">
531
- {templates.map((template) => (
532
- <motion.div
533
- key={template.id}
534
- whileHover={{ y: -4 }}
535
- className="cursor-pointer"
536
- onClick={() => applyTemplate(template)}
537
- >
538
- <div className={cn(
539
- "relative overflow-hidden rounded-lg border p-4 hover:shadow-lg transition-all",
540
- "bg-gradient-to-br", THEME_COLORS[template.theme]
541
- )}>
542
- {template.isPro && (
543
- <Badge className="absolute top-2 right-2" variant="secondary">
544
- PRO
545
- </Badge>
546
- )}
547
- <h3 className="font-semibold mb-1">{template.name}</h3>
548
- <p className="text-sm text-muted-foreground">
549
- {template.description}
550
- </p>
551
- <div className="mt-3 flex items-center gap-2 text-xs text-muted-foreground">
552
- <span>{template.widgets.length} widgets</span>
553
- <span>•</span>
554
- <span className="capitalize">{template.category}</span>
555
- </div>
556
- </div>
557
- </motion.div>
558
- ))}
559
- </div>
560
- </TabsContent>
561
- </Tabs>
562
- </DialogContent>
563
- </Dialog>
564
- )
565
-
566
- return (
567
- <motion.div
568
- className={cn(
569
- "w-full min-h-screen",
570
- glassmorphism && "bg-gradient-to-br",
571
- glassmorphism && THEME_COLORS[selectedTheme],
572
- className
573
- )}
574
- initial={{ opacity: 0 }}
575
- animate={{ opacity: 1 }}
576
- transition={{ duration: 0.5 }}
577
- >
578
- {/* Header */}
579
- {showHeader && (
580
- <motion.div
581
- className={cn(
582
- "sticky top-0 z-30 border-b",
583
- glassmorphism ? "bg-background/80 backdrop-blur-md" : "bg-background"
584
- )}
585
- initial={{ y: -50 }}
586
- animate={{ y: 0 }}
587
- transition={{ type: "spring", stiffness: 300, damping: 30 }}
588
- >
589
- <div className="px-6 py-4">
590
- <div className="flex items-center justify-between">
591
- <div className="flex items-center gap-4">
592
- <motion.div
593
- whileHover={{ scale: 1.05 }}
594
- whileTap={{ scale: 0.95 }}
595
- >
596
- <Button
597
- variant="ghost"
598
- size="sm"
599
- className="lg:hidden"
600
- onClick={onMenuClick}
601
- >
602
- <Menu className="h-5 w-5" />
603
- </Button>
604
- </motion.div>
605
-
606
- {/* Logo and Brand */}
607
- {(logo || brandName) && (
608
- <div className="flex items-center gap-2">
609
- {logo}
610
- {brandName && (
611
- <span className="font-semibold text-lg">{brandName}</span>
612
- )}
613
- </div>
614
- )}
615
-
616
- <div>
617
- <div className="flex items-center gap-2">
618
- <h1 className="text-2xl font-bold tracking-tight">{title}</h1>
619
- {realtime && (
620
- <Badge variant="secondary" className="animate-pulse">
621
- <span className="mr-1 h-1.5 w-1.5 rounded-full bg-green-500" />
622
- Real-time
623
- </Badge>
624
- )}
625
- </div>
626
- <p className="text-sm text-muted-foreground">{description}</p>
627
- </div>
628
- </div>
629
-
630
- {/* Header actions */}
631
- <div className="flex items-center gap-2">
632
- {/* Time range picker */}
633
- <TimeRangePicker
634
- value={timeRange}
635
- onChange={(range) => {
636
- setTimeRange(range);
637
- onTimeRangeChange?.(range);
638
- }}
639
- glassmorphism={glassmorphism}
640
- />
641
-
642
- {/* Notifications */}
643
- <DropdownMenu open={showNotifications} onOpenChange={setShowNotifications}>
644
- <DropdownMenuTrigger asChild>
645
- <Button variant="ghost" size="sm" className="relative h-9 w-9 p-0">
646
- <Bell className="h-5 w-5" />
647
- {notifications.filter(n => !n.read).length > 0 && (
648
- <span className="absolute -top-1 -right-1 min-w-[1rem] h-4 px-1 rounded-full bg-destructive text-[10px] font-medium text-destructive-foreground flex items-center justify-center">
649
- {notifications.filter(n => !n.read).length}
650
- </span>
651
- )}
652
- </Button>
653
- </DropdownMenuTrigger>
654
- <DropdownMenuContent
655
- align="end"
656
- className="w-80"
657
- sideOffset={8}
658
- >
659
- <div className="flex items-center justify-between px-4 py-2">
660
- <h4 className="text-sm font-semibold">Notifications</h4>
661
- {notifications.length > 0 && (
662
- <div className="flex items-center gap-2">
663
- <Button
664
- variant="ghost"
665
- size="sm"
666
- className="h-auto p-1 text-xs"
667
- onClick={() => onNotificationMarkAllAsRead?.()}
668
- >
669
- <CheckCheck className="h-3 w-3 mr-1" />
670
- Mark all read
671
- </Button>
672
- <Button
673
- variant="ghost"
674
- size="sm"
675
- className="h-auto p-1 text-xs"
676
- onClick={() => onNotificationClearAll?.()}
677
- >
678
- Clear all
679
- </Button>
680
- </div>
681
- )}
682
- </div>
683
- <Separator />
684
- <ScrollArea className="h-[400px]">
685
- {notifications.length === 0 ? (
686
- <div className="p-8 text-center text-sm text-muted-foreground">
687
- <Bell className="h-8 w-8 mx-auto mb-2 opacity-20" />
688
- <p>No notifications</p>
689
- </div>
690
- ) : (
691
- <div className="p-1">
692
- {notifications.map((notification) => {
693
- const Icon = notification.type === 'error' ? AlertCircle :
694
- notification.type === 'warning' ? AlertCircle :
695
- notification.type === 'success' ? CheckCircle :
696
- Info;
697
-
698
- return (
699
- <motion.div
700
- key={notification.id}
701
- initial={{ opacity: 0, x: -20 }}
702
- animate={{ opacity: 1, x: 0 }}
703
- className={cn(
704
- "flex items-start gap-3 p-3 rounded-lg cursor-pointer transition-colors",
705
- "hover:bg-muted/50",
706
- !notification.read && "bg-muted/30"
707
- )}
708
- onClick={() => {
709
- onNotificationClick?.(notification);
710
- if (!notification.read) {
711
- onNotificationMarkAsRead?.(notification.id);
712
- }
713
- }}
714
- >
715
- <div className={cn(
716
- "mt-0.5 p-1.5 rounded-full",
717
- notification.type === 'error' && "bg-destructive/10 text-destructive",
718
- notification.type === 'warning' && "bg-yellow-500/10 text-yellow-600 dark:text-yellow-500",
719
- notification.type === 'success' && "bg-green-500/10 text-green-600 dark:text-green-500",
720
- notification.type === 'info' && "bg-blue-500/10 text-blue-600 dark:text-blue-500"
721
- )}>
722
- <Icon className="h-3.5 w-3.5" />
723
- </div>
724
- <div className="flex-1 space-y-1">
725
- <p className="text-sm font-medium leading-none">
726
- {notification.title}
727
- </p>
728
- {notification.message && (
729
- <p className="text-xs text-muted-foreground">
730
- {notification.message}
731
- </p>
732
- )}
733
- <p className="text-xs text-muted-foreground">
734
- {formatRelativeTime(notification.timestamp)}
735
- </p>
736
- </div>
737
- <Button
738
- variant="ghost"
739
- size="sm"
740
- className="h-6 w-6 p-0"
741
- onClick={(e) => {
742
- e.stopPropagation();
743
- onNotificationClear?.(notification.id);
744
- }}
745
- >
746
- <X className="h-3 w-3" />
747
- </Button>
748
- </motion.div>
749
- );
750
- })}
751
- </div>
752
- )}
753
- </ScrollArea>
754
- </DropdownMenuContent>
755
- </DropdownMenu>
756
-
757
- {/* Theme selector */}
758
- <DropdownMenu>
759
- <DropdownMenuTrigger asChild>
760
- <Button variant="ghost" size="sm">
761
- <Palette className="h-4 w-4" />
762
- </Button>
763
- </DropdownMenuTrigger>
764
- <DropdownMenuContent align="end">
765
- <DropdownMenuItem onClick={() => {
766
- setSelectedTheme('analytics');
767
- onThemeChange?.('analytics');
768
- }}>
769
- <div className="flex items-center gap-2">
770
- <div className="h-4 w-4 rounded bg-gradient-to-br from-blue-500 to-purple-500" />
771
- Analytics
772
- </div>
773
- </DropdownMenuItem>
774
- <DropdownMenuItem onClick={() => {
775
- setSelectedTheme('sales');
776
- onThemeChange?.('sales');
777
- }}>
778
- <div className="flex items-center gap-2">
779
- <div className="h-4 w-4 rounded bg-gradient-to-br from-green-500 to-emerald-500" />
780
- Sales
781
- </div>
782
- </DropdownMenuItem>
783
- <DropdownMenuItem onClick={() => {
784
- setSelectedTheme('monitoring');
785
- onThemeChange?.('monitoring');
786
- }}>
787
- <div className="flex items-center gap-2">
788
- <div className="h-4 w-4 rounded bg-gradient-to-br from-orange-500 to-red-500" />
789
- Monitoring
790
- </div>
791
- </DropdownMenuItem>
792
- </DropdownMenuContent>
793
- </DropdownMenu>
794
-
795
- {/* Custom header actions */}
796
- {headerActions}
797
-
798
- {/* User Profile */}
799
- {user && (
800
- <DropdownMenu>
801
- <DropdownMenuTrigger asChild>
802
- <Button variant="ghost" size="sm" className="relative h-8 w-8 rounded-full">
803
- <Avatar className="h-8 w-8">
804
- <AvatarImage src={user.avatar} alt={user.name} />
805
- <AvatarFallback>
806
- {user.name.split(' ').map(n => n[0]).join('').toUpperCase()}
807
- </AvatarFallback>
808
- </Avatar>
809
- </Button>
810
- </DropdownMenuTrigger>
811
- <DropdownMenuContent align="end" className="w-56">
812
- <div className="flex items-center justify-start gap-2 p-2">
813
- <div className="flex flex-col space-y-1 leading-none">
814
- {user.name && (
815
- <p className="font-medium">{user.name}</p>
816
- )}
817
- {user.email && (
818
- <p className="text-xs text-muted-foreground">
819
- {user.email}
820
- </p>
821
- )}
822
- </div>
823
- </div>
824
- <DropdownMenuSeparator />
825
- {userMenuItems ? (
826
- // Custom menu items
827
- userMenuItems.map((item, index) => (
828
- item.separator ? (
829
- <DropdownMenuSeparator key={item.id || `sep-${index}`} />
830
- ) : (
831
- <DropdownMenuItem
832
- key={item.id}
833
- onClick={() => item.onClick?.()}
834
- >
835
- {item.icon && <span className="mr-2">{item.icon}</span>}
836
- {item.label}
837
- </DropdownMenuItem>
838
- )
839
- ))
840
- ) : (
841
- // Default menu items
842
- <>
843
- <DropdownMenuItem onClick={() => onProfileClick?.()}>
844
- <User className="mr-2 h-4 w-4" />
845
- Profile
846
- </DropdownMenuItem>
847
- <DropdownMenuItem onClick={() => onUserMenuClick?.()}>
848
- <Settings2 className="mr-2 h-4 w-4" />
849
- Settings
850
- </DropdownMenuItem>
851
- <DropdownMenuSeparator />
852
- <DropdownMenuItem onClick={() => onLogout?.()}>
853
- <LogOut className="mr-2 h-4 w-4" />
854
- Log out
855
- </DropdownMenuItem>
856
- </>
857
- )}
858
- </DropdownMenuContent>
859
- </DropdownMenu>
860
- )}
861
-
862
- {/* More actions */}
863
- <DropdownMenu>
864
- <DropdownMenuTrigger asChild>
865
- <Button variant="outline" size="sm">
866
- <Settings className="h-4 w-4 mr-2" />
867
- Actions
868
- </Button>
869
- </DropdownMenuTrigger>
870
- <DropdownMenuContent align="end" className="w-48">
871
- {editable && (
872
- <>
873
- <DropdownMenuItem onClick={() => setEditMode(!editMode)}>
874
- <Edit3 className="mr-2 h-4 w-4" />
875
- {editMode ? 'Exit Edit Mode' : 'Edit Layout'}
876
- </DropdownMenuItem>
877
- <DropdownMenuItem onClick={() => setShowWidgetLibrary(true)}>
878
- <Plus className="mr-2 h-4 w-4" />
879
- Add Widget
880
- </DropdownMenuItem>
881
- <DropdownMenuItem onClick={() => setShowTemplates(true)}>
882
- <LayoutGrid className="mr-2 h-4 w-4" />
883
- Templates
884
- </DropdownMenuItem>
885
- <DropdownMenuSeparator />
886
- </>
887
- )}
888
-
889
- <DropdownMenuSub>
890
- <DropdownMenuSubTrigger>
891
- <Download className="mr-2 h-4 w-4" />
892
- Export
893
- </DropdownMenuSubTrigger>
894
- <DropdownMenuSubContent>
895
- <DropdownMenuItem onClick={() => onExport?.('json')}>
896
- As JSON
897
- </DropdownMenuItem>
898
- <DropdownMenuItem onClick={() => onExport?.('pdf')}>
899
- As PDF
900
- </DropdownMenuItem>
901
- <DropdownMenuItem onClick={() => onExport?.('png')}>
902
- As Image
903
- </DropdownMenuItem>
904
- </DropdownMenuSubContent>
905
- </DropdownMenuSub>
906
-
907
- <DropdownMenuItem>
908
- <Upload className="mr-2 h-4 w-4" />
909
- Import
910
- </DropdownMenuItem>
911
-
912
- <DropdownMenuSeparator />
913
-
914
- <DropdownMenuItem onClick={() => {
915
- setRefreshing(true);
916
- onRefresh?.();
917
- setTimeout(() => setRefreshing(false), 1000);
918
- }}>
919
- <RefreshCw className="mr-2 h-4 w-4" />
920
- Refresh Data
921
- </DropdownMenuItem>
922
-
923
- <DropdownMenuItem>
924
- <Share2 className="mr-2 h-4 w-4" />
925
- Share Dashboard
926
- </DropdownMenuItem>
927
- </DropdownMenuContent>
928
- </DropdownMenu>
929
- </div>
930
- </div>
931
- </div>
932
-
933
- {/* Edit mode banner */}
934
- <AnimatePresence>
935
- {editMode && (
936
- <motion.div
937
- initial={{ height: 0, opacity: 0 }}
938
- animate={{ height: "auto", opacity: 1 }}
939
- exit={{ height: 0, opacity: 0 }}
940
- className="bg-primary/10 border-t border-primary/20"
941
- >
942
- <div className="px-6 py-2 flex items-center justify-between">
943
- <div className="flex items-center gap-2 text-sm">
944
- <Sparkles className="h-4 w-4 text-primary" />
945
- <span>Edit mode enabled - Drag widgets to rearrange</span>
946
- </div>
947
- <div className="flex items-center gap-2">
948
- <Button
949
- variant="ghost"
950
- size="sm"
951
- onClick={() => setEditMode(false)}
952
- >
953
- <X className="h-4 w-4 mr-1" />
954
- Cancel
955
- </Button>
956
- <Button
957
- variant="primary"
958
- size="sm"
959
- onClick={() => {
960
- setEditMode(false)
961
- // Save layout changes
962
- }}
963
- >
964
- <Save className="h-4 w-4 mr-1" />
965
- Save Changes
966
- </Button>
967
- </div>
968
- </div>
969
- </motion.div>
970
- )}
971
- </AnimatePresence>
972
- </motion.div>
973
- )}
974
-
975
- {/* Main content */}
976
- <div className="p-6">
977
- {widgets.length === 0 ? (
978
- // Empty state
979
- <motion.div
980
- initial={{ opacity: 0, scale: 0.9 }}
981
- animate={{ opacity: 1, scale: 1 }}
982
- className="flex flex-col items-center justify-center min-h-[400px] text-center"
983
- >
984
- <div className={cn(
985
- "p-4 rounded-full mb-4",
986
- glassmorphism ? "bg-background/60 backdrop-blur-sm" : "bg-muted"
987
- )}>
988
- <LayoutGrid className="h-8 w-8 text-muted-foreground" />
989
- </div>
990
- <h3 className="text-lg font-semibold mb-2">No widgets added yet</h3>
991
- <p className="text-muted-foreground mb-4">
992
- Start by adding widgets or choosing a template
993
- </p>
994
- <div className="flex gap-2">
995
- <Button onClick={() => setShowWidgetLibrary(true)}>
996
- <Plus className="h-4 w-4 mr-2" />
997
- Add Widget
998
- </Button>
999
- <Button variant="outline" onClick={() => setShowTemplates(true)}>
1000
- <LayoutGrid className="h-4 w-4 mr-2" />
1001
- Browse Templates
1002
- </Button>
1003
- </div>
1004
- </motion.div>
1005
- ) : (
1006
- // Dashboard grid
1007
- <DashboardGrid
1008
- widgets={widgets}
1009
- onLayoutChange={(layout) => {
1010
- // Update widget positions
1011
- const updatedWidgets = widgets.map(widget => {
1012
- const layoutItem = layout.find(l => l.i === widget.id)
1013
- if (layoutItem) {
1014
- return {
1015
- ...widget,
1016
- position: { x: layoutItem.x, y: layoutItem.y },
1017
- size: { ...widget.size, w: layoutItem.w, h: layoutItem.h }
1018
- }
1019
- }
1020
- return widget
1021
- })
1022
- setWidgets(updatedWidgets)
1023
- }}
1024
- onWidgetRemove={(widgetId) => {
1025
- setWidgets(prev => prev.filter(w => w.id !== widgetId))
1026
- onWidgetRemove?.(widgetId)
1027
- }}
1028
- onWidgetAction={(widgetId, action, data) => {
1029
- console.log('Widget action:', widgetId, action, data)
1030
- // Handle widget actions
1031
- }}
1032
- editMode={editMode}
1033
- glassmorphism={glassmorphism}
1034
- />
1035
- )}
1036
- </div>
1037
-
1038
- {/* Modals */}
1039
- <WidgetLibrary />
1040
- <TemplateGallery />
1041
- </motion.div>
1042
- )
1043
- }
1044
-
1045
- export type { Widget, MetricData, ChartData, ActivityItem, ProgressData, ComparisonData } from './types'
1046
- export default Dashboard