@contractspec/lib.example-shared-ui 1.10.1 → 1.12.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/.turbo/turbo-build.log +86 -11
- package/.turbo/turbo-prebuild.log +1 -0
- package/CHANGELOG.md +32 -0
- package/dist/EvolutionDashboard.d.ts +11 -0
- package/dist/EvolutionDashboard.d.ts.map +1 -0
- package/dist/EvolutionDashboard.js +804 -0
- package/dist/EvolutionSidebar.d.ts +19 -0
- package/dist/EvolutionSidebar.d.ts.map +1 -0
- package/dist/EvolutionSidebar.js +532 -0
- package/dist/LocalDataIndicator.d.ts +2 -0
- package/dist/LocalDataIndicator.d.ts.map +1 -0
- package/dist/LocalDataIndicator.js +63 -0
- package/dist/MarkdownView.d.ts +20 -0
- package/dist/MarkdownView.d.ts.map +1 -0
- package/dist/MarkdownView.js +304 -0
- package/dist/OverlayContextProvider.d.ts +79 -0
- package/dist/OverlayContextProvider.d.ts.map +1 -0
- package/dist/OverlayContextProvider.js +203 -0
- package/dist/PersonalizationInsights.d.ts +14 -0
- package/dist/PersonalizationInsights.d.ts.map +1 -0
- package/dist/PersonalizationInsights.js +456 -0
- package/dist/SaveToStudioButton.d.ts +8 -0
- package/dist/SaveToStudioButton.d.ts.map +1 -0
- package/dist/SaveToStudioButton.js +74 -0
- package/dist/SpecEditorPanel.d.ts +23 -0
- package/dist/SpecEditorPanel.d.ts.map +1 -0
- package/dist/SpecEditorPanel.js +720 -0
- package/dist/TemplateShell.d.ts +13 -0
- package/dist/TemplateShell.d.ts.map +1 -0
- package/dist/TemplateShell.js +190 -0
- package/dist/browser/EvolutionDashboard.js +803 -0
- package/dist/browser/EvolutionSidebar.js +531 -0
- package/dist/browser/LocalDataIndicator.js +62 -0
- package/dist/browser/MarkdownView.js +303 -0
- package/dist/browser/OverlayContextProvider.js +202 -0
- package/dist/browser/PersonalizationInsights.js +455 -0
- package/dist/browser/SaveToStudioButton.js +73 -0
- package/dist/browser/SpecEditorPanel.js +719 -0
- package/dist/browser/TemplateShell.js +189 -0
- package/dist/browser/hooks/index.js +1516 -0
- package/dist/browser/hooks/useBehaviorTracking.js +157 -0
- package/dist/browser/hooks/useEvolution.js +260 -0
- package/dist/browser/hooks/useRegistryTemplates.js +31 -0
- package/dist/browser/hooks/useSpecContent.js +579 -0
- package/dist/browser/hooks/useWorkflowComposer.js +493 -0
- package/dist/browser/index.js +3497 -0
- package/dist/browser/lib/component-registry.js +42 -0
- package/dist/browser/lib/runtime-context.js +15 -0
- package/dist/browser/lib/types.js +0 -0
- package/dist/browser/overlay-types.js +0 -0
- package/dist/browser/utils/fetchPresentationData.js +15 -0
- package/dist/browser/utils/generateSpecFromTemplate.js +423 -0
- package/dist/browser/utils/index.js +437 -0
- package/dist/hooks/index.d.ts +6 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +1517 -0
- package/dist/hooks/useBehaviorTracking.d.ts +56 -0
- package/dist/hooks/useBehaviorTracking.d.ts.map +1 -0
- package/dist/hooks/useBehaviorTracking.js +158 -0
- package/dist/hooks/useEvolution.d.ts +111 -0
- package/dist/hooks/useEvolution.d.ts.map +1 -0
- package/dist/hooks/useEvolution.js +261 -0
- package/dist/hooks/useRegistryTemplates.d.ts +10 -0
- package/dist/hooks/useRegistryTemplates.d.ts.map +1 -0
- package/dist/hooks/useRegistryTemplates.js +32 -0
- package/dist/hooks/useSpecContent.d.ts +41 -0
- package/dist/hooks/useSpecContent.d.ts.map +1 -0
- package/dist/hooks/useSpecContent.js +580 -0
- package/dist/hooks/useWorkflowComposer.d.ts +94 -0
- package/dist/hooks/useWorkflowComposer.d.ts.map +1 -0
- package/dist/hooks/useWorkflowComposer.js +494 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3498 -0
- package/dist/lib/component-registry.d.ts +18 -0
- package/dist/lib/component-registry.d.ts.map +1 -0
- package/dist/lib/component-registry.js +43 -0
- package/dist/lib/runtime-context.d.ts +29 -0
- package/dist/lib/runtime-context.d.ts.map +1 -0
- package/dist/lib/runtime-context.js +16 -0
- package/dist/lib/types.d.ts +69 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +1 -0
- package/dist/node/EvolutionDashboard.js +803 -0
- package/dist/node/EvolutionSidebar.js +531 -0
- package/dist/node/LocalDataIndicator.js +62 -0
- package/dist/node/MarkdownView.js +303 -0
- package/dist/node/OverlayContextProvider.js +202 -0
- package/dist/node/PersonalizationInsights.js +455 -0
- package/dist/node/SaveToStudioButton.js +73 -0
- package/dist/node/SpecEditorPanel.js +719 -0
- package/dist/node/TemplateShell.js +189 -0
- package/dist/node/hooks/index.js +1516 -0
- package/dist/node/hooks/useBehaviorTracking.js +157 -0
- package/dist/node/hooks/useEvolution.js +260 -0
- package/dist/node/hooks/useRegistryTemplates.js +31 -0
- package/dist/node/hooks/useSpecContent.js +579 -0
- package/dist/node/hooks/useWorkflowComposer.js +493 -0
- package/dist/node/index.js +3497 -0
- package/dist/node/lib/component-registry.js +42 -0
- package/dist/node/lib/runtime-context.js +15 -0
- package/dist/node/lib/types.js +0 -0
- package/dist/node/overlay-types.js +0 -0
- package/dist/node/utils/fetchPresentationData.js +15 -0
- package/dist/node/utils/generateSpecFromTemplate.js +423 -0
- package/dist/node/utils/index.js +437 -0
- package/dist/overlay-types.d.ts +41 -0
- package/dist/overlay-types.d.ts.map +1 -0
- package/dist/overlay-types.js +1 -0
- package/dist/utils/fetchPresentationData.d.ts +34 -0
- package/dist/utils/fetchPresentationData.d.ts.map +1 -0
- package/dist/utils/fetchPresentationData.js +16 -0
- package/dist/utils/generateSpecFromTemplate.d.ts +7 -0
- package/dist/utils/generateSpecFromTemplate.d.ts.map +1 -0
- package/dist/utils/generateSpecFromTemplate.js +424 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +438 -0
- package/package.json +222 -17
- package/.turbo/turbo-build$colon$bundle.log +0 -9
- package/dist/index.mjs +0 -3121
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/hooks/useBehaviorTracking.ts
|
|
3
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
"use client";
|
|
5
|
+
var BEHAVIOR_STORAGE_KEY = "contractspec-behavior-data";
|
|
6
|
+
var ALL_FEATURES = [
|
|
7
|
+
"playground",
|
|
8
|
+
"specs",
|
|
9
|
+
"builder",
|
|
10
|
+
"markdown",
|
|
11
|
+
"evolution",
|
|
12
|
+
"canvas_add",
|
|
13
|
+
"canvas_delete",
|
|
14
|
+
"spec_save",
|
|
15
|
+
"spec_validate",
|
|
16
|
+
"ai_suggestions"
|
|
17
|
+
];
|
|
18
|
+
function useBehaviorTracking(templateId) {
|
|
19
|
+
const [events, setEvents] = useState([]);
|
|
20
|
+
const sessionStartRef = useRef(new Date);
|
|
21
|
+
const [eventCount, setEventCount] = useState(0);
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
try {
|
|
24
|
+
const stored = localStorage.getItem(BEHAVIOR_STORAGE_KEY);
|
|
25
|
+
if (stored) {
|
|
26
|
+
const data = JSON.parse(stored);
|
|
27
|
+
setEvents(data.events.map((e) => ({
|
|
28
|
+
...e,
|
|
29
|
+
timestamp: new Date(e.timestamp)
|
|
30
|
+
})));
|
|
31
|
+
sessionStartRef.current = new Date(data.sessionStart);
|
|
32
|
+
}
|
|
33
|
+
} catch {}
|
|
34
|
+
}, []);
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
if (events.length > 0) {
|
|
37
|
+
try {
|
|
38
|
+
localStorage.setItem(BEHAVIOR_STORAGE_KEY, JSON.stringify({
|
|
39
|
+
events: events.map((e) => ({
|
|
40
|
+
...e,
|
|
41
|
+
timestamp: e.timestamp.toISOString()
|
|
42
|
+
})),
|
|
43
|
+
sessionStart: sessionStartRef.current.toISOString()
|
|
44
|
+
}));
|
|
45
|
+
} catch {}
|
|
46
|
+
}
|
|
47
|
+
}, [events]);
|
|
48
|
+
const trackEvent = useCallback((type, metadata) => {
|
|
49
|
+
const event = {
|
|
50
|
+
type,
|
|
51
|
+
timestamp: new Date,
|
|
52
|
+
templateId,
|
|
53
|
+
metadata
|
|
54
|
+
};
|
|
55
|
+
setEvents((prev) => [...prev, event]);
|
|
56
|
+
setEventCount((prev) => prev + 1);
|
|
57
|
+
}, [templateId]);
|
|
58
|
+
const getEventsByType = useCallback((type) => {
|
|
59
|
+
return events.filter((e) => e.type === type);
|
|
60
|
+
}, [events]);
|
|
61
|
+
const getSummary = useCallback(() => {
|
|
62
|
+
const now = new Date;
|
|
63
|
+
const sessionDuration = now.getTime() - sessionStartRef.current.getTime();
|
|
64
|
+
const templateCounts = new Map;
|
|
65
|
+
for (const event of events) {
|
|
66
|
+
const count = templateCounts.get(event.templateId) ?? 0;
|
|
67
|
+
templateCounts.set(event.templateId, count + 1);
|
|
68
|
+
}
|
|
69
|
+
const mostUsedTemplates = Array.from(templateCounts.entries()).map(([templateId2, count]) => ({ templateId: templateId2, count })).sort((a, b) => b.count - a.count).slice(0, 3);
|
|
70
|
+
const modeCounts = new Map;
|
|
71
|
+
for (const event of events) {
|
|
72
|
+
if (event.type === "mode_change" && event.metadata?.mode) {
|
|
73
|
+
const mode = event.metadata.mode;
|
|
74
|
+
const count = modeCounts.get(mode) ?? 0;
|
|
75
|
+
modeCounts.set(mode, count + 1);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
const mostUsedModes = Array.from(modeCounts.entries()).map(([mode, count]) => ({ mode, count })).sort((a, b) => b.count - a.count);
|
|
79
|
+
const featuresUsed = new Set;
|
|
80
|
+
for (const event of events) {
|
|
81
|
+
if (event.type === "mode_change" && event.metadata?.mode) {
|
|
82
|
+
featuresUsed.add(event.metadata.mode);
|
|
83
|
+
}
|
|
84
|
+
if (event.type === "feature_usage" && event.metadata?.feature) {
|
|
85
|
+
featuresUsed.add(event.metadata.feature);
|
|
86
|
+
}
|
|
87
|
+
if (event.type === "canvas_interaction") {
|
|
88
|
+
const action = event.metadata?.action;
|
|
89
|
+
if (action === "add")
|
|
90
|
+
featuresUsed.add("canvas_add");
|
|
91
|
+
if (action === "delete")
|
|
92
|
+
featuresUsed.add("canvas_delete");
|
|
93
|
+
}
|
|
94
|
+
if (event.type === "spec_edit") {
|
|
95
|
+
const action = event.metadata?.action;
|
|
96
|
+
if (action === "save")
|
|
97
|
+
featuresUsed.add("spec_save");
|
|
98
|
+
if (action === "validate")
|
|
99
|
+
featuresUsed.add("spec_validate");
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const unusedFeatures = ALL_FEATURES.filter((f) => !featuresUsed.has(f));
|
|
103
|
+
const errorCount = events.filter((e) => e.type === "error").length;
|
|
104
|
+
const recommendations = generateRecommendations(Array.from(featuresUsed), unusedFeatures, mostUsedModes, events.length);
|
|
105
|
+
return {
|
|
106
|
+
totalEvents: events.length,
|
|
107
|
+
sessionDuration,
|
|
108
|
+
mostUsedTemplates,
|
|
109
|
+
mostUsedModes,
|
|
110
|
+
featuresUsed: Array.from(featuresUsed),
|
|
111
|
+
unusedFeatures,
|
|
112
|
+
errorCount,
|
|
113
|
+
recommendations
|
|
114
|
+
};
|
|
115
|
+
}, [events]);
|
|
116
|
+
const clear = useCallback(() => {
|
|
117
|
+
setEvents([]);
|
|
118
|
+
setEventCount(0);
|
|
119
|
+
sessionStartRef.current = new Date;
|
|
120
|
+
localStorage.removeItem(BEHAVIOR_STORAGE_KEY);
|
|
121
|
+
}, []);
|
|
122
|
+
return useMemo(() => ({
|
|
123
|
+
trackEvent,
|
|
124
|
+
getSummary,
|
|
125
|
+
getEventsByType,
|
|
126
|
+
eventCount,
|
|
127
|
+
sessionStart: sessionStartRef.current,
|
|
128
|
+
clear
|
|
129
|
+
}), [trackEvent, getSummary, getEventsByType, eventCount, clear]);
|
|
130
|
+
}
|
|
131
|
+
function generateRecommendations(featuresUsed, unusedFeatures, mostUsedModes, totalEvents) {
|
|
132
|
+
const recommendations = [];
|
|
133
|
+
if (unusedFeatures.includes("evolution")) {
|
|
134
|
+
recommendations.push("Try the AI Evolution mode to get automated improvement suggestions");
|
|
135
|
+
}
|
|
136
|
+
if (unusedFeatures.includes("markdown")) {
|
|
137
|
+
recommendations.push("Use Markdown preview to see documentation for your specs");
|
|
138
|
+
}
|
|
139
|
+
if (unusedFeatures.includes("builder")) {
|
|
140
|
+
recommendations.push("Explore the Visual Builder to design your UI components");
|
|
141
|
+
}
|
|
142
|
+
if (!featuresUsed.includes("spec_validate") && featuresUsed.includes("specs")) {
|
|
143
|
+
recommendations.push("Don't forget to validate your specs before saving");
|
|
144
|
+
}
|
|
145
|
+
if (featuresUsed.includes("evolution") && !featuresUsed.includes("ai_suggestions")) {
|
|
146
|
+
recommendations.push("Generate AI suggestions to get actionable improvement recommendations");
|
|
147
|
+
}
|
|
148
|
+
if (totalEvents > 50) {
|
|
149
|
+
recommendations.push("Great engagement! Consider saving your work regularly");
|
|
150
|
+
}
|
|
151
|
+
if (mostUsedModes.length === 1) {
|
|
152
|
+
recommendations.push("Try different modes to explore all sandbox capabilities");
|
|
153
|
+
}
|
|
154
|
+
return recommendations;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// src/PersonalizationInsights.tsx
|
|
158
|
+
import { useCallback as useCallback2, useMemo as useMemo2, useState as useState2 } from "react";
|
|
159
|
+
import { Button } from "@contractspec/lib.design-system";
|
|
160
|
+
import { Card } from "@contractspec/lib.ui-kit-web/ui/card";
|
|
161
|
+
import { Badge } from "@contractspec/lib.ui-kit-web/ui/badge";
|
|
162
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
163
|
+
"use client";
|
|
164
|
+
function PersonalizationInsights({
|
|
165
|
+
templateId,
|
|
166
|
+
collapsed = false,
|
|
167
|
+
onToggle
|
|
168
|
+
}) {
|
|
169
|
+
const { getSummary, eventCount, clear, sessionStart } = useBehaviorTracking(templateId);
|
|
170
|
+
const [showDetails, setShowDetails] = useState2(false);
|
|
171
|
+
const summary = useMemo2(() => getSummary(), [getSummary]);
|
|
172
|
+
const formatDuration = useCallback2((ms) => {
|
|
173
|
+
const seconds = Math.floor(ms / 1000);
|
|
174
|
+
const minutes = Math.floor(seconds / 60);
|
|
175
|
+
const hours = Math.floor(minutes / 60);
|
|
176
|
+
if (hours > 0) {
|
|
177
|
+
return `${hours}h ${minutes % 60}m`;
|
|
178
|
+
}
|
|
179
|
+
if (minutes > 0) {
|
|
180
|
+
return `${minutes}m ${seconds % 60}s`;
|
|
181
|
+
}
|
|
182
|
+
return `${seconds}s`;
|
|
183
|
+
}, []);
|
|
184
|
+
const handleClear = useCallback2(() => {
|
|
185
|
+
clear();
|
|
186
|
+
}, [clear]);
|
|
187
|
+
if (collapsed) {
|
|
188
|
+
return /* @__PURE__ */ jsxDEV("button", {
|
|
189
|
+
onClick: onToggle,
|
|
190
|
+
className: "flex items-center gap-2 rounded-lg border border-blue-500/30 bg-blue-500/10 px-3 py-2 text-sm transition hover:bg-blue-500/20",
|
|
191
|
+
type: "button",
|
|
192
|
+
children: [
|
|
193
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
194
|
+
children: "\uD83D\uDCCA"
|
|
195
|
+
}, undefined, false, undefined, this),
|
|
196
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
197
|
+
children: "Insights"
|
|
198
|
+
}, undefined, false, undefined, this),
|
|
199
|
+
/* @__PURE__ */ jsxDEV(Badge, {
|
|
200
|
+
variant: "secondary",
|
|
201
|
+
children: eventCount
|
|
202
|
+
}, undefined, false, undefined, this)
|
|
203
|
+
]
|
|
204
|
+
}, undefined, true, undefined, this);
|
|
205
|
+
}
|
|
206
|
+
return /* @__PURE__ */ jsxDEV(Card, {
|
|
207
|
+
className: "overflow-hidden",
|
|
208
|
+
children: [
|
|
209
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
210
|
+
className: "flex items-center justify-between border-b border-blue-500/20 bg-blue-500/5 px-4 py-3",
|
|
211
|
+
children: [
|
|
212
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
213
|
+
className: "flex items-center gap-2",
|
|
214
|
+
children: [
|
|
215
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
216
|
+
children: "\uD83D\uDCCA"
|
|
217
|
+
}, undefined, false, undefined, this),
|
|
218
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
219
|
+
className: "font-semibold",
|
|
220
|
+
children: "Personalization Insights"
|
|
221
|
+
}, undefined, false, undefined, this)
|
|
222
|
+
]
|
|
223
|
+
}, undefined, true, undefined, this),
|
|
224
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
225
|
+
className: "flex items-center gap-2",
|
|
226
|
+
children: [
|
|
227
|
+
/* @__PURE__ */ jsxDEV(Button, {
|
|
228
|
+
variant: "ghost",
|
|
229
|
+
size: "sm",
|
|
230
|
+
onPress: () => setShowDetails(!showDetails),
|
|
231
|
+
children: showDetails ? "Hide Details" : "Show Details"
|
|
232
|
+
}, undefined, false, undefined, this),
|
|
233
|
+
onToggle && /* @__PURE__ */ jsxDEV("button", {
|
|
234
|
+
onClick: onToggle,
|
|
235
|
+
className: "text-muted-foreground hover:text-foreground p-1",
|
|
236
|
+
type: "button",
|
|
237
|
+
title: "Collapse",
|
|
238
|
+
children: "\u2715"
|
|
239
|
+
}, undefined, false, undefined, this)
|
|
240
|
+
]
|
|
241
|
+
}, undefined, true, undefined, this)
|
|
242
|
+
]
|
|
243
|
+
}, undefined, true, undefined, this),
|
|
244
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
245
|
+
className: "p-4",
|
|
246
|
+
children: [
|
|
247
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
248
|
+
className: "mb-4 grid grid-cols-2 gap-3 md:grid-cols-4",
|
|
249
|
+
children: [
|
|
250
|
+
/* @__PURE__ */ jsxDEV(StatCard, {
|
|
251
|
+
label: "Session Time",
|
|
252
|
+
value: formatDuration(summary.sessionDuration),
|
|
253
|
+
icon: "\u23F1\uFE0F"
|
|
254
|
+
}, undefined, false, undefined, this),
|
|
255
|
+
/* @__PURE__ */ jsxDEV(StatCard, {
|
|
256
|
+
label: "Events Tracked",
|
|
257
|
+
value: summary.totalEvents.toString(),
|
|
258
|
+
icon: "\uD83D\uDCC8"
|
|
259
|
+
}, undefined, false, undefined, this),
|
|
260
|
+
/* @__PURE__ */ jsxDEV(StatCard, {
|
|
261
|
+
label: "Features Used",
|
|
262
|
+
value: `${summary.featuresUsed.length}/${summary.featuresUsed.length + summary.unusedFeatures.length}`,
|
|
263
|
+
icon: "\u2728"
|
|
264
|
+
}, undefined, false, undefined, this),
|
|
265
|
+
/* @__PURE__ */ jsxDEV(StatCard, {
|
|
266
|
+
label: "Errors",
|
|
267
|
+
value: summary.errorCount.toString(),
|
|
268
|
+
icon: "\u26A0\uFE0F",
|
|
269
|
+
variant: summary.errorCount > 0 ? "warning" : "success"
|
|
270
|
+
}, undefined, false, undefined, this)
|
|
271
|
+
]
|
|
272
|
+
}, undefined, true, undefined, this),
|
|
273
|
+
summary.recommendations.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
274
|
+
className: "mb-4",
|
|
275
|
+
children: [
|
|
276
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
277
|
+
className: "mb-2 text-xs font-semibold text-blue-400 uppercase",
|
|
278
|
+
children: "Recommendations"
|
|
279
|
+
}, undefined, false, undefined, this),
|
|
280
|
+
/* @__PURE__ */ jsxDEV("ul", {
|
|
281
|
+
className: "space-y-1",
|
|
282
|
+
children: summary.recommendations.map((rec, index) => /* @__PURE__ */ jsxDEV("li", {
|
|
283
|
+
className: "flex items-start gap-2 text-sm",
|
|
284
|
+
children: [
|
|
285
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
286
|
+
className: "text-blue-400",
|
|
287
|
+
children: "\uD83D\uDCA1"
|
|
288
|
+
}, undefined, false, undefined, this),
|
|
289
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
290
|
+
children: rec
|
|
291
|
+
}, undefined, false, undefined, this)
|
|
292
|
+
]
|
|
293
|
+
}, index, true, undefined, this))
|
|
294
|
+
}, undefined, false, undefined, this)
|
|
295
|
+
]
|
|
296
|
+
}, undefined, true, undefined, this),
|
|
297
|
+
summary.unusedFeatures.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
298
|
+
className: "mb-4",
|
|
299
|
+
children: [
|
|
300
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
301
|
+
className: "mb-2 text-xs font-semibold text-blue-400 uppercase",
|
|
302
|
+
children: "Try These Features"
|
|
303
|
+
}, undefined, false, undefined, this),
|
|
304
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
305
|
+
className: "flex flex-wrap gap-2",
|
|
306
|
+
children: summary.unusedFeatures.slice(0, 5).map((feature) => /* @__PURE__ */ jsxDEV(Badge, {
|
|
307
|
+
variant: "secondary",
|
|
308
|
+
children: formatFeatureName(feature)
|
|
309
|
+
}, feature, false, undefined, this))
|
|
310
|
+
}, undefined, false, undefined, this)
|
|
311
|
+
]
|
|
312
|
+
}, undefined, true, undefined, this),
|
|
313
|
+
showDetails && /* @__PURE__ */ jsxDEV(DetailedInsights, {
|
|
314
|
+
summary,
|
|
315
|
+
sessionStart
|
|
316
|
+
}, undefined, false, undefined, this),
|
|
317
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
318
|
+
className: "mt-4 flex justify-end border-t border-blue-500/10 pt-4",
|
|
319
|
+
children: /* @__PURE__ */ jsxDEV(Button, {
|
|
320
|
+
variant: "ghost",
|
|
321
|
+
size: "sm",
|
|
322
|
+
onPress: handleClear,
|
|
323
|
+
children: "Clear Data"
|
|
324
|
+
}, undefined, false, undefined, this)
|
|
325
|
+
}, undefined, false, undefined, this)
|
|
326
|
+
]
|
|
327
|
+
}, undefined, true, undefined, this)
|
|
328
|
+
]
|
|
329
|
+
}, undefined, true, undefined, this);
|
|
330
|
+
}
|
|
331
|
+
function StatCard({
|
|
332
|
+
label,
|
|
333
|
+
value,
|
|
334
|
+
icon,
|
|
335
|
+
variant = "default"
|
|
336
|
+
}) {
|
|
337
|
+
const bgColors = {
|
|
338
|
+
default: "bg-blue-500/5 border-blue-500/20",
|
|
339
|
+
warning: "bg-amber-500/5 border-amber-500/20",
|
|
340
|
+
success: "bg-green-500/5 border-green-500/20"
|
|
341
|
+
};
|
|
342
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
343
|
+
className: `rounded-lg border p-3 text-center ${bgColors[variant]}`,
|
|
344
|
+
children: [
|
|
345
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
346
|
+
className: "mb-1 text-lg",
|
|
347
|
+
children: icon
|
|
348
|
+
}, undefined, false, undefined, this),
|
|
349
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
350
|
+
className: "text-lg font-bold",
|
|
351
|
+
children: value
|
|
352
|
+
}, undefined, false, undefined, this),
|
|
353
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
354
|
+
className: "text-muted-foreground text-xs",
|
|
355
|
+
children: label
|
|
356
|
+
}, undefined, false, undefined, this)
|
|
357
|
+
]
|
|
358
|
+
}, undefined, true, undefined, this);
|
|
359
|
+
}
|
|
360
|
+
function DetailedInsights({
|
|
361
|
+
summary,
|
|
362
|
+
sessionStart
|
|
363
|
+
}) {
|
|
364
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
365
|
+
className: "mt-4 space-y-4 border-t border-blue-500/10 pt-4",
|
|
366
|
+
children: [
|
|
367
|
+
summary.mostUsedTemplates.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
370
|
+
className: "mb-2 text-xs font-semibold text-blue-400 uppercase",
|
|
371
|
+
children: "Most Used Templates"
|
|
372
|
+
}, undefined, false, undefined, this),
|
|
373
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
374
|
+
className: "space-y-1",
|
|
375
|
+
children: summary.mostUsedTemplates.map(({ templateId, count }) => /* @__PURE__ */ jsxDEV("div", {
|
|
376
|
+
className: "flex items-center justify-between text-sm",
|
|
377
|
+
children: [
|
|
378
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
379
|
+
children: formatTemplateId(templateId)
|
|
380
|
+
}, undefined, false, undefined, this),
|
|
381
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
382
|
+
className: "text-muted-foreground",
|
|
383
|
+
children: [
|
|
384
|
+
count,
|
|
385
|
+
" events"
|
|
386
|
+
]
|
|
387
|
+
}, undefined, true, undefined, this)
|
|
388
|
+
]
|
|
389
|
+
}, templateId, true, undefined, this))
|
|
390
|
+
}, undefined, false, undefined, this)
|
|
391
|
+
]
|
|
392
|
+
}, undefined, true, undefined, this),
|
|
393
|
+
summary.mostUsedModes.length > 0 && /* @__PURE__ */ jsxDEV("div", {
|
|
394
|
+
children: [
|
|
395
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
396
|
+
className: "mb-2 text-xs font-semibold text-blue-400 uppercase",
|
|
397
|
+
children: "Mode Usage"
|
|
398
|
+
}, undefined, false, undefined, this),
|
|
399
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
400
|
+
className: "space-y-1",
|
|
401
|
+
children: summary.mostUsedModes.map(({ mode, count }) => /* @__PURE__ */ jsxDEV("div", {
|
|
402
|
+
className: "flex items-center justify-between text-sm",
|
|
403
|
+
children: [
|
|
404
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
405
|
+
children: formatFeatureName(mode)
|
|
406
|
+
}, undefined, false, undefined, this),
|
|
407
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
408
|
+
className: "text-muted-foreground",
|
|
409
|
+
children: [
|
|
410
|
+
count,
|
|
411
|
+
" switches"
|
|
412
|
+
]
|
|
413
|
+
}, undefined, true, undefined, this)
|
|
414
|
+
]
|
|
415
|
+
}, mode, true, undefined, this))
|
|
416
|
+
}, undefined, false, undefined, this)
|
|
417
|
+
]
|
|
418
|
+
}, undefined, true, undefined, this),
|
|
419
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
420
|
+
children: [
|
|
421
|
+
/* @__PURE__ */ jsxDEV("h4", {
|
|
422
|
+
className: "mb-2 text-xs font-semibold text-blue-400 uppercase",
|
|
423
|
+
children: "Features Used"
|
|
424
|
+
}, undefined, false, undefined, this),
|
|
425
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
426
|
+
className: "flex flex-wrap gap-2",
|
|
427
|
+
children: summary.featuresUsed.map((feature) => /* @__PURE__ */ jsxDEV(Badge, {
|
|
428
|
+
variant: "default",
|
|
429
|
+
className: "border-green-500/30 bg-green-500/20 text-green-400",
|
|
430
|
+
children: [
|
|
431
|
+
"\u2713 ",
|
|
432
|
+
formatFeatureName(feature)
|
|
433
|
+
]
|
|
434
|
+
}, feature, true, undefined, this))
|
|
435
|
+
}, undefined, false, undefined, this)
|
|
436
|
+
]
|
|
437
|
+
}, undefined, true, undefined, this),
|
|
438
|
+
/* @__PURE__ */ jsxDEV("div", {
|
|
439
|
+
className: "text-muted-foreground text-xs",
|
|
440
|
+
children: [
|
|
441
|
+
"Session started: ",
|
|
442
|
+
sessionStart.toLocaleString()
|
|
443
|
+
]
|
|
444
|
+
}, undefined, true, undefined, this)
|
|
445
|
+
]
|
|
446
|
+
}, undefined, true, undefined, this);
|
|
447
|
+
}
|
|
448
|
+
function formatFeatureName(feature) {
|
|
449
|
+
return feature.replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
450
|
+
}
|
|
451
|
+
function formatTemplateId(id) {
|
|
452
|
+
return id.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
|
|
453
|
+
}
|
|
454
|
+
export {
|
|
455
|
+
PersonalizationInsights
|
|
456
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface SaveToStudioButtonProps {
|
|
2
|
+
organizationId?: string;
|
|
3
|
+
projectName?: string;
|
|
4
|
+
endpoint?: string;
|
|
5
|
+
token?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function SaveToStudioButton({ organizationId, projectName, endpoint, token, }: SaveToStudioButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
//# sourceMappingURL=SaveToStudioButton.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SaveToStudioButton.d.ts","sourceRoot":"","sources":["../src/SaveToStudioButton.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,uBAAuB;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAA2B,EAC3B,WAAW,EACX,QAAQ,EACR,KAAK,GACN,EAAE,uBAAuB,2CA6CzB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/lib/runtime-context.tsx
|
|
3
|
+
import { createContext, useContext } from "react";
|
|
4
|
+
"use client";
|
|
5
|
+
var TemplateRuntimeContext = createContext(null);
|
|
6
|
+
function useTemplateRuntime() {
|
|
7
|
+
const context = useContext(TemplateRuntimeContext);
|
|
8
|
+
if (!context) {
|
|
9
|
+
throw new Error("useTemplateRuntime must be used within a TemplateRuntimeProvider");
|
|
10
|
+
}
|
|
11
|
+
return context;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// src/SaveToStudioButton.tsx
|
|
15
|
+
import { useState } from "react";
|
|
16
|
+
import { Sparkles } from "lucide-react";
|
|
17
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
18
|
+
"use client";
|
|
19
|
+
function SaveToStudioButton({
|
|
20
|
+
organizationId = "demo-org",
|
|
21
|
+
projectName,
|
|
22
|
+
endpoint,
|
|
23
|
+
token
|
|
24
|
+
}) {
|
|
25
|
+
const { installer, templateId, template } = useTemplateRuntime();
|
|
26
|
+
const [status, setStatus] = useState("idle");
|
|
27
|
+
const [error, setError] = useState(null);
|
|
28
|
+
const handleSave = async () => {
|
|
29
|
+
setStatus("saving");
|
|
30
|
+
setError(null);
|
|
31
|
+
try {
|
|
32
|
+
await installer.saveToStudio({
|
|
33
|
+
templateId,
|
|
34
|
+
projectName: projectName ?? `${template.name} demo`,
|
|
35
|
+
organizationId,
|
|
36
|
+
endpoint,
|
|
37
|
+
token
|
|
38
|
+
});
|
|
39
|
+
setStatus("saved");
|
|
40
|
+
setTimeout(() => setStatus("idle"), 3000);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
setStatus("error");
|
|
43
|
+
setError(err instanceof Error ? err.message : "Unknown error");
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
47
|
+
className: "flex flex-col items-end gap-1",
|
|
48
|
+
children: [
|
|
49
|
+
/* @__PURE__ */ jsxDEV("button", {
|
|
50
|
+
type: "button",
|
|
51
|
+
className: "btn-primary inline-flex items-center gap-2 text-sm",
|
|
52
|
+
onClick: handleSave,
|
|
53
|
+
disabled: status === "saving",
|
|
54
|
+
children: [
|
|
55
|
+
/* @__PURE__ */ jsxDEV(Sparkles, {
|
|
56
|
+
className: "h-4 w-4"
|
|
57
|
+
}, undefined, false, undefined, this),
|
|
58
|
+
status === "saving" ? "Publishing\u2026" : "Save to Studio"
|
|
59
|
+
]
|
|
60
|
+
}, undefined, true, undefined, this),
|
|
61
|
+
status === "error" && error ? /* @__PURE__ */ jsxDEV("p", {
|
|
62
|
+
className: "text-destructive text-xs",
|
|
63
|
+
children: error
|
|
64
|
+
}, undefined, false, undefined, this) : null,
|
|
65
|
+
status === "saved" ? /* @__PURE__ */ jsxDEV("p", {
|
|
66
|
+
className: "text-xs text-emerald-400",
|
|
67
|
+
children: "Template sent to Studio."
|
|
68
|
+
}, undefined, false, undefined, this) : null
|
|
69
|
+
]
|
|
70
|
+
}, undefined, true, undefined, this);
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
SaveToStudioButton
|
|
74
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { TemplateId } from './lib/types';
|
|
2
|
+
export interface SpecEditorProps {
|
|
3
|
+
projectId: string;
|
|
4
|
+
type?: 'CAPABILITY' | 'DATAVIEW' | 'WORKFLOW' | 'POLICY' | 'COMPONENT';
|
|
5
|
+
content: string;
|
|
6
|
+
onChange: (content: string) => void;
|
|
7
|
+
metadata?: Record<string, unknown>;
|
|
8
|
+
onSave?: () => void;
|
|
9
|
+
onValidate?: () => void;
|
|
10
|
+
}
|
|
11
|
+
export interface SpecEditorPanelProps {
|
|
12
|
+
templateId: TemplateId;
|
|
13
|
+
/** SpecEditor component passed as a prop (for dynamic import compatibility) */
|
|
14
|
+
SpecEditor: React.ComponentType<SpecEditorProps>;
|
|
15
|
+
/** Callback for logging actions */
|
|
16
|
+
onLog?: (message: string) => void;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Spec editor panel that wraps SpecEditor with persisted spec content.
|
|
20
|
+
* Uses useSpecContent hook to manage spec persistence and validation.
|
|
21
|
+
*/
|
|
22
|
+
export declare function SpecEditorPanel({ templateId, SpecEditor, onLog, }: SpecEditorPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
//# sourceMappingURL=SpecEditorPanel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SpecEditorPanel.d.ts","sourceRoot":"","sources":["../src/SpecEditorPanel.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,WAAW,CAAC;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,oBAAoB;IACnC,UAAU,EAAE,UAAU,CAAC;IACvB,+EAA+E;IAC/E,UAAU,EAAE,KAAK,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IACjD,mCAAmC;IACnC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,UAAU,EACV,UAAU,EACV,KAAK,GACN,EAAE,oBAAoB,2CAkItB"}
|