@contractspec/example.learning-journey-ui-shared 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.
Files changed (60) hide show
  1. package/.turbo/turbo-build$colon$bundle.log +48 -0
  2. package/.turbo/turbo-build.log +49 -0
  3. package/CHANGELOG.md +211 -0
  4. package/LICENSE +21 -0
  5. package/README.md +42 -0
  6. package/dist/components/BadgeDisplay.d.ts +12 -0
  7. package/dist/components/BadgeDisplay.d.ts.map +1 -0
  8. package/dist/components/BadgeDisplay.js +45 -0
  9. package/dist/components/BadgeDisplay.js.map +1 -0
  10. package/dist/components/StreakCounter.d.ts +12 -0
  11. package/dist/components/StreakCounter.d.ts.map +1 -0
  12. package/dist/components/StreakCounter.js +46 -0
  13. package/dist/components/StreakCounter.js.map +1 -0
  14. package/dist/components/ViewTabs.d.ts +12 -0
  15. package/dist/components/ViewTabs.d.ts.map +1 -0
  16. package/dist/components/ViewTabs.js +49 -0
  17. package/dist/components/ViewTabs.js.map +1 -0
  18. package/dist/components/XpBar.d.ts +14 -0
  19. package/dist/components/XpBar.d.ts.map +1 -0
  20. package/dist/components/XpBar.js +47 -0
  21. package/dist/components/XpBar.js.map +1 -0
  22. package/dist/components/index.d.ts +5 -0
  23. package/dist/components/index.js +6 -0
  24. package/dist/docs/index.d.ts +1 -0
  25. package/dist/docs/index.js +1 -0
  26. package/dist/docs/learning-journey-ui-shared.docblock.d.ts +1 -0
  27. package/dist/docs/learning-journey-ui-shared.docblock.js +20 -0
  28. package/dist/docs/learning-journey-ui-shared.docblock.js.map +1 -0
  29. package/dist/example.d.ts +33 -0
  30. package/dist/example.d.ts.map +1 -0
  31. package/dist/example.js +35 -0
  32. package/dist/example.js.map +1 -0
  33. package/dist/hooks/index.d.ts +2 -0
  34. package/dist/hooks/index.js +3 -0
  35. package/dist/hooks/useLearningProgress.d.ts +22 -0
  36. package/dist/hooks/useLearningProgress.d.ts.map +1 -0
  37. package/dist/hooks/useLearningProgress.js +74 -0
  38. package/dist/hooks/useLearningProgress.js.map +1 -0
  39. package/dist/index.d.ts +9 -0
  40. package/dist/index.js +11 -0
  41. package/dist/types.d.ts +58 -0
  42. package/dist/types.d.ts.map +1 -0
  43. package/dist/types.js +0 -0
  44. package/example.ts +1 -0
  45. package/package.json +75 -0
  46. package/src/components/BadgeDisplay.tsx +65 -0
  47. package/src/components/StreakCounter.tsx +49 -0
  48. package/src/components/ViewTabs.tsx +46 -0
  49. package/src/components/XpBar.tsx +54 -0
  50. package/src/components/index.ts +4 -0
  51. package/src/docs/index.ts +1 -0
  52. package/src/docs/learning-journey-ui-shared.docblock.ts +17 -0
  53. package/src/example.ts +23 -0
  54. package/src/hooks/index.ts +1 -0
  55. package/src/hooks/useLearningProgress.ts +101 -0
  56. package/src/index.ts +20 -0
  57. package/src/types.ts +61 -0
  58. package/tsconfig.json +9 -0
  59. package/tsconfig.tsbuildinfo +1 -0
  60. package/tsdown.config.js +17 -0
@@ -0,0 +1,17 @@
1
+ import type { DocBlock } from '@contractspec/lib.contracts/docs';
2
+ import { registerDocBlocks } from '@contractspec/lib.contracts/docs';
3
+
4
+ const blocks: DocBlock[] = [
5
+ {
6
+ id: 'docs.examples.learning-journey-ui-shared',
7
+ title: 'Learning Journey UI — Shared',
8
+ summary: 'Shared UI components and hooks for learning journey mini-apps.',
9
+ kind: 'reference',
10
+ visibility: 'public',
11
+ route: '/docs/examples/learning-journey-ui-shared',
12
+ tags: ['learning', 'ui', 'shared'],
13
+ body: `## Includes\n- Hooks: useLearningProgress\n- Components: XpBar, StreakCounter, BadgeDisplay, ViewTabs\n\n## Notes\n- Keep components accessible (labels, focus, contrast).\n- Prefer design-system tokens and components.`,
14
+ },
15
+ ];
16
+
17
+ registerDocBlocks(blocks);
package/src/example.ts ADDED
@@ -0,0 +1,23 @@
1
+ const example = {
2
+ id: 'learning-journey-ui-shared',
3
+ title: 'Learning Journey UI — Shared',
4
+ summary: 'Shared UI components and hooks for learning journey mini-apps.',
5
+ tags: ['learning', 'ui', 'shared'],
6
+ kind: 'ui',
7
+ visibility: 'public',
8
+ docs: {
9
+ rootDocId: 'docs.examples.learning-journey-ui-shared',
10
+ },
11
+ entrypoints: {
12
+ packageName: '@contractspec/example.learning-journey-ui-shared',
13
+ docs: './docs',
14
+ },
15
+ surfaces: {
16
+ templates: true,
17
+ sandbox: { enabled: true, modes: ['playground', 'markdown'] },
18
+ studio: { enabled: true, installable: true },
19
+ mcp: { enabled: true },
20
+ },
21
+ } as const;
22
+
23
+ export default example;
@@ -0,0 +1 @@
1
+ export { useLearningProgress } from './useLearningProgress';
@@ -0,0 +1,101 @@
1
+ 'use client';
2
+
3
+ import { useState, useCallback, useMemo } from 'react';
4
+ import type { LearningJourneyTrackSpec } from '@contractspec/module.learning-journey/track-spec';
5
+ import type { LearningProgressState } from '../types';
6
+
7
+ /** Default progress state for a new track */
8
+ function createDefaultProgress(trackId: string): LearningProgressState {
9
+ return {
10
+ trackId,
11
+ completedStepIds: [],
12
+ currentStepId: null,
13
+ xpEarned: 0,
14
+ streakDays: 0,
15
+ lastActivityDate: null,
16
+ badges: [],
17
+ };
18
+ }
19
+
20
+ /** Hook for managing learning progress state */
21
+ export function useLearningProgress(track: LearningJourneyTrackSpec) {
22
+ const [progress, setProgress] = useState<LearningProgressState>(() =>
23
+ createDefaultProgress(track.id)
24
+ );
25
+
26
+ const completeStep = useCallback(
27
+ (stepId: string) => {
28
+ const step = track.steps.find((s) => s.id === stepId);
29
+ if (!step || progress.completedStepIds.includes(stepId)) return;
30
+
31
+ setProgress((prev) => {
32
+ const newCompletedIds = [...prev.completedStepIds, stepId];
33
+ const xpReward = step.xpReward ?? 0;
34
+
35
+ // Find next incomplete step
36
+ const nextStep = track.steps.find(
37
+ (s) => !newCompletedIds.includes(s.id)
38
+ );
39
+
40
+ // Check if track is complete
41
+ const isTrackComplete = newCompletedIds.length === track.steps.length;
42
+ const completionBonus = isTrackComplete
43
+ ? (track.completionRewards?.xpBonus ?? 0)
44
+ : 0;
45
+
46
+ return {
47
+ ...prev,
48
+ completedStepIds: newCompletedIds,
49
+ currentStepId: nextStep?.id ?? null,
50
+ xpEarned: prev.xpEarned + xpReward + completionBonus,
51
+ lastActivityDate: new Date().toISOString(),
52
+ badges:
53
+ isTrackComplete && track.completionRewards?.badgeKey
54
+ ? [...prev.badges, track.completionRewards.badgeKey]
55
+ : prev.badges,
56
+ };
57
+ });
58
+ },
59
+ [track, progress.completedStepIds]
60
+ );
61
+
62
+ const resetProgress = useCallback(() => {
63
+ setProgress(createDefaultProgress(track.id));
64
+ }, [track.id]);
65
+
66
+ const incrementStreak = useCallback(() => {
67
+ setProgress((prev) => ({
68
+ ...prev,
69
+ streakDays: prev.streakDays + 1,
70
+ lastActivityDate: new Date().toISOString(),
71
+ }));
72
+ }, []);
73
+
74
+ const stats = useMemo(() => {
75
+ const totalSteps = track.steps.length;
76
+ const completedSteps = progress.completedStepIds.length;
77
+ const percentComplete =
78
+ totalSteps > 0 ? Math.round((completedSteps / totalSteps) * 100) : 0;
79
+ const totalXp =
80
+ track.totalXp ??
81
+ track.steps.reduce((sum, s) => sum + (s.xpReward ?? 0), 0) +
82
+ (track.completionRewards?.xpBonus ?? 0);
83
+
84
+ return {
85
+ totalSteps,
86
+ completedSteps,
87
+ remainingSteps: totalSteps - completedSteps,
88
+ percentComplete,
89
+ totalXp,
90
+ isComplete: completedSteps === totalSteps,
91
+ };
92
+ }, [track, progress.completedStepIds]);
93
+
94
+ return {
95
+ progress,
96
+ stats,
97
+ completeStep,
98
+ resetProgress,
99
+ incrementStreak,
100
+ };
101
+ }
package/src/index.ts ADDED
@@ -0,0 +1,20 @@
1
+ // Hooks
2
+ export { useLearningProgress } from './hooks';
3
+
4
+ // Components
5
+ export { XpBar, StreakCounter, BadgeDisplay, ViewTabs } from './components';
6
+
7
+ // Types
8
+ export type {
9
+ LearningView,
10
+ LearningProgressState,
11
+ LearningMiniAppProps,
12
+ LearningViewProps,
13
+ XpBarProps,
14
+ StreakCounterProps,
15
+ BadgeDisplayProps,
16
+ ViewTabsProps,
17
+ } from './types';
18
+
19
+ export { default as example } from './example';
20
+ import './docs';
package/src/types.ts ADDED
@@ -0,0 +1,61 @@
1
+ import type { LearningJourneyTrackSpec } from '@contractspec/module.learning-journey/track-spec';
2
+
3
+ /** View types for learning mini-apps */
4
+ export type LearningView = 'overview' | 'steps' | 'progress' | 'timeline';
5
+
6
+ /** Progress state for a learning track */
7
+ export interface LearningProgressState {
8
+ trackId: string;
9
+ completedStepIds: string[];
10
+ currentStepId: string | null;
11
+ xpEarned: number;
12
+ streakDays: number;
13
+ lastActivityDate: string | null;
14
+ badges: string[];
15
+ }
16
+
17
+ /** Props for mini-app components */
18
+ export interface LearningMiniAppProps {
19
+ track: LearningJourneyTrackSpec;
20
+ progress: LearningProgressState;
21
+ onStepComplete?: (stepId: string) => void;
22
+ onViewChange?: (view: LearningView) => void;
23
+ initialView?: LearningView;
24
+ }
25
+
26
+ /** Props for view components */
27
+ export interface LearningViewProps {
28
+ track: LearningJourneyTrackSpec;
29
+ progress: LearningProgressState;
30
+ onStepComplete?: (stepId: string) => void;
31
+ }
32
+
33
+ /** XP bar props */
34
+ export interface XpBarProps {
35
+ current: number;
36
+ max: number;
37
+ level?: number;
38
+ showLabel?: boolean;
39
+ size?: 'sm' | 'md' | 'lg';
40
+ }
41
+
42
+ /** Streak counter props */
43
+ export interface StreakCounterProps {
44
+ days: number;
45
+ isActive?: boolean;
46
+ size?: 'sm' | 'md' | 'lg';
47
+ }
48
+
49
+ /** Badge display props */
50
+ export interface BadgeDisplayProps {
51
+ badges: string[];
52
+ maxVisible?: number;
53
+ size?: 'sm' | 'md' | 'lg';
54
+ }
55
+
56
+ /** View tabs props */
57
+ export interface ViewTabsProps {
58
+ currentView: LearningView;
59
+ onViewChange: (view: LearningView) => void;
60
+ availableViews?: LearningView[];
61
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
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
+ }