@lssm/example.learning-journey-ui-gamified 0.0.0-canary-20251212210835
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 +22 -0
- package/CHANGELOG.md +13 -0
- package/README.md +30 -0
- package/dist/DayCalendar-Cha869Bi.mjs +178 -0
- package/dist/components/index.d.mts +2 -0
- package/dist/components/index.mjs +4 -0
- package/dist/components-kh0CpIG2.mjs +1 -0
- package/dist/index-Bi5V3Ihq.d.mts +33 -0
- package/dist/index-DrzEZfnF.d.mts +44 -0
- package/dist/index.d.mts +18 -0
- package/dist/index.mjs +59 -0
- package/dist/views/index.d.mts +2 -0
- package/dist/views/index.mjs +4 -0
- package/dist/views-B-DapxWu.mjs +467 -0
- package/package.json +53 -0
- package/src/GamifiedMiniApp.tsx +94 -0
- package/src/components/DayCalendar.tsx +54 -0
- package/src/components/FlashCard.tsx +101 -0
- package/src/components/MasteryRing.tsx +82 -0
- package/src/components/index.ts +4 -0
- package/src/index.ts +9 -0
- package/src/views/Overview.tsx +165 -0
- package/src/views/Progress.tsx +181 -0
- package/src/views/Steps.tsx +51 -0
- package/src/views/Timeline.tsx +198 -0
- package/src/views/index.ts +5 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +13 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
$ bun build:bundle && bun build:types
|
|
2
|
+
$ tsdown
|
|
3
|
+
[34mℹ[39m tsdown [2mv0.17.0[22m powered by rolldown [2mv1.0.0-beta.53[22m
|
|
4
|
+
[34mℹ[39m config file: [4m/home/runner/work/contractspec/contractspec/packages/examples/learning-journey-ui-gamified/tsdown.config.js[24m
|
|
5
|
+
[34mℹ[39m entry: [34msrc/index.ts, src/views/index.ts, src/components/index.ts[39m
|
|
6
|
+
[34mℹ[39m target: [34mesnext[39m
|
|
7
|
+
[34mℹ[39m tsconfig: [34mtsconfig.json[39m
|
|
8
|
+
[34mℹ[39m Build start
|
|
9
|
+
[34mℹ[39m [2mdist/[22m[1mindex.mjs[22m [2m 2.36 kB[22m [2m│ gzip: 0.83 kB[22m
|
|
10
|
+
[34mℹ[39m [2mdist/[22m[1mcomponents/index.mjs[22m [2m 0.18 kB[22m [2m│ gzip: 0.15 kB[22m
|
|
11
|
+
[34mℹ[39m [2mdist/[22m[1mviews/index.mjs[22m [2m 0.18 kB[22m [2m│ gzip: 0.15 kB[22m
|
|
12
|
+
[34mℹ[39m [2mdist/[22mviews-B-DapxWu.mjs [2m18.35 kB[22m [2m│ gzip: 3.52 kB[22m
|
|
13
|
+
[34mℹ[39m [2mdist/[22mDayCalendar-Cha869Bi.mjs [2m 6.20 kB[22m [2m│ gzip: 1.87 kB[22m
|
|
14
|
+
[34mℹ[39m [2mdist/[22mcomponents-kh0CpIG2.mjs [2m 0.01 kB[22m [2m│ gzip: 0.03 kB[22m
|
|
15
|
+
[34mℹ[39m [2mdist/[22m[32m[1mindex.d.mts[22m[39m [2m 0.80 kB[22m [2m│ gzip: 0.41 kB[22m
|
|
16
|
+
[34mℹ[39m [2mdist/[22m[32m[1mviews/index.d.mts[22m[39m [2m 0.14 kB[22m [2m│ gzip: 0.12 kB[22m
|
|
17
|
+
[34mℹ[39m [2mdist/[22m[32m[1mcomponents/index.d.mts[22m[39m [2m 0.14 kB[22m [2m│ gzip: 0.12 kB[22m
|
|
18
|
+
[34mℹ[39m [2mdist/[22m[32mindex-DrzEZfnF.d.mts[39m [2m 1.13 kB[22m [2m│ gzip: 0.47 kB[22m
|
|
19
|
+
[34mℹ[39m [2mdist/[22m[32mindex-Bi5V3Ihq.d.mts[39m [2m 0.92 kB[22m [2m│ gzip: 0.34 kB[22m
|
|
20
|
+
[34mℹ[39m 11 files, total: 30.42 kB
|
|
21
|
+
[32m✔[39m Build complete in [32m8002ms[39m
|
|
22
|
+
$ tsc --noEmit
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# @lssm/example.learning-journey-ui-gamified
|
|
2
|
+
|
|
3
|
+
## 0.0.0-canary-20251212210835
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [3086383]
|
|
8
|
+
- @lssm/lib.design-system@0.0.0-canary-20251212210835
|
|
9
|
+
- @lssm/lib.ui-kit-web@0.0.0-canary-20251212210835
|
|
10
|
+
- @lssm/example.learning-journey-ui-shared@0.0.0-canary-20251212210835
|
|
11
|
+
- @lssm/example.learning-journey.duo-drills@0.0.0-canary-20251212210835
|
|
12
|
+
- @lssm/example.learning-journey.quest-challenges@0.0.0-canary-20251212210835
|
|
13
|
+
- @lssm/module.learning-journey@0.0.0-canary-20251212210835
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# @lssm/example.learning-journey-ui-gamified
|
|
2
|
+
|
|
3
|
+
Duolingo-style gamified learning UI for drills and quests.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Overview**: Hero card with XP, streak, and next challenge preview
|
|
8
|
+
- **Steps**: Interactive flashcard-style step cards
|
|
9
|
+
- **Progress**: Mastery rings, XP bar, and badge display
|
|
10
|
+
- **Timeline**: Day calendar for quests, step timeline for drills
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import { GamifiedMiniApp } from '@lssm/example.learning-journey-ui-gamified';
|
|
16
|
+
import { drillsLanguageBasicsTrack } from '@lssm/example.learning-journey.duo-drills/track';
|
|
17
|
+
|
|
18
|
+
function MyApp() {
|
|
19
|
+
return (
|
|
20
|
+
<GamifiedMiniApp track={drillsLanguageBasicsTrack} initialView="overview" />
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Components
|
|
26
|
+
|
|
27
|
+
- **FlashCard** - Tappable card that reveals action on flip
|
|
28
|
+
- **MasteryRing** - Circular progress indicator
|
|
29
|
+
- **DayCalendar** - 7-day grid for quest progress
|
|
30
|
+
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import { Card, CardContent } from "@lssm/lib.ui-kit-web/ui/card";
|
|
3
|
+
import { Button } from "@lssm/lib.design-system";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { cn } from "@lssm/lib.ui-kit-web/ui/utils";
|
|
6
|
+
|
|
7
|
+
//#region src/components/FlashCard.tsx
|
|
8
|
+
function FlashCard({ step, isCompleted, isCurrent, onComplete }) {
|
|
9
|
+
const [isFlipped, setIsFlipped] = useState(false);
|
|
10
|
+
return /* @__PURE__ */ jsx(Card, {
|
|
11
|
+
className: cn("relative cursor-pointer overflow-hidden transition-all duration-300", isCurrent && "ring-primary ring-2", isCompleted && "opacity-60"),
|
|
12
|
+
onClick: () => !isCompleted && setIsFlipped(!isFlipped),
|
|
13
|
+
children: /* @__PURE__ */ jsxs(CardContent, {
|
|
14
|
+
className: "p-6",
|
|
15
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
16
|
+
className: cn("space-y-4 transition-opacity duration-200", isFlipped ? "opacity-0" : "opacity-100"),
|
|
17
|
+
children: [
|
|
18
|
+
/* @__PURE__ */ jsxs("div", {
|
|
19
|
+
className: "flex items-start justify-between",
|
|
20
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
21
|
+
className: "flex-1",
|
|
22
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
23
|
+
className: "text-lg font-semibold",
|
|
24
|
+
children: step.title
|
|
25
|
+
}), step.description && /* @__PURE__ */ jsx("p", {
|
|
26
|
+
className: "text-muted-foreground mt-1 text-sm",
|
|
27
|
+
children: step.description
|
|
28
|
+
})]
|
|
29
|
+
}), step.xpReward && /* @__PURE__ */ jsxs("span", {
|
|
30
|
+
className: "rounded-full bg-green-500/10 px-2 py-1 text-xs font-semibold text-green-500",
|
|
31
|
+
children: [
|
|
32
|
+
"+",
|
|
33
|
+
step.xpReward,
|
|
34
|
+
" XP"
|
|
35
|
+
]
|
|
36
|
+
})]
|
|
37
|
+
}),
|
|
38
|
+
isCompleted && /* @__PURE__ */ jsxs("div", {
|
|
39
|
+
className: "flex items-center gap-2 text-green-500",
|
|
40
|
+
children: [/* @__PURE__ */ jsx("span", { children: "✓" }), /* @__PURE__ */ jsx("span", {
|
|
41
|
+
className: "text-sm font-medium",
|
|
42
|
+
children: "Completed"
|
|
43
|
+
})]
|
|
44
|
+
}),
|
|
45
|
+
isCurrent && !isCompleted && /* @__PURE__ */ jsx("p", {
|
|
46
|
+
className: "text-muted-foreground text-xs",
|
|
47
|
+
children: "Tap to reveal action"
|
|
48
|
+
})
|
|
49
|
+
]
|
|
50
|
+
}), isFlipped && !isCompleted && /* @__PURE__ */ jsxs("div", {
|
|
51
|
+
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",
|
|
52
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
53
|
+
className: "text-center text-sm",
|
|
54
|
+
children: step.instructions ?? "Complete this step to earn XP"
|
|
55
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
56
|
+
className: "flex gap-2",
|
|
57
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
58
|
+
variant: "outline",
|
|
59
|
+
size: "sm",
|
|
60
|
+
onClick: () => setIsFlipped(false),
|
|
61
|
+
children: "Back"
|
|
62
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
63
|
+
size: "sm",
|
|
64
|
+
onClick: (e) => {
|
|
65
|
+
e.stopPropagation();
|
|
66
|
+
onComplete?.();
|
|
67
|
+
},
|
|
68
|
+
children: "Mark Complete"
|
|
69
|
+
})]
|
|
70
|
+
})]
|
|
71
|
+
})]
|
|
72
|
+
})
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/components/MasteryRing.tsx
|
|
78
|
+
const sizeStyles = {
|
|
79
|
+
sm: {
|
|
80
|
+
container: "h-16 w-16",
|
|
81
|
+
text: "text-xs",
|
|
82
|
+
ring: 48,
|
|
83
|
+
stroke: 4
|
|
84
|
+
},
|
|
85
|
+
md: {
|
|
86
|
+
container: "h-24 w-24",
|
|
87
|
+
text: "text-sm",
|
|
88
|
+
ring: 72,
|
|
89
|
+
stroke: 6
|
|
90
|
+
},
|
|
91
|
+
lg: {
|
|
92
|
+
container: "h-32 w-32",
|
|
93
|
+
text: "text-base",
|
|
94
|
+
ring: 96,
|
|
95
|
+
stroke: 8
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const colorStyles = {
|
|
99
|
+
green: "stroke-green-500",
|
|
100
|
+
blue: "stroke-blue-500",
|
|
101
|
+
violet: "stroke-violet-500",
|
|
102
|
+
orange: "stroke-orange-500"
|
|
103
|
+
};
|
|
104
|
+
function MasteryRing({ label, percentage, size = "md", color = "violet" }) {
|
|
105
|
+
const styles = sizeStyles[size];
|
|
106
|
+
const radius = (styles.ring - styles.stroke) / 2;
|
|
107
|
+
const circumference = 2 * Math.PI * radius;
|
|
108
|
+
const strokeDashoffset = circumference - percentage / 100 * circumference;
|
|
109
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
110
|
+
className: cn("relative flex flex-col items-center gap-1", styles.container),
|
|
111
|
+
children: [
|
|
112
|
+
/* @__PURE__ */ jsxs("svg", {
|
|
113
|
+
className: "absolute -rotate-90",
|
|
114
|
+
width: styles.ring,
|
|
115
|
+
height: styles.ring,
|
|
116
|
+
viewBox: `0 0 ${styles.ring} ${styles.ring}`,
|
|
117
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
118
|
+
cx: styles.ring / 2,
|
|
119
|
+
cy: styles.ring / 2,
|
|
120
|
+
r: radius,
|
|
121
|
+
fill: "none",
|
|
122
|
+
strokeWidth: styles.stroke,
|
|
123
|
+
className: "stroke-muted"
|
|
124
|
+
}), /* @__PURE__ */ jsx("circle", {
|
|
125
|
+
cx: styles.ring / 2,
|
|
126
|
+
cy: styles.ring / 2,
|
|
127
|
+
r: radius,
|
|
128
|
+
fill: "none",
|
|
129
|
+
strokeWidth: styles.stroke,
|
|
130
|
+
strokeLinecap: "round",
|
|
131
|
+
strokeDasharray: circumference,
|
|
132
|
+
strokeDashoffset,
|
|
133
|
+
className: cn("transition-all duration-500", colorStyles[color])
|
|
134
|
+
})]
|
|
135
|
+
}),
|
|
136
|
+
/* @__PURE__ */ jsx("div", {
|
|
137
|
+
className: "flex h-full flex-col items-center justify-center",
|
|
138
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
139
|
+
className: cn("font-bold", styles.text),
|
|
140
|
+
children: [Math.round(percentage), "%"]
|
|
141
|
+
})
|
|
142
|
+
}),
|
|
143
|
+
/* @__PURE__ */ jsx("span", {
|
|
144
|
+
className: cn("text-muted-foreground mt-1 truncate", styles.text),
|
|
145
|
+
children: label
|
|
146
|
+
})
|
|
147
|
+
]
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
//#endregion
|
|
152
|
+
//#region src/components/DayCalendar.tsx
|
|
153
|
+
function DayCalendar({ totalDays, currentDay, completedDays }) {
|
|
154
|
+
return /* @__PURE__ */ jsx("div", {
|
|
155
|
+
className: "grid grid-cols-7 gap-2",
|
|
156
|
+
children: Array.from({ length: totalDays }, (_, i) => i + 1).map((day) => {
|
|
157
|
+
const isCompleted = completedDays.includes(day);
|
|
158
|
+
const isCurrent = day === currentDay;
|
|
159
|
+
const isLocked = day > currentDay;
|
|
160
|
+
return /* @__PURE__ */ jsx("div", {
|
|
161
|
+
className: cn("flex h-12 w-12 flex-col items-center justify-center rounded-lg border text-sm font-medium transition-all", isCompleted && "border-green-500 bg-green-500/10 text-green-500", isCurrent && !isCompleted && "border-violet-500 bg-violet-500/10 text-violet-500 ring-2 ring-violet-500/50", isLocked && "border-muted bg-muted/50 text-muted-foreground", !isCompleted && !isCurrent && !isLocked && "border-border bg-card"),
|
|
162
|
+
children: isCompleted ? /* @__PURE__ */ jsx("span", {
|
|
163
|
+
className: "text-lg",
|
|
164
|
+
children: "✓"
|
|
165
|
+
}) : isLocked ? /* @__PURE__ */ jsx("span", {
|
|
166
|
+
className: "text-lg",
|
|
167
|
+
children: "🔒"
|
|
168
|
+
}) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
169
|
+
className: "text-muted-foreground text-xs",
|
|
170
|
+
children: "Day"
|
|
171
|
+
}), /* @__PURE__ */ jsx("span", { children: day })] })
|
|
172
|
+
}, day);
|
|
173
|
+
})
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
//#endregion
|
|
178
|
+
export { MasteryRing as n, FlashCard as r, DayCalendar as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { LearningViewProps } from "@lssm/example.learning-journey-ui-shared";
|
|
2
|
+
import * as react_jsx_runtime1 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/views/Overview.d.ts
|
|
5
|
+
interface GamifiedOverviewProps extends LearningViewProps {
|
|
6
|
+
onStart?: () => void;
|
|
7
|
+
}
|
|
8
|
+
declare function Overview({
|
|
9
|
+
track,
|
|
10
|
+
progress,
|
|
11
|
+
onStart
|
|
12
|
+
}: GamifiedOverviewProps): react_jsx_runtime1.JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
//#region src/views/Steps.d.ts
|
|
15
|
+
declare function Steps({
|
|
16
|
+
track,
|
|
17
|
+
progress,
|
|
18
|
+
onStepComplete
|
|
19
|
+
}: LearningViewProps): react_jsx_runtime1.JSX.Element;
|
|
20
|
+
//#endregion
|
|
21
|
+
//#region src/views/Progress.d.ts
|
|
22
|
+
declare function Progress({
|
|
23
|
+
track,
|
|
24
|
+
progress
|
|
25
|
+
}: LearningViewProps): react_jsx_runtime1.JSX.Element;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/views/Timeline.d.ts
|
|
28
|
+
declare function Timeline({
|
|
29
|
+
track,
|
|
30
|
+
progress
|
|
31
|
+
}: LearningViewProps): react_jsx_runtime1.JSX.Element;
|
|
32
|
+
//#endregion
|
|
33
|
+
export { Overview as i, Progress as n, Steps as r, Timeline as t };
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as react_jsx_runtime5 from "react/jsx-runtime";
|
|
2
|
+
import { LearningJourneyStepSpec } from "@lssm/module.learning-journey/track-spec";
|
|
3
|
+
|
|
4
|
+
//#region src/components/FlashCard.d.ts
|
|
5
|
+
interface FlashCardProps {
|
|
6
|
+
step: LearningJourneyStepSpec;
|
|
7
|
+
isCompleted: boolean;
|
|
8
|
+
isCurrent: boolean;
|
|
9
|
+
onComplete?: () => void;
|
|
10
|
+
}
|
|
11
|
+
declare function FlashCard({
|
|
12
|
+
step,
|
|
13
|
+
isCompleted,
|
|
14
|
+
isCurrent,
|
|
15
|
+
onComplete
|
|
16
|
+
}: FlashCardProps): react_jsx_runtime5.JSX.Element;
|
|
17
|
+
//#endregion
|
|
18
|
+
//#region src/components/MasteryRing.d.ts
|
|
19
|
+
interface MasteryRingProps {
|
|
20
|
+
label: string;
|
|
21
|
+
percentage: number;
|
|
22
|
+
size?: 'sm' | 'md' | 'lg';
|
|
23
|
+
color?: 'green' | 'blue' | 'violet' | 'orange';
|
|
24
|
+
}
|
|
25
|
+
declare function MasteryRing({
|
|
26
|
+
label,
|
|
27
|
+
percentage,
|
|
28
|
+
size,
|
|
29
|
+
color
|
|
30
|
+
}: MasteryRingProps): react_jsx_runtime5.JSX.Element;
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/components/DayCalendar.d.ts
|
|
33
|
+
interface DayCalendarProps {
|
|
34
|
+
totalDays: number;
|
|
35
|
+
currentDay: number;
|
|
36
|
+
completedDays: number[];
|
|
37
|
+
}
|
|
38
|
+
declare function DayCalendar({
|
|
39
|
+
totalDays,
|
|
40
|
+
currentDay,
|
|
41
|
+
completedDays
|
|
42
|
+
}: DayCalendarProps): react_jsx_runtime5.JSX.Element;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { MasteryRing as n, FlashCard as r, DayCalendar as t };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { n as MasteryRing, r as FlashCard, t as DayCalendar } from "./index-DrzEZfnF.mjs";
|
|
2
|
+
import { i as Overview, n as Progress, r as Steps, t as Timeline } from "./index-Bi5V3Ihq.mjs";
|
|
3
|
+
import { LearningMiniAppProps } from "@lssm/example.learning-journey-ui-shared";
|
|
4
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
5
|
+
|
|
6
|
+
//#region src/GamifiedMiniApp.d.ts
|
|
7
|
+
type GamifiedMiniAppProps = Omit<LearningMiniAppProps, 'progress'> & {
|
|
8
|
+
progress?: LearningMiniAppProps['progress'];
|
|
9
|
+
};
|
|
10
|
+
declare function GamifiedMiniApp({
|
|
11
|
+
track,
|
|
12
|
+
progress: externalProgress,
|
|
13
|
+
onStepComplete: externalOnStepComplete,
|
|
14
|
+
onViewChange,
|
|
15
|
+
initialView
|
|
16
|
+
}: GamifiedMiniAppProps): react_jsx_runtime0.JSX.Element;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { DayCalendar, FlashCard, GamifiedMiniApp, MasteryRing, Overview, Progress, Steps, Timeline };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { i as Overview, n as Progress, r as Steps, t as Timeline } from "./views-B-DapxWu.mjs";
|
|
2
|
+
import { n as MasteryRing, r as FlashCard, t as DayCalendar } from "./DayCalendar-Cha869Bi.mjs";
|
|
3
|
+
import "./components-kh0CpIG2.mjs";
|
|
4
|
+
import { useCallback, useState } from "react";
|
|
5
|
+
import { Card, CardContent } from "@lssm/lib.ui-kit-web/ui/card";
|
|
6
|
+
import { ViewTabs, useLearningProgress } from "@lssm/example.learning-journey-ui-shared";
|
|
7
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
8
|
+
|
|
9
|
+
//#region src/GamifiedMiniApp.tsx
|
|
10
|
+
function GamifiedMiniApp({ track, progress: externalProgress, onStepComplete: externalOnStepComplete, onViewChange, initialView = "overview" }) {
|
|
11
|
+
const [currentView, setCurrentView] = useState(initialView);
|
|
12
|
+
const { progress: internalProgress, completeStep: internalCompleteStep } = useLearningProgress(track);
|
|
13
|
+
const progress = externalProgress ?? internalProgress;
|
|
14
|
+
const handleViewChange = useCallback((view) => {
|
|
15
|
+
setCurrentView(view);
|
|
16
|
+
onViewChange?.(view);
|
|
17
|
+
}, [onViewChange]);
|
|
18
|
+
const handleStepComplete = useCallback((stepId) => {
|
|
19
|
+
if (externalOnStepComplete) externalOnStepComplete(stepId);
|
|
20
|
+
else internalCompleteStep(stepId);
|
|
21
|
+
}, [externalOnStepComplete, internalCompleteStep]);
|
|
22
|
+
const handleStartFromOverview = useCallback(() => {
|
|
23
|
+
setCurrentView("steps");
|
|
24
|
+
onViewChange?.("steps");
|
|
25
|
+
}, [onViewChange]);
|
|
26
|
+
const renderView = () => {
|
|
27
|
+
const viewProps = {
|
|
28
|
+
track,
|
|
29
|
+
progress,
|
|
30
|
+
onStepComplete: handleStepComplete
|
|
31
|
+
};
|
|
32
|
+
switch (currentView) {
|
|
33
|
+
case "overview": return /* @__PURE__ */ jsx(Overview, {
|
|
34
|
+
...viewProps,
|
|
35
|
+
onStart: handleStartFromOverview
|
|
36
|
+
});
|
|
37
|
+
case "steps": return /* @__PURE__ */ jsx(Steps, { ...viewProps });
|
|
38
|
+
case "progress": return /* @__PURE__ */ jsx(Progress, { ...viewProps });
|
|
39
|
+
case "timeline": return /* @__PURE__ */ jsx(Timeline, { ...viewProps });
|
|
40
|
+
default: return /* @__PURE__ */ jsx(Overview, {
|
|
41
|
+
...viewProps,
|
|
42
|
+
onStart: handleStartFromOverview
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
47
|
+
className: "space-y-6",
|
|
48
|
+
children: [/* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, {
|
|
49
|
+
className: "p-4",
|
|
50
|
+
children: /* @__PURE__ */ jsx(ViewTabs, {
|
|
51
|
+
currentView,
|
|
52
|
+
onViewChange: handleViewChange
|
|
53
|
+
})
|
|
54
|
+
}) }), renderView()]
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
//#endregion
|
|
59
|
+
export { DayCalendar, FlashCard, GamifiedMiniApp, MasteryRing, Overview, Progress, Steps, Timeline };
|