@contractspec/example.learning-journey-ui-gamified 3.7.6 → 3.7.10
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 +5 -5
- package/AGENTS.md +50 -25
- package/CHANGELOG.md +32 -0
- package/README.md +63 -20
- package/dist/GamifiedMiniApp.js +246 -246
- package/dist/browser/GamifiedMiniApp.js +246 -246
- package/dist/browser/components/DayCalendar.js +1 -1
- package/dist/browser/components/FlashCard.js +6 -6
- package/dist/browser/components/MasteryRing.js +1 -1
- package/dist/browser/components/index.js +100 -100
- package/dist/browser/index.js +247 -246
- package/dist/browser/views/Overview.js +16 -16
- package/dist/browser/views/Progress.js +7 -7
- package/dist/browser/views/Steps.js +8 -8
- package/dist/browser/views/Timeline.js +8 -8
- package/dist/browser/views/index.js +242 -242
- package/dist/components/DayCalendar.js +1 -1
- package/dist/components/FlashCard.js +6 -6
- package/dist/components/MasteryRing.js +1 -1
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +100 -100
- package/dist/index.d.ts +3 -3
- package/dist/index.js +247 -246
- package/dist/node/GamifiedMiniApp.js +246 -246
- package/dist/node/components/DayCalendar.js +1 -1
- package/dist/node/components/FlashCard.js +6 -6
- package/dist/node/components/MasteryRing.js +1 -1
- package/dist/node/components/index.js +100 -100
- package/dist/node/index.js +247 -246
- package/dist/node/views/Overview.js +16 -16
- package/dist/node/views/Progress.js +7 -7
- package/dist/node/views/Steps.js +8 -8
- package/dist/node/views/Timeline.js +8 -8
- package/dist/node/views/index.js +242 -242
- package/dist/views/Overview.js +16 -16
- package/dist/views/Progress.js +7 -7
- package/dist/views/Steps.js +8 -8
- package/dist/views/Timeline.js +8 -8
- package/dist/views/index.d.ts +1 -1
- package/dist/views/index.js +242 -242
- package/package.json +12 -12
- package/src/GamifiedMiniApp.tsx +70 -70
- package/src/components/DayCalendar.tsx +41 -41
- package/src/components/FlashCard.tsx +83 -83
- package/src/components/MasteryRing.tsx +64 -64
- package/src/components/index.ts +1 -1
- package/src/docs/learning-journey-ui-gamified.docblock.ts +11 -11
- package/src/example.ts +25 -25
- package/src/index.ts +5 -6
- package/src/learning-journey-ui-gamified.feature.ts +12 -12
- package/src/views/Overview.tsx +145 -145
- package/src/views/Progress.tsx +167 -167
- package/src/views/Steps.tsx +40 -40
- package/src/views/Timeline.tsx +177 -177
- package/src/views/index.ts +1 -1
- package/tsconfig.json +7 -8
- package/tsdown.config.js +7 -13
package/src/views/Timeline.tsx
CHANGED
|
@@ -1,197 +1,197 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
+
import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';
|
|
3
4
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
Card,
|
|
6
|
+
CardContent,
|
|
7
|
+
CardHeader,
|
|
8
|
+
CardTitle,
|
|
8
9
|
} from '@contractspec/lib.ui-kit-web/ui/card';
|
|
9
10
|
import { DayCalendar } from '../components/DayCalendar';
|
|
10
|
-
import type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';
|
|
11
11
|
|
|
12
12
|
export function Timeline({ track, progress }: LearningViewProps) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Check if this is a quest with day unlocks
|
|
14
|
+
const hasQuestDays = track.steps.some(
|
|
15
|
+
(s) => s.availability?.unlockOnDay !== undefined
|
|
16
|
+
);
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
if (hasQuestDays) {
|
|
19
|
+
// Quest-style calendar view
|
|
20
|
+
const totalDays = Math.max(
|
|
21
|
+
...track.steps.map((s) => s.availability?.unlockOnDay ?? 1),
|
|
22
|
+
7
|
|
23
|
+
);
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const completedDays = track.steps
|
|
26
|
+
.filter((s) => progress.completedStepIds.includes(s.id))
|
|
27
|
+
.map((s) => s.availability?.unlockOnDay ?? 1);
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
// Current day is the first incomplete day
|
|
30
|
+
const currentDay =
|
|
31
|
+
track.steps.find((s) => !progress.completedStepIds.includes(s.id))
|
|
32
|
+
?.availability?.unlockOnDay ?? 1;
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
34
|
+
return (
|
|
35
|
+
<div className="space-y-6">
|
|
36
|
+
{/* Header */}
|
|
37
|
+
<div className="text-center">
|
|
38
|
+
<h2 className="font-bold text-xl">{track.name}</h2>
|
|
39
|
+
<p className="text-muted-foreground">
|
|
40
|
+
Complete each day's challenge to progress
|
|
41
|
+
</p>
|
|
42
|
+
</div>
|
|
43
43
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
44
|
+
{/* Calendar Grid */}
|
|
45
|
+
<Card>
|
|
46
|
+
<CardHeader>
|
|
47
|
+
<CardTitle className="flex items-center gap-2">
|
|
48
|
+
<span>📅</span>
|
|
49
|
+
<span>Your Journey</span>
|
|
50
|
+
</CardTitle>
|
|
51
|
+
</CardHeader>
|
|
52
|
+
<CardContent className="flex justify-center">
|
|
53
|
+
<DayCalendar
|
|
54
|
+
totalDays={totalDays}
|
|
55
|
+
currentDay={currentDay}
|
|
56
|
+
completedDays={completedDays}
|
|
57
|
+
/>
|
|
58
|
+
</CardContent>
|
|
59
|
+
</Card>
|
|
60
60
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
61
|
+
{/* Daily Steps */}
|
|
62
|
+
<Card>
|
|
63
|
+
<CardHeader>
|
|
64
|
+
<CardTitle className="flex items-center gap-2">
|
|
65
|
+
<span>📝</span>
|
|
66
|
+
<span>Daily Challenges</span>
|
|
67
|
+
</CardTitle>
|
|
68
|
+
</CardHeader>
|
|
69
|
+
<CardContent>
|
|
70
|
+
<div className="space-y-3">
|
|
71
|
+
{track.steps.map((step) => {
|
|
72
|
+
const day = step.availability?.unlockOnDay ?? 1;
|
|
73
|
+
const isCompleted = progress.completedStepIds.includes(step.id);
|
|
74
|
+
const isLocked = day > currentDay;
|
|
75
75
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
76
|
+
return (
|
|
77
|
+
<div
|
|
78
|
+
key={step.id}
|
|
79
|
+
className={`flex items-start gap-4 rounded-lg border p-4 ${
|
|
80
|
+
isLocked ? 'opacity-50' : ''
|
|
81
|
+
}`}
|
|
82
|
+
>
|
|
83
|
+
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-muted font-semibold">
|
|
84
|
+
{isCompleted ? '✓' : isLocked ? '🔒' : day}
|
|
85
|
+
</div>
|
|
86
|
+
<div className="flex-1">
|
|
87
|
+
<h4 className="font-semibold">{step.title}</h4>
|
|
88
|
+
<p className="text-muted-foreground text-sm">
|
|
89
|
+
{step.description}
|
|
90
|
+
</p>
|
|
91
|
+
</div>
|
|
92
|
+
{step.xpReward && (
|
|
93
|
+
<span
|
|
94
|
+
className={`font-medium text-sm ${
|
|
95
|
+
isCompleted
|
|
96
|
+
? 'text-green-500'
|
|
97
|
+
: 'text-muted-foreground'
|
|
98
|
+
}`}
|
|
99
|
+
>
|
|
100
|
+
+{step.xpReward} XP
|
|
101
|
+
</span>
|
|
102
|
+
)}
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
})}
|
|
106
|
+
</div>
|
|
107
|
+
</CardContent>
|
|
108
|
+
</Card>
|
|
109
|
+
</div>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
113
|
+
// Drill-style timeline (step order)
|
|
114
|
+
return (
|
|
115
|
+
<div className="space-y-6">
|
|
116
|
+
{/* Header */}
|
|
117
|
+
<div className="text-center">
|
|
118
|
+
<h2 className="font-bold text-xl">Learning Path</h2>
|
|
119
|
+
<p className="text-muted-foreground">
|
|
120
|
+
Follow the steps to master this skill
|
|
121
|
+
</p>
|
|
122
|
+
</div>
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
124
|
+
{/* Timeline */}
|
|
125
|
+
<Card>
|
|
126
|
+
<CardContent className="p-6">
|
|
127
|
+
<div className="relative">
|
|
128
|
+
{/* Vertical line */}
|
|
129
|
+
<div className="absolute top-0 left-5 h-full w-0.5 bg-border" />
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
131
|
+
{/* Steps */}
|
|
132
|
+
<div className="space-y-6">
|
|
133
|
+
{track.steps.map((step, index) => {
|
|
134
|
+
const isCompleted = progress.completedStepIds.includes(step.id);
|
|
135
|
+
const isCurrent =
|
|
136
|
+
!isCompleted &&
|
|
137
|
+
track.steps
|
|
138
|
+
.slice(0, index)
|
|
139
|
+
.every((s) => progress.completedStepIds.includes(s.id));
|
|
140
140
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
141
|
+
return (
|
|
142
|
+
<div key={step.id} className="relative flex gap-4 pl-2">
|
|
143
|
+
{/* Node */}
|
|
144
|
+
<div
|
|
145
|
+
className={`relative z-10 flex h-8 w-8 shrink-0 items-center justify-center rounded-full border-2 ${
|
|
146
|
+
isCompleted
|
|
147
|
+
? 'border-green-500 bg-green-500 text-white'
|
|
148
|
+
: isCurrent
|
|
149
|
+
? 'border-violet-500 bg-violet-500 text-white'
|
|
150
|
+
: 'border-border bg-background'
|
|
151
|
+
}`}
|
|
152
|
+
>
|
|
153
|
+
{isCompleted ? '✓' : index + 1}
|
|
154
|
+
</div>
|
|
155
155
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
156
|
+
{/* Content */}
|
|
157
|
+
<div className="flex-1 pb-4">
|
|
158
|
+
<div className="flex items-start justify-between gap-2">
|
|
159
|
+
<div>
|
|
160
|
+
<h4
|
|
161
|
+
className={`font-semibold ${
|
|
162
|
+
isCompleted
|
|
163
|
+
? 'text-foreground'
|
|
164
|
+
: isCurrent
|
|
165
|
+
? 'text-violet-500'
|
|
166
|
+
: 'text-muted-foreground'
|
|
167
|
+
}`}
|
|
168
|
+
>
|
|
169
|
+
{step.title}
|
|
170
|
+
</h4>
|
|
171
|
+
<p className="mt-1 text-muted-foreground text-sm">
|
|
172
|
+
{step.description}
|
|
173
|
+
</p>
|
|
174
|
+
</div>
|
|
175
|
+
{step.xpReward && (
|
|
176
|
+
<span
|
|
177
|
+
className={`shrink-0 rounded-full px-2 py-1 font-semibold text-xs ${
|
|
178
|
+
isCompleted
|
|
179
|
+
? 'bg-green-500/10 text-green-500'
|
|
180
|
+
: 'bg-muted text-muted-foreground'
|
|
181
|
+
}`}
|
|
182
|
+
>
|
|
183
|
+
+{step.xpReward} XP
|
|
184
|
+
</span>
|
|
185
|
+
)}
|
|
186
|
+
</div>
|
|
187
|
+
</div>
|
|
188
|
+
</div>
|
|
189
|
+
);
|
|
190
|
+
})}
|
|
191
|
+
</div>
|
|
192
|
+
</div>
|
|
193
|
+
</CardContent>
|
|
194
|
+
</Card>
|
|
195
|
+
</div>
|
|
196
|
+
);
|
|
197
197
|
}
|
package/src/views/index.ts
CHANGED
package/tsconfig.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"extends": "@contractspec/tool.typescript/react-library.json",
|
|
3
|
+
"include": ["src"],
|
|
4
|
+
"exclude": ["node_modules"],
|
|
5
|
+
"compilerOptions": {
|
|
6
|
+
"rootDir": "src",
|
|
7
|
+
"outDir": "dist"
|
|
8
|
+
}
|
|
9
9
|
}
|
|
10
|
-
|
package/tsdown.config.js
CHANGED
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
defineConfig,
|
|
3
|
+
moduleLibrary,
|
|
4
|
+
withDevExports,
|
|
5
|
+
} from '@contractspec/tool.bun';
|
|
2
6
|
|
|
3
7
|
export default defineConfig(() => ({
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
...moduleLibrary,
|
|
9
|
+
...withDevExports,
|
|
6
10
|
}));
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|