@contractspec/example.learning-journey-ui-gamified 3.7.6 → 3.7.7

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 (56) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/AGENTS.md +50 -25
  3. package/README.md +63 -20
  4. package/dist/GamifiedMiniApp.js +246 -246
  5. package/dist/browser/GamifiedMiniApp.js +246 -246
  6. package/dist/browser/components/DayCalendar.js +1 -1
  7. package/dist/browser/components/FlashCard.js +6 -6
  8. package/dist/browser/components/MasteryRing.js +1 -1
  9. package/dist/browser/components/index.js +100 -100
  10. package/dist/browser/index.js +247 -246
  11. package/dist/browser/views/Overview.js +16 -16
  12. package/dist/browser/views/Progress.js +7 -7
  13. package/dist/browser/views/Steps.js +8 -8
  14. package/dist/browser/views/Timeline.js +8 -8
  15. package/dist/browser/views/index.js +242 -242
  16. package/dist/components/DayCalendar.js +1 -1
  17. package/dist/components/FlashCard.js +6 -6
  18. package/dist/components/MasteryRing.js +1 -1
  19. package/dist/components/index.d.ts +1 -1
  20. package/dist/components/index.js +100 -100
  21. package/dist/index.d.ts +3 -3
  22. package/dist/index.js +247 -246
  23. package/dist/node/GamifiedMiniApp.js +246 -246
  24. package/dist/node/components/DayCalendar.js +1 -1
  25. package/dist/node/components/FlashCard.js +6 -6
  26. package/dist/node/components/MasteryRing.js +1 -1
  27. package/dist/node/components/index.js +100 -100
  28. package/dist/node/index.js +247 -246
  29. package/dist/node/views/Overview.js +16 -16
  30. package/dist/node/views/Progress.js +7 -7
  31. package/dist/node/views/Steps.js +8 -8
  32. package/dist/node/views/Timeline.js +8 -8
  33. package/dist/node/views/index.js +242 -242
  34. package/dist/views/Overview.js +16 -16
  35. package/dist/views/Progress.js +7 -7
  36. package/dist/views/Steps.js +8 -8
  37. package/dist/views/Timeline.js +8 -8
  38. package/dist/views/index.d.ts +1 -1
  39. package/dist/views/index.js +242 -242
  40. package/package.json +10 -10
  41. package/src/GamifiedMiniApp.tsx +70 -70
  42. package/src/components/DayCalendar.tsx +41 -41
  43. package/src/components/FlashCard.tsx +83 -83
  44. package/src/components/MasteryRing.tsx +64 -64
  45. package/src/components/index.ts +1 -1
  46. package/src/docs/learning-journey-ui-gamified.docblock.ts +11 -11
  47. package/src/example.ts +25 -25
  48. package/src/index.ts +5 -6
  49. package/src/learning-journey-ui-gamified.feature.ts +12 -12
  50. package/src/views/Overview.tsx +145 -145
  51. package/src/views/Progress.tsx +167 -167
  52. package/src/views/Steps.tsx +40 -40
  53. package/src/views/Timeline.tsx +177 -177
  54. package/src/views/index.ts +1 -1
  55. package/tsconfig.json +7 -8
  56. package/tsdown.config.js +7 -13
@@ -1,183 +1,183 @@
1
1
  'use client';
2
2
 
3
+ import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';
3
4
  import {
4
- Card,
5
- CardContent,
6
- CardHeader,
7
- CardTitle,
8
- } from '@contractspec/lib.ui-kit-web/ui/card';
9
- import {
10
- XpBar,
11
- BadgeDisplay,
5
+ BadgeDisplay,
6
+ XpBar,
12
7
  } from '@contractspec/example.learning-journey-ui-shared';
8
+ import {
9
+ Card,
10
+ CardContent,
11
+ CardHeader,
12
+ CardTitle,
13
+ } from '@contractspec/lib.ui-kit-web/ui/card';
13
14
  import { MasteryRing } from '../components/MasteryRing';
14
- import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';
15
15
 
16
16
  export function Progress({ track, progress }: LearningViewProps) {
17
- const totalXp =
18
- track.totalXp ??
19
- track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) +
20
- (track.completionRewards?.xpBonus ?? 0);
17
+ const totalXp =
18
+ track.totalXp ??
19
+ track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) +
20
+ (track.completionRewards?.xpBonus ?? 0);
21
21
 
22
- const completedSteps = progress.completedStepIds.length;
23
- const totalSteps = track.steps.length;
24
- const percentComplete =
25
- totalSteps > 0 ? (completedSteps / totalSteps) * 100 : 0;
22
+ const completedSteps = progress.completedStepIds.length;
23
+ const totalSteps = track.steps.length;
24
+ const percentComplete =
25
+ totalSteps > 0 ? (completedSteps / totalSteps) * 100 : 0;
26
26
 
27
- // Group steps by metadata surface for mastery rings
28
- const surfaces = new Map<string, { total: number; completed: number }>();
29
- track.steps.forEach((step) => {
30
- const surface = (step.metadata?.surface as string) ?? 'general';
31
- const current = surfaces.get(surface) ?? { total: 0, completed: 0 };
32
- surfaces.set(surface, {
33
- total: current.total + 1,
34
- completed:
35
- current.completed +
36
- (progress.completedStepIds.includes(step.id) ? 1 : 0),
37
- });
38
- });
27
+ // Group steps by metadata surface for mastery rings
28
+ const surfaces = new Map<string, { total: number; completed: number }>();
29
+ track.steps.forEach((step) => {
30
+ const surface = (step.metadata?.surface as string) ?? 'general';
31
+ const current = surfaces.get(surface) ?? { total: 0, completed: 0 };
32
+ surfaces.set(surface, {
33
+ total: current.total + 1,
34
+ completed:
35
+ current.completed +
36
+ (progress.completedStepIds.includes(step.id) ? 1 : 0),
37
+ });
38
+ });
39
39
 
40
- const surfaceColors: ('green' | 'blue' | 'violet' | 'orange')[] = [
41
- 'green',
42
- 'blue',
43
- 'violet',
44
- 'orange',
45
- ];
40
+ const surfaceColors: ('green' | 'blue' | 'violet' | 'orange')[] = [
41
+ 'green',
42
+ 'blue',
43
+ 'violet',
44
+ 'orange',
45
+ ];
46
46
 
47
- return (
48
- <div className="space-y-6">
49
- {/* XP Progress */}
50
- <Card>
51
- <CardHeader>
52
- <CardTitle className="flex items-center gap-2">
53
- <span>⚡</span>
54
- <span>Experience Points</span>
55
- </CardTitle>
56
- </CardHeader>
57
- <CardContent className="space-y-4">
58
- <div className="flex items-baseline gap-2">
59
- <span className="text-4xl font-bold text-violet-500">
60
- {progress.xpEarned.toLocaleString()}
61
- </span>
62
- <span className="text-muted-foreground">
63
- / {totalXp.toLocaleString()} XP
64
- </span>
65
- </div>
66
- <XpBar
67
- current={progress.xpEarned}
68
- max={totalXp}
69
- showLabel={false}
70
- size="lg"
71
- />
47
+ return (
48
+ <div className="space-y-6">
49
+ {/* XP Progress */}
50
+ <Card>
51
+ <CardHeader>
52
+ <CardTitle className="flex items-center gap-2">
53
+ <span>⚡</span>
54
+ <span>Experience Points</span>
55
+ </CardTitle>
56
+ </CardHeader>
57
+ <CardContent className="space-y-4">
58
+ <div className="flex items-baseline gap-2">
59
+ <span className="font-bold text-4xl text-violet-500">
60
+ {progress.xpEarned.toLocaleString()}
61
+ </span>
62
+ <span className="text-muted-foreground">
63
+ / {totalXp.toLocaleString()} XP
64
+ </span>
65
+ </div>
66
+ <XpBar
67
+ current={progress.xpEarned}
68
+ max={totalXp}
69
+ showLabel={false}
70
+ size="lg"
71
+ />
72
72
 
73
- {track.completionRewards?.xpBonus && percentComplete < 100 && (
74
- <p className="text-muted-foreground text-sm">
75
- 🎁 Complete all steps for a{' '}
76
- <span className="font-semibold text-green-500">
77
- +{track.completionRewards.xpBonus} XP
78
- </span>{' '}
79
- bonus!
80
- </p>
81
- )}
82
- </CardContent>
83
- </Card>
73
+ {track.completionRewards?.xpBonus && percentComplete < 100 && (
74
+ <p className="text-muted-foreground text-sm">
75
+ 🎁 Complete all steps for a{' '}
76
+ <span className="font-semibold text-green-500">
77
+ +{track.completionRewards.xpBonus} XP
78
+ </span>{' '}
79
+ bonus!
80
+ </p>
81
+ )}
82
+ </CardContent>
83
+ </Card>
84
84
 
85
- {/* Mastery Rings */}
86
- <Card>
87
- <CardHeader>
88
- <CardTitle className="flex items-center gap-2">
89
- <span>🎯</span>
90
- <span>Skill Mastery</span>
91
- </CardTitle>
92
- </CardHeader>
93
- <CardContent>
94
- <div className="flex flex-wrap justify-center gap-6">
95
- {Array.from(surfaces.entries()).map(([surface, data], index) => (
96
- <MasteryRing
97
- key={surface}
98
- label={surface.charAt(0).toUpperCase() + surface.slice(1)}
99
- percentage={(data.completed / data.total) * 100}
100
- color={surfaceColors[index % surfaceColors.length]}
101
- size="lg"
102
- />
103
- ))}
104
- <MasteryRing
105
- label="Overall"
106
- percentage={percentComplete}
107
- color="violet"
108
- size="lg"
109
- />
110
- </div>
111
- </CardContent>
112
- </Card>
85
+ {/* Mastery Rings */}
86
+ <Card>
87
+ <CardHeader>
88
+ <CardTitle className="flex items-center gap-2">
89
+ <span>🎯</span>
90
+ <span>Skill Mastery</span>
91
+ </CardTitle>
92
+ </CardHeader>
93
+ <CardContent>
94
+ <div className="flex flex-wrap justify-center gap-6">
95
+ {Array.from(surfaces.entries()).map(([surface, data], index) => (
96
+ <MasteryRing
97
+ key={surface}
98
+ label={surface.charAt(0).toUpperCase() + surface.slice(1)}
99
+ percentage={(data.completed / data.total) * 100}
100
+ color={surfaceColors[index % surfaceColors.length]}
101
+ size="lg"
102
+ />
103
+ ))}
104
+ <MasteryRing
105
+ label="Overall"
106
+ percentage={percentComplete}
107
+ color="violet"
108
+ size="lg"
109
+ />
110
+ </div>
111
+ </CardContent>
112
+ </Card>
113
113
 
114
- {/* Badges */}
115
- <Card>
116
- <CardHeader>
117
- <CardTitle className="flex items-center gap-2">
118
- <span>🏅</span>
119
- <span>Badges Earned</span>
120
- </CardTitle>
121
- </CardHeader>
122
- <CardContent>
123
- <BadgeDisplay badges={progress.badges} size="lg" maxVisible={10} />
124
- {progress.badges.length === 0 && (
125
- <p className="text-muted-foreground text-sm">
126
- Complete the track to earn your first badge!
127
- </p>
128
- )}
129
- </CardContent>
130
- </Card>
114
+ {/* Badges */}
115
+ <Card>
116
+ <CardHeader>
117
+ <CardTitle className="flex items-center gap-2">
118
+ <span>🏅</span>
119
+ <span>Badges Earned</span>
120
+ </CardTitle>
121
+ </CardHeader>
122
+ <CardContent>
123
+ <BadgeDisplay badges={progress.badges} size="lg" maxVisible={10} />
124
+ {progress.badges.length === 0 && (
125
+ <p className="text-muted-foreground text-sm">
126
+ Complete the track to earn your first badge!
127
+ </p>
128
+ )}
129
+ </CardContent>
130
+ </Card>
131
131
 
132
- {/* Step Breakdown */}
133
- <Card>
134
- <CardHeader>
135
- <CardTitle className="flex items-center gap-2">
136
- <span>📊</span>
137
- <span>Step Breakdown</span>
138
- </CardTitle>
139
- </CardHeader>
140
- <CardContent>
141
- <div className="space-y-2">
142
- {track.steps.map((step) => {
143
- const isCompleted = progress.completedStepIds.includes(step.id);
144
- return (
145
- <div
146
- key={step.id}
147
- className="flex items-center justify-between rounded-lg border p-3"
148
- >
149
- <div className="flex items-center gap-3">
150
- <span
151
- className={
152
- isCompleted ? 'text-green-500' : 'text-muted-foreground'
153
- }
154
- >
155
- {isCompleted ? '✓' : '○'}
156
- </span>
157
- <span
158
- className={
159
- isCompleted
160
- ? 'text-foreground'
161
- : 'text-muted-foreground'
162
- }
163
- >
164
- {step.title}
165
- </span>
166
- </div>
167
- {step.xpReward && (
168
- <span
169
- className={`text-sm font-medium ${isCompleted ? 'text-green-500' : 'text-muted-foreground'}`}
170
- >
171
- {isCompleted ? '+' : ''}
172
- {step.xpReward} XP
173
- </span>
174
- )}
175
- </div>
176
- );
177
- })}
178
- </div>
179
- </CardContent>
180
- </Card>
181
- </div>
182
- );
132
+ {/* Step Breakdown */}
133
+ <Card>
134
+ <CardHeader>
135
+ <CardTitle className="flex items-center gap-2">
136
+ <span>📊</span>
137
+ <span>Step Breakdown</span>
138
+ </CardTitle>
139
+ </CardHeader>
140
+ <CardContent>
141
+ <div className="space-y-2">
142
+ {track.steps.map((step) => {
143
+ const isCompleted = progress.completedStepIds.includes(step.id);
144
+ return (
145
+ <div
146
+ key={step.id}
147
+ className="flex items-center justify-between rounded-lg border p-3"
148
+ >
149
+ <div className="flex items-center gap-3">
150
+ <span
151
+ className={
152
+ isCompleted ? 'text-green-500' : 'text-muted-foreground'
153
+ }
154
+ >
155
+ {isCompleted ? '✓' : '○'}
156
+ </span>
157
+ <span
158
+ className={
159
+ isCompleted
160
+ ? 'text-foreground'
161
+ : 'text-muted-foreground'
162
+ }
163
+ >
164
+ {step.title}
165
+ </span>
166
+ </div>
167
+ {step.xpReward && (
168
+ <span
169
+ className={`font-medium text-sm ${isCompleted ? 'text-green-500' : 'text-muted-foreground'}`}
170
+ >
171
+ {isCompleted ? '+' : ''}
172
+ {step.xpReward} XP
173
+ </span>
174
+ )}
175
+ </div>
176
+ );
177
+ })}
178
+ </div>
179
+ </CardContent>
180
+ </Card>
181
+ </div>
182
+ );
183
183
  }
@@ -1,50 +1,50 @@
1
1
  'use client';
2
2
 
3
- import { FlashCard } from '../components/FlashCard';
4
3
  import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';
4
+ import { FlashCard } from '../components/FlashCard';
5
5
 
6
6
  export function Steps({ track, progress, onStepComplete }: LearningViewProps) {
7
- const currentStepIndex = track.steps.findIndex(
8
- (s) => !progress.completedStepIds.includes(s.id)
9
- );
7
+ const currentStepIndex = track.steps.findIndex(
8
+ (s) => !progress.completedStepIds.includes(s.id)
9
+ );
10
10
 
11
- return (
12
- <div className="space-y-6">
13
- {/* Header */}
14
- <div className="text-center">
15
- <h2 className="text-xl font-bold">Complete Your Challenges</h2>
16
- <p className="text-muted-foreground">
17
- Tap each card to reveal the action, then mark as complete
18
- </p>
19
- </div>
11
+ return (
12
+ <div className="space-y-6">
13
+ {/* Header */}
14
+ <div className="text-center">
15
+ <h2 className="font-bold text-xl">Complete Your Challenges</h2>
16
+ <p className="text-muted-foreground">
17
+ Tap each card to reveal the action, then mark as complete
18
+ </p>
19
+ </div>
20
20
 
21
- {/* Card Stack */}
22
- <div className="grid gap-4 md:grid-cols-2">
23
- {track.steps.map((step, index) => {
24
- const isCompleted = progress.completedStepIds.includes(step.id);
25
- const isCurrent = index === currentStepIndex;
21
+ {/* Card Stack */}
22
+ <div className="grid gap-4 md:grid-cols-2">
23
+ {track.steps.map((step, index) => {
24
+ const isCompleted = progress.completedStepIds.includes(step.id);
25
+ const isCurrent = index === currentStepIndex;
26
26
 
27
- return (
28
- <FlashCard
29
- key={step.id}
30
- step={step}
31
- isCompleted={isCompleted}
32
- isCurrent={isCurrent}
33
- onComplete={() => onStepComplete?.(step.id)}
34
- />
35
- );
36
- })}
37
- </div>
27
+ return (
28
+ <FlashCard
29
+ key={step.id}
30
+ step={step}
31
+ isCompleted={isCompleted}
32
+ isCurrent={isCurrent}
33
+ onComplete={() => onStepComplete?.(step.id)}
34
+ />
35
+ );
36
+ })}
37
+ </div>
38
38
 
39
- {/* Progress Summary */}
40
- <div className="text-muted-foreground text-center text-sm">
41
- {progress.completedStepIds.length} of {track.steps.length} completed
42
- {track.completionRewards?.xpBonus && (
43
- <span className="ml-2 text-green-500">
44
- (+{track.completionRewards.xpBonus} XP bonus on completion)
45
- </span>
46
- )}
47
- </div>
48
- </div>
49
- );
39
+ {/* Progress Summary */}
40
+ <div className="text-center text-muted-foreground text-sm">
41
+ {progress.completedStepIds.length} of {track.steps.length} completed
42
+ {track.completionRewards?.xpBonus && (
43
+ <span className="ml-2 text-green-500">
44
+ (+{track.completionRewards.xpBonus} XP bonus on completion)
45
+ </span>
46
+ )}
47
+ </div>
48
+ </div>
49
+ );
50
50
  }