@wakastellar/ui 2.1.0 → 2.1.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/README.md +71 -8
- package/dist/blocks/auth-2fa/index.d.ts +38 -0
- package/dist/blocks/chat-interface/index.d.ts +66 -0
- package/dist/blocks/checkout-flow/index.d.ts +76 -0
- package/dist/blocks/dashboard-kpi/index.d.ts +69 -0
- package/dist/blocks/deployment-dashboard/index.d.ts +68 -0
- package/dist/blocks/index.d.ts +7 -0
- package/dist/blocks/player-profile/index.d.ts +78 -0
- package/dist/cli/index.cjs +1324 -154
- package/dist/index.cjs.js +136 -134
- package/dist/index.es.js +17304 -15120
- package/package.json +1 -1
- package/src/blocks/auth-2fa/index.tsx +655 -0
- package/src/blocks/chat-interface/index.tsx +611 -0
- package/src/blocks/checkout-flow/index.tsx +771 -0
- package/src/blocks/dashboard-kpi/index.tsx +424 -0
- package/src/blocks/deployment-dashboard/index.tsx +609 -0
- package/src/blocks/index.ts +24 -0
- package/src/blocks/player-profile/index.tsx +541 -0
- package/src/components/language-selector/index.tsx +21 -11
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { cn } from "../../utils"
|
|
5
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "../../components/card"
|
|
6
|
+
import { Button } from "../../components/button"
|
|
7
|
+
import { Badge } from "../../components/badge"
|
|
8
|
+
import { Progress } from "../../components/progress"
|
|
9
|
+
import { Separator } from "../../components/separator"
|
|
10
|
+
import {
|
|
11
|
+
Select,
|
|
12
|
+
SelectContent,
|
|
13
|
+
SelectItem,
|
|
14
|
+
SelectTrigger,
|
|
15
|
+
SelectValue,
|
|
16
|
+
} from "../../components/select"
|
|
17
|
+
import {
|
|
18
|
+
TrendingUp,
|
|
19
|
+
TrendingDown,
|
|
20
|
+
Users,
|
|
21
|
+
DollarSign,
|
|
22
|
+
ShoppingCart,
|
|
23
|
+
Activity,
|
|
24
|
+
ArrowUpRight,
|
|
25
|
+
ArrowDownRight,
|
|
26
|
+
MoreHorizontal,
|
|
27
|
+
RefreshCw,
|
|
28
|
+
Download,
|
|
29
|
+
Calendar,
|
|
30
|
+
Target,
|
|
31
|
+
Zap,
|
|
32
|
+
Eye,
|
|
33
|
+
Clock,
|
|
34
|
+
} from "lucide-react"
|
|
35
|
+
|
|
36
|
+
// ============================================
|
|
37
|
+
// TYPES
|
|
38
|
+
// ============================================
|
|
39
|
+
|
|
40
|
+
export interface KPIMetric {
|
|
41
|
+
id: string
|
|
42
|
+
label: string
|
|
43
|
+
value: string | number
|
|
44
|
+
previousValue?: string | number
|
|
45
|
+
change?: number
|
|
46
|
+
changeLabel?: string
|
|
47
|
+
trend?: "up" | "down" | "neutral"
|
|
48
|
+
icon?: React.ReactNode
|
|
49
|
+
color?: "default" | "blue" | "green" | "yellow" | "red" | "purple"
|
|
50
|
+
sparkline?: number[]
|
|
51
|
+
target?: number
|
|
52
|
+
current?: number
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface KPIChartData {
|
|
56
|
+
label: string
|
|
57
|
+
value: number
|
|
58
|
+
color?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export interface DashboardKPIProps {
|
|
62
|
+
/** Title of the dashboard */
|
|
63
|
+
title?: string
|
|
64
|
+
/** Description */
|
|
65
|
+
description?: string
|
|
66
|
+
/** Main KPI metrics */
|
|
67
|
+
metrics: KPIMetric[]
|
|
68
|
+
/** Period selector options */
|
|
69
|
+
periods?: { value: string; label: string }[]
|
|
70
|
+
/** Selected period */
|
|
71
|
+
selectedPeriod?: string
|
|
72
|
+
/** Period change handler */
|
|
73
|
+
onPeriodChange?: (period: string) => void
|
|
74
|
+
/** Refresh handler */
|
|
75
|
+
onRefresh?: () => void
|
|
76
|
+
/** Export handler */
|
|
77
|
+
onExport?: () => void
|
|
78
|
+
/** Custom chart component */
|
|
79
|
+
chart?: React.ReactNode
|
|
80
|
+
/** Secondary metrics for the bottom section */
|
|
81
|
+
secondaryMetrics?: KPIMetric[]
|
|
82
|
+
/** Goals/targets section */
|
|
83
|
+
goals?: {
|
|
84
|
+
id: string
|
|
85
|
+
label: string
|
|
86
|
+
current: number
|
|
87
|
+
target: number
|
|
88
|
+
unit?: string
|
|
89
|
+
}[]
|
|
90
|
+
/** Loading state */
|
|
91
|
+
isLoading?: boolean
|
|
92
|
+
/** Last updated timestamp */
|
|
93
|
+
lastUpdated?: string | Date
|
|
94
|
+
/** Custom className */
|
|
95
|
+
className?: string
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ============================================
|
|
99
|
+
// SUBCOMPONENTS
|
|
100
|
+
// ============================================
|
|
101
|
+
|
|
102
|
+
const colorMap = {
|
|
103
|
+
default: "text-foreground",
|
|
104
|
+
blue: "text-blue-500",
|
|
105
|
+
green: "text-green-500",
|
|
106
|
+
yellow: "text-yellow-500",
|
|
107
|
+
red: "text-red-500",
|
|
108
|
+
purple: "text-purple-500",
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const bgColorMap = {
|
|
112
|
+
default: "bg-muted",
|
|
113
|
+
blue: "bg-blue-500/10",
|
|
114
|
+
green: "bg-green-500/10",
|
|
115
|
+
yellow: "bg-yellow-500/10",
|
|
116
|
+
red: "bg-red-500/10",
|
|
117
|
+
purple: "bg-purple-500/10",
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function MiniSparkline({ data, color = "blue" }: { data: number[]; color?: string }) {
|
|
121
|
+
const max = Math.max(...data)
|
|
122
|
+
const min = Math.min(...data)
|
|
123
|
+
const range = max - min || 1
|
|
124
|
+
|
|
125
|
+
const points = data
|
|
126
|
+
.map((value, index) => {
|
|
127
|
+
const x = (index / (data.length - 1)) * 100
|
|
128
|
+
const y = 100 - ((value - min) / range) * 100
|
|
129
|
+
return `${x},${y}`
|
|
130
|
+
})
|
|
131
|
+
.join(" ")
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<svg className="w-16 h-8" viewBox="0 0 100 100" preserveAspectRatio="none">
|
|
135
|
+
<polyline
|
|
136
|
+
points={points}
|
|
137
|
+
fill="none"
|
|
138
|
+
stroke="currentColor"
|
|
139
|
+
strokeWidth="3"
|
|
140
|
+
className={cn("opacity-60", colorMap[color as keyof typeof colorMap] || colorMap.blue)}
|
|
141
|
+
/>
|
|
142
|
+
</svg>
|
|
143
|
+
)
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function KPICard({ metric }: { metric: KPIMetric }) {
|
|
147
|
+
const Icon = metric.icon
|
|
148
|
+
const trendColor = metric.trend === "up" ? "text-green-500" : metric.trend === "down" ? "text-red-500" : "text-muted-foreground"
|
|
149
|
+
const TrendIcon = metric.trend === "up" ? TrendingUp : metric.trend === "down" ? TrendingDown : null
|
|
150
|
+
|
|
151
|
+
return (
|
|
152
|
+
<Card className="relative overflow-hidden">
|
|
153
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
154
|
+
<CardTitle className="text-sm font-medium text-muted-foreground">
|
|
155
|
+
{metric.label}
|
|
156
|
+
</CardTitle>
|
|
157
|
+
{Icon && (
|
|
158
|
+
<div className={cn("p-2 rounded-lg", bgColorMap[metric.color || "default"])}>
|
|
159
|
+
<span className={cn("h-4 w-4", colorMap[metric.color || "default"])}>
|
|
160
|
+
{Icon}
|
|
161
|
+
</span>
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
164
|
+
</CardHeader>
|
|
165
|
+
<CardContent>
|
|
166
|
+
<div className="flex items-end justify-between">
|
|
167
|
+
<div>
|
|
168
|
+
<div className="text-2xl font-bold">{metric.value}</div>
|
|
169
|
+
{metric.change !== undefined && (
|
|
170
|
+
<div className={cn("flex items-center gap-1 text-sm", trendColor)}>
|
|
171
|
+
{TrendIcon && <TrendIcon className="h-3 w-3" />}
|
|
172
|
+
<span>{metric.change > 0 ? "+" : ""}{metric.change}%</span>
|
|
173
|
+
{metric.changeLabel && (
|
|
174
|
+
<span className="text-muted-foreground">{metric.changeLabel}</span>
|
|
175
|
+
)}
|
|
176
|
+
</div>
|
|
177
|
+
)}
|
|
178
|
+
</div>
|
|
179
|
+
{metric.sparkline && (
|
|
180
|
+
<MiniSparkline data={metric.sparkline} color={metric.color} />
|
|
181
|
+
)}
|
|
182
|
+
</div>
|
|
183
|
+
{metric.target !== undefined && metric.current !== undefined && (
|
|
184
|
+
<div className="mt-4">
|
|
185
|
+
<div className="flex justify-between text-xs text-muted-foreground mb-1">
|
|
186
|
+
<span>Progress</span>
|
|
187
|
+
<span>{Math.round((metric.current / metric.target) * 100)}%</span>
|
|
188
|
+
</div>
|
|
189
|
+
<Progress value={(metric.current / metric.target) * 100} className="h-1.5" />
|
|
190
|
+
</div>
|
|
191
|
+
)}
|
|
192
|
+
</CardContent>
|
|
193
|
+
</Card>
|
|
194
|
+
)
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function GoalCard({ goal }: { goal: { id: string; label: string; current: number; target: number; unit?: string } }) {
|
|
198
|
+
const progress = (goal.current / goal.target) * 100
|
|
199
|
+
const isComplete = progress >= 100
|
|
200
|
+
|
|
201
|
+
return (
|
|
202
|
+
<div className="flex items-center gap-4 p-4 rounded-lg border bg-card">
|
|
203
|
+
<div className={cn(
|
|
204
|
+
"h-10 w-10 rounded-full flex items-center justify-center",
|
|
205
|
+
isComplete ? "bg-green-500/10 text-green-500" : "bg-muted text-muted-foreground"
|
|
206
|
+
)}>
|
|
207
|
+
<Target className="h-5 w-5" />
|
|
208
|
+
</div>
|
|
209
|
+
<div className="flex-1 min-w-0">
|
|
210
|
+
<div className="flex items-center justify-between mb-1">
|
|
211
|
+
<span className="font-medium truncate">{goal.label}</span>
|
|
212
|
+
<span className="text-sm text-muted-foreground">
|
|
213
|
+
{goal.current}{goal.unit} / {goal.target}{goal.unit}
|
|
214
|
+
</span>
|
|
215
|
+
</div>
|
|
216
|
+
<Progress value={Math.min(progress, 100)} className="h-2" />
|
|
217
|
+
</div>
|
|
218
|
+
{isComplete && (
|
|
219
|
+
<Badge variant="default" className="bg-green-500">Complete</Badge>
|
|
220
|
+
)}
|
|
221
|
+
</div>
|
|
222
|
+
)
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ============================================
|
|
226
|
+
// MAIN COMPONENT
|
|
227
|
+
// ============================================
|
|
228
|
+
|
|
229
|
+
export function DashboardKPI({
|
|
230
|
+
title = "Dashboard",
|
|
231
|
+
description,
|
|
232
|
+
metrics,
|
|
233
|
+
periods = [
|
|
234
|
+
{ value: "7d", label: "7 days" },
|
|
235
|
+
{ value: "30d", label: "30 days" },
|
|
236
|
+
{ value: "90d", label: "90 days" },
|
|
237
|
+
{ value: "12m", label: "12 months" },
|
|
238
|
+
],
|
|
239
|
+
selectedPeriod = "30d",
|
|
240
|
+
onPeriodChange,
|
|
241
|
+
onRefresh,
|
|
242
|
+
onExport,
|
|
243
|
+
chart,
|
|
244
|
+
secondaryMetrics,
|
|
245
|
+
goals,
|
|
246
|
+
isLoading = false,
|
|
247
|
+
lastUpdated,
|
|
248
|
+
className,
|
|
249
|
+
}: DashboardKPIProps) {
|
|
250
|
+
return (
|
|
251
|
+
<div className={cn("space-y-6", className)}>
|
|
252
|
+
{/* Header */}
|
|
253
|
+
<div className="flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
|
254
|
+
<div>
|
|
255
|
+
<h1 className="text-2xl font-bold tracking-tight">{title}</h1>
|
|
256
|
+
{description && (
|
|
257
|
+
<p className="text-muted-foreground">{description}</p>
|
|
258
|
+
)}
|
|
259
|
+
</div>
|
|
260
|
+
<div className="flex items-center gap-2">
|
|
261
|
+
{periods.length > 0 && (
|
|
262
|
+
<Select value={selectedPeriod} onValueChange={onPeriodChange}>
|
|
263
|
+
<SelectTrigger className="w-[140px]">
|
|
264
|
+
<Calendar className="h-4 w-4 mr-2" />
|
|
265
|
+
<SelectValue />
|
|
266
|
+
</SelectTrigger>
|
|
267
|
+
<SelectContent>
|
|
268
|
+
{periods.map((period) => (
|
|
269
|
+
<SelectItem key={period.value} value={period.value}>
|
|
270
|
+
{period.label}
|
|
271
|
+
</SelectItem>
|
|
272
|
+
))}
|
|
273
|
+
</SelectContent>
|
|
274
|
+
</Select>
|
|
275
|
+
)}
|
|
276
|
+
{onRefresh && (
|
|
277
|
+
<Button variant="outline" size="icon" onClick={onRefresh} disabled={isLoading}>
|
|
278
|
+
<RefreshCw className={cn("h-4 w-4", isLoading && "animate-spin")} />
|
|
279
|
+
</Button>
|
|
280
|
+
)}
|
|
281
|
+
{onExport && (
|
|
282
|
+
<Button variant="outline" size="icon" onClick={onExport}>
|
|
283
|
+
<Download className="h-4 w-4" />
|
|
284
|
+
</Button>
|
|
285
|
+
)}
|
|
286
|
+
</div>
|
|
287
|
+
</div>
|
|
288
|
+
|
|
289
|
+
{/* Last Updated */}
|
|
290
|
+
{lastUpdated && (
|
|
291
|
+
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
292
|
+
<Clock className="h-4 w-4" />
|
|
293
|
+
<span>Last updated: {typeof lastUpdated === "string" ? lastUpdated : lastUpdated.toLocaleString()}</span>
|
|
294
|
+
</div>
|
|
295
|
+
)}
|
|
296
|
+
|
|
297
|
+
{/* Main KPI Grid */}
|
|
298
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
|
|
299
|
+
{metrics.slice(0, 4).map((metric) => (
|
|
300
|
+
<KPICard key={metric.id} metric={metric} />
|
|
301
|
+
))}
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
{/* Chart Section */}
|
|
305
|
+
{chart && (
|
|
306
|
+
<Card>
|
|
307
|
+
<CardHeader>
|
|
308
|
+
<CardTitle>Overview</CardTitle>
|
|
309
|
+
<CardDescription>Performance metrics over time</CardDescription>
|
|
310
|
+
</CardHeader>
|
|
311
|
+
<CardContent>{chart}</CardContent>
|
|
312
|
+
</Card>
|
|
313
|
+
)}
|
|
314
|
+
|
|
315
|
+
{/* Secondary Metrics */}
|
|
316
|
+
{secondaryMetrics && secondaryMetrics.length > 0 && (
|
|
317
|
+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
|
|
318
|
+
{secondaryMetrics.map((metric) => (
|
|
319
|
+
<Card key={metric.id}>
|
|
320
|
+
<CardContent className="pt-6">
|
|
321
|
+
<div className="flex items-center justify-between">
|
|
322
|
+
<div>
|
|
323
|
+
<p className="text-sm text-muted-foreground">{metric.label}</p>
|
|
324
|
+
<p className="text-xl font-bold">{metric.value}</p>
|
|
325
|
+
</div>
|
|
326
|
+
{metric.change !== undefined && (
|
|
327
|
+
<Badge
|
|
328
|
+
variant={metric.trend === "up" ? "default" : metric.trend === "down" ? "destructive" : "secondary"}
|
|
329
|
+
className="gap-1"
|
|
330
|
+
>
|
|
331
|
+
{metric.trend === "up" ? (
|
|
332
|
+
<ArrowUpRight className="h-3 w-3" />
|
|
333
|
+
) : metric.trend === "down" ? (
|
|
334
|
+
<ArrowDownRight className="h-3 w-3" />
|
|
335
|
+
) : null}
|
|
336
|
+
{metric.change > 0 ? "+" : ""}{metric.change}%
|
|
337
|
+
</Badge>
|
|
338
|
+
)}
|
|
339
|
+
</div>
|
|
340
|
+
</CardContent>
|
|
341
|
+
</Card>
|
|
342
|
+
))}
|
|
343
|
+
</div>
|
|
344
|
+
)}
|
|
345
|
+
|
|
346
|
+
{/* Goals Section */}
|
|
347
|
+
{goals && goals.length > 0 && (
|
|
348
|
+
<Card>
|
|
349
|
+
<CardHeader>
|
|
350
|
+
<CardTitle className="flex items-center gap-2">
|
|
351
|
+
<Target className="h-5 w-5" />
|
|
352
|
+
Goals & Targets
|
|
353
|
+
</CardTitle>
|
|
354
|
+
<CardDescription>Track your progress towards key objectives</CardDescription>
|
|
355
|
+
</CardHeader>
|
|
356
|
+
<CardContent className="space-y-4">
|
|
357
|
+
{goals.map((goal) => (
|
|
358
|
+
<GoalCard key={goal.id} goal={goal} />
|
|
359
|
+
))}
|
|
360
|
+
</CardContent>
|
|
361
|
+
</Card>
|
|
362
|
+
)}
|
|
363
|
+
</div>
|
|
364
|
+
)
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// ============================================
|
|
368
|
+
// PRESET DATA
|
|
369
|
+
// ============================================
|
|
370
|
+
|
|
371
|
+
export const defaultKPIMetrics: KPIMetric[] = [
|
|
372
|
+
{
|
|
373
|
+
id: "revenue",
|
|
374
|
+
label: "Total Revenue",
|
|
375
|
+
value: "$45,231.89",
|
|
376
|
+
change: 20.1,
|
|
377
|
+
changeLabel: "from last month",
|
|
378
|
+
trend: "up",
|
|
379
|
+
icon: <DollarSign className="h-4 w-4" />,
|
|
380
|
+
color: "green",
|
|
381
|
+
sparkline: [30, 40, 35, 50, 49, 60, 70, 91, 125],
|
|
382
|
+
},
|
|
383
|
+
{
|
|
384
|
+
id: "subscriptions",
|
|
385
|
+
label: "Subscriptions",
|
|
386
|
+
value: "+2,350",
|
|
387
|
+
change: 180.1,
|
|
388
|
+
changeLabel: "from last month",
|
|
389
|
+
trend: "up",
|
|
390
|
+
icon: <Users className="h-4 w-4" />,
|
|
391
|
+
color: "blue",
|
|
392
|
+
sparkline: [10, 20, 30, 40, 50, 60, 70, 80, 90],
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
id: "sales",
|
|
396
|
+
label: "Sales",
|
|
397
|
+
value: "+12,234",
|
|
398
|
+
change: 19,
|
|
399
|
+
changeLabel: "from last month",
|
|
400
|
+
trend: "up",
|
|
401
|
+
icon: <ShoppingCart className="h-4 w-4" />,
|
|
402
|
+
color: "purple",
|
|
403
|
+
sparkline: [65, 59, 80, 81, 56, 55, 70, 80, 95],
|
|
404
|
+
},
|
|
405
|
+
{
|
|
406
|
+
id: "active",
|
|
407
|
+
label: "Active Now",
|
|
408
|
+
value: "+573",
|
|
409
|
+
change: -2.5,
|
|
410
|
+
changeLabel: "from last hour",
|
|
411
|
+
trend: "down",
|
|
412
|
+
icon: <Activity className="h-4 w-4" />,
|
|
413
|
+
color: "yellow",
|
|
414
|
+
sparkline: [100, 90, 85, 88, 70, 65, 60, 58, 55],
|
|
415
|
+
},
|
|
416
|
+
]
|
|
417
|
+
|
|
418
|
+
export const defaultGoals = [
|
|
419
|
+
{ id: "revenue-goal", label: "Monthly Revenue Target", current: 45231, target: 50000, unit: "$" },
|
|
420
|
+
{ id: "users-goal", label: "New User Signups", current: 2350, target: 2000, unit: "" },
|
|
421
|
+
{ id: "conversion-goal", label: "Conversion Rate", current: 3.2, target: 5, unit: "%" },
|
|
422
|
+
]
|
|
423
|
+
|
|
424
|
+
export default DashboardKPI
|