@contractspec/example.learning-journey-ui-gamified 1.44.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$colon$bundle.log +57 -0
- package/.turbo/turbo-build.log +58 -0
- package/CHANGELOG.md +262 -0
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/dist/GamifiedMiniApp.d.ts +17 -0
- package/dist/GamifiedMiniApp.d.ts.map +1 -0
- package/dist/GamifiedMiniApp.js +63 -0
- package/dist/GamifiedMiniApp.js.map +1 -0
- package/dist/components/DayCalendar.d.ts +16 -0
- package/dist/components/DayCalendar.d.ts.map +1 -0
- package/dist/components/DayCalendar.js +33 -0
- package/dist/components/DayCalendar.js.map +1 -0
- package/dist/components/FlashCard.d.ts +19 -0
- package/dist/components/FlashCard.d.ts.map +1 -0
- package/dist/components/FlashCard.js +80 -0
- package/dist/components/FlashCard.js.map +1 -0
- package/dist/components/MasteryRing.d.ts +18 -0
- package/dist/components/MasteryRing.d.ts.map +1 -0
- package/dist/components/MasteryRing.js +82 -0
- package/dist/components/MasteryRing.js.map +1 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +5 -0
- package/dist/docs/index.d.ts +1 -0
- package/dist/docs/index.js +1 -0
- package/dist/docs/learning-journey-ui-gamified.docblock.d.ts +1 -0
- package/dist/docs/learning-journey-ui-gamified.docblock.js +20 -0
- package/dist/docs/learning-journey-ui-gamified.docblock.js.map +1 -0
- package/dist/example.d.ts +33 -0
- package/dist/example.d.ts.map +1 -0
- package/dist/example.js +35 -0
- package/dist/example.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +14 -0
- package/dist/views/Overview.d.ts +15 -0
- package/dist/views/Overview.d.ts.map +1 -0
- package/dist/views/Overview.js +161 -0
- package/dist/views/Overview.js.map +1 -0
- package/dist/views/Progress.d.ts +11 -0
- package/dist/views/Progress.d.ts.map +1 -0
- package/dist/views/Progress.js +143 -0
- package/dist/views/Progress.js.map +1 -0
- package/dist/views/Steps.d.ts +12 -0
- package/dist/views/Steps.d.ts.map +1 -0
- package/dist/views/Steps.js +56 -0
- package/dist/views/Steps.js.map +1 -0
- package/dist/views/Timeline.d.ts +11 -0
- package/dist/views/Timeline.d.ts.map +1 -0
- package/dist/views/Timeline.js +133 -0
- package/dist/views/Timeline.js.map +1 -0
- package/dist/views/index.d.ts +5 -0
- package/dist/views/index.js +6 -0
- package/example.ts +1 -0
- package/package.json +79 -0
- package/src/GamifiedMiniApp.tsx +93 -0
- package/src/components/DayCalendar.tsx +53 -0
- package/src/components/FlashCard.tsx +100 -0
- package/src/components/MasteryRing.tsx +81 -0
- package/src/components/index.ts +3 -0
- package/src/docs/index.ts +1 -0
- package/src/docs/learning-journey-ui-gamified.docblock.ts +18 -0
- package/src/example.ts +24 -0
- package/src/index.ts +10 -0
- package/src/views/Overview.tsx +164 -0
- package/src/views/Progress.tsx +183 -0
- package/src/views/Steps.tsx +50 -0
- package/src/views/Timeline.tsx +197 -0
- package/src/views/index.ts +4 -0
- package/tsconfig.json +10 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/tsdown.config.js +17 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from "react";
|
|
4
|
+
import { Card, CardContent } from "@contractspec/lib.ui-kit-web/ui/card";
|
|
5
|
+
import { Button } from "@contractspec/lib.design-system";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
import { cn } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
8
|
+
|
|
9
|
+
//#region src/components/FlashCard.tsx
|
|
10
|
+
function FlashCard({ step, isCompleted, isCurrent, onComplete }) {
|
|
11
|
+
const [isFlipped, setIsFlipped] = useState(false);
|
|
12
|
+
return /* @__PURE__ */ jsx(Card, {
|
|
13
|
+
className: cn("relative cursor-pointer overflow-hidden transition-all duration-300", isCurrent && "ring-primary ring-2", isCompleted && "opacity-60"),
|
|
14
|
+
onClick: () => !isCompleted && setIsFlipped(!isFlipped),
|
|
15
|
+
children: /* @__PURE__ */ jsxs(CardContent, {
|
|
16
|
+
className: "p-6",
|
|
17
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
18
|
+
className: cn("space-y-4 transition-opacity duration-200", isFlipped ? "opacity-0" : "opacity-100"),
|
|
19
|
+
children: [
|
|
20
|
+
/* @__PURE__ */ jsxs("div", {
|
|
21
|
+
className: "flex items-start justify-between",
|
|
22
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
23
|
+
className: "flex-1",
|
|
24
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
25
|
+
className: "text-lg font-semibold",
|
|
26
|
+
children: step.title
|
|
27
|
+
}), step.description && /* @__PURE__ */ jsx("p", {
|
|
28
|
+
className: "text-muted-foreground mt-1 text-sm",
|
|
29
|
+
children: step.description
|
|
30
|
+
})]
|
|
31
|
+
}), step.xpReward && /* @__PURE__ */ jsxs("span", {
|
|
32
|
+
className: "rounded-full bg-green-500/10 px-2 py-1 text-xs font-semibold text-green-500",
|
|
33
|
+
children: [
|
|
34
|
+
"+",
|
|
35
|
+
step.xpReward,
|
|
36
|
+
" XP"
|
|
37
|
+
]
|
|
38
|
+
})]
|
|
39
|
+
}),
|
|
40
|
+
isCompleted && /* @__PURE__ */ jsxs("div", {
|
|
41
|
+
className: "flex items-center gap-2 text-green-500",
|
|
42
|
+
children: [/* @__PURE__ */ jsx("span", { children: "✓" }), /* @__PURE__ */ jsx("span", {
|
|
43
|
+
className: "text-sm font-medium",
|
|
44
|
+
children: "Completed"
|
|
45
|
+
})]
|
|
46
|
+
}),
|
|
47
|
+
isCurrent && !isCompleted && /* @__PURE__ */ jsx("p", {
|
|
48
|
+
className: "text-muted-foreground text-xs",
|
|
49
|
+
children: "Tap to reveal action"
|
|
50
|
+
})
|
|
51
|
+
]
|
|
52
|
+
}), isFlipped && !isCompleted && /* @__PURE__ */ jsxs("div", {
|
|
53
|
+
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",
|
|
54
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
55
|
+
className: "text-center text-sm",
|
|
56
|
+
children: step.instructions ?? "Complete this step to earn XP"
|
|
57
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
58
|
+
className: "flex gap-2",
|
|
59
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
60
|
+
variant: "outline",
|
|
61
|
+
size: "sm",
|
|
62
|
+
onClick: () => setIsFlipped(false),
|
|
63
|
+
children: "Back"
|
|
64
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
65
|
+
size: "sm",
|
|
66
|
+
onClick: (e) => {
|
|
67
|
+
e.stopPropagation();
|
|
68
|
+
onComplete?.();
|
|
69
|
+
},
|
|
70
|
+
children: "Mark Complete"
|
|
71
|
+
})]
|
|
72
|
+
})]
|
|
73
|
+
})]
|
|
74
|
+
})
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//#endregion
|
|
79
|
+
export { FlashCard };
|
|
80
|
+
//# sourceMappingURL=FlashCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FlashCard.js","names":[],"sources":["../../src/components/FlashCard.tsx"],"sourcesContent":["'use client';\n\nimport { useState } from 'react';\nimport { Button } from '@contractspec/lib.design-system';\nimport { Card, CardContent } from '@contractspec/lib.ui-kit-web/ui/card';\nimport { cn } from '@contractspec/lib.ui-kit-web/ui/utils';\nimport type { LearningJourneyStepSpec } from '@contractspec/module.learning-journey/track-spec';\n\ninterface FlashCardProps {\n step: LearningJourneyStepSpec;\n isCompleted: boolean;\n isCurrent: boolean;\n onComplete?: () => void;\n}\n\nexport function FlashCard({\n step,\n isCompleted,\n isCurrent,\n onComplete,\n}: FlashCardProps) {\n const [isFlipped, setIsFlipped] = useState(false);\n\n return (\n <Card\n className={cn(\n 'relative cursor-pointer overflow-hidden transition-all duration-300',\n isCurrent && 'ring-primary ring-2',\n isCompleted && 'opacity-60'\n )}\n onClick={() => !isCompleted && setIsFlipped(!isFlipped)}\n >\n <CardContent className=\"p-6\">\n {/* Front of card */}\n <div\n className={cn(\n 'space-y-4 transition-opacity duration-200',\n isFlipped ? 'opacity-0' : 'opacity-100'\n )}\n >\n <div className=\"flex items-start justify-between\">\n <div className=\"flex-1\">\n <h3 className=\"text-lg font-semibold\">{step.title}</h3>\n {step.description && (\n <p className=\"text-muted-foreground mt-1 text-sm\">\n {step.description}\n </p>\n )}\n </div>\n {step.xpReward && (\n <span className=\"rounded-full bg-green-500/10 px-2 py-1 text-xs font-semibold text-green-500\">\n +{step.xpReward} XP\n </span>\n )}\n </div>\n\n {isCompleted && (\n <div className=\"flex items-center gap-2 text-green-500\">\n <span>✓</span>\n <span className=\"text-sm font-medium\">Completed</span>\n </div>\n )}\n\n {isCurrent && !isCompleted && (\n <p className=\"text-muted-foreground text-xs\">\n Tap to reveal action\n </p>\n )}\n </div>\n\n {/* Back of card (action) */}\n {isFlipped && !isCompleted && (\n <div 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\">\n <p className=\"text-center text-sm\">\n {step.instructions ?? 'Complete this step to earn XP'}\n </p>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={() => setIsFlipped(false)}\n >\n Back\n </Button>\n <Button\n size=\"sm\"\n onClick={(e) => {\n e.stopPropagation();\n onComplete?.();\n }}\n >\n Mark Complete\n </Button>\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n );\n}\n"],"mappings":";;;;;;;;;AAeA,SAAgB,UAAU,EACxB,MACA,aACA,WACA,cACiB;CACjB,MAAM,CAAC,WAAW,gBAAgB,SAAS,MAAM;AAEjD,QACE,oBAAC;EACC,WAAW,GACT,uEACA,aAAa,uBACb,eAAe,aAChB;EACD,eAAe,CAAC,eAAe,aAAa,CAAC,UAAU;YAEvD,qBAAC;GAAY,WAAU;cAErB,qBAAC;IACC,WAAW,GACT,6CACA,YAAY,cAAc,cAC3B;;KAED,qBAAC;MAAI,WAAU;iBACb,qBAAC;OAAI,WAAU;kBACb,oBAAC;QAAG,WAAU;kBAAyB,KAAK;SAAW,EACtD,KAAK,eACJ,oBAAC;QAAE,WAAU;kBACV,KAAK;SACJ;QAEF,EACL,KAAK,YACJ,qBAAC;OAAK,WAAU;;QAA8E;QAC1F,KAAK;QAAS;;QACX;OAEL;KAEL,eACC,qBAAC;MAAI,WAAU;iBACb,oBAAC,oBAAK,MAAQ,EACd,oBAAC;OAAK,WAAU;iBAAsB;QAAgB;OAClD;KAGP,aAAa,CAAC,eACb,oBAAC;MAAE,WAAU;gBAAgC;OAEzC;;KAEF,EAGL,aAAa,CAAC,eACb,qBAAC;IAAI,WAAU;eACb,oBAAC;KAAE,WAAU;eACV,KAAK,gBAAgB;MACpB,EACJ,qBAAC;KAAI,WAAU;gBACb,oBAAC;MACC,SAAQ;MACR,MAAK;MACL,eAAe,aAAa,MAAM;gBACnC;OAEQ,EACT,oBAAC;MACC,MAAK;MACL,UAAU,MAAM;AACd,SAAE,iBAAiB;AACnB,qBAAc;;gBAEjB;OAEQ;MACL;KACF;IAEI;GACT"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
2
|
+
|
|
3
|
+
//#region src/components/MasteryRing.d.ts
|
|
4
|
+
interface MasteryRingProps {
|
|
5
|
+
label: string;
|
|
6
|
+
percentage: number;
|
|
7
|
+
size?: 'sm' | 'md' | 'lg';
|
|
8
|
+
color?: 'green' | 'blue' | 'violet' | 'orange';
|
|
9
|
+
}
|
|
10
|
+
declare function MasteryRing({
|
|
11
|
+
label,
|
|
12
|
+
percentage,
|
|
13
|
+
size,
|
|
14
|
+
color
|
|
15
|
+
}: MasteryRingProps): react_jsx_runtime0.JSX.Element;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { MasteryRing };
|
|
18
|
+
//# sourceMappingURL=MasteryRing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MasteryRing.d.ts","names":[],"sources":["../../src/components/MasteryRing.tsx"],"sourcesContent":[],"mappings":";;;UAIU,gBAAA;;;EAAA,IAAA,CAAA,EAAA,IAAA,GAAA,IAAA,GAAgB,IAAA;EAoBV,KAAA,CAAA,EAAA,OAAW,GAAA,MAAA,GAAA,QAAA,GAAA,QAAA;;AAEzB,iBAFc,WAAA,CAEd;EAAA,KAAA;EAAA,UAAA;EAAA,IAAA;EAAA;AAAA,CAAA,EAGC,gBAHD,CAAA,EAGiB,kBAAA,CAAA,GAAA,CAAA,OAHjB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { cn } from "@contractspec/lib.ui-kit-web/ui/utils";
|
|
5
|
+
|
|
6
|
+
//#region src/components/MasteryRing.tsx
|
|
7
|
+
const sizeStyles = {
|
|
8
|
+
sm: {
|
|
9
|
+
container: "h-16 w-16",
|
|
10
|
+
text: "text-xs",
|
|
11
|
+
ring: 48,
|
|
12
|
+
stroke: 4
|
|
13
|
+
},
|
|
14
|
+
md: {
|
|
15
|
+
container: "h-24 w-24",
|
|
16
|
+
text: "text-sm",
|
|
17
|
+
ring: 72,
|
|
18
|
+
stroke: 6
|
|
19
|
+
},
|
|
20
|
+
lg: {
|
|
21
|
+
container: "h-32 w-32",
|
|
22
|
+
text: "text-base",
|
|
23
|
+
ring: 96,
|
|
24
|
+
stroke: 8
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
const colorStyles = {
|
|
28
|
+
green: "stroke-green-500",
|
|
29
|
+
blue: "stroke-blue-500",
|
|
30
|
+
violet: "stroke-violet-500",
|
|
31
|
+
orange: "stroke-orange-500"
|
|
32
|
+
};
|
|
33
|
+
function MasteryRing({ label, percentage, size = "md", color = "violet" }) {
|
|
34
|
+
const styles = sizeStyles[size];
|
|
35
|
+
const radius = (styles.ring - styles.stroke) / 2;
|
|
36
|
+
const circumference = 2 * Math.PI * radius;
|
|
37
|
+
const strokeDashoffset = circumference - percentage / 100 * circumference;
|
|
38
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
39
|
+
className: cn("relative flex flex-col items-center gap-1", styles.container),
|
|
40
|
+
children: [
|
|
41
|
+
/* @__PURE__ */ jsxs("svg", {
|
|
42
|
+
className: "absolute -rotate-90",
|
|
43
|
+
width: styles.ring,
|
|
44
|
+
height: styles.ring,
|
|
45
|
+
viewBox: `0 0 ${styles.ring} ${styles.ring}`,
|
|
46
|
+
children: [/* @__PURE__ */ jsx("circle", {
|
|
47
|
+
cx: styles.ring / 2,
|
|
48
|
+
cy: styles.ring / 2,
|
|
49
|
+
r: radius,
|
|
50
|
+
fill: "none",
|
|
51
|
+
strokeWidth: styles.stroke,
|
|
52
|
+
className: "stroke-muted"
|
|
53
|
+
}), /* @__PURE__ */ jsx("circle", {
|
|
54
|
+
cx: styles.ring / 2,
|
|
55
|
+
cy: styles.ring / 2,
|
|
56
|
+
r: radius,
|
|
57
|
+
fill: "none",
|
|
58
|
+
strokeWidth: styles.stroke,
|
|
59
|
+
strokeLinecap: "round",
|
|
60
|
+
strokeDasharray: circumference,
|
|
61
|
+
strokeDashoffset,
|
|
62
|
+
className: cn("transition-all duration-500", colorStyles[color])
|
|
63
|
+
})]
|
|
64
|
+
}),
|
|
65
|
+
/* @__PURE__ */ jsx("div", {
|
|
66
|
+
className: "flex h-full flex-col items-center justify-center",
|
|
67
|
+
children: /* @__PURE__ */ jsxs("span", {
|
|
68
|
+
className: cn("font-bold", styles.text),
|
|
69
|
+
children: [Math.round(percentage), "%"]
|
|
70
|
+
})
|
|
71
|
+
}),
|
|
72
|
+
/* @__PURE__ */ jsx("span", {
|
|
73
|
+
className: cn("text-muted-foreground mt-1 truncate", styles.text),
|
|
74
|
+
children: label
|
|
75
|
+
})
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
//#endregion
|
|
81
|
+
export { MasteryRing };
|
|
82
|
+
//# sourceMappingURL=MasteryRing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MasteryRing.js","names":[],"sources":["../../src/components/MasteryRing.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@contractspec/lib.ui-kit-web/ui/utils';\n\ninterface MasteryRingProps {\n label: string;\n percentage: number;\n size?: 'sm' | 'md' | 'lg';\n color?: 'green' | 'blue' | 'violet' | 'orange';\n}\n\nconst sizeStyles = {\n sm: { container: 'h-16 w-16', text: 'text-xs', ring: 48, stroke: 4 },\n md: { container: 'h-24 w-24', text: 'text-sm', ring: 72, stroke: 6 },\n lg: { container: 'h-32 w-32', text: 'text-base', ring: 96, stroke: 8 },\n};\n\nconst colorStyles = {\n green: 'stroke-green-500',\n blue: 'stroke-blue-500',\n violet: 'stroke-violet-500',\n orange: 'stroke-orange-500',\n};\n\nexport function MasteryRing({\n label,\n percentage,\n size = 'md',\n color = 'violet',\n}: MasteryRingProps) {\n const styles = sizeStyles[size];\n const radius = (styles.ring - styles.stroke) / 2;\n const circumference = 2 * Math.PI * radius;\n const strokeDashoffset = circumference - (percentage / 100) * circumference;\n\n return (\n <div\n className={cn(\n 'relative flex flex-col items-center gap-1',\n styles.container\n )}\n >\n <svg\n className=\"absolute -rotate-90\"\n width={styles.ring}\n height={styles.ring}\n viewBox={`0 0 ${styles.ring} ${styles.ring}`}\n >\n {/* Background ring */}\n <circle\n cx={styles.ring / 2}\n cy={styles.ring / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={styles.stroke}\n className=\"stroke-muted\"\n />\n {/* Progress ring */}\n <circle\n cx={styles.ring / 2}\n cy={styles.ring / 2}\n r={radius}\n fill=\"none\"\n strokeWidth={styles.stroke}\n strokeLinecap=\"round\"\n strokeDasharray={circumference}\n strokeDashoffset={strokeDashoffset}\n className={cn('transition-all duration-500', colorStyles[color])}\n />\n </svg>\n <div className=\"flex h-full flex-col items-center justify-center\">\n <span className={cn('font-bold', styles.text)}>\n {Math.round(percentage)}%\n </span>\n </div>\n <span className={cn('text-muted-foreground mt-1 truncate', styles.text)}>\n {label}\n </span>\n </div>\n );\n}\n"],"mappings":";;;;;;AAWA,MAAM,aAAa;CACjB,IAAI;EAAE,WAAW;EAAa,MAAM;EAAW,MAAM;EAAI,QAAQ;EAAG;CACpE,IAAI;EAAE,WAAW;EAAa,MAAM;EAAW,MAAM;EAAI,QAAQ;EAAG;CACpE,IAAI;EAAE,WAAW;EAAa,MAAM;EAAa,MAAM;EAAI,QAAQ;EAAG;CACvE;AAED,MAAM,cAAc;CAClB,OAAO;CACP,MAAM;CACN,QAAQ;CACR,QAAQ;CACT;AAED,SAAgB,YAAY,EAC1B,OACA,YACA,OAAO,MACP,QAAQ,YACW;CACnB,MAAM,SAAS,WAAW;CAC1B,MAAM,UAAU,OAAO,OAAO,OAAO,UAAU;CAC/C,MAAM,gBAAgB,IAAI,KAAK,KAAK;CACpC,MAAM,mBAAmB,gBAAiB,aAAa,MAAO;AAE9D,QACE,qBAAC;EACC,WAAW,GACT,6CACA,OAAO,UACR;;GAED,qBAAC;IACC,WAAU;IACV,OAAO,OAAO;IACd,QAAQ,OAAO;IACf,SAAS,OAAO,OAAO,KAAK,GAAG,OAAO;eAGtC,oBAAC;KACC,IAAI,OAAO,OAAO;KAClB,IAAI,OAAO,OAAO;KAClB,GAAG;KACH,MAAK;KACL,aAAa,OAAO;KACpB,WAAU;MACV,EAEF,oBAAC;KACC,IAAI,OAAO,OAAO;KAClB,IAAI,OAAO,OAAO;KAClB,GAAG;KACH,MAAK;KACL,aAAa,OAAO;KACpB,eAAc;KACd,iBAAiB;KACC;KAClB,WAAW,GAAG,+BAA+B,YAAY,OAAO;MAChE;KACE;GACN,oBAAC;IAAI,WAAU;cACb,qBAAC;KAAK,WAAW,GAAG,aAAa,OAAO,KAAK;gBAC1C,KAAK,MAAM,WAAW,EAAC;MACnB;KACH;GACN,oBAAC;IAAK,WAAW,GAAG,uCAAuC,OAAO,KAAK;cACpE;KACI;;GACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./learning-journey-ui-gamified.docblock.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { registerDocBlocks } from "@contractspec/lib.contracts/docs";
|
|
2
|
+
|
|
3
|
+
//#region src/docs/learning-journey-ui-gamified.docblock.ts
|
|
4
|
+
registerDocBlocks([{
|
|
5
|
+
id: "docs.examples.learning-journey-ui-gamified",
|
|
6
|
+
title: "Learning Journey UI — Gamified",
|
|
7
|
+
summary: "UI mini-app components for gamified learning: flashcards, mastery, streak/calendar.",
|
|
8
|
+
kind: "reference",
|
|
9
|
+
visibility: "public",
|
|
10
|
+
route: "/docs/examples/learning-journey-ui-gamified",
|
|
11
|
+
tags: [
|
|
12
|
+
"learning",
|
|
13
|
+
"ui",
|
|
14
|
+
"gamified"
|
|
15
|
+
],
|
|
16
|
+
body: `## Includes\n- Gamified mini-app shell\n- Views: overview, steps, progress, timeline\n- Components: flash card, mastery ring, day calendar\n\n## Notes\n- Compose with design system components.\n- Respect prefers-reduced-motion; keep tap targets large.`
|
|
17
|
+
}]);
|
|
18
|
+
|
|
19
|
+
//#endregion
|
|
20
|
+
//# sourceMappingURL=learning-journey-ui-gamified.docblock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learning-journey-ui-gamified.docblock.js","names":[],"sources":["../../src/docs/learning-journey-ui-gamified.docblock.ts"],"sourcesContent":["import type { DocBlock } from '@contractspec/lib.contracts/docs';\nimport { registerDocBlocks } from '@contractspec/lib.contracts/docs';\n\nconst blocks: DocBlock[] = [\n {\n id: 'docs.examples.learning-journey-ui-gamified',\n title: 'Learning Journey UI — Gamified',\n summary:\n 'UI mini-app components for gamified learning: flashcards, mastery, streak/calendar.',\n kind: 'reference',\n visibility: 'public',\n route: '/docs/examples/learning-journey-ui-gamified',\n tags: ['learning', 'ui', 'gamified'],\n body: `## Includes\\n- Gamified mini-app shell\\n- Views: overview, steps, progress, timeline\\n- Components: flash card, mastery ring, day calendar\\n\\n## Notes\\n- Compose with design system components.\\n- Respect prefers-reduced-motion; keep tap targets large.`,\n },\n];\n\nregisterDocBlocks(blocks);\n"],"mappings":";;;AAiBA,kBAd2B,CACzB;CACE,IAAI;CACJ,OAAO;CACP,SACE;CACF,MAAM;CACN,YAAY;CACZ,OAAO;CACP,MAAM;EAAC;EAAY;EAAM;EAAW;CACpC,MAAM;CACP,CACF,CAEwB"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
//#region src/example.d.ts
|
|
2
|
+
declare const example: {
|
|
3
|
+
readonly id: "learning-journey-ui-gamified";
|
|
4
|
+
readonly title: "Learning Journey UI — Gamified";
|
|
5
|
+
readonly summary: "UI mini-app for gamified learning: flashcards, mastery ring, calendar.";
|
|
6
|
+
readonly tags: readonly ["learning", "ui", "gamified"];
|
|
7
|
+
readonly kind: "ui";
|
|
8
|
+
readonly visibility: "public";
|
|
9
|
+
readonly docs: {
|
|
10
|
+
readonly rootDocId: "docs.examples.learning-journey-ui-gamified";
|
|
11
|
+
};
|
|
12
|
+
readonly entrypoints: {
|
|
13
|
+
readonly packageName: "@contractspec/example.learning-journey-ui-gamified";
|
|
14
|
+
readonly docs: "./docs";
|
|
15
|
+
};
|
|
16
|
+
readonly surfaces: {
|
|
17
|
+
readonly templates: true;
|
|
18
|
+
readonly sandbox: {
|
|
19
|
+
readonly enabled: true;
|
|
20
|
+
readonly modes: readonly ["playground", "markdown"];
|
|
21
|
+
};
|
|
22
|
+
readonly studio: {
|
|
23
|
+
readonly enabled: true;
|
|
24
|
+
readonly installable: true;
|
|
25
|
+
};
|
|
26
|
+
readonly mcp: {
|
|
27
|
+
readonly enabled: true;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
//#endregion
|
|
32
|
+
export { example as default };
|
|
33
|
+
//# sourceMappingURL=example.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example.d.ts","names":[],"sources":["../src/example.ts"],"sourcesContent":[],"mappings":";cAAM;EAAA,SAAA,EAqBI,EAAA,8BAAA"}
|
package/dist/example.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//#region src/example.ts
|
|
2
|
+
const example = {
|
|
3
|
+
id: "learning-journey-ui-gamified",
|
|
4
|
+
title: "Learning Journey UI — Gamified",
|
|
5
|
+
summary: "UI mini-app for gamified learning: flashcards, mastery ring, calendar.",
|
|
6
|
+
tags: [
|
|
7
|
+
"learning",
|
|
8
|
+
"ui",
|
|
9
|
+
"gamified"
|
|
10
|
+
],
|
|
11
|
+
kind: "ui",
|
|
12
|
+
visibility: "public",
|
|
13
|
+
docs: { rootDocId: "docs.examples.learning-journey-ui-gamified" },
|
|
14
|
+
entrypoints: {
|
|
15
|
+
packageName: "@contractspec/example.learning-journey-ui-gamified",
|
|
16
|
+
docs: "./docs"
|
|
17
|
+
},
|
|
18
|
+
surfaces: {
|
|
19
|
+
templates: true,
|
|
20
|
+
sandbox: {
|
|
21
|
+
enabled: true,
|
|
22
|
+
modes: ["playground", "markdown"]
|
|
23
|
+
},
|
|
24
|
+
studio: {
|
|
25
|
+
enabled: true,
|
|
26
|
+
installable: true
|
|
27
|
+
},
|
|
28
|
+
mcp: { enabled: true }
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
var example_default = example;
|
|
32
|
+
|
|
33
|
+
//#endregion
|
|
34
|
+
export { example_default as default };
|
|
35
|
+
//# sourceMappingURL=example.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"example.js","names":[],"sources":["../src/example.ts"],"sourcesContent":["const example = {\n id: 'learning-journey-ui-gamified',\n title: 'Learning Journey UI — Gamified',\n summary:\n 'UI mini-app for gamified learning: flashcards, mastery ring, calendar.',\n tags: ['learning', 'ui', 'gamified'],\n kind: 'ui',\n visibility: 'public',\n docs: {\n rootDocId: 'docs.examples.learning-journey-ui-gamified',\n },\n entrypoints: {\n packageName: '@contractspec/example.learning-journey-ui-gamified',\n docs: './docs',\n },\n surfaces: {\n templates: true,\n sandbox: { enabled: true, modes: ['playground', 'markdown'] },\n studio: { enabled: true, installable: true },\n mcp: { enabled: true },\n },\n} as const;\n\nexport default example;\n"],"mappings":";AAAA,MAAM,UAAU;CACd,IAAI;CACJ,OAAO;CACP,SACE;CACF,MAAM;EAAC;EAAY;EAAM;EAAW;CACpC,MAAM;CACN,YAAY;CACZ,MAAM,EACJ,WAAW,8CACZ;CACD,aAAa;EACX,aAAa;EACb,MAAM;EACP;CACD,UAAU;EACR,WAAW;EACX,SAAS;GAAE,SAAS;GAAM,OAAO,CAAC,cAAc,WAAW;GAAE;EAC7D,QAAQ;GAAE,SAAS;GAAM,aAAa;GAAM;EAC5C,KAAK,EAAE,SAAS,MAAM;EACvB;CACF;AAED,sBAAe"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { GamifiedMiniApp } from "./GamifiedMiniApp.js";
|
|
2
|
+
import { DayCalendar } from "./components/DayCalendar.js";
|
|
3
|
+
import { FlashCard } from "./components/FlashCard.js";
|
|
4
|
+
import { MasteryRing } from "./components/MasteryRing.js";
|
|
5
|
+
import "./components/index.js";
|
|
6
|
+
import example from "./example.js";
|
|
7
|
+
import { Overview } from "./views/Overview.js";
|
|
8
|
+
import { Steps } from "./views/Steps.js";
|
|
9
|
+
import { Progress } from "./views/Progress.js";
|
|
10
|
+
import { Timeline } from "./views/Timeline.js";
|
|
11
|
+
import "./views/index.js";
|
|
12
|
+
export { DayCalendar, FlashCard, GamifiedMiniApp, MasteryRing, Overview, Progress, Steps, Timeline, example };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Overview } from "./views/Overview.js";
|
|
2
|
+
import { FlashCard } from "./components/FlashCard.js";
|
|
3
|
+
import { Steps } from "./views/Steps.js";
|
|
4
|
+
import { MasteryRing } from "./components/MasteryRing.js";
|
|
5
|
+
import { Progress } from "./views/Progress.js";
|
|
6
|
+
import { DayCalendar } from "./components/DayCalendar.js";
|
|
7
|
+
import { Timeline } from "./views/Timeline.js";
|
|
8
|
+
import { GamifiedMiniApp } from "./GamifiedMiniApp.js";
|
|
9
|
+
import example_default from "./example.js";
|
|
10
|
+
import "./views/index.js";
|
|
11
|
+
import "./components/index.js";
|
|
12
|
+
import "./docs/index.js";
|
|
13
|
+
|
|
14
|
+
export { DayCalendar, FlashCard, GamifiedMiniApp, MasteryRing, Overview, Progress, Steps, Timeline, example_default as example };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { LearningViewProps } from "@contractspec/example.learning-journey-ui-shared";
|
|
2
|
+
import * as react_jsx_runtime4 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_runtime4.JSX.Element;
|
|
13
|
+
//#endregion
|
|
14
|
+
export { Overview };
|
|
15
|
+
//# sourceMappingURL=Overview.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Overview.d.ts","names":[],"sources":["../../src/views/Overview.tsx"],"sourcesContent":[],"mappings":";;;;UAgBU,qBAAA,SAA8B;;;AAA9B,iBAIM,QAAA,CAJgB;EAAA,KAAQ;EAAA,QAAA;EAAA;AAAiB,CAAA,EAIF,qBAJE,CAAA,EAImB,kBAAA,CAAA,GAAA,CAAA,OAJnB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Card, CardContent, CardHeader, CardTitle } from "@contractspec/lib.ui-kit-web/ui/card";
|
|
4
|
+
import { BadgeDisplay, StreakCounter, XpBar } from "@contractspec/example.learning-journey-ui-shared";
|
|
5
|
+
import { Button } from "@contractspec/lib.design-system";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
|
|
8
|
+
//#region src/views/Overview.tsx
|
|
9
|
+
function Overview({ track, progress, onStart }) {
|
|
10
|
+
const totalXp = track.totalXp ?? track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) + (track.completionRewards?.xpBonus ?? 0);
|
|
11
|
+
const completedSteps = progress.completedStepIds.length;
|
|
12
|
+
const totalSteps = track.steps.length;
|
|
13
|
+
const isComplete = completedSteps === totalSteps;
|
|
14
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
15
|
+
className: "space-y-6",
|
|
16
|
+
children: [
|
|
17
|
+
/* @__PURE__ */ jsx(Card, {
|
|
18
|
+
className: "overflow-hidden bg-gradient-to-br from-violet-500/10 via-purple-500/10 to-fuchsia-500/10",
|
|
19
|
+
children: /* @__PURE__ */ jsx(CardContent, {
|
|
20
|
+
className: "p-6",
|
|
21
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
22
|
+
className: "flex flex-col items-center gap-4 text-center md:flex-row md:text-left",
|
|
23
|
+
children: [
|
|
24
|
+
/* @__PURE__ */ jsx("div", {
|
|
25
|
+
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",
|
|
26
|
+
children: isComplete ? "🏆" : "🎯"
|
|
27
|
+
}),
|
|
28
|
+
/* @__PURE__ */ jsxs("div", {
|
|
29
|
+
className: "flex-1",
|
|
30
|
+
children: [/* @__PURE__ */ jsx("h1", {
|
|
31
|
+
className: "text-2xl font-bold",
|
|
32
|
+
children: track.name
|
|
33
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
34
|
+
className: "text-muted-foreground mt-1",
|
|
35
|
+
children: track.description
|
|
36
|
+
})]
|
|
37
|
+
}),
|
|
38
|
+
/* @__PURE__ */ jsx("div", {
|
|
39
|
+
className: "flex items-center gap-3",
|
|
40
|
+
children: /* @__PURE__ */ jsx(StreakCounter, {
|
|
41
|
+
days: progress.streakDays,
|
|
42
|
+
size: "lg"
|
|
43
|
+
})
|
|
44
|
+
})
|
|
45
|
+
]
|
|
46
|
+
})
|
|
47
|
+
})
|
|
48
|
+
}),
|
|
49
|
+
/* @__PURE__ */ jsxs("div", {
|
|
50
|
+
className: "grid gap-4 md:grid-cols-3",
|
|
51
|
+
children: [
|
|
52
|
+
/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(CardHeader, {
|
|
53
|
+
className: "pb-2",
|
|
54
|
+
children: /* @__PURE__ */ jsx(CardTitle, {
|
|
55
|
+
className: "text-muted-foreground text-sm font-medium",
|
|
56
|
+
children: "XP Progress"
|
|
57
|
+
})
|
|
58
|
+
}), /* @__PURE__ */ jsxs(CardContent, { children: [/* @__PURE__ */ jsx("div", {
|
|
59
|
+
className: "text-3xl font-bold text-violet-500",
|
|
60
|
+
children: progress.xpEarned.toLocaleString()
|
|
61
|
+
}), /* @__PURE__ */ jsx(XpBar, {
|
|
62
|
+
current: progress.xpEarned,
|
|
63
|
+
max: totalXp,
|
|
64
|
+
showLabel: false,
|
|
65
|
+
size: "sm"
|
|
66
|
+
})] })] }),
|
|
67
|
+
/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(CardHeader, {
|
|
68
|
+
className: "pb-2",
|
|
69
|
+
children: /* @__PURE__ */ jsx(CardTitle, {
|
|
70
|
+
className: "text-muted-foreground text-sm font-medium",
|
|
71
|
+
children: "Steps Completed"
|
|
72
|
+
})
|
|
73
|
+
}), /* @__PURE__ */ jsxs(CardContent, { children: [/* @__PURE__ */ jsxs("div", {
|
|
74
|
+
className: "text-3xl font-bold",
|
|
75
|
+
children: [
|
|
76
|
+
completedSteps,
|
|
77
|
+
" ",
|
|
78
|
+
/* @__PURE__ */ jsxs("span", {
|
|
79
|
+
className: "text-muted-foreground text-lg",
|
|
80
|
+
children: ["/ ", totalSteps]
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
84
|
+
className: "bg-muted mt-2 h-2 w-full overflow-hidden rounded-full",
|
|
85
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
86
|
+
className: "h-full bg-green-500 transition-all duration-500",
|
|
87
|
+
style: { width: `${completedSteps / totalSteps * 100}%` }
|
|
88
|
+
})
|
|
89
|
+
})] })] }),
|
|
90
|
+
/* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(CardHeader, {
|
|
91
|
+
className: "pb-2",
|
|
92
|
+
children: /* @__PURE__ */ jsx(CardTitle, {
|
|
93
|
+
className: "text-muted-foreground text-sm font-medium",
|
|
94
|
+
children: "Badges Earned"
|
|
95
|
+
})
|
|
96
|
+
}), /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(BadgeDisplay, {
|
|
97
|
+
badges: progress.badges,
|
|
98
|
+
size: "lg"
|
|
99
|
+
}) })] })
|
|
100
|
+
]
|
|
101
|
+
}),
|
|
102
|
+
!isComplete && /* @__PURE__ */ jsxs(Card, { children: [/* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs(CardTitle, {
|
|
103
|
+
className: "flex items-center gap-2",
|
|
104
|
+
children: [/* @__PURE__ */ jsx("span", { children: "🎯" }), /* @__PURE__ */ jsx("span", { children: "Next Challenge" })]
|
|
105
|
+
}) }), /* @__PURE__ */ jsx(CardContent, { children: (() => {
|
|
106
|
+
const nextStep = track.steps.find((s) => !progress.completedStepIds.includes(s.id));
|
|
107
|
+
if (!nextStep) return null;
|
|
108
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
109
|
+
className: "flex items-center justify-between gap-4",
|
|
110
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
111
|
+
className: "font-semibold",
|
|
112
|
+
children: nextStep.title
|
|
113
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
114
|
+
className: "text-muted-foreground text-sm",
|
|
115
|
+
children: nextStep.description
|
|
116
|
+
})] }), /* @__PURE__ */ jsxs("div", {
|
|
117
|
+
className: "flex items-center gap-3",
|
|
118
|
+
children: [nextStep.xpReward && /* @__PURE__ */ jsxs("span", {
|
|
119
|
+
className: "rounded-full bg-green-500/10 px-3 py-1 text-sm font-semibold text-green-500",
|
|
120
|
+
children: [
|
|
121
|
+
"+",
|
|
122
|
+
nextStep.xpReward,
|
|
123
|
+
" XP"
|
|
124
|
+
]
|
|
125
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
126
|
+
onClick: onStart,
|
|
127
|
+
children: "Start"
|
|
128
|
+
})]
|
|
129
|
+
})]
|
|
130
|
+
});
|
|
131
|
+
})() })] }),
|
|
132
|
+
isComplete && /* @__PURE__ */ jsx(Card, {
|
|
133
|
+
className: "border-green-500/50 bg-green-500/5",
|
|
134
|
+
children: /* @__PURE__ */ jsxs(CardContent, {
|
|
135
|
+
className: "flex items-center gap-4 p-6",
|
|
136
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
137
|
+
className: "text-4xl",
|
|
138
|
+
children: "🎉"
|
|
139
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("h3", {
|
|
140
|
+
className: "text-lg font-semibold text-green-500",
|
|
141
|
+
children: "Track Complete!"
|
|
142
|
+
}), /* @__PURE__ */ jsxs("p", {
|
|
143
|
+
className: "text-muted-foreground",
|
|
144
|
+
children: [
|
|
145
|
+
"You've mastered all ",
|
|
146
|
+
totalSteps,
|
|
147
|
+
" challenges and earned",
|
|
148
|
+
" ",
|
|
149
|
+
progress.xpEarned,
|
|
150
|
+
" XP."
|
|
151
|
+
]
|
|
152
|
+
})] })]
|
|
153
|
+
})
|
|
154
|
+
})
|
|
155
|
+
]
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
//#endregion
|
|
160
|
+
export { Overview };
|
|
161
|
+
//# sourceMappingURL=Overview.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Overview.js","names":[],"sources":["../../src/views/Overview.tsx"],"sourcesContent":["'use client';\n\nimport { Button } from '@contractspec/lib.design-system';\nimport {\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n} from '@contractspec/lib.ui-kit-web/ui/card';\nimport {\n XpBar,\n StreakCounter,\n BadgeDisplay,\n} from '@contractspec/example.learning-journey-ui-shared';\nimport type { LearningViewProps } from '@contractspec/example.learning-journey-ui-shared';\n\ninterface GamifiedOverviewProps extends LearningViewProps {\n onStart?: () => void;\n}\n\nexport function Overview({ track, progress, onStart }: GamifiedOverviewProps) {\n const totalXp =\n track.totalXp ??\n track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) +\n (track.completionRewards?.xpBonus ?? 0);\n\n const completedSteps = progress.completedStepIds.length;\n const totalSteps = track.steps.length;\n const isComplete = completedSteps === totalSteps;\n\n return (\n <div className=\"space-y-6\">\n {/* Hero Card */}\n <Card className=\"overflow-hidden bg-gradient-to-br from-violet-500/10 via-purple-500/10 to-fuchsia-500/10\">\n <CardContent className=\"p-6\">\n <div className=\"flex flex-col items-center gap-4 text-center md:flex-row md:text-left\">\n <div 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\">\n {isComplete ? '🏆' : '🎯'}\n </div>\n <div className=\"flex-1\">\n <h1 className=\"text-2xl font-bold\">{track.name}</h1>\n <p className=\"text-muted-foreground mt-1\">{track.description}</p>\n </div>\n <div className=\"flex items-center gap-3\">\n <StreakCounter days={progress.streakDays} size=\"lg\" />\n </div>\n </div>\n </CardContent>\n </Card>\n\n {/* Stats Grid */}\n <div className=\"grid gap-4 md:grid-cols-3\">\n <Card>\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-muted-foreground text-sm font-medium\">\n XP Progress\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"text-3xl font-bold text-violet-500\">\n {progress.xpEarned.toLocaleString()}\n </div>\n <XpBar\n current={progress.xpEarned}\n max={totalXp}\n showLabel={false}\n size=\"sm\"\n />\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-muted-foreground text-sm font-medium\">\n Steps Completed\n </CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"text-3xl font-bold\">\n {completedSteps}{' '}\n <span className=\"text-muted-foreground text-lg\">\n / {totalSteps}\n </span>\n </div>\n <div className=\"bg-muted mt-2 h-2 w-full overflow-hidden rounded-full\">\n <div\n className=\"h-full bg-green-500 transition-all duration-500\"\n style={{ width: `${(completedSteps / totalSteps) * 100}%` }}\n />\n </div>\n </CardContent>\n </Card>\n\n <Card>\n <CardHeader className=\"pb-2\">\n <CardTitle className=\"text-muted-foreground text-sm font-medium\">\n Badges Earned\n </CardTitle>\n </CardHeader>\n <CardContent>\n <BadgeDisplay badges={progress.badges} size=\"lg\" />\n </CardContent>\n </Card>\n </div>\n\n {/* Next Step Preview */}\n {!isComplete && (\n <Card>\n <CardHeader>\n <CardTitle className=\"flex items-center gap-2\">\n <span>🎯</span>\n <span>Next Challenge</span>\n </CardTitle>\n </CardHeader>\n <CardContent>\n {(() => {\n const nextStep = track.steps.find(\n (s) => !progress.completedStepIds.includes(s.id)\n );\n if (!nextStep) return null;\n\n return (\n <div className=\"flex items-center justify-between gap-4\">\n <div>\n <h3 className=\"font-semibold\">{nextStep.title}</h3>\n <p className=\"text-muted-foreground text-sm\">\n {nextStep.description}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n {nextStep.xpReward && (\n <span className=\"rounded-full bg-green-500/10 px-3 py-1 text-sm font-semibold text-green-500\">\n +{nextStep.xpReward} XP\n </span>\n )}\n <Button onClick={onStart}>Start</Button>\n </div>\n </div>\n );\n })()}\n </CardContent>\n </Card>\n )}\n\n {/* Completion Message */}\n {isComplete && (\n <Card className=\"border-green-500/50 bg-green-500/5\">\n <CardContent className=\"flex items-center gap-4 p-6\">\n <div className=\"text-4xl\">🎉</div>\n <div>\n <h3 className=\"text-lg font-semibold text-green-500\">\n Track Complete!\n </h3>\n <p className=\"text-muted-foreground\">\n You've mastered all {totalSteps} challenges and earned{' '}\n {progress.xpEarned} XP.\n </p>\n </div>\n </CardContent>\n </Card>\n )}\n </div>\n );\n}\n"],"mappings":";;;;;;;;AAoBA,SAAgB,SAAS,EAAE,OAAO,UAAU,WAAkC;CAC5E,MAAM,UACJ,MAAM,WACN,MAAM,MAAM,QAAQ,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,EAAE,IACvD,MAAM,mBAAmB,WAAW;CAEzC,MAAM,iBAAiB,SAAS,iBAAiB;CACjD,MAAM,aAAa,MAAM,MAAM;CAC/B,MAAM,aAAa,mBAAmB;AAEtC,QACE,qBAAC;EAAI,WAAU;;GAEb,oBAAC;IAAK,WAAU;cACd,oBAAC;KAAY,WAAU;eACrB,qBAAC;MAAI,WAAU;;OACb,oBAAC;QAAI,WAAU;kBACZ,aAAa,OAAO;SACjB;OACN,qBAAC;QAAI,WAAU;mBACb,oBAAC;SAAG,WAAU;mBAAsB,MAAM;UAAU,EACpD,oBAAC;SAAE,WAAU;mBAA8B,MAAM;UAAgB;SAC7D;OACN,oBAAC;QAAI,WAAU;kBACb,oBAAC;SAAc,MAAM,SAAS;SAAY,MAAK;UAAO;SAClD;;OACF;MACM;KACT;GAGP,qBAAC;IAAI,WAAU;;KACb,qBAAC,mBACC,oBAAC;MAAW,WAAU;gBACpB,oBAAC;OAAU,WAAU;iBAA4C;QAErD;OACD,EACb,qBAAC,0BACC,oBAAC;MAAI,WAAU;gBACZ,SAAS,SAAS,gBAAgB;OAC/B,EACN,oBAAC;MACC,SAAS,SAAS;MAClB,KAAK;MACL,WAAW;MACX,MAAK;OACL,IACU,IACT;KAEP,qBAAC,mBACC,oBAAC;MAAW,WAAU;gBACpB,oBAAC;OAAU,WAAU;iBAA4C;QAErD;OACD,EACb,qBAAC,0BACC,qBAAC;MAAI,WAAU;;OACZ;OAAgB;OACjB,qBAAC;QAAK,WAAU;mBAAgC,MAC3C;SACE;;OACH,EACN,oBAAC;MAAI,WAAU;gBACb,oBAAC;OACC,WAAU;OACV,OAAO,EAAE,OAAO,GAAI,iBAAiB,aAAc,IAAI,IAAI;QAC3D;OACE,IACM,IACT;KAEP,qBAAC,mBACC,oBAAC;MAAW,WAAU;gBACpB,oBAAC;OAAU,WAAU;iBAA4C;QAErD;OACD,EACb,oBAAC,yBACC,oBAAC;MAAa,QAAQ,SAAS;MAAQ,MAAK;OAAO,GACvC,IACT;;KACH;GAGL,CAAC,cACA,qBAAC,mBACC,oBAAC,wBACC,qBAAC;IAAU,WAAU;eACnB,oBAAC,oBAAK,OAAS,EACf,oBAAC,oBAAK,mBAAqB;KACjB,GACD,EACb,oBAAC,gCACS;IACN,MAAM,WAAW,MAAM,MAAM,MAC1B,MAAM,CAAC,SAAS,iBAAiB,SAAS,EAAE,GAAG,CACjD;AACD,QAAI,CAAC,SAAU,QAAO;AAEtB,WACE,qBAAC;KAAI,WAAU;gBACb,qBAAC,oBACC,oBAAC;MAAG,WAAU;gBAAiB,SAAS;OAAW,EACnD,oBAAC;MAAE,WAAU;gBACV,SAAS;OACR,IACA,EACN,qBAAC;MAAI,WAAU;iBACZ,SAAS,YACR,qBAAC;OAAK,WAAU;;QAA8E;QAC1F,SAAS;QAAS;;QACf,EAET,oBAAC;OAAO,SAAS;iBAAS;QAAc;OACpC;MACF;OAEN,GACQ,IACT;GAIR,cACC,oBAAC;IAAK,WAAU;cACd,qBAAC;KAAY,WAAU;gBACrB,oBAAC;MAAI,WAAU;gBAAW;OAAQ,EAClC,qBAAC,oBACC,oBAAC;MAAG,WAAU;gBAAuC;OAEhD,EACL,qBAAC;MAAE,WAAU;;OAAwB;OACd;OAAW;OAAuB;OACtD,SAAS;OAAS;;OACjB,IACA;MACM;KACT;;GAEL"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { LearningViewProps } from "@contractspec/example.learning-journey-ui-shared";
|
|
2
|
+
import * as react_jsx_runtime3 from "react/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
//#region src/views/Progress.d.ts
|
|
5
|
+
declare function Progress({
|
|
6
|
+
track,
|
|
7
|
+
progress
|
|
8
|
+
}: LearningViewProps): react_jsx_runtime3.JSX.Element;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { Progress };
|
|
11
|
+
//# sourceMappingURL=Progress.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Progress.d.ts","names":[],"sources":["../../src/views/Progress.tsx"],"sourcesContent":[],"mappings":";;;;iBAegB,QAAA;;;GAA8B,oBAAiB,kBAAA,CAAA,GAAA,CAAA"}
|