@moontra/moonui-pro 2.20.2 → 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 (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 +176 -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,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