helix-lang 11.0.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/README.md +168 -0
- package/dist/architect.d.ts +14 -0
- package/dist/architect.d.ts.map +1 -0
- package/dist/architect.js +127 -0
- package/dist/architect.js.map +1 -0
- package/dist/bin/helix.d.ts +20 -0
- package/dist/bin/helix.d.ts.map +1 -0
- package/dist/bin/helix.js +921 -0
- package/dist/bin/helix.js.map +1 -0
- package/dist/commands/collaborate/index.d.ts +2 -0
- package/dist/commands/collaborate/index.d.ts.map +1 -0
- package/dist/commands/collaborate/index.js +129 -0
- package/dist/commands/collaborate/index.js.map +1 -0
- package/dist/commands/collaborate/server.d.ts +31 -0
- package/dist/commands/collaborate/server.d.ts.map +1 -0
- package/dist/commands/collaborate/server.js +159 -0
- package/dist/commands/collaborate/server.js.map +1 -0
- package/dist/commands/deploy/index.d.ts +25 -0
- package/dist/commands/deploy/index.d.ts.map +1 -0
- package/dist/commands/deploy/index.js +130 -0
- package/dist/commands/deploy/index.js.map +1 -0
- package/dist/commands/deploy/platforms/fly.d.ts +9 -0
- package/dist/commands/deploy/platforms/fly.d.ts.map +1 -0
- package/dist/commands/deploy/platforms/fly.js +68 -0
- package/dist/commands/deploy/platforms/fly.js.map +1 -0
- package/dist/commands/deploy/platforms/railway.d.ts +9 -0
- package/dist/commands/deploy/platforms/railway.d.ts.map +1 -0
- package/dist/commands/deploy/platforms/railway.js +115 -0
- package/dist/commands/deploy/platforms/railway.js.map +1 -0
- package/dist/commands/deploy/platforms/vercel.d.ts +10 -0
- package/dist/commands/deploy/platforms/vercel.d.ts.map +1 -0
- package/dist/commands/deploy/platforms/vercel.js +126 -0
- package/dist/commands/deploy/platforms/vercel.js.map +1 -0
- package/dist/commands/deploy.d.ts +6 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +56 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/evolve/analyzers/performance.d.ts +13 -0
- package/dist/commands/evolve/analyzers/performance.d.ts.map +1 -0
- package/dist/commands/evolve/analyzers/performance.js +591 -0
- package/dist/commands/evolve/analyzers/performance.js.map +1 -0
- package/dist/commands/evolve/analyzers/security.d.ts +21 -0
- package/dist/commands/evolve/analyzers/security.d.ts.map +1 -0
- package/dist/commands/evolve/analyzers/security.js +280 -0
- package/dist/commands/evolve/analyzers/security.js.map +1 -0
- package/dist/commands/evolve/index.d.ts +2 -0
- package/dist/commands/evolve/index.d.ts.map +1 -0
- package/dist/commands/evolve/index.js +122 -0
- package/dist/commands/evolve/index.js.map +1 -0
- package/dist/commands/generate.d.ts +6 -0
- package/dist/commands/generate.d.ts.map +1 -0
- package/dist/commands/generate.js +277 -0
- package/dist/commands/generate.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +176 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/library/index.d.ts +27 -0
- package/dist/commands/library/index.d.ts.map +1 -0
- package/dist/commands/library/index.js +126 -0
- package/dist/commands/library/index.js.map +1 -0
- package/dist/commands/migrate.d.ts +5 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +258 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/commands/new.d.ts +6 -0
- package/dist/commands/new.d.ts.map +1 -0
- package/dist/commands/new.js +195 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/preflight.d.ts +20 -0
- package/dist/commands/preflight.d.ts.map +1 -0
- package/dist/commands/preflight.js +182 -0
- package/dist/commands/preflight.js.map +1 -0
- package/dist/commands/preview.d.ts +13 -0
- package/dist/commands/preview.d.ts.map +1 -0
- package/dist/commands/preview.js +260 -0
- package/dist/commands/preview.js.map +1 -0
- package/dist/commands/run.d.ts +6 -0
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/commands/run.js +96 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/spawn.d.ts +11 -0
- package/dist/commands/spawn.d.ts.map +1 -0
- package/dist/commands/spawn.js +916 -0
- package/dist/commands/spawn.js.map +1 -0
- package/dist/compiler.d.ts +12 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +92 -0
- package/dist/compiler.js.map +1 -0
- package/dist/core/file-writer.d.ts +36 -0
- package/dist/core/file-writer.d.ts.map +1 -0
- package/dist/core/file-writer.js +268 -0
- package/dist/core/file-writer.js.map +1 -0
- package/dist/core/registry.d.ts +57 -0
- package/dist/core/registry.d.ts.map +1 -0
- package/dist/core/registry.js +222 -0
- package/dist/core/registry.js.map +1 -0
- package/dist/core/self-healing.d.ts +47 -0
- package/dist/core/self-healing.d.ts.map +1 -0
- package/dist/core/self-healing.js +250 -0
- package/dist/core/self-healing.js.map +1 -0
- package/dist/core/types.d.ts +126 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +7 -0
- package/dist/core/types.js.map +1 -0
- package/dist/generators/databases/mongodb.d.ts +10 -0
- package/dist/generators/databases/mongodb.d.ts.map +1 -0
- package/dist/generators/databases/mongodb.js +83 -0
- package/dist/generators/databases/mongodb.js.map +1 -0
- package/dist/generators/databases/redis.d.ts +2 -0
- package/dist/generators/databases/redis.d.ts.map +1 -0
- package/dist/generators/databases/redis.js +140 -0
- package/dist/generators/databases/redis.js.map +1 -0
- package/dist/generators/flutter.d.ts +32 -0
- package/dist/generators/flutter.d.ts.map +1 -0
- package/dist/generators/flutter.js +628 -0
- package/dist/generators/flutter.js.map +1 -0
- package/dist/openrouter.d.ts +68 -0
- package/dist/openrouter.d.ts.map +1 -0
- package/dist/openrouter.js +241 -0
- package/dist/openrouter.js.map +1 -0
- package/dist/page-generator.d.ts +22 -0
- package/dist/page-generator.d.ts.map +1 -0
- package/dist/page-generator.js +192 -0
- package/dist/page-generator.js.map +1 -0
- package/dist/parser.d.ts +76 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +691 -0
- package/dist/parser.js.map +1 -0
- package/dist/prompts/master-architect.d.ts +9 -0
- package/dist/prompts/master-architect.d.ts.map +1 -0
- package/dist/prompts/master-architect.js +150 -0
- package/dist/prompts/master-architect.js.map +1 -0
- package/dist/researcher.d.ts +12 -0
- package/dist/researcher.d.ts.map +1 -0
- package/dist/researcher.js +85 -0
- package/dist/researcher.js.map +1 -0
- package/dist/self-heal.d.ts +29 -0
- package/dist/self-heal.d.ts.map +1 -0
- package/dist/self-heal.js +260 -0
- package/dist/self-heal.js.map +1 -0
- package/dist/services/SupabaseDeployer.d.ts +9 -0
- package/dist/services/SupabaseDeployer.d.ts.map +1 -0
- package/dist/services/SupabaseDeployer.js +50 -0
- package/dist/services/SupabaseDeployer.js.map +1 -0
- package/dist/test-generator.d.ts +18 -0
- package/dist/test-generator.d.ts.map +1 -0
- package/dist/test-generator.js +180 -0
- package/dist/test-generator.js.map +1 -0
- package/dist/themes/index.d.ts +52 -0
- package/dist/themes/index.d.ts.map +1 -0
- package/dist/themes/index.js +273 -0
- package/dist/themes/index.js.map +1 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +81 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/constitutional-validator.d.ts +73 -0
- package/dist/utils/constitutional-validator.d.ts.map +1 -0
- package/dist/utils/constitutional-validator.js +249 -0
- package/dist/utils/constitutional-validator.js.map +1 -0
- package/library/auth-flow/app/api/auth/[...nextauth]/route.ts +31 -0
- package/library/auth-flow/app/api/auth/login/route.ts +90 -0
- package/library/auth-flow/app/api/auth/register/route.ts +91 -0
- package/library/auth-flow/components/auth/AuthMiddleware.tsx +139 -0
- package/library/auth-flow/components/auth/LoginForm.tsx +125 -0
- package/library/auth-flow/components/auth/RegisterForm.tsx +168 -0
- package/library/auth-flow/components/auth/nextauth-config.ts +99 -0
- package/library/auth-flow/manifest.json +29 -0
- package/library/auth-flow/schema.prisma +45 -0
- package/library/dashboard-analytics/components/dashboard/ActivityFeed.tsx +109 -0
- package/library/dashboard-analytics/components/dashboard/LineChart.tsx +180 -0
- package/library/dashboard-analytics/components/dashboard/StatsCard.tsx +47 -0
- package/library/dashboard-analytics/components/dashboard/SummaryGrid.tsx +39 -0
- package/library/dashboard-analytics/manifest.json +19 -0
- package/library/data-table/components/table/BulkActions.tsx +59 -0
- package/library/data-table/components/table/ColumnToggle.tsx +65 -0
- package/library/data-table/components/table/DataTable.tsx +318 -0
- package/library/data-table/components/table/ExportCSV.tsx +52 -0
- package/library/data-table/components/table/SearchFilter.tsx +48 -0
- package/library/data-table/manifest.json +20 -0
- package/library/file-upload/app/api/upload/route.ts +107 -0
- package/library/file-upload/components/upload/DropZone.tsx +268 -0
- package/library/file-upload/components/upload/FilePreview.tsx +82 -0
- package/library/file-upload/components/upload/UploadProgress.tsx +92 -0
- package/library/file-upload/components/upload/fileStorage.ts +142 -0
- package/library/file-upload/manifest.json +21 -0
- package/library/notification-system/app/api/notifications/route.ts +121 -0
- package/library/notification-system/components/notifications/NotificationBell.tsx +154 -0
- package/library/notification-system/components/notifications/NotificationProvider.tsx +161 -0
- package/library/notification-system/components/notifications/Toast.tsx +112 -0
- package/library/notification-system/manifest.json +20 -0
- package/package.json +66 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
export interface ActivityItem {
|
|
4
|
+
id: string;
|
|
5
|
+
user: string;
|
|
6
|
+
action: string;
|
|
7
|
+
target?: string;
|
|
8
|
+
timestamp: string | Date;
|
|
9
|
+
avatar?: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
interface ActivityFeedProps {
|
|
13
|
+
items: ActivityItem[];
|
|
14
|
+
title?: string;
|
|
15
|
+
maxItems?: number;
|
|
16
|
+
onViewAll?: () => void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function formatRelativeTime(date: string | Date): string {
|
|
20
|
+
const now = Date.now();
|
|
21
|
+
const then = new Date(date).getTime();
|
|
22
|
+
const diffMs = now - then;
|
|
23
|
+
const diffSec = Math.floor(diffMs / 1000);
|
|
24
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
25
|
+
const diffHour = Math.floor(diffMin / 60);
|
|
26
|
+
const diffDay = Math.floor(diffHour / 24);
|
|
27
|
+
|
|
28
|
+
if (diffSec < 60) return 'just now';
|
|
29
|
+
if (diffMin < 60) return `${diffMin}m ago`;
|
|
30
|
+
if (diffHour < 24) return `${diffHour}h ago`;
|
|
31
|
+
if (diffDay < 7) return `${diffDay}d ago`;
|
|
32
|
+
return new Date(date).toLocaleDateString();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function getInitials(name: string): string {
|
|
36
|
+
return name
|
|
37
|
+
.split(' ')
|
|
38
|
+
.map((part) => part[0])
|
|
39
|
+
.join('')
|
|
40
|
+
.toUpperCase()
|
|
41
|
+
.slice(0, 2);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export default function ActivityFeed({
|
|
45
|
+
items,
|
|
46
|
+
title = 'Recent Activity',
|
|
47
|
+
maxItems = 10,
|
|
48
|
+
onViewAll,
|
|
49
|
+
}: ActivityFeedProps) {
|
|
50
|
+
const displayItems = items.slice(0, maxItems);
|
|
51
|
+
|
|
52
|
+
return (
|
|
53
|
+
<div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6">
|
|
54
|
+
<div className="flex items-center justify-between mb-5">
|
|
55
|
+
<h3 className="text-lg font-semibold text-white">{title}</h3>
|
|
56
|
+
{onViewAll && (
|
|
57
|
+
<button
|
|
58
|
+
onClick={onViewAll}
|
|
59
|
+
className="text-sm text-cyan-400 hover:text-cyan-300 transition-colors"
|
|
60
|
+
>
|
|
61
|
+
View all
|
|
62
|
+
</button>
|
|
63
|
+
)}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
{displayItems.length === 0 ? (
|
|
67
|
+
<p className="text-white/30 text-sm py-8 text-center">No recent activity</p>
|
|
68
|
+
) : (
|
|
69
|
+
<div className="space-y-4">
|
|
70
|
+
{displayItems.map((item) => (
|
|
71
|
+
<div
|
|
72
|
+
key={item.id}
|
|
73
|
+
className="flex items-start gap-3 group"
|
|
74
|
+
>
|
|
75
|
+
{/* Avatar */}
|
|
76
|
+
<div className="flex-shrink-0 w-8 h-8 rounded-full bg-cyan-500/10 border border-cyan-500/20 flex items-center justify-center">
|
|
77
|
+
{item.avatar ? (
|
|
78
|
+
<img
|
|
79
|
+
src={item.avatar}
|
|
80
|
+
alt={item.user}
|
|
81
|
+
className="w-8 h-8 rounded-full object-cover"
|
|
82
|
+
/>
|
|
83
|
+
) : (
|
|
84
|
+
<span className="text-xs font-medium text-cyan-400">
|
|
85
|
+
{getInitials(item.user)}
|
|
86
|
+
</span>
|
|
87
|
+
)}
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
{/* Content */}
|
|
91
|
+
<div className="flex-1 min-w-0">
|
|
92
|
+
<p className="text-sm text-white/80">
|
|
93
|
+
<span className="font-medium text-white">{item.user}</span>{' '}
|
|
94
|
+
{item.action}
|
|
95
|
+
{item.target && (
|
|
96
|
+
<span className="font-medium text-cyan-400"> {item.target}</span>
|
|
97
|
+
)}
|
|
98
|
+
</p>
|
|
99
|
+
<p className="text-xs text-white/30 mt-0.5">
|
|
100
|
+
{formatRelativeTime(item.timestamp)}
|
|
101
|
+
</p>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
))}
|
|
105
|
+
</div>
|
|
106
|
+
)}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
export interface DataPoint {
|
|
6
|
+
label: string;
|
|
7
|
+
value: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
interface LineChartProps {
|
|
11
|
+
data: DataPoint[];
|
|
12
|
+
title?: string;
|
|
13
|
+
height?: number;
|
|
14
|
+
color?: string;
|
|
15
|
+
showGrid?: boolean;
|
|
16
|
+
showLabels?: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default function LineChart({
|
|
20
|
+
data,
|
|
21
|
+
title,
|
|
22
|
+
height = 200,
|
|
23
|
+
color = '#06b6d4',
|
|
24
|
+
showGrid = true,
|
|
25
|
+
showLabels = true,
|
|
26
|
+
}: LineChartProps) {
|
|
27
|
+
const chartData = useMemo(() => {
|
|
28
|
+
if (data.length === 0) return null;
|
|
29
|
+
|
|
30
|
+
const values = data.map((d) => d.value);
|
|
31
|
+
const maxVal = Math.max(...values);
|
|
32
|
+
const minVal = Math.min(...values);
|
|
33
|
+
const range = maxVal - minVal || 1;
|
|
34
|
+
|
|
35
|
+
const padding = { top: 20, right: 20, bottom: 40, left: 50 };
|
|
36
|
+
const chartWidth = 600;
|
|
37
|
+
const chartHeight = height;
|
|
38
|
+
const innerWidth = chartWidth - padding.left - padding.right;
|
|
39
|
+
const innerHeight = chartHeight - padding.top - padding.bottom;
|
|
40
|
+
|
|
41
|
+
const points = data.map((d, i) => ({
|
|
42
|
+
x: padding.left + (i / Math.max(data.length - 1, 1)) * innerWidth,
|
|
43
|
+
y: padding.top + innerHeight - ((d.value - minVal) / range) * innerHeight,
|
|
44
|
+
label: d.label,
|
|
45
|
+
value: d.value,
|
|
46
|
+
}));
|
|
47
|
+
|
|
48
|
+
const pathD = points
|
|
49
|
+
.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`)
|
|
50
|
+
.join(' ');
|
|
51
|
+
|
|
52
|
+
const areaD =
|
|
53
|
+
pathD +
|
|
54
|
+
` L ${points[points.length - 1].x} ${padding.top + innerHeight}` +
|
|
55
|
+
` L ${points[0].x} ${padding.top + innerHeight} Z`;
|
|
56
|
+
|
|
57
|
+
const gridLines = [];
|
|
58
|
+
const gridCount = 4;
|
|
59
|
+
for (let i = 0; i <= gridCount; i++) {
|
|
60
|
+
const y = padding.top + (i / gridCount) * innerHeight;
|
|
61
|
+
const val = maxVal - (i / gridCount) * range;
|
|
62
|
+
gridLines.push({ y, label: val.toFixed(0) });
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
points,
|
|
67
|
+
pathD,
|
|
68
|
+
areaD,
|
|
69
|
+
gridLines,
|
|
70
|
+
chartWidth,
|
|
71
|
+
chartHeight,
|
|
72
|
+
padding,
|
|
73
|
+
innerHeight,
|
|
74
|
+
};
|
|
75
|
+
}, [data, height]);
|
|
76
|
+
|
|
77
|
+
if (!chartData || data.length === 0) {
|
|
78
|
+
return (
|
|
79
|
+
<div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6">
|
|
80
|
+
{title && <h3 className="text-lg font-semibold text-white mb-4">{title}</h3>}
|
|
81
|
+
<div
|
|
82
|
+
className="flex items-center justify-center text-white/30"
|
|
83
|
+
style={{ height }}
|
|
84
|
+
>
|
|
85
|
+
No data available
|
|
86
|
+
</div>
|
|
87
|
+
</div>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6">
|
|
93
|
+
{title && <h3 className="text-lg font-semibold text-white mb-4">{title}</h3>}
|
|
94
|
+
|
|
95
|
+
<svg
|
|
96
|
+
viewBox={`0 0 ${chartData.chartWidth} ${chartData.chartHeight}`}
|
|
97
|
+
className="w-full"
|
|
98
|
+
style={{ height }}
|
|
99
|
+
>
|
|
100
|
+
{/* Gradient fill */}
|
|
101
|
+
<defs>
|
|
102
|
+
<linearGradient id="areaGradient" x1="0" y1="0" x2="0" y2="1">
|
|
103
|
+
<stop offset="0%" stopColor={color} stopOpacity="0.3" />
|
|
104
|
+
<stop offset="100%" stopColor={color} stopOpacity="0" />
|
|
105
|
+
</linearGradient>
|
|
106
|
+
</defs>
|
|
107
|
+
|
|
108
|
+
{/* Grid lines */}
|
|
109
|
+
{showGrid &&
|
|
110
|
+
chartData.gridLines.map((line, i) => (
|
|
111
|
+
<g key={i}>
|
|
112
|
+
<line
|
|
113
|
+
x1={chartData.padding.left}
|
|
114
|
+
y1={line.y}
|
|
115
|
+
x2={chartData.chartWidth - chartData.padding.right}
|
|
116
|
+
y2={line.y}
|
|
117
|
+
stroke="rgba(255,255,255,0.06)"
|
|
118
|
+
strokeDasharray="4 4"
|
|
119
|
+
/>
|
|
120
|
+
<text
|
|
121
|
+
x={chartData.padding.left - 10}
|
|
122
|
+
y={line.y + 4}
|
|
123
|
+
textAnchor="end"
|
|
124
|
+
fill="rgba(255,255,255,0.3)"
|
|
125
|
+
fontSize="11"
|
|
126
|
+
>
|
|
127
|
+
{line.label}
|
|
128
|
+
</text>
|
|
129
|
+
</g>
|
|
130
|
+
))}
|
|
131
|
+
|
|
132
|
+
{/* Area fill */}
|
|
133
|
+
<path d={chartData.areaD} fill="url(#areaGradient)" />
|
|
134
|
+
|
|
135
|
+
{/* Line */}
|
|
136
|
+
<path
|
|
137
|
+
d={chartData.pathD}
|
|
138
|
+
fill="none"
|
|
139
|
+
stroke={color}
|
|
140
|
+
strokeWidth="2.5"
|
|
141
|
+
strokeLinecap="round"
|
|
142
|
+
strokeLinejoin="round"
|
|
143
|
+
/>
|
|
144
|
+
|
|
145
|
+
{/* Data points */}
|
|
146
|
+
{chartData.points.map((point, i) => (
|
|
147
|
+
<circle
|
|
148
|
+
key={i}
|
|
149
|
+
cx={point.x}
|
|
150
|
+
cy={point.y}
|
|
151
|
+
r="3.5"
|
|
152
|
+
fill="#0f172a"
|
|
153
|
+
stroke={color}
|
|
154
|
+
strokeWidth="2"
|
|
155
|
+
/>
|
|
156
|
+
))}
|
|
157
|
+
|
|
158
|
+
{/* X-axis labels */}
|
|
159
|
+
{showLabels &&
|
|
160
|
+
chartData.points
|
|
161
|
+
.filter((_, i) => {
|
|
162
|
+
const step = Math.max(1, Math.floor(data.length / 6));
|
|
163
|
+
return i % step === 0 || i === data.length - 1;
|
|
164
|
+
})
|
|
165
|
+
.map((point, i) => (
|
|
166
|
+
<text
|
|
167
|
+
key={i}
|
|
168
|
+
x={point.x}
|
|
169
|
+
y={chartData.chartHeight - 8}
|
|
170
|
+
textAnchor="middle"
|
|
171
|
+
fill="rgba(255,255,255,0.3)"
|
|
172
|
+
fontSize="11"
|
|
173
|
+
>
|
|
174
|
+
{point.label}
|
|
175
|
+
</text>
|
|
176
|
+
))}
|
|
177
|
+
</svg>
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
interface StatsCardProps {
|
|
4
|
+
title: string;
|
|
5
|
+
value: string | number;
|
|
6
|
+
change?: number;
|
|
7
|
+
changeLabel?: string;
|
|
8
|
+
icon?: React.ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function StatsCard({
|
|
12
|
+
title,
|
|
13
|
+
value,
|
|
14
|
+
change,
|
|
15
|
+
changeLabel = 'vs last period',
|
|
16
|
+
icon,
|
|
17
|
+
}: StatsCardProps) {
|
|
18
|
+
const isPositive = change !== undefined && change >= 0;
|
|
19
|
+
const changeColor = isPositive ? 'text-emerald-400' : 'text-red-400';
|
|
20
|
+
const changeIcon = isPositive ? '\u2191' : '\u2193';
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="backdrop-blur-xl bg-white/5 border border-white/10 rounded-2xl p-6 hover:bg-white/[0.07] transition-all group">
|
|
24
|
+
<div className="flex items-start justify-between mb-4">
|
|
25
|
+
<p className="text-sm font-medium text-white/50 uppercase tracking-wider">
|
|
26
|
+
{title}
|
|
27
|
+
</p>
|
|
28
|
+
{icon && (
|
|
29
|
+
<div className="p-2 bg-cyan-500/10 rounded-lg text-cyan-400 group-hover:bg-cyan-500/20 transition-colors">
|
|
30
|
+
{icon}
|
|
31
|
+
</div>
|
|
32
|
+
)}
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<p className="text-3xl font-bold text-white mb-2">{value}</p>
|
|
36
|
+
|
|
37
|
+
{change !== undefined && (
|
|
38
|
+
<div className="flex items-center gap-1.5">
|
|
39
|
+
<span className={`text-sm font-medium ${changeColor}`}>
|
|
40
|
+
{changeIcon} {Math.abs(change).toFixed(1)}%
|
|
41
|
+
</span>
|
|
42
|
+
<span className="text-xs text-white/30">{changeLabel}</span>
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
interface SummaryGridProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
columns?: 2 | 3 | 4;
|
|
6
|
+
title?: string;
|
|
7
|
+
subtitle?: string;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const columnClasses: Record<number, string> = {
|
|
11
|
+
2: 'grid-cols-1 sm:grid-cols-2',
|
|
12
|
+
3: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-3',
|
|
13
|
+
4: 'grid-cols-1 sm:grid-cols-2 lg:grid-cols-4',
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export default function SummaryGrid({
|
|
17
|
+
children,
|
|
18
|
+
columns = 4,
|
|
19
|
+
title,
|
|
20
|
+
subtitle,
|
|
21
|
+
}: SummaryGridProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div>
|
|
24
|
+
{(title || subtitle) && (
|
|
25
|
+
<div className="mb-6">
|
|
26
|
+
{title && (
|
|
27
|
+
<h2 className="text-xl font-bold text-white">{title}</h2>
|
|
28
|
+
)}
|
|
29
|
+
{subtitle && (
|
|
30
|
+
<p className="text-sm text-white/50 mt-1">{subtitle}</p>
|
|
31
|
+
)}
|
|
32
|
+
</div>
|
|
33
|
+
)}
|
|
34
|
+
<div className={`grid ${columnClasses[columns]} gap-4`}>
|
|
35
|
+
{children}
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dashboard-analytics",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Analytics dashboard with stats cards, line charts, activity feed, and summary grid",
|
|
5
|
+
"author": "AD AI Engine",
|
|
6
|
+
"category": "dashboard",
|
|
7
|
+
"dependencies": [],
|
|
8
|
+
"files": {
|
|
9
|
+
"components": [
|
|
10
|
+
"components/dashboard/StatsCard.tsx",
|
|
11
|
+
"components/dashboard/LineChart.tsx",
|
|
12
|
+
"components/dashboard/ActivityFeed.tsx",
|
|
13
|
+
"components/dashboard/SummaryGrid.tsx"
|
|
14
|
+
],
|
|
15
|
+
"api": []
|
|
16
|
+
},
|
|
17
|
+
"schema": null,
|
|
18
|
+
"instructions": "1. Import components into your dashboard page\n2. Pass data props to each component\n3. Use SummaryGrid as the layout wrapper for StatsCards\n4. LineChart accepts an array of { label, value } data points\n5. ActivityFeed accepts an array of activity items with timestamp, user, and action"
|
|
19
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
interface BulkActionsProps {
|
|
4
|
+
selectedCount: number;
|
|
5
|
+
totalCount: number;
|
|
6
|
+
onSelectAll: () => void;
|
|
7
|
+
onDeselectAll: () => void;
|
|
8
|
+
onDeleteSelected: () => void;
|
|
9
|
+
allSelected: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export default function BulkActions({
|
|
13
|
+
selectedCount,
|
|
14
|
+
totalCount,
|
|
15
|
+
onSelectAll,
|
|
16
|
+
onDeselectAll,
|
|
17
|
+
onDeleteSelected,
|
|
18
|
+
allSelected,
|
|
19
|
+
}: BulkActionsProps) {
|
|
20
|
+
if (selectedCount === 0) return null;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="flex items-center gap-3 px-4 py-2.5 bg-cyan-500/10 border border-cyan-500/20 rounded-lg">
|
|
24
|
+
<span className="text-sm text-cyan-400 font-medium">
|
|
25
|
+
{selectedCount} of {totalCount} selected
|
|
26
|
+
</span>
|
|
27
|
+
|
|
28
|
+
<div className="h-4 w-px bg-white/10" />
|
|
29
|
+
|
|
30
|
+
{!allSelected ? (
|
|
31
|
+
<button
|
|
32
|
+
onClick={onSelectAll}
|
|
33
|
+
className="text-sm text-white/60 hover:text-white transition-colors"
|
|
34
|
+
>
|
|
35
|
+
Select all
|
|
36
|
+
</button>
|
|
37
|
+
) : (
|
|
38
|
+
<button
|
|
39
|
+
onClick={onDeselectAll}
|
|
40
|
+
className="text-sm text-white/60 hover:text-white transition-colors"
|
|
41
|
+
>
|
|
42
|
+
Deselect all
|
|
43
|
+
</button>
|
|
44
|
+
)}
|
|
45
|
+
|
|
46
|
+
<div className="ml-auto">
|
|
47
|
+
<button
|
|
48
|
+
onClick={onDeleteSelected}
|
|
49
|
+
className="flex items-center gap-1.5 px-3 py-1.5 bg-red-500/10 border border-red-500/20 rounded-lg text-sm text-red-400 hover:bg-red-500/20 transition-all"
|
|
50
|
+
>
|
|
51
|
+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
52
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
53
|
+
</svg>
|
|
54
|
+
Delete selected
|
|
55
|
+
</button>
|
|
56
|
+
</div>
|
|
57
|
+
</div>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useRef, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
interface ColumnToggleProps {
|
|
6
|
+
columns: { key: string; label: string }[];
|
|
7
|
+
visibleColumns: Set<string>;
|
|
8
|
+
onToggle: (key: string) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export default function ColumnToggle({
|
|
12
|
+
columns,
|
|
13
|
+
visibleColumns,
|
|
14
|
+
onToggle,
|
|
15
|
+
}: ColumnToggleProps) {
|
|
16
|
+
const [open, setOpen] = useState(false);
|
|
17
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
function handleClickOutside(e: MouseEvent) {
|
|
21
|
+
if (ref.current && !ref.current.contains(e.target as Node)) {
|
|
22
|
+
setOpen(false);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
26
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<div className="relative" ref={ref}>
|
|
31
|
+
<button
|
|
32
|
+
onClick={() => setOpen(!open)}
|
|
33
|
+
className="flex items-center gap-2 px-3 py-2 bg-white/5 border border-white/10 rounded-lg text-sm text-white/70 hover:bg-white/10 hover:text-white transition-all"
|
|
34
|
+
>
|
|
35
|
+
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
|
|
36
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.066 2.573c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.573 1.066c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.066-2.573c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z" />
|
|
37
|
+
<path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
38
|
+
</svg>
|
|
39
|
+
Columns
|
|
40
|
+
</button>
|
|
41
|
+
|
|
42
|
+
{open && (
|
|
43
|
+
<div className="absolute right-0 top-full mt-2 w-56 backdrop-blur-xl bg-gray-900/95 border border-white/10 rounded-lg shadow-xl z-50 py-2">
|
|
44
|
+
<p className="px-3 py-1.5 text-xs font-medium text-white/40 uppercase tracking-wider">
|
|
45
|
+
Toggle columns
|
|
46
|
+
</p>
|
|
47
|
+
{columns.map((col) => (
|
|
48
|
+
<label
|
|
49
|
+
key={col.key}
|
|
50
|
+
className="flex items-center gap-2.5 px-3 py-2 hover:bg-white/5 cursor-pointer transition-colors"
|
|
51
|
+
>
|
|
52
|
+
<input
|
|
53
|
+
type="checkbox"
|
|
54
|
+
checked={visibleColumns.has(col.key)}
|
|
55
|
+
onChange={() => onToggle(col.key)}
|
|
56
|
+
className="w-4 h-4 rounded border-white/20 bg-white/5 text-cyan-500 focus:ring-cyan-500/50 focus:ring-offset-0"
|
|
57
|
+
/>
|
|
58
|
+
<span className="text-sm text-white/70">{col.label}</span>
|
|
59
|
+
</label>
|
|
60
|
+
))}
|
|
61
|
+
</div>
|
|
62
|
+
)}
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|