@contractspec/example.learning-journey-ui-gamified 1.56.1 → 1.58.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.
Files changed (87) hide show
  1. package/.turbo/turbo-build.log +59 -58
  2. package/.turbo/turbo-prebuild.log +1 -0
  3. package/CHANGELOG.md +40 -0
  4. package/dist/GamifiedMiniApp.d.ts +4 -14
  5. package/dist/GamifiedMiniApp.d.ts.map +1 -1
  6. package/dist/GamifiedMiniApp.js +995 -59
  7. package/dist/browser/GamifiedMiniApp.js +998 -0
  8. package/dist/browser/components/DayCalendar.js +42 -0
  9. package/dist/browser/components/FlashCard.js +102 -0
  10. package/dist/browser/components/MasteryRing.js +75 -0
  11. package/dist/browser/components/index.js +217 -0
  12. package/dist/browser/docs/index.js +22 -0
  13. package/dist/browser/docs/learning-journey-ui-gamified.docblock.js +22 -0
  14. package/dist/browser/example.js +32 -0
  15. package/dist/browser/index.js +1057 -0
  16. package/dist/browser/views/Overview.js +236 -0
  17. package/dist/browser/views/Progress.js +294 -0
  18. package/dist/browser/views/Steps.js +157 -0
  19. package/dist/browser/views/Timeline.js +235 -0
  20. package/dist/browser/views/index.js +919 -0
  21. package/dist/components/DayCalendar.d.ts +5 -13
  22. package/dist/components/DayCalendar.d.ts.map +1 -1
  23. package/dist/components/DayCalendar.js +41 -31
  24. package/dist/components/FlashCard.d.ts +7 -16
  25. package/dist/components/FlashCard.d.ts.map +1 -1
  26. package/dist/components/FlashCard.js +99 -76
  27. package/dist/components/MasteryRing.d.ts +6 -15
  28. package/dist/components/MasteryRing.d.ts.map +1 -1
  29. package/dist/components/MasteryRing.js +72 -78
  30. package/dist/components/index.d.ts +4 -4
  31. package/dist/components/index.d.ts.map +1 -0
  32. package/dist/components/index.js +217 -4
  33. package/dist/docs/index.d.ts +2 -1
  34. package/dist/docs/index.d.ts.map +1 -0
  35. package/dist/docs/index.js +23 -1
  36. package/dist/docs/learning-journey-ui-gamified.docblock.d.ts +2 -1
  37. package/dist/docs/learning-journey-ui-gamified.docblock.d.ts.map +1 -0
  38. package/dist/docs/learning-journey-ui-gamified.docblock.js +21 -18
  39. package/dist/example.d.ts +2 -6
  40. package/dist/example.d.ts.map +1 -1
  41. package/dist/example.js +30 -39
  42. package/dist/index.d.ts +6 -12
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +1058 -14
  45. package/dist/node/GamifiedMiniApp.js +998 -0
  46. package/dist/node/components/DayCalendar.js +42 -0
  47. package/dist/node/components/FlashCard.js +102 -0
  48. package/dist/node/components/MasteryRing.js +75 -0
  49. package/dist/node/components/index.js +217 -0
  50. package/dist/node/docs/index.js +22 -0
  51. package/dist/node/docs/learning-journey-ui-gamified.docblock.js +22 -0
  52. package/dist/node/example.js +32 -0
  53. package/dist/node/index.js +1057 -0
  54. package/dist/node/views/Overview.js +236 -0
  55. package/dist/node/views/Progress.js +294 -0
  56. package/dist/node/views/Steps.js +157 -0
  57. package/dist/node/views/Timeline.js +235 -0
  58. package/dist/node/views/index.js +919 -0
  59. package/dist/views/Overview.d.ts +4 -12
  60. package/dist/views/Overview.d.ts.map +1 -1
  61. package/dist/views/Overview.js +234 -158
  62. package/dist/views/Progress.d.ts +2 -10
  63. package/dist/views/Progress.d.ts.map +1 -1
  64. package/dist/views/Progress.js +292 -140
  65. package/dist/views/Steps.d.ts +2 -11
  66. package/dist/views/Steps.d.ts.map +1 -1
  67. package/dist/views/Steps.js +155 -53
  68. package/dist/views/Timeline.d.ts +2 -10
  69. package/dist/views/Timeline.d.ts.map +1 -1
  70. package/dist/views/Timeline.js +233 -130
  71. package/dist/views/index.d.ts +5 -5
  72. package/dist/views/index.d.ts.map +1 -0
  73. package/dist/views/index.js +919 -5
  74. package/package.json +155 -39
  75. package/tsdown.config.js +1 -2
  76. package/.turbo/turbo-build$colon$bundle.log +0 -57
  77. package/dist/GamifiedMiniApp.js.map +0 -1
  78. package/dist/components/DayCalendar.js.map +0 -1
  79. package/dist/components/FlashCard.js.map +0 -1
  80. package/dist/components/MasteryRing.js.map +0 -1
  81. package/dist/docs/learning-journey-ui-gamified.docblock.js.map +0 -1
  82. package/dist/example.js.map +0 -1
  83. package/dist/views/Overview.js.map +0 -1
  84. package/dist/views/Progress.js.map +0 -1
  85. package/dist/views/Steps.js.map +0 -1
  86. package/dist/views/Timeline.js.map +0 -1
  87. package/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,236 @@
1
+ // src/views/Overview.tsx
2
+ import { Button } from "@contractspec/lib.design-system";
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardHeader,
7
+ CardTitle
8
+ } from "@contractspec/lib.ui-kit-web/ui/card";
9
+ import {
10
+ XpBar,
11
+ StreakCounter,
12
+ BadgeDisplay
13
+ } from "@contractspec/example.learning-journey-ui-shared";
14
+ import { jsxDEV } from "react/jsx-dev-runtime";
15
+ "use client";
16
+ function Overview({ track, progress, onStart }) {
17
+ const totalXp = track.totalXp ?? track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) + (track.completionRewards?.xpBonus ?? 0);
18
+ const completedSteps = progress.completedStepIds.length;
19
+ const totalSteps = track.steps.length;
20
+ const isComplete = completedSteps === totalSteps;
21
+ return /* @__PURE__ */ jsxDEV("div", {
22
+ className: "space-y-6",
23
+ children: [
24
+ /* @__PURE__ */ jsxDEV(Card, {
25
+ className: "overflow-hidden bg-gradient-to-br from-violet-500/10 via-purple-500/10 to-fuchsia-500/10",
26
+ children: /* @__PURE__ */ jsxDEV(CardContent, {
27
+ className: "p-6",
28
+ children: /* @__PURE__ */ jsxDEV("div", {
29
+ className: "flex flex-col items-center gap-4 text-center md:flex-row md:text-left",
30
+ children: [
31
+ /* @__PURE__ */ jsxDEV("div", {
32
+ className: "flex h-20 w-20 items-center justify-center rounded-2xl bg-gradient-to-br from-violet-500 to-purple-600 text-4xl shadow-lg",
33
+ children: isComplete ? "\uD83C\uDFC6" : "\uD83C\uDFAF"
34
+ }, undefined, false, undefined, this),
35
+ /* @__PURE__ */ jsxDEV("div", {
36
+ className: "flex-1",
37
+ children: [
38
+ /* @__PURE__ */ jsxDEV("h1", {
39
+ className: "text-2xl font-bold",
40
+ children: track.name
41
+ }, undefined, false, undefined, this),
42
+ /* @__PURE__ */ jsxDEV("p", {
43
+ className: "text-muted-foreground mt-1",
44
+ children: track.description
45
+ }, undefined, false, undefined, this)
46
+ ]
47
+ }, undefined, true, undefined, this),
48
+ /* @__PURE__ */ jsxDEV("div", {
49
+ className: "flex items-center gap-3",
50
+ children: /* @__PURE__ */ jsxDEV(StreakCounter, {
51
+ days: progress.streakDays,
52
+ size: "lg"
53
+ }, undefined, false, undefined, this)
54
+ }, undefined, false, undefined, this)
55
+ ]
56
+ }, undefined, true, undefined, this)
57
+ }, undefined, false, undefined, this)
58
+ }, undefined, false, undefined, this),
59
+ /* @__PURE__ */ jsxDEV("div", {
60
+ className: "grid gap-4 md:grid-cols-3",
61
+ children: [
62
+ /* @__PURE__ */ jsxDEV(Card, {
63
+ children: [
64
+ /* @__PURE__ */ jsxDEV(CardHeader, {
65
+ className: "pb-2",
66
+ children: /* @__PURE__ */ jsxDEV(CardTitle, {
67
+ className: "text-muted-foreground text-sm font-medium",
68
+ children: "XP Progress"
69
+ }, undefined, false, undefined, this)
70
+ }, undefined, false, undefined, this),
71
+ /* @__PURE__ */ jsxDEV(CardContent, {
72
+ children: [
73
+ /* @__PURE__ */ jsxDEV("div", {
74
+ className: "text-3xl font-bold text-violet-500",
75
+ children: progress.xpEarned.toLocaleString()
76
+ }, undefined, false, undefined, this),
77
+ /* @__PURE__ */ jsxDEV(XpBar, {
78
+ current: progress.xpEarned,
79
+ max: totalXp,
80
+ showLabel: false,
81
+ size: "sm"
82
+ }, undefined, false, undefined, this)
83
+ ]
84
+ }, undefined, true, undefined, this)
85
+ ]
86
+ }, undefined, true, undefined, this),
87
+ /* @__PURE__ */ jsxDEV(Card, {
88
+ children: [
89
+ /* @__PURE__ */ jsxDEV(CardHeader, {
90
+ className: "pb-2",
91
+ children: /* @__PURE__ */ jsxDEV(CardTitle, {
92
+ className: "text-muted-foreground text-sm font-medium",
93
+ children: "Steps Completed"
94
+ }, undefined, false, undefined, this)
95
+ }, undefined, false, undefined, this),
96
+ /* @__PURE__ */ jsxDEV(CardContent, {
97
+ children: [
98
+ /* @__PURE__ */ jsxDEV("div", {
99
+ className: "text-3xl font-bold",
100
+ children: [
101
+ completedSteps,
102
+ " ",
103
+ /* @__PURE__ */ jsxDEV("span", {
104
+ className: "text-muted-foreground text-lg",
105
+ children: [
106
+ "/ ",
107
+ totalSteps
108
+ ]
109
+ }, undefined, true, undefined, this)
110
+ ]
111
+ }, undefined, true, undefined, this),
112
+ /* @__PURE__ */ jsxDEV("div", {
113
+ className: "bg-muted mt-2 h-2 w-full overflow-hidden rounded-full",
114
+ children: /* @__PURE__ */ jsxDEV("div", {
115
+ className: "h-full bg-green-500 transition-all duration-500",
116
+ style: { width: `${completedSteps / totalSteps * 100}%` }
117
+ }, undefined, false, undefined, this)
118
+ }, undefined, false, undefined, this)
119
+ ]
120
+ }, undefined, true, undefined, this)
121
+ ]
122
+ }, undefined, true, undefined, this),
123
+ /* @__PURE__ */ jsxDEV(Card, {
124
+ children: [
125
+ /* @__PURE__ */ jsxDEV(CardHeader, {
126
+ className: "pb-2",
127
+ children: /* @__PURE__ */ jsxDEV(CardTitle, {
128
+ className: "text-muted-foreground text-sm font-medium",
129
+ children: "Badges Earned"
130
+ }, undefined, false, undefined, this)
131
+ }, undefined, false, undefined, this),
132
+ /* @__PURE__ */ jsxDEV(CardContent, {
133
+ children: /* @__PURE__ */ jsxDEV(BadgeDisplay, {
134
+ badges: progress.badges,
135
+ size: "lg"
136
+ }, undefined, false, undefined, this)
137
+ }, undefined, false, undefined, this)
138
+ ]
139
+ }, undefined, true, undefined, this)
140
+ ]
141
+ }, undefined, true, undefined, this),
142
+ !isComplete && /* @__PURE__ */ jsxDEV(Card, {
143
+ children: [
144
+ /* @__PURE__ */ jsxDEV(CardHeader, {
145
+ children: /* @__PURE__ */ jsxDEV(CardTitle, {
146
+ className: "flex items-center gap-2",
147
+ children: [
148
+ /* @__PURE__ */ jsxDEV("span", {
149
+ children: "\uD83C\uDFAF"
150
+ }, undefined, false, undefined, this),
151
+ /* @__PURE__ */ jsxDEV("span", {
152
+ children: "Next Challenge"
153
+ }, undefined, false, undefined, this)
154
+ ]
155
+ }, undefined, true, undefined, this)
156
+ }, undefined, false, undefined, this),
157
+ /* @__PURE__ */ jsxDEV(CardContent, {
158
+ children: (() => {
159
+ const nextStep = track.steps.find((s) => !progress.completedStepIds.includes(s.id));
160
+ if (!nextStep)
161
+ return null;
162
+ return /* @__PURE__ */ jsxDEV("div", {
163
+ className: "flex items-center justify-between gap-4",
164
+ children: [
165
+ /* @__PURE__ */ jsxDEV("div", {
166
+ children: [
167
+ /* @__PURE__ */ jsxDEV("h3", {
168
+ className: "font-semibold",
169
+ children: nextStep.title
170
+ }, undefined, false, undefined, this),
171
+ /* @__PURE__ */ jsxDEV("p", {
172
+ className: "text-muted-foreground text-sm",
173
+ children: nextStep.description
174
+ }, undefined, false, undefined, this)
175
+ ]
176
+ }, undefined, true, undefined, this),
177
+ /* @__PURE__ */ jsxDEV("div", {
178
+ className: "flex items-center gap-3",
179
+ children: [
180
+ nextStep.xpReward && /* @__PURE__ */ jsxDEV("span", {
181
+ className: "rounded-full bg-green-500/10 px-3 py-1 text-sm font-semibold text-green-500",
182
+ children: [
183
+ "+",
184
+ nextStep.xpReward,
185
+ " XP"
186
+ ]
187
+ }, undefined, true, undefined, this),
188
+ /* @__PURE__ */ jsxDEV(Button, {
189
+ onClick: onStart,
190
+ children: "Start"
191
+ }, undefined, false, undefined, this)
192
+ ]
193
+ }, undefined, true, undefined, this)
194
+ ]
195
+ }, undefined, true, undefined, this);
196
+ })()
197
+ }, undefined, false, undefined, this)
198
+ ]
199
+ }, undefined, true, undefined, this),
200
+ isComplete && /* @__PURE__ */ jsxDEV(Card, {
201
+ className: "border-green-500/50 bg-green-500/5",
202
+ children: /* @__PURE__ */ jsxDEV(CardContent, {
203
+ className: "flex items-center gap-4 p-6",
204
+ children: [
205
+ /* @__PURE__ */ jsxDEV("div", {
206
+ className: "text-4xl",
207
+ children: "\uD83C\uDF89"
208
+ }, undefined, false, undefined, this),
209
+ /* @__PURE__ */ jsxDEV("div", {
210
+ children: [
211
+ /* @__PURE__ */ jsxDEV("h3", {
212
+ className: "text-lg font-semibold text-green-500",
213
+ children: "Track Complete!"
214
+ }, undefined, false, undefined, this),
215
+ /* @__PURE__ */ jsxDEV("p", {
216
+ className: "text-muted-foreground",
217
+ children: [
218
+ "You've mastered all ",
219
+ totalSteps,
220
+ " challenges and earned",
221
+ " ",
222
+ progress.xpEarned,
223
+ " XP."
224
+ ]
225
+ }, undefined, true, undefined, this)
226
+ ]
227
+ }, undefined, true, undefined, this)
228
+ ]
229
+ }, undefined, true, undefined, this)
230
+ }, undefined, false, undefined, this)
231
+ ]
232
+ }, undefined, true, undefined, this);
233
+ }
234
+ export {
235
+ Overview
236
+ };
@@ -0,0 +1,294 @@
1
+ // src/components/MasteryRing.tsx
2
+ import { cn } from "@contractspec/lib.ui-kit-web/ui/utils";
3
+ import { jsxDEV } from "react/jsx-dev-runtime";
4
+ "use client";
5
+ var sizeStyles = {
6
+ sm: { container: "h-16 w-16", text: "text-xs", ring: 48, stroke: 4 },
7
+ md: { container: "h-24 w-24", text: "text-sm", ring: 72, stroke: 6 },
8
+ lg: { container: "h-32 w-32", text: "text-base", ring: 96, stroke: 8 }
9
+ };
10
+ var colorStyles = {
11
+ green: "stroke-green-500",
12
+ blue: "stroke-blue-500",
13
+ violet: "stroke-violet-500",
14
+ orange: "stroke-orange-500"
15
+ };
16
+ function MasteryRing({
17
+ label,
18
+ percentage,
19
+ size = "md",
20
+ color = "violet"
21
+ }) {
22
+ const styles = sizeStyles[size];
23
+ const radius = (styles.ring - styles.stroke) / 2;
24
+ const circumference = 2 * Math.PI * radius;
25
+ const strokeDashoffset = circumference - percentage / 100 * circumference;
26
+ return /* @__PURE__ */ jsxDEV("div", {
27
+ className: cn("relative flex flex-col items-center gap-1", styles.container),
28
+ children: [
29
+ /* @__PURE__ */ jsxDEV("svg", {
30
+ className: "absolute -rotate-90",
31
+ width: styles.ring,
32
+ height: styles.ring,
33
+ viewBox: `0 0 ${styles.ring} ${styles.ring}`,
34
+ children: [
35
+ /* @__PURE__ */ jsxDEV("circle", {
36
+ cx: styles.ring / 2,
37
+ cy: styles.ring / 2,
38
+ r: radius,
39
+ fill: "none",
40
+ strokeWidth: styles.stroke,
41
+ className: "stroke-muted"
42
+ }, undefined, false, undefined, this),
43
+ /* @__PURE__ */ jsxDEV("circle", {
44
+ cx: styles.ring / 2,
45
+ cy: styles.ring / 2,
46
+ r: radius,
47
+ fill: "none",
48
+ strokeWidth: styles.stroke,
49
+ strokeLinecap: "round",
50
+ strokeDasharray: circumference,
51
+ strokeDashoffset,
52
+ className: cn("transition-all duration-500", colorStyles[color])
53
+ }, undefined, false, undefined, this)
54
+ ]
55
+ }, undefined, true, undefined, this),
56
+ /* @__PURE__ */ jsxDEV("div", {
57
+ className: "flex h-full flex-col items-center justify-center",
58
+ children: /* @__PURE__ */ jsxDEV("span", {
59
+ className: cn("font-bold", styles.text),
60
+ children: [
61
+ Math.round(percentage),
62
+ "%"
63
+ ]
64
+ }, undefined, true, undefined, this)
65
+ }, undefined, false, undefined, this),
66
+ /* @__PURE__ */ jsxDEV("span", {
67
+ className: cn("text-muted-foreground mt-1 truncate", styles.text),
68
+ children: label
69
+ }, undefined, false, undefined, this)
70
+ ]
71
+ }, undefined, true, undefined, this);
72
+ }
73
+
74
+ // src/views/Progress.tsx
75
+ import {
76
+ Card,
77
+ CardContent,
78
+ CardHeader,
79
+ CardTitle
80
+ } from "@contractspec/lib.ui-kit-web/ui/card";
81
+ import {
82
+ XpBar,
83
+ BadgeDisplay
84
+ } from "@contractspec/example.learning-journey-ui-shared";
85
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
86
+ "use client";
87
+ function Progress({ track, progress }) {
88
+ const totalXp = track.totalXp ?? track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) + (track.completionRewards?.xpBonus ?? 0);
89
+ const completedSteps = progress.completedStepIds.length;
90
+ const totalSteps = track.steps.length;
91
+ const percentComplete = totalSteps > 0 ? completedSteps / totalSteps * 100 : 0;
92
+ const surfaces = new Map;
93
+ track.steps.forEach((step) => {
94
+ const surface = step.metadata?.surface ?? "general";
95
+ const current = surfaces.get(surface) ?? { total: 0, completed: 0 };
96
+ surfaces.set(surface, {
97
+ total: current.total + 1,
98
+ completed: current.completed + (progress.completedStepIds.includes(step.id) ? 1 : 0)
99
+ });
100
+ });
101
+ const surfaceColors = [
102
+ "green",
103
+ "blue",
104
+ "violet",
105
+ "orange"
106
+ ];
107
+ return /* @__PURE__ */ jsxDEV2("div", {
108
+ className: "space-y-6",
109
+ children: [
110
+ /* @__PURE__ */ jsxDEV2(Card, {
111
+ children: [
112
+ /* @__PURE__ */ jsxDEV2(CardHeader, {
113
+ children: /* @__PURE__ */ jsxDEV2(CardTitle, {
114
+ className: "flex items-center gap-2",
115
+ children: [
116
+ /* @__PURE__ */ jsxDEV2("span", {
117
+ children: "⚡"
118
+ }, undefined, false, undefined, this),
119
+ /* @__PURE__ */ jsxDEV2("span", {
120
+ children: "Experience Points"
121
+ }, undefined, false, undefined, this)
122
+ ]
123
+ }, undefined, true, undefined, this)
124
+ }, undefined, false, undefined, this),
125
+ /* @__PURE__ */ jsxDEV2(CardContent, {
126
+ className: "space-y-4",
127
+ children: [
128
+ /* @__PURE__ */ jsxDEV2("div", {
129
+ className: "flex items-baseline gap-2",
130
+ children: [
131
+ /* @__PURE__ */ jsxDEV2("span", {
132
+ className: "text-4xl font-bold text-violet-500",
133
+ children: progress.xpEarned.toLocaleString()
134
+ }, undefined, false, undefined, this),
135
+ /* @__PURE__ */ jsxDEV2("span", {
136
+ className: "text-muted-foreground",
137
+ children: [
138
+ "/ ",
139
+ totalXp.toLocaleString(),
140
+ " XP"
141
+ ]
142
+ }, undefined, true, undefined, this)
143
+ ]
144
+ }, undefined, true, undefined, this),
145
+ /* @__PURE__ */ jsxDEV2(XpBar, {
146
+ current: progress.xpEarned,
147
+ max: totalXp,
148
+ showLabel: false,
149
+ size: "lg"
150
+ }, undefined, false, undefined, this),
151
+ track.completionRewards?.xpBonus && percentComplete < 100 && /* @__PURE__ */ jsxDEV2("p", {
152
+ className: "text-muted-foreground text-sm",
153
+ children: [
154
+ "\uD83C\uDF81 Complete all steps for a",
155
+ " ",
156
+ /* @__PURE__ */ jsxDEV2("span", {
157
+ className: "font-semibold text-green-500",
158
+ children: [
159
+ "+",
160
+ track.completionRewards.xpBonus,
161
+ " XP"
162
+ ]
163
+ }, undefined, true, undefined, this),
164
+ " ",
165
+ "bonus!"
166
+ ]
167
+ }, undefined, true, undefined, this)
168
+ ]
169
+ }, undefined, true, undefined, this)
170
+ ]
171
+ }, undefined, true, undefined, this),
172
+ /* @__PURE__ */ jsxDEV2(Card, {
173
+ children: [
174
+ /* @__PURE__ */ jsxDEV2(CardHeader, {
175
+ children: /* @__PURE__ */ jsxDEV2(CardTitle, {
176
+ className: "flex items-center gap-2",
177
+ children: [
178
+ /* @__PURE__ */ jsxDEV2("span", {
179
+ children: "\uD83C\uDFAF"
180
+ }, undefined, false, undefined, this),
181
+ /* @__PURE__ */ jsxDEV2("span", {
182
+ children: "Skill Mastery"
183
+ }, undefined, false, undefined, this)
184
+ ]
185
+ }, undefined, true, undefined, this)
186
+ }, undefined, false, undefined, this),
187
+ /* @__PURE__ */ jsxDEV2(CardContent, {
188
+ children: /* @__PURE__ */ jsxDEV2("div", {
189
+ className: "flex flex-wrap justify-center gap-6",
190
+ children: [
191
+ Array.from(surfaces.entries()).map(([surface, data], index) => /* @__PURE__ */ jsxDEV2(MasteryRing, {
192
+ label: surface.charAt(0).toUpperCase() + surface.slice(1),
193
+ percentage: data.completed / data.total * 100,
194
+ color: surfaceColors[index % surfaceColors.length],
195
+ size: "lg"
196
+ }, surface, false, undefined, this)),
197
+ /* @__PURE__ */ jsxDEV2(MasteryRing, {
198
+ label: "Overall",
199
+ percentage: percentComplete,
200
+ color: "violet",
201
+ size: "lg"
202
+ }, undefined, false, undefined, this)
203
+ ]
204
+ }, undefined, true, undefined, this)
205
+ }, undefined, false, undefined, this)
206
+ ]
207
+ }, undefined, true, undefined, this),
208
+ /* @__PURE__ */ jsxDEV2(Card, {
209
+ children: [
210
+ /* @__PURE__ */ jsxDEV2(CardHeader, {
211
+ children: /* @__PURE__ */ jsxDEV2(CardTitle, {
212
+ className: "flex items-center gap-2",
213
+ children: [
214
+ /* @__PURE__ */ jsxDEV2("span", {
215
+ children: "\uD83C\uDFC5"
216
+ }, undefined, false, undefined, this),
217
+ /* @__PURE__ */ jsxDEV2("span", {
218
+ children: "Badges Earned"
219
+ }, undefined, false, undefined, this)
220
+ ]
221
+ }, undefined, true, undefined, this)
222
+ }, undefined, false, undefined, this),
223
+ /* @__PURE__ */ jsxDEV2(CardContent, {
224
+ children: [
225
+ /* @__PURE__ */ jsxDEV2(BadgeDisplay, {
226
+ badges: progress.badges,
227
+ size: "lg",
228
+ maxVisible: 10
229
+ }, undefined, false, undefined, this),
230
+ progress.badges.length === 0 && /* @__PURE__ */ jsxDEV2("p", {
231
+ className: "text-muted-foreground text-sm",
232
+ children: "Complete the track to earn your first badge!"
233
+ }, undefined, false, undefined, this)
234
+ ]
235
+ }, undefined, true, undefined, this)
236
+ ]
237
+ }, undefined, true, undefined, this),
238
+ /* @__PURE__ */ jsxDEV2(Card, {
239
+ children: [
240
+ /* @__PURE__ */ jsxDEV2(CardHeader, {
241
+ children: /* @__PURE__ */ jsxDEV2(CardTitle, {
242
+ className: "flex items-center gap-2",
243
+ children: [
244
+ /* @__PURE__ */ jsxDEV2("span", {
245
+ children: "\uD83D\uDCCA"
246
+ }, undefined, false, undefined, this),
247
+ /* @__PURE__ */ jsxDEV2("span", {
248
+ children: "Step Breakdown"
249
+ }, undefined, false, undefined, this)
250
+ ]
251
+ }, undefined, true, undefined, this)
252
+ }, undefined, false, undefined, this),
253
+ /* @__PURE__ */ jsxDEV2(CardContent, {
254
+ children: /* @__PURE__ */ jsxDEV2("div", {
255
+ className: "space-y-2",
256
+ children: track.steps.map((step) => {
257
+ const isCompleted = progress.completedStepIds.includes(step.id);
258
+ return /* @__PURE__ */ jsxDEV2("div", {
259
+ className: "flex items-center justify-between rounded-lg border p-3",
260
+ children: [
261
+ /* @__PURE__ */ jsxDEV2("div", {
262
+ className: "flex items-center gap-3",
263
+ children: [
264
+ /* @__PURE__ */ jsxDEV2("span", {
265
+ className: isCompleted ? "text-green-500" : "text-muted-foreground",
266
+ children: isCompleted ? "✓" : "○"
267
+ }, undefined, false, undefined, this),
268
+ /* @__PURE__ */ jsxDEV2("span", {
269
+ className: isCompleted ? "text-foreground" : "text-muted-foreground",
270
+ children: step.title
271
+ }, undefined, false, undefined, this)
272
+ ]
273
+ }, undefined, true, undefined, this),
274
+ step.xpReward && /* @__PURE__ */ jsxDEV2("span", {
275
+ className: `text-sm font-medium ${isCompleted ? "text-green-500" : "text-muted-foreground"}`,
276
+ children: [
277
+ isCompleted ? "+" : "",
278
+ step.xpReward,
279
+ " XP"
280
+ ]
281
+ }, undefined, true, undefined, this)
282
+ ]
283
+ }, step.id, true, undefined, this);
284
+ })
285
+ }, undefined, false, undefined, this)
286
+ }, undefined, false, undefined, this)
287
+ ]
288
+ }, undefined, true, undefined, this)
289
+ ]
290
+ }, undefined, true, undefined, this);
291
+ }
292
+ export {
293
+ Progress
294
+ };
@@ -0,0 +1,157 @@
1
+ // src/components/FlashCard.tsx
2
+ import { useState } from "react";
3
+ import { Button } from "@contractspec/lib.design-system";
4
+ import { Card, CardContent } from "@contractspec/lib.ui-kit-web/ui/card";
5
+ import { cn } from "@contractspec/lib.ui-kit-web/ui/utils";
6
+ import { jsxDEV } from "react/jsx-dev-runtime";
7
+ "use client";
8
+ function FlashCard({
9
+ step,
10
+ isCompleted,
11
+ isCurrent,
12
+ onComplete
13
+ }) {
14
+ const [isFlipped, setIsFlipped] = useState(false);
15
+ return /* @__PURE__ */ jsxDEV(Card, {
16
+ className: cn("relative cursor-pointer overflow-hidden transition-all duration-300", isCurrent && "ring-primary ring-2", isCompleted && "opacity-60"),
17
+ onClick: () => !isCompleted && setIsFlipped(!isFlipped),
18
+ children: /* @__PURE__ */ jsxDEV(CardContent, {
19
+ className: "p-6",
20
+ children: [
21
+ /* @__PURE__ */ jsxDEV("div", {
22
+ className: cn("space-y-4 transition-opacity duration-200", isFlipped ? "opacity-0" : "opacity-100"),
23
+ children: [
24
+ /* @__PURE__ */ jsxDEV("div", {
25
+ className: "flex items-start justify-between",
26
+ children: [
27
+ /* @__PURE__ */ jsxDEV("div", {
28
+ className: "flex-1",
29
+ children: [
30
+ /* @__PURE__ */ jsxDEV("h3", {
31
+ className: "text-lg font-semibold",
32
+ children: step.title
33
+ }, undefined, false, undefined, this),
34
+ step.description && /* @__PURE__ */ jsxDEV("p", {
35
+ className: "text-muted-foreground mt-1 text-sm",
36
+ children: step.description
37
+ }, undefined, false, undefined, this)
38
+ ]
39
+ }, undefined, true, undefined, this),
40
+ step.xpReward && /* @__PURE__ */ jsxDEV("span", {
41
+ className: "rounded-full bg-green-500/10 px-2 py-1 text-xs font-semibold text-green-500",
42
+ children: [
43
+ "+",
44
+ step.xpReward,
45
+ " XP"
46
+ ]
47
+ }, undefined, true, undefined, this)
48
+ ]
49
+ }, undefined, true, undefined, this),
50
+ isCompleted && /* @__PURE__ */ jsxDEV("div", {
51
+ className: "flex items-center gap-2 text-green-500",
52
+ children: [
53
+ /* @__PURE__ */ jsxDEV("span", {
54
+ children: "✓"
55
+ }, undefined, false, undefined, this),
56
+ /* @__PURE__ */ jsxDEV("span", {
57
+ className: "text-sm font-medium",
58
+ children: "Completed"
59
+ }, undefined, false, undefined, this)
60
+ ]
61
+ }, undefined, true, undefined, this),
62
+ isCurrent && !isCompleted && /* @__PURE__ */ jsxDEV("p", {
63
+ className: "text-muted-foreground text-xs",
64
+ children: "Tap to reveal action"
65
+ }, undefined, false, undefined, this)
66
+ ]
67
+ }, undefined, true, undefined, this),
68
+ isFlipped && !isCompleted && /* @__PURE__ */ jsxDEV("div", {
69
+ className: "absolute inset-0 flex flex-col items-center justify-center gap-4 bg-gradient-to-br from-violet-500/10 to-violet-600/10 p-6",
70
+ children: [
71
+ /* @__PURE__ */ jsxDEV("p", {
72
+ className: "text-center text-sm",
73
+ children: step.instructions ?? "Complete this step to earn XP"
74
+ }, undefined, false, undefined, this),
75
+ /* @__PURE__ */ jsxDEV("div", {
76
+ className: "flex gap-2",
77
+ children: [
78
+ /* @__PURE__ */ jsxDEV(Button, {
79
+ variant: "outline",
80
+ size: "sm",
81
+ onClick: () => setIsFlipped(false),
82
+ children: "Back"
83
+ }, undefined, false, undefined, this),
84
+ /* @__PURE__ */ jsxDEV(Button, {
85
+ size: "sm",
86
+ onClick: (e) => {
87
+ e.stopPropagation();
88
+ onComplete?.();
89
+ },
90
+ children: "Mark Complete"
91
+ }, undefined, false, undefined, this)
92
+ ]
93
+ }, undefined, true, undefined, this)
94
+ ]
95
+ }, undefined, true, undefined, this)
96
+ ]
97
+ }, undefined, true, undefined, this)
98
+ }, undefined, false, undefined, this);
99
+ }
100
+
101
+ // src/views/Steps.tsx
102
+ import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
103
+ "use client";
104
+ function Steps({ track, progress, onStepComplete }) {
105
+ const currentStepIndex = track.steps.findIndex((s) => !progress.completedStepIds.includes(s.id));
106
+ return /* @__PURE__ */ jsxDEV2("div", {
107
+ className: "space-y-6",
108
+ children: [
109
+ /* @__PURE__ */ jsxDEV2("div", {
110
+ className: "text-center",
111
+ children: [
112
+ /* @__PURE__ */ jsxDEV2("h2", {
113
+ className: "text-xl font-bold",
114
+ children: "Complete Your Challenges"
115
+ }, undefined, false, undefined, this),
116
+ /* @__PURE__ */ jsxDEV2("p", {
117
+ className: "text-muted-foreground",
118
+ children: "Tap each card to reveal the action, then mark as complete"
119
+ }, undefined, false, undefined, this)
120
+ ]
121
+ }, undefined, true, undefined, this),
122
+ /* @__PURE__ */ jsxDEV2("div", {
123
+ className: "grid gap-4 md:grid-cols-2",
124
+ children: track.steps.map((step, index) => {
125
+ const isCompleted = progress.completedStepIds.includes(step.id);
126
+ const isCurrent = index === currentStepIndex;
127
+ return /* @__PURE__ */ jsxDEV2(FlashCard, {
128
+ step,
129
+ isCompleted,
130
+ isCurrent,
131
+ onComplete: () => onStepComplete?.(step.id)
132
+ }, step.id, false, undefined, this);
133
+ })
134
+ }, undefined, false, undefined, this),
135
+ /* @__PURE__ */ jsxDEV2("div", {
136
+ className: "text-muted-foreground text-center text-sm",
137
+ children: [
138
+ progress.completedStepIds.length,
139
+ " of ",
140
+ track.steps.length,
141
+ " completed",
142
+ track.completionRewards?.xpBonus && /* @__PURE__ */ jsxDEV2("span", {
143
+ className: "ml-2 text-green-500",
144
+ children: [
145
+ "(+",
146
+ track.completionRewards.xpBonus,
147
+ " XP bonus on completion)"
148
+ ]
149
+ }, undefined, true, undefined, this)
150
+ ]
151
+ }, undefined, true, undefined, this)
152
+ ]
153
+ }, undefined, true, undefined, this);
154
+ }
155
+ export {
156
+ Steps
157
+ };