@moontra/moonui-pro 2.5.0 → 2.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +119 -3
- package/dist/index.mjs +508 -39
- package/package.json +1 -1
- package/src/components/dashboard/dashboard-grid.tsx +162 -27
- package/src/components/dashboard/demo.tsx +3 -0
- package/src/components/dashboard/index.tsx +9 -1
- package/src/components/dashboard/time-range-picker.tsx +3 -1
- package/src/components/dashboard/types.ts +2 -2
- package/src/components/index.ts +4 -1
- package/src/components/sidebar/index.tsx +579 -0
- package/src/components/ui/calendar.tsx +4 -4
- package/src/styles/index.css +69 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moontra/moonui-pro",
|
|
3
|
-
"version": "2.5.
|
|
3
|
+
"version": "2.5.2",
|
|
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",
|
|
@@ -7,7 +7,8 @@ import { Widget } from './types'
|
|
|
7
7
|
import { MetricCard } from './widgets/metric-card'
|
|
8
8
|
import { ChartWidget } from './widgets/chart-widget'
|
|
9
9
|
import { ActivityFeed } from './widgets/activity-feed'
|
|
10
|
-
import
|
|
10
|
+
import { Responsive, WidthProvider, Layout, Layouts } from 'react-grid-layout'
|
|
11
|
+
const ResponsiveGridLayout = WidthProvider(Responsive)
|
|
11
12
|
import 'react-grid-layout/css/styles.css'
|
|
12
13
|
import 'react-resizable/css/styles.css'
|
|
13
14
|
import {
|
|
@@ -45,31 +46,114 @@ export function DashboardGrid({
|
|
|
45
46
|
className,
|
|
46
47
|
glassmorphism = false,
|
|
47
48
|
breakpoints = { lg: 1200, md: 996, sm: 768, xs: 480, xxs: 0 },
|
|
48
|
-
cols = { lg: 12, md:
|
|
49
|
-
rowHeight =
|
|
50
|
-
margin = [16,
|
|
49
|
+
cols = { lg: 12, md: 8, sm: 4, xs: 2, xxs: 1 },
|
|
50
|
+
rowHeight = 80,
|
|
51
|
+
margin = [16, 24],
|
|
51
52
|
containerPadding = [0, 0]
|
|
52
53
|
}: DashboardGridProps) {
|
|
53
54
|
const [layouts, setLayouts] = React.useState<Layouts>({})
|
|
54
55
|
const [currentBreakpoint, setCurrentBreakpoint] = React.useState('lg')
|
|
55
56
|
const [lockedWidgets, setLockedWidgets] = React.useState<Set<string>>(new Set())
|
|
56
57
|
const [fullscreenWidget, setFullscreenWidget] = React.useState<string | null>(null)
|
|
58
|
+
const [containerWidth, setContainerWidth] = React.useState(1200)
|
|
59
|
+
const containerRef = React.useRef<HTMLDivElement>(null)
|
|
60
|
+
const [compactType, setCompactType] = React.useState<'vertical' | 'horizontal' | null>('vertical')
|
|
57
61
|
|
|
58
|
-
//
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
// Container genişliğini ölç ve breakpoint'i güncelle
|
|
63
|
+
React.useEffect(() => {
|
|
64
|
+
const updateWidth = () => {
|
|
65
|
+
if (containerRef.current) {
|
|
66
|
+
const width = containerRef.current.offsetWidth
|
|
67
|
+
setContainerWidth(width)
|
|
68
|
+
|
|
69
|
+
// Breakpoint'i manuel olarak belirle
|
|
70
|
+
if (width < 480) {
|
|
71
|
+
setCurrentBreakpoint('xxs')
|
|
72
|
+
} else if (width < 768) {
|
|
73
|
+
setCurrentBreakpoint('xs')
|
|
74
|
+
} else if (width < 996) {
|
|
75
|
+
setCurrentBreakpoint('sm')
|
|
76
|
+
} else if (width < 1200) {
|
|
77
|
+
setCurrentBreakpoint('md')
|
|
78
|
+
} else {
|
|
79
|
+
setCurrentBreakpoint('lg')
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
updateWidth()
|
|
85
|
+
window.addEventListener('resize', updateWidth)
|
|
86
|
+
return () => window.removeEventListener('resize', updateWidth)
|
|
87
|
+
}, [])
|
|
88
|
+
|
|
89
|
+
// Responsive layout oluştur
|
|
90
|
+
const generateResponsiveLayouts = (): Layouts => {
|
|
91
|
+
const baseLayout = widgets.map((widget, index) => ({
|
|
61
92
|
i: widget.id,
|
|
62
|
-
x: widget.position
|
|
63
|
-
y: widget.position.
|
|
64
|
-
w: widget.size
|
|
65
|
-
h: widget.size
|
|
66
|
-
minW: widget.size
|
|
67
|
-
maxW: widget.size
|
|
68
|
-
minH: widget.size
|
|
69
|
-
maxH: widget.size
|
|
93
|
+
x: widget.position?.x ?? (index * 3) % 12,
|
|
94
|
+
y: widget.position?.y ?? Math.floor((index * 3) / 12) * 3,
|
|
95
|
+
w: widget.size?.w ?? 3,
|
|
96
|
+
h: widget.size?.h ?? 3,
|
|
97
|
+
minW: widget.size?.minW || 2,
|
|
98
|
+
maxW: widget.size?.maxW || 12,
|
|
99
|
+
minH: widget.size?.minH || 2,
|
|
100
|
+
maxH: widget.size?.maxH || 8,
|
|
70
101
|
isDraggable: editMode && !lockedWidgets.has(widget.id) && widget.permissions?.canMove !== false,
|
|
71
102
|
isResizable: editMode && !lockedWidgets.has(widget.id) && widget.permissions?.canResize !== false,
|
|
72
103
|
}))
|
|
104
|
+
|
|
105
|
+
// Farklı breakpoint'ler için layout'ları ayarla
|
|
106
|
+
const sortedLayout = [...baseLayout].sort((a, b) => {
|
|
107
|
+
if (a.y === b.y) return a.x - b.x;
|
|
108
|
+
return a.y - b.y;
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
lg: baseLayout,
|
|
113
|
+
md: sortedLayout.map((item, index) => {
|
|
114
|
+
const cols = 8;
|
|
115
|
+
const maxW = Math.min(item.w, 4);
|
|
116
|
+
const row = Math.floor(index / 2);
|
|
117
|
+
const col = (index % 2) * 4;
|
|
118
|
+
return {
|
|
119
|
+
...item,
|
|
120
|
+
w: maxW,
|
|
121
|
+
x: col,
|
|
122
|
+
y: row * 3,
|
|
123
|
+
h: Math.min(item.h, 3)
|
|
124
|
+
};
|
|
125
|
+
}),
|
|
126
|
+
sm: sortedLayout.map((item, index) => {
|
|
127
|
+
const maxW = Math.min(item.w, 4);
|
|
128
|
+
return {
|
|
129
|
+
...item,
|
|
130
|
+
w: maxW,
|
|
131
|
+
x: 0,
|
|
132
|
+
y: index * 3,
|
|
133
|
+
h: Math.min(item.h, 3)
|
|
134
|
+
};
|
|
135
|
+
}),
|
|
136
|
+
xs: sortedLayout.map((item, index) => ({
|
|
137
|
+
...item,
|
|
138
|
+
w: 2, // Full width on mobile
|
|
139
|
+
x: 0,
|
|
140
|
+
y: index * 2,
|
|
141
|
+
h: Math.min(item.h, 2)
|
|
142
|
+
})),
|
|
143
|
+
xxs: sortedLayout.map((item, index) => ({
|
|
144
|
+
...item,
|
|
145
|
+
w: 1, // Full width on extra small
|
|
146
|
+
x: 0,
|
|
147
|
+
y: index * 2,
|
|
148
|
+
h: Math.min(item.h, 2)
|
|
149
|
+
}))
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Layout oluştur (geriye uyumluluk için)
|
|
154
|
+
const generateLayout = (): Layout[] => {
|
|
155
|
+
const responsiveLayouts = generateResponsiveLayouts()
|
|
156
|
+
return responsiveLayouts[currentBreakpoint as keyof Layouts] || responsiveLayouts.lg
|
|
73
157
|
}
|
|
74
158
|
|
|
75
159
|
// Widget kilit durumunu değiştir
|
|
@@ -134,6 +218,27 @@ export function DashboardGrid({
|
|
|
134
218
|
onAction={(action, data) => onWidgetAction?.(widget.id, action, data)}
|
|
135
219
|
/>
|
|
136
220
|
)
|
|
221
|
+
|
|
222
|
+
case 'table':
|
|
223
|
+
case 'map':
|
|
224
|
+
case 'calendar':
|
|
225
|
+
case 'progress':
|
|
226
|
+
case 'comparison':
|
|
227
|
+
// Bu widget tipleri için geçici olarak basit bir görünüm
|
|
228
|
+
return (
|
|
229
|
+
<div className={cn(
|
|
230
|
+
"h-full p-4 rounded-lg border",
|
|
231
|
+
glassmorphism ? "bg-background/60 backdrop-blur-md border-white/10" : "bg-card"
|
|
232
|
+
)}>
|
|
233
|
+
<h3 className="font-semibold mb-2">{widget.title}</h3>
|
|
234
|
+
{widget.description && (
|
|
235
|
+
<p className="text-sm text-muted-foreground mb-4">{widget.description}</p>
|
|
236
|
+
)}
|
|
237
|
+
<div className="flex items-center justify-center h-32 text-muted-foreground">
|
|
238
|
+
<span className="text-sm">{widget.type} widget content</span>
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
)
|
|
137
242
|
|
|
138
243
|
default:
|
|
139
244
|
return (
|
|
@@ -248,8 +353,11 @@ export function DashboardGrid({
|
|
|
248
353
|
)
|
|
249
354
|
}
|
|
250
355
|
|
|
356
|
+
// Mobile kontrolü
|
|
357
|
+
const isMobile = currentBreakpoint === 'xs' || currentBreakpoint === 'xxs' || currentBreakpoint === 'sm';
|
|
358
|
+
|
|
251
359
|
return (
|
|
252
|
-
<div className={cn("w-full", className)}>
|
|
360
|
+
<div ref={containerRef} className={cn("w-full relative", className)}>
|
|
253
361
|
<AnimatePresence>
|
|
254
362
|
{fullscreenWidget ? (
|
|
255
363
|
// Fullscreen widget
|
|
@@ -263,34 +371,61 @@ export function DashboardGrid({
|
|
|
263
371
|
.filter(w => w.id === fullscreenWidget)
|
|
264
372
|
.map(renderWidget)}
|
|
265
373
|
</motion.div>
|
|
374
|
+
) : isMobile ? (
|
|
375
|
+
// Mobile layout - Grid Layout yerine normal flex kullan
|
|
376
|
+
<div className="space-y-6">
|
|
377
|
+
{widgets.map(widget => (
|
|
378
|
+
<motion.div
|
|
379
|
+
key={widget.id}
|
|
380
|
+
initial={{ opacity: 0, y: 20 }}
|
|
381
|
+
animate={{ opacity: 1, y: 0 }}
|
|
382
|
+
transition={{ duration: 0.3 }}
|
|
383
|
+
className="w-full"
|
|
384
|
+
>
|
|
385
|
+
{renderWidget(widget)}
|
|
386
|
+
</motion.div>
|
|
387
|
+
))}
|
|
388
|
+
</div>
|
|
266
389
|
) : (
|
|
267
|
-
// Grid layout
|
|
268
|
-
<
|
|
390
|
+
// Desktop Grid layout
|
|
391
|
+
<ResponsiveGridLayout
|
|
269
392
|
className="layout"
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
margin={margin}
|
|
275
|
-
containerPadding={containerPadding}
|
|
276
|
-
onLayoutChange={(layout) => {
|
|
393
|
+
layouts={layouts.lg ? layouts : generateResponsiveLayouts()}
|
|
394
|
+
breakpoints={breakpoints}
|
|
395
|
+
cols={cols}
|
|
396
|
+
rowHeight={currentBreakpoint === 'xs' || currentBreakpoint === 'xxs' ? 60 : currentBreakpoint === 'sm' ? 70 : rowHeight}
|
|
397
|
+
margin={currentBreakpoint === 'xs' || currentBreakpoint === 'xxs' ? [12, 20] : margin}
|
|
398
|
+
containerPadding={currentBreakpoint === 'xs' || currentBreakpoint === 'xxs' ? [8, 8] : containerPadding}
|
|
399
|
+
onLayoutChange={(layout, allLayouts) => {
|
|
400
|
+
setLayouts(allLayouts)
|
|
277
401
|
onLayoutChange?.(layout)
|
|
278
402
|
}}
|
|
279
403
|
onBreakpointChange={(breakpoint) => {
|
|
280
404
|
setCurrentBreakpoint(breakpoint)
|
|
405
|
+
// Dar alanlarda compact type'ı değiştir
|
|
406
|
+
if (breakpoint === 'xs' || breakpoint === 'xxs' || breakpoint === 'sm') {
|
|
407
|
+
setCompactType('vertical')
|
|
408
|
+
} else {
|
|
409
|
+
setCompactType('vertical')
|
|
410
|
+
}
|
|
281
411
|
}}
|
|
282
412
|
draggableHandle=".drag-handle"
|
|
283
413
|
isDraggable={editMode}
|
|
284
414
|
isResizable={editMode}
|
|
285
|
-
compactType=
|
|
415
|
+
compactType={compactType}
|
|
286
416
|
preventCollision={false}
|
|
417
|
+
useCSSTransforms={true}
|
|
418
|
+
transformScale={1}
|
|
419
|
+
isDroppable={true}
|
|
420
|
+
autoSize={true}
|
|
421
|
+
verticalCompact={true}
|
|
287
422
|
>
|
|
288
423
|
{widgets.map(widget => (
|
|
289
424
|
<div key={widget.id}>
|
|
290
425
|
{renderWidget(widget)}
|
|
291
426
|
</div>
|
|
292
427
|
))}
|
|
293
|
-
</
|
|
428
|
+
</ResponsiveGridLayout>
|
|
294
429
|
)}
|
|
295
430
|
</AnimatePresence>
|
|
296
431
|
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { Dashboard } from './index'
|
|
5
5
|
import { Widget, MetricData, ChartData, ActivityItem } from './types'
|
|
6
|
+
import { MetricCard } from './widgets/metric-card'
|
|
7
|
+
import { ChartWidget } from './widgets/chart-widget'
|
|
8
|
+
import { ActivityFeed } from './widgets/activity-feed'
|
|
6
9
|
import {
|
|
7
10
|
Users,
|
|
8
11
|
DollarSign,
|
|
@@ -259,6 +259,11 @@ export function Dashboard({
|
|
|
259
259
|
const [refreshing, setRefreshing] = React.useState(false)
|
|
260
260
|
const [notifications, setNotifications] = React.useState<number>(3)
|
|
261
261
|
|
|
262
|
+
// initialWidgets değiştiğinde state'i güncelle
|
|
263
|
+
React.useEffect(() => {
|
|
264
|
+
setWidgets(initialWidgets)
|
|
265
|
+
}, [initialWidgets])
|
|
266
|
+
|
|
262
267
|
// WebSocket bağlantısı (real-time için)
|
|
263
268
|
React.useEffect(() => {
|
|
264
269
|
if (!realtime) return
|
|
@@ -308,7 +313,9 @@ export function Dashboard({
|
|
|
308
313
|
const applyTemplate = (template: DashboardTemplate) => {
|
|
309
314
|
const newWidgets = template.widgets.map((w, index) => ({
|
|
310
315
|
...w,
|
|
311
|
-
id: `widget-${Date.now()}-${index}
|
|
316
|
+
id: `widget-${Date.now()}-${index}`,
|
|
317
|
+
position: w.position || { x: (index * 3) % 12, y: Math.floor((index * 3) / 12) * 3 },
|
|
318
|
+
size: w.size || { w: 3, h: 3 }
|
|
312
319
|
}))
|
|
313
320
|
|
|
314
321
|
setWidgets(newWidgets as Widget[])
|
|
@@ -739,4 +746,5 @@ export function Dashboard({
|
|
|
739
746
|
)
|
|
740
747
|
}
|
|
741
748
|
|
|
749
|
+
export type { Widget, MetricData, ChartData, ActivityItem, ProgressData, ComparisonData } from './types'
|
|
742
750
|
export default Dashboard
|
|
@@ -160,7 +160,9 @@ export function TimeRangePicker({
|
|
|
160
160
|
"w-auto p-0",
|
|
161
161
|
glassmorphism && "bg-background/95 backdrop-blur-md border-white/10"
|
|
162
162
|
)}
|
|
163
|
-
align="
|
|
163
|
+
align="end"
|
|
164
|
+
side="bottom"
|
|
165
|
+
sideOffset={4}
|
|
164
166
|
>
|
|
165
167
|
<motion.div
|
|
166
168
|
initial={{ opacity: 0, y: -10 }}
|