@moontra/moonui-pro 2.4.6 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moontra/moonui-pro",
3
- "version": "2.4.6",
3
+ "version": "2.5.0",
4
4
  "description": "Premium React components for MoonUI - Advanced UI library with 50+ pro components including performance, interactive, and gesture components",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -83,6 +83,7 @@
83
83
  "@radix-ui/react-dropdown-menu": "^2.1.15",
84
84
  "@radix-ui/react-label": "^2.1.7",
85
85
  "@radix-ui/react-popover": "^1.1.14",
86
+ "@radix-ui/react-scroll-area": "^1.2.9",
86
87
  "@radix-ui/react-select": "^2.2.5",
87
88
  "@radix-ui/react-separator": "^1.1.7",
88
89
  "@radix-ui/react-slot": "^1.2.3",
@@ -96,7 +97,9 @@
96
97
  "date-fns": "^3.6.0",
97
98
  "framer-motion": "^11.11.17",
98
99
  "lucide-react": "^0.525.0",
100
+ "react-day-picker": "^9.8.0",
99
101
  "react-dropzone": "^14.3.5",
102
+ "react-grid-layout": "^1.5.2",
100
103
  "react-hook-form": "^7.53.2",
101
104
  "react-intersection-observer": "^9.13.1",
102
105
  "react-virtualized-auto-sizer": "^1.0.24",
@@ -340,15 +340,20 @@ export function AdvancedChart({
340
340
 
341
341
  // Calculate trend for the first series
342
342
  const trend = React.useMemo(() => {
343
- if (!data.length || !series.length) return null
343
+ if (!data || !Array.isArray(data) || !data.length || !series || !Array.isArray(series) || !series.length) return null
344
344
 
345
345
  const firstSeries = series[0]
346
+ if (!firstSeries || !firstSeries.dataKey) return null
347
+
346
348
  const values = data.map(d => Number(d[firstSeries.dataKey])).filter(v => !isNaN(v))
347
349
 
348
350
  if (values.length < 2) return null
349
351
 
350
352
  const first = values[0]
351
353
  const last = values[values.length - 1]
354
+
355
+ if (first === 0) return null // Avoid division by zero
356
+
352
357
  const change = ((last - first) / first) * 100
353
358
 
354
359
  return {
@@ -411,6 +416,11 @@ export function AdvancedChart({
411
416
  )
412
417
 
413
418
  const renderChart = () => {
419
+ // Güvenlik kontrolleri
420
+ if (!data || !Array.isArray(data) || !series || !Array.isArray(series)) {
421
+ return <div className="flex items-center justify-center h-full text-muted-foreground">No data available</div>
422
+ }
423
+
414
424
  const commonProps = {
415
425
  data,
416
426
  width: typeof width === 'string' ? undefined : width,
@@ -0,0 +1,327 @@
1
+ "use client"
2
+
3
+ import React from 'react'
4
+ import { motion, AnimatePresence } from 'framer-motion'
5
+ import { cn } from '../../lib/utils'
6
+ import { Widget } from './types'
7
+ import { MetricCard } from './widgets/metric-card'
8
+ import { ChartWidget } from './widgets/chart-widget'
9
+ import { ActivityFeed } from './widgets/activity-feed'
10
+ import GridLayout, { Layout, Layouts } from 'react-grid-layout'
11
+ import 'react-grid-layout/css/styles.css'
12
+ import 'react-resizable/css/styles.css'
13
+ import {
14
+ Grip,
15
+ X,
16
+ Maximize2,
17
+ Minimize2,
18
+ Lock,
19
+ Unlock,
20
+ Settings
21
+ } from 'lucide-react'
22
+ import { Button } from '../ui/button'
23
+
24
+ interface DashboardGridProps {
25
+ widgets: Widget[]
26
+ onLayoutChange?: (layout: Layout[]) => void
27
+ onWidgetRemove?: (widgetId: string) => void
28
+ onWidgetAction?: (widgetId: string, action: string, data?: any) => void
29
+ editMode?: boolean
30
+ className?: string
31
+ glassmorphism?: boolean
32
+ breakpoints?: { lg: number; md: number; sm: number; xs: number; xxs: number }
33
+ cols?: { lg: number; md: number; sm: number; xs: number; xxs: number }
34
+ rowHeight?: number
35
+ margin?: [number, number]
36
+ containerPadding?: [number, number]
37
+ }
38
+
39
+ export function DashboardGrid({
40
+ widgets,
41
+ onLayoutChange,
42
+ onWidgetRemove,
43
+ onWidgetAction,
44
+ editMode = false,
45
+ className,
46
+ glassmorphism = false,
47
+ breakpoints = { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
48
+ cols = { lg: 12, md: 10, sm: 6, xs: 4, xxs: 2 },
49
+ rowHeight = 60,
50
+ margin = [16, 16],
51
+ containerPadding = [0, 0]
52
+ }: DashboardGridProps) {
53
+ const [layouts, setLayouts] = React.useState<Layouts>({})
54
+ const [currentBreakpoint, setCurrentBreakpoint] = React.useState('lg')
55
+ const [lockedWidgets, setLockedWidgets] = React.useState<Set<string>>(new Set())
56
+ const [fullscreenWidget, setFullscreenWidget] = React.useState<string | null>(null)
57
+
58
+ // Layout oluştur
59
+ const generateLayout = (): Layout[] => {
60
+ return widgets.map((widget) => ({
61
+ i: widget.id,
62
+ x: widget.position.x,
63
+ y: widget.position.y,
64
+ w: widget.size.w,
65
+ h: widget.size.h,
66
+ minW: widget.size.minW || 2,
67
+ maxW: widget.size.maxW || 12,
68
+ minH: widget.size.minH || 2,
69
+ maxH: widget.size.maxH || 8,
70
+ isDraggable: editMode && !lockedWidgets.has(widget.id) && widget.permissions?.canMove !== false,
71
+ isResizable: editMode && !lockedWidgets.has(widget.id) && widget.permissions?.canResize !== false,
72
+ }))
73
+ }
74
+
75
+ // Widget kilit durumunu değiştir
76
+ const toggleWidgetLock = (widgetId: string) => {
77
+ setLockedWidgets(prev => {
78
+ const newSet = new Set(prev)
79
+ if (newSet.has(widgetId)) {
80
+ newSet.delete(widgetId)
81
+ } else {
82
+ newSet.add(widgetId)
83
+ }
84
+ return newSet
85
+ })
86
+ }
87
+
88
+ // Widget'ı tam ekran yap
89
+ const toggleFullscreen = (widgetId: string) => {
90
+ if (fullscreenWidget === widgetId) {
91
+ setFullscreenWidget(null)
92
+ } else {
93
+ setFullscreenWidget(widgetId)
94
+ }
95
+ }
96
+
97
+ // Widget render
98
+ const renderWidget = (widget: Widget) => {
99
+ const isLocked = lockedWidgets.has(widget.id)
100
+ const isFullscreen = fullscreenWidget === widget.id
101
+
102
+ const widgetContent = () => {
103
+ switch (widget.type) {
104
+ case 'metric':
105
+ return (
106
+ <MetricCard
107
+ data={widget.data}
108
+ onAction={(action) => onWidgetAction?.(widget.id, action)}
109
+ glassmorphism={glassmorphism}
110
+ />
111
+ )
112
+
113
+ case 'chart':
114
+ return (
115
+ <ChartWidget
116
+ id={widget.id}
117
+ title={widget.title}
118
+ description={widget.description}
119
+ data={widget.data}
120
+ loading={widget.loading}
121
+ glassmorphism={glassmorphism}
122
+ onAction={(action, data) => onWidgetAction?.(widget.id, action, data)}
123
+ />
124
+ )
125
+
126
+ case 'activity':
127
+ return (
128
+ <ActivityFeed
129
+ items={widget.data?.items || []}
130
+ title={widget.title}
131
+ loading={widget.loading}
132
+ glassmorphism={glassmorphism}
133
+ realtime={widget.data?.realtime}
134
+ onAction={(action, data) => onWidgetAction?.(widget.id, action, data)}
135
+ />
136
+ )
137
+
138
+ default:
139
+ return (
140
+ <div className="flex items-center justify-center h-full text-muted-foreground">
141
+ Widget type not supported: {widget.type}
142
+ </div>
143
+ )
144
+ }
145
+ }
146
+
147
+ return (
148
+ <motion.div
149
+ key={widget.id}
150
+ className={cn(
151
+ "relative group h-full",
152
+ isFullscreen && "!fixed !inset-4 !z-50 !h-auto !w-auto"
153
+ )}
154
+ layout={!isFullscreen}
155
+ transition={{ duration: 0.2 }}
156
+ >
157
+ {/* Widget içeriği */}
158
+ <div className="h-full">
159
+ {widgetContent()}
160
+ </div>
161
+
162
+ {/* Edit mode kontrolleri */}
163
+ {editMode && !isFullscreen && (
164
+ <motion.div
165
+ initial={{ opacity: 0 }}
166
+ animate={{ opacity: 1 }}
167
+ className="absolute top-2 right-2 z-10 opacity-0 group-hover:opacity-100 transition-opacity"
168
+ >
169
+ <div className={cn(
170
+ "flex items-center gap-1 p-1 rounded-lg",
171
+ glassmorphism ? "bg-background/80 backdrop-blur-sm" : "bg-background/95",
172
+ "border shadow-sm"
173
+ )}>
174
+ {/* Drag handle */}
175
+ {!isLocked && (
176
+ <div className="drag-handle cursor-move p-1 hover:bg-muted rounded">
177
+ <Grip className="h-4 w-4" />
178
+ </div>
179
+ )}
180
+
181
+ {/* Lock/Unlock */}
182
+ <Button
183
+ variant="ghost"
184
+ size="sm"
185
+ className="h-6 w-6 p-0"
186
+ onClick={() => toggleWidgetLock(widget.id)}
187
+ >
188
+ {isLocked ? (
189
+ <Lock className="h-3 w-3" />
190
+ ) : (
191
+ <Unlock className="h-3 w-3" />
192
+ )}
193
+ </Button>
194
+
195
+ {/* Fullscreen */}
196
+ <Button
197
+ variant="ghost"
198
+ size="sm"
199
+ className="h-6 w-6 p-0"
200
+ onClick={() => toggleFullscreen(widget.id)}
201
+ >
202
+ <Maximize2 className="h-3 w-3" />
203
+ </Button>
204
+
205
+ {/* Settings */}
206
+ <Button
207
+ variant="ghost"
208
+ size="sm"
209
+ className="h-6 w-6 p-0"
210
+ onClick={() => onWidgetAction?.(widget.id, 'settings')}
211
+ >
212
+ <Settings className="h-3 w-3" />
213
+ </Button>
214
+
215
+ {/* Remove */}
216
+ {widget.permissions?.canDelete !== false && (
217
+ <Button
218
+ variant="ghost"
219
+ size="sm"
220
+ className="h-6 w-6 p-0 text-destructive hover:text-destructive"
221
+ onClick={() => onWidgetRemove?.(widget.id)}
222
+ >
223
+ <X className="h-3 w-3" />
224
+ </Button>
225
+ )}
226
+ </div>
227
+ </motion.div>
228
+ )}
229
+
230
+ {/* Fullscreen kontrolleri */}
231
+ {isFullscreen && (
232
+ <motion.div
233
+ initial={{ opacity: 0, y: -10 }}
234
+ animate={{ opacity: 1, y: 0 }}
235
+ className="absolute top-4 right-4 z-10"
236
+ >
237
+ <Button
238
+ variant="outline"
239
+ size="sm"
240
+ onClick={() => toggleFullscreen(widget.id)}
241
+ >
242
+ <Minimize2 className="h-4 w-4 mr-2" />
243
+ Exit Fullscreen
244
+ </Button>
245
+ </motion.div>
246
+ )}
247
+ </motion.div>
248
+ )
249
+ }
250
+
251
+ return (
252
+ <div className={cn("w-full", className)}>
253
+ <AnimatePresence>
254
+ {fullscreenWidget ? (
255
+ // Fullscreen widget
256
+ <motion.div
257
+ initial={{ opacity: 0 }}
258
+ animate={{ opacity: 1 }}
259
+ exit={{ opacity: 0 }}
260
+ className="fixed inset-0 z-40 bg-background"
261
+ >
262
+ {widgets
263
+ .filter(w => w.id === fullscreenWidget)
264
+ .map(renderWidget)}
265
+ </motion.div>
266
+ ) : (
267
+ // Grid layout
268
+ <GridLayout
269
+ className="layout"
270
+ layout={generateLayout()}
271
+ cols={cols[currentBreakpoint as keyof typeof cols] || cols.lg}
272
+ rowHeight={rowHeight}
273
+ width={1200}
274
+ margin={margin}
275
+ containerPadding={containerPadding}
276
+ onLayoutChange={(layout) => {
277
+ onLayoutChange?.(layout)
278
+ }}
279
+ onBreakpointChange={(breakpoint) => {
280
+ setCurrentBreakpoint(breakpoint)
281
+ }}
282
+ draggableHandle=".drag-handle"
283
+ isDraggable={editMode}
284
+ isResizable={editMode}
285
+ compactType="vertical"
286
+ preventCollision={false}
287
+ >
288
+ {widgets.map(widget => (
289
+ <div key={widget.id}>
290
+ {renderWidget(widget)}
291
+ </div>
292
+ ))}
293
+ </GridLayout>
294
+ )}
295
+ </AnimatePresence>
296
+
297
+ {/* Grid çizgileri (edit mode) */}
298
+ {editMode && !fullscreenWidget && (
299
+ <motion.div
300
+ initial={{ opacity: 0 }}
301
+ animate={{ opacity: 0.1 }}
302
+ className="absolute inset-0 pointer-events-none"
303
+ style={{
304
+ backgroundImage: `
305
+ repeating-linear-gradient(
306
+ 0deg,
307
+ var(--border) 0px,
308
+ transparent 1px,
309
+ transparent ${rowHeight + margin[1]}px,
310
+ var(--border) ${rowHeight + margin[1]}px
311
+ ),
312
+ repeating-linear-gradient(
313
+ 90deg,
314
+ var(--border) 0px,
315
+ transparent 1px,
316
+ transparent ${100 / cols[currentBreakpoint as keyof typeof cols]}%,
317
+ var(--border) ${100 / cols[currentBreakpoint as keyof typeof cols]}%
318
+ )
319
+ `
320
+ }}
321
+ />
322
+ )}
323
+ </div>
324
+ )
325
+ }
326
+
327
+ export default DashboardGrid
@@ -0,0 +1,308 @@
1
+ "use client"
2
+
3
+ import React from 'react'
4
+ import { Dashboard } from './index'
5
+ import { Widget, MetricData, ChartData, ActivityItem } from './types'
6
+ import {
7
+ Users,
8
+ DollarSign,
9
+ ShoppingCart,
10
+ TrendingUp,
11
+ Package,
12
+ CreditCard,
13
+ Activity,
14
+ AlertCircle
15
+ } from 'lucide-react'
16
+
17
+ // Örnek metrik verileri
18
+ const sampleMetrics: MetricData[] = [
19
+ {
20
+ id: 'revenue',
21
+ title: 'Total Revenue',
22
+ value: 54234,
23
+ unit: '$',
24
+ change: { value: 12.5, type: 'increase', period: 'last month' },
25
+ icon: <DollarSign className="h-4 w-4" />,
26
+ color: 'success',
27
+ sparkline: [30, 40, 35, 50, 49, 60, 70, 91, 125],
28
+ target: 60000,
29
+ forecast: 58500
30
+ },
31
+ {
32
+ id: 'users',
33
+ title: 'Active Users',
34
+ value: 2453,
35
+ change: { value: 8.2, type: 'increase', period: 'last week' },
36
+ icon: <Users className="h-4 w-4" />,
37
+ color: 'primary',
38
+ sparkline: [200, 220, 210, 230, 225, 240, 254, 260, 245]
39
+ },
40
+ {
41
+ id: 'orders',
42
+ title: 'New Orders',
43
+ value: 846,
44
+ change: { value: 3.1, type: 'decrease', period: 'yesterday' },
45
+ icon: <ShoppingCart className="h-4 w-4" />,
46
+ color: 'warning',
47
+ sparkline: [80, 85, 90, 88, 85, 82, 84, 86, 84]
48
+ },
49
+ {
50
+ id: 'conversion',
51
+ title: 'Conversion Rate',
52
+ value: '3.24%',
53
+ change: { value: 0.5, type: 'increase', period: 'last month' },
54
+ icon: <TrendingUp className="h-4 w-4" />,
55
+ color: 'info',
56
+ sparkline: [2.8, 2.9, 3.0, 2.95, 3.1, 3.15, 3.2, 3.22, 3.24]
57
+ }
58
+ ]
59
+
60
+ // Örnek chart verileri
61
+ const revenueChartData: ChartData = {
62
+ type: 'area',
63
+ data: [
64
+ { name: 'Jan', revenue: 4000, profit: 2400, expenses: 1600 },
65
+ { name: 'Feb', revenue: 3000, profit: 1398, expenses: 1602 },
66
+ { name: 'Mar', revenue: 5000, profit: 3200, expenses: 1800 },
67
+ { name: 'Apr', revenue: 4500, profit: 2900, expenses: 1600 },
68
+ { name: 'May', revenue: 6000, profit: 3800, expenses: 2200 },
69
+ { name: 'Jun', revenue: 5500, profit: 3400, expenses: 2100 },
70
+ { name: 'Jul', revenue: 7000, profit: 4200, expenses: 2800 }
71
+ ]
72
+ }
73
+
74
+ const salesByProductData: ChartData = {
75
+ type: 'pie',
76
+ data: [
77
+ { name: 'Product A', value: 35 },
78
+ { name: 'Product B', value: 25 },
79
+ { name: 'Product C', value: 20 },
80
+ { name: 'Product D', value: 15 },
81
+ { name: 'Product E', value: 5 }
82
+ ]
83
+ }
84
+
85
+ const performanceData: ChartData = {
86
+ type: 'radar',
87
+ data: [
88
+ { subject: 'Sales', A: 120, B: 110, fullMark: 150 },
89
+ { subject: 'Marketing', A: 98, B: 130, fullMark: 150 },
90
+ { subject: 'Development', A: 86, B: 130, fullMark: 150 },
91
+ { subject: 'Customer Support', A: 99, B: 100, fullMark: 150 },
92
+ { subject: 'Technology', A: 85, B: 90, fullMark: 150 },
93
+ { subject: 'HR', A: 65, B: 85, fullMark: 150 }
94
+ ]
95
+ }
96
+
97
+ // Örnek aktivite verileri
98
+ const sampleActivities: ActivityItem[] = [
99
+ {
100
+ id: '1',
101
+ type: 'success',
102
+ title: 'completed a purchase',
103
+ description: 'Order #12345 - Premium Plan ($299)',
104
+ timestamp: new Date(Date.now() - 1000 * 60 * 5),
105
+ user: { name: 'John Doe', avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=John' },
106
+ icon: <CreditCard className="h-4 w-4" />
107
+ },
108
+ {
109
+ id: '2',
110
+ type: 'info',
111
+ title: 'deployed new version',
112
+ description: 'v2.1.0 deployed to production',
113
+ timestamp: new Date(Date.now() - 1000 * 60 * 15),
114
+ user: { name: 'Sarah Chen' },
115
+ icon: <Package className="h-4 w-4" />
116
+ },
117
+ {
118
+ id: '3',
119
+ type: 'warning',
120
+ title: 'high server load detected',
121
+ description: 'CPU usage above 80% on server-02',
122
+ timestamp: new Date(Date.now() - 1000 * 60 * 30),
123
+ icon: <AlertCircle className="h-4 w-4" />
124
+ },
125
+ {
126
+ id: '4',
127
+ type: 'success',
128
+ title: 'new user registered',
129
+ description: 'Welcome email sent',
130
+ timestamp: new Date(Date.now() - 1000 * 60 * 45),
131
+ user: { name: 'Mike Johnson' }
132
+ },
133
+ {
134
+ id: '5',
135
+ type: 'error',
136
+ title: 'payment failed',
137
+ description: 'Card declined - Order #12346',
138
+ timestamp: new Date(Date.now() - 1000 * 60 * 60),
139
+ user: { name: 'Emma Wilson' }
140
+ }
141
+ ]
142
+
143
+ // Örnek widget'lar
144
+ const sampleWidgets: Widget[] = [
145
+ // Metrik widget'ları
146
+ {
147
+ id: 'metric-revenue',
148
+ type: 'metric',
149
+ title: 'Revenue',
150
+ size: { w: 3, h: 2 },
151
+ position: { x: 0, y: 0 },
152
+ data: sampleMetrics[0]
153
+ },
154
+ {
155
+ id: 'metric-users',
156
+ type: 'metric',
157
+ title: 'Users',
158
+ size: { w: 3, h: 2 },
159
+ position: { x: 3, y: 0 },
160
+ data: sampleMetrics[1]
161
+ },
162
+ {
163
+ id: 'metric-orders',
164
+ type: 'metric',
165
+ title: 'Orders',
166
+ size: { w: 3, h: 2 },
167
+ position: { x: 6, y: 0 },
168
+ data: sampleMetrics[2]
169
+ },
170
+ {
171
+ id: 'metric-conversion',
172
+ type: 'metric',
173
+ title: 'Conversion',
174
+ size: { w: 3, h: 2 },
175
+ position: { x: 9, y: 0 },
176
+ data: sampleMetrics[3]
177
+ },
178
+ // Chart widget'ları
179
+ {
180
+ id: 'chart-revenue-trend',
181
+ type: 'chart',
182
+ title: 'Revenue Trend',
183
+ description: 'Monthly revenue, profit and expenses',
184
+ size: { w: 8, h: 4 },
185
+ position: { x: 0, y: 2 },
186
+ data: revenueChartData
187
+ },
188
+ {
189
+ id: 'chart-sales-by-product',
190
+ type: 'chart',
191
+ title: 'Sales by Product',
192
+ description: 'Product distribution',
193
+ size: { w: 4, h: 4 },
194
+ position: { x: 8, y: 2 },
195
+ data: salesByProductData
196
+ },
197
+ {
198
+ id: 'chart-performance',
199
+ type: 'chart',
200
+ title: 'Team Performance',
201
+ description: 'Department comparison',
202
+ size: { w: 6, h: 4 },
203
+ position: { x: 0, y: 6 },
204
+ data: performanceData
205
+ },
206
+ // Activity feed
207
+ {
208
+ id: 'activity-feed',
209
+ type: 'activity',
210
+ title: 'Recent Activity',
211
+ size: { w: 6, h: 4 },
212
+ position: { x: 6, y: 6 },
213
+ data: {
214
+ items: sampleActivities,
215
+ realtime: true
216
+ }
217
+ }
218
+ ]
219
+
220
+ export function DashboardDemo() {
221
+ return (
222
+ <div className="min-h-screen bg-background">
223
+ <Dashboard
224
+ title="Analytics Dashboard"
225
+ description="Real-time insights and performance metrics"
226
+ widgets={sampleWidgets}
227
+ editable={true}
228
+ realtime={true}
229
+ glassmorphism={true}
230
+ onWidgetAdd={(widget) => {
231
+ console.log('Widget added:', widget)
232
+ }}
233
+ onWidgetRemove={(widgetId) => {
234
+ console.log('Widget removed:', widgetId)
235
+ }}
236
+ onWidgetUpdate={(widgetId, updates) => {
237
+ console.log('Widget updated:', widgetId, updates)
238
+ }}
239
+ onExport={(format) => {
240
+ console.log('Export dashboard as:', format)
241
+ }}
242
+ />
243
+ </div>
244
+ )
245
+ }
246
+
247
+ // Standalone widget demos
248
+ export function MetricCardDemo() {
249
+ return (
250
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 p-6">
251
+ {sampleMetrics.map((metric) => (
252
+ <MetricCard
253
+ key={metric.id}
254
+ data={metric}
255
+ showSparkline={true}
256
+ showForecast={true}
257
+ interactive={true}
258
+ glassmorphism={true}
259
+ onAction={(action) => console.log('Metric action:', action)}
260
+ />
261
+ ))}
262
+ </div>
263
+ )
264
+ }
265
+
266
+ export function ChartWidgetDemo() {
267
+ return (
268
+ <div className="grid grid-cols-1 lg:grid-cols-2 gap-6 p-6">
269
+ <ChartWidget
270
+ id="demo-1"
271
+ title="Revenue Analysis"
272
+ description="Monthly revenue breakdown"
273
+ data={revenueChartData}
274
+ height={300}
275
+ interactive={true}
276
+ glassmorphism={true}
277
+ onAction={(action, data) => console.log('Chart action:', action, data)}
278
+ />
279
+ <ChartWidget
280
+ id="demo-2"
281
+ title="Product Sales"
282
+ description="Sales distribution by product"
283
+ data={salesByProductData}
284
+ height={300}
285
+ interactive={true}
286
+ glassmorphism={true}
287
+ />
288
+ </div>
289
+ )
290
+ }
291
+
292
+ export function ActivityFeedDemo() {
293
+ return (
294
+ <div className="max-w-2xl mx-auto p-6">
295
+ <ActivityFeed
296
+ items={sampleActivities}
297
+ title="System Activity"
298
+ height={400}
299
+ showFilters={true}
300
+ showNotifications={true}
301
+ glassmorphism={true}
302
+ realtime={true}
303
+ onItemClick={(item) => console.log('Activity clicked:', item)}
304
+ onAction={(action, data) => console.log('Feed action:', action, data)}
305
+ />
306
+ </div>
307
+ )
308
+ }