@hydralms/components 0.2.0 → 0.3.1
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/dist/StudentProfile-BPsZBaJj.cjs +1 -0
- package/dist/StudentProfile-Cw2p-RZn.js +3273 -0
- package/dist/assessment-toolbar/question-navigator.d.ts +1 -1
- package/dist/assessment-toolbar/timer-display.d.ts +1 -1
- package/dist/common/index.d.ts +2 -1
- package/dist/common/pagination.d.ts +26 -0
- package/dist/common/types.d.ts +1 -0
- package/dist/components.css +1 -1
- package/dist/content/audio-player.d.ts +22 -0
- package/dist/content/code-block.d.ts +30 -0
- package/dist/content/embed-block.d.ts +28 -0
- package/dist/content/index.d.ts +6 -0
- package/dist/content/types.d.ts +24 -0
- package/dist/curriculum/course-card.d.ts +51 -0
- package/dist/curriculum/index.d.ts +2 -0
- package/dist/curriculum/types.d.ts +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +495 -439
- package/dist/license/HydraContext.d.ts +16 -0
- package/dist/license/ProBadge.d.ts +6 -0
- package/dist/license/index.d.ts +7 -0
- package/dist/license/tiers.d.ts +6 -0
- package/dist/license/useHydraLicense.d.ts +6 -0
- package/dist/license/validate.d.ts +13 -0
- package/dist/license/withProGate.d.ts +6 -0
- package/dist/modules/AssignmentModule/AssignmentModule.d.ts +4 -7
- package/dist/modules/AssignmentModule/types.d.ts +5 -1
- package/dist/modules/CertificateModule/CertificateModule.d.ts +4 -8
- package/dist/modules/CertificateModule/types.d.ts +6 -4
- package/dist/modules/CourseCatalogModule/CourseCatalogModule.d.ts +5 -0
- package/dist/modules/CourseCatalogModule/types.d.ts +43 -0
- package/dist/modules/CoursePlayer/CoursePlayer.d.ts +4 -1
- package/dist/modules/DiscussionModule/DiscussionModule.d.ts +4 -7
- package/dist/modules/ExamModule/ExamModule.d.ts +4 -7
- package/dist/modules/ExamModule/types.d.ts +5 -14
- package/dist/modules/FlashcardLab/FlashcardLab.d.ts +4 -1
- package/dist/modules/FlashcardLab/types.d.ts +2 -0
- package/dist/modules/GradeCenterModule/GradeCenterModule.d.ts +4 -8
- package/dist/modules/GradeCenterModule/types.d.ts +2 -0
- package/dist/modules/QuizModule/QuizModule.d.ts +4 -1
- package/dist/modules/QuizModule/types.d.ts +5 -14
- package/dist/modules/StudentDashboardModule/StudentDashboardModule.d.ts +5 -0
- package/dist/modules/StudentDashboardModule/types.d.ts +54 -0
- package/dist/modules/StudentProfileModule/StudentProfileModule.d.ts +5 -0
- package/dist/modules/StudentProfileModule/types.d.ts +43 -0
- package/dist/modules/SurveyModule/SurveyModule.d.ts +4 -6
- package/dist/modules/SurveyModule/types.d.ts +2 -0
- package/dist/modules/_shared/assessment-intro.d.ts +16 -0
- package/dist/modules/_shared/assessment-results.d.ts +23 -0
- package/dist/modules/_shared/types.d.ts +10 -0
- package/dist/modules/_shared/use-timer.d.ts +9 -0
- package/dist/modules/index.d.ts +6 -0
- package/dist/modules.cjs +1 -1
- package/dist/modules.js +1267 -854
- package/dist/progress/types.d.ts +2 -0
- package/dist/provider/HydraProvider.d.ts +5 -1
- package/dist/questions/choice.d.ts +1 -1
- package/dist/questions/confidence-indicator.d.ts +37 -0
- package/dist/questions/essay.d.ts +1 -1
- package/dist/questions/fill-in-the-blank.d.ts +1 -1
- package/dist/questions/hotspot.d.ts +1 -1
- package/dist/questions/index.d.ts +2 -0
- package/dist/questions/inline-choice.d.ts +1 -1
- package/dist/questions/matching.d.ts +1 -1
- package/dist/questions/multiple-choice.d.ts +1 -1
- package/dist/questions/numeric.d.ts +1 -1
- package/dist/questions/ordering.d.ts +1 -1
- package/dist/questions/question-renderer.d.ts +1 -1
- package/dist/questions/scenario.d.ts +1 -1
- package/dist/questions/spreadsheet.d.ts +1 -1
- package/dist/questions/true-false.d.ts +1 -1
- package/dist/sections/AdaptiveLearningPath/AdaptiveLearningPath.d.ts +5 -0
- package/dist/sections/AdaptiveLearningPath/path-connector.d.ts +8 -0
- package/dist/sections/AdaptiveLearningPath/path-milestone-marker.d.ts +7 -0
- package/dist/sections/AdaptiveLearningPath/path-node-card.d.ts +10 -0
- package/dist/sections/AdaptiveLearningPath/path-skill-bar.d.ts +8 -0
- package/dist/sections/AdaptiveLearningPath/types.d.ts +136 -0
- package/dist/sections/AnnouncementFeed/AnnouncementFeed.d.ts +1 -1
- package/dist/sections/AnnouncementFeed/types.d.ts +15 -1
- package/dist/sections/AssessmentReview/AssessmentReview.d.ts +1 -1
- package/dist/sections/AssessmentReview/types.d.ts +6 -0
- package/dist/sections/AssignmentSubmission/AssignmentSubmission.d.ts +1 -1
- package/dist/sections/AssignmentSubmission/types.d.ts +6 -0
- package/dist/sections/CertificateViewer/CertificateViewer.d.ts +1 -1
- package/dist/sections/CertificateViewer/certificate-variants.d.ts +42 -0
- package/dist/sections/CertificateViewer/types.d.ts +6 -0
- package/dist/sections/ContentAuthoringStudio/ContentAuthoringStudio.d.ts +5 -0
- package/dist/sections/ContentAuthoringStudio/block-editor-item.d.ts +14 -0
- package/dist/sections/ContentAuthoringStudio/block-type-picker.d.ts +12 -0
- package/dist/sections/ContentAuthoringStudio/types.d.ts +67 -0
- package/dist/sections/CourseCatalog/CourseCatalog.d.ts +2 -0
- package/dist/sections/CourseCatalog/types.d.ts +80 -0
- package/dist/sections/CourseOutline/CourseOutline.d.ts +1 -1
- package/dist/sections/CourseOutline/types.d.ts +6 -0
- package/dist/sections/DiscussionThread/DiscussionThread.d.ts +1 -1
- package/dist/sections/DiscussionThread/types.d.ts +6 -0
- package/dist/sections/EnrollmentWizard/EnrollmentWizard.d.ts +2 -0
- package/dist/sections/EnrollmentWizard/types.d.ts +66 -0
- package/dist/sections/ExamSession/ExamSession.d.ts +1 -1
- package/dist/sections/ExamSession/types.d.ts +6 -0
- package/dist/sections/FlashcardStudySession/FlashcardStudySession.d.ts +1 -1
- package/dist/sections/FlashcardStudySession/types.d.ts +6 -0
- package/dist/sections/ForumBoard/ForumBoard.d.ts +1 -1
- package/dist/sections/ForumBoard/types.d.ts +14 -0
- package/dist/sections/GradebookTable/GradebookTable.d.ts +1 -1
- package/dist/sections/GradebookTable/types.d.ts +14 -0
- package/dist/sections/LecturePlayer/LecturePlayer.d.ts +1 -1
- package/dist/sections/LecturePlayer/types.d.ts +8 -0
- package/dist/sections/LessonPage/LessonPage.d.ts +1 -1
- package/dist/sections/LessonPage/types.d.ts +6 -0
- package/dist/sections/PracticeQuiz/PracticeQuiz.d.ts +1 -1
- package/dist/sections/PracticeQuiz/types.d.ts +6 -0
- package/dist/sections/ProgressDashboard/ProgressDashboard.d.ts +1 -1
- package/dist/sections/ProgressDashboard/types.d.ts +6 -0
- package/dist/sections/QuizSession/QuizSession.d.ts +1 -1
- package/dist/sections/QuizSession/types.d.ts +6 -0
- package/dist/sections/RequirementsChecklist/RequirementsChecklist.d.ts +1 -1
- package/dist/sections/RequirementsChecklist/types.d.ts +6 -0
- package/dist/sections/ResourceLibrary/ResourceLibrary.d.ts +1 -1
- package/dist/sections/ResourceLibrary/types.d.ts +15 -1
- package/dist/sections/RubricView/RubricView.d.ts +1 -1
- package/dist/sections/RubricView/types.d.ts +6 -0
- package/dist/sections/ScrollableQuiz/ScrollableQuiz.d.ts +1 -1
- package/dist/sections/ScrollableQuiz/types.d.ts +6 -0
- package/dist/sections/StudentProfile/StudentProfile.d.ts +2 -0
- package/dist/sections/StudentProfile/types.d.ts +98 -0
- package/dist/sections/SurveyForm/SurveyForm.d.ts +1 -1
- package/dist/sections/SurveyForm/types.d.ts +6 -0
- package/dist/sections/_shared/merge-answers.d.ts +9 -0
- package/dist/sections/_shared/section-shell.d.ts +20 -0
- package/dist/sections/_shared/use-assessment-session.d.ts +30 -0
- package/dist/sections/index.d.ts +10 -0
- package/dist/sections.cjs +1 -1
- package/dist/sections.js +1361 -307
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/index.d.ts +2 -0
- package/dist/ui/progress.d.ts +1 -1
- package/dist/ui/rich-text-editor.d.ts +3 -1
- package/dist/ui/toast.d.ts +43 -0
- package/dist/utils/debounce.d.ts +5 -1
- package/dist/utils/pick-palette-color.d.ts +19 -0
- package/dist/video/types.d.ts +15 -0
- package/dist/video/video-player.d.ts +1 -1
- package/dist/withProGate-BJdu1T9Y.cjs +2 -0
- package/dist/withProGate-BvFc7Jwy.js +4975 -0
- package/package.json +57 -226
- package/src/assessment-toolbar/question-navigator.tsx +10 -5
- package/src/assessment-toolbar/timer-display.tsx +4 -3
- package/src/assessment-toolbar/use-countdown.ts +1 -1
- package/src/common/empty-state.tsx +1 -0
- package/src/common/index.ts +2 -0
- package/src/common/pagination.tsx +135 -0
- package/src/common/search-input.tsx +2 -1
- package/src/common/types.ts +2 -0
- package/src/content/attachment-list.tsx +2 -0
- package/src/content/audio-player.tsx +196 -0
- package/src/content/code-block.tsx +113 -0
- package/src/content/content-block.tsx +64 -0
- package/src/content/embed-block.tsx +78 -0
- package/src/content/file-upload-zone.tsx +10 -0
- package/src/content/index.ts +6 -0
- package/src/content/types.ts +5 -0
- package/src/curriculum/course-card.tsx +199 -0
- package/src/curriculum/curriculum-item.tsx +3 -3
- package/src/curriculum/curriculum-tree.tsx +20 -13
- package/src/curriculum/index.ts +2 -0
- package/src/curriculum/types.ts +2 -2
- package/src/flashcards/flashcard.tsx +28 -8
- package/src/index.ts +3 -0
- package/src/license/HydraContext.tsx +62 -0
- package/src/license/ProBadge.tsx +43 -0
- package/src/license/index.ts +7 -0
- package/src/license/tiers.ts +34 -0
- package/src/license/useHydraLicense.ts +10 -0
- package/src/license/validate.ts +90 -0
- package/src/license/withProGate.tsx +21 -0
- package/src/modules/AssignmentModule/AssignmentModule.tsx +17 -8
- package/src/modules/AssignmentModule/types.ts +5 -1
- package/src/modules/CertificateModule/CertificateModule.tsx +21 -9
- package/src/modules/CertificateModule/types.ts +6 -4
- package/src/modules/CourseCatalogModule/CourseCatalogModule.tsx +126 -0
- package/src/modules/CourseCatalogModule/types.ts +47 -0
- package/src/modules/CoursePlayer/CoursePlayer.tsx +39 -22
- package/src/modules/DiscussionModule/DiscussionModule.tsx +57 -22
- package/src/modules/ExamModule/ExamModule.tsx +64 -198
- package/src/modules/ExamModule/types.ts +5 -14
- package/src/modules/FlashcardLab/FlashcardLab.tsx +10 -5
- package/src/modules/FlashcardLab/types.ts +2 -0
- package/src/modules/GradeCenterModule/GradeCenterModule.tsx +7 -2
- package/src/modules/GradeCenterModule/types.ts +2 -0
- package/src/modules/QuizModule/QuizModule.tsx +49 -169
- package/src/modules/QuizModule/types.ts +5 -15
- package/src/modules/StudentDashboardModule/StudentDashboardModule.tsx +117 -0
- package/src/modules/StudentDashboardModule/types.ts +56 -0
- package/src/modules/StudentProfileModule/StudentProfileModule.tsx +289 -0
- package/src/modules/StudentProfileModule/types.ts +45 -0
- package/src/modules/SurveyModule/SurveyModule.tsx +9 -4
- package/src/modules/SurveyModule/types.ts +2 -0
- package/src/modules/_shared/assessment-intro.tsx +75 -0
- package/src/modules/_shared/assessment-results.tsx +133 -0
- package/src/modules/_shared/types.ts +11 -0
- package/src/modules/_shared/use-timer.ts +49 -0
- package/src/modules/index.ts +9 -0
- package/src/progress/achievement-badge.tsx +3 -3
- package/src/progress/grade-indicator.tsx +9 -1
- package/src/progress/progress-ring.tsx +2 -1
- package/src/progress/stat-card.tsx +14 -2
- package/src/progress/types.ts +2 -0
- package/src/provider/HydraProvider.tsx +15 -6
- package/src/questions/choice.tsx +13 -6
- package/src/questions/confidence-indicator.tsx +107 -0
- package/src/questions/essay.tsx +6 -4
- package/src/questions/fill-in-the-blank.tsx +8 -4
- package/src/questions/hotspot.tsx +4 -4
- package/src/questions/index.ts +2 -0
- package/src/questions/inline-choice.tsx +5 -4
- package/src/questions/matching.tsx +5 -4
- package/src/questions/multiple-choice.tsx +13 -6
- package/src/questions/numeric.tsx +8 -4
- package/src/questions/ordering.tsx +12 -4
- package/src/questions/question-renderer.tsx +3 -2
- package/src/questions/scenario.tsx +4 -4
- package/src/questions/spreadsheet.tsx +5 -4
- package/src/questions/true-false.tsx +13 -6
- package/src/sections/AdaptiveLearningPath/AdaptiveLearningPath.tsx +251 -0
- package/src/sections/AdaptiveLearningPath/path-connector.tsx +27 -0
- package/src/sections/AdaptiveLearningPath/path-milestone-marker.tsx +50 -0
- package/src/sections/AdaptiveLearningPath/path-node-card.tsx +166 -0
- package/src/sections/AdaptiveLearningPath/path-skill-bar.tsx +49 -0
- package/src/sections/AdaptiveLearningPath/types.ts +159 -0
- package/src/sections/AnnouncementFeed/AnnouncementFeed.tsx +64 -8
- package/src/sections/AnnouncementFeed/types.ts +15 -1
- package/src/sections/AssessmentReview/AssessmentReview.tsx +37 -0
- package/src/sections/AssessmentReview/types.ts +6 -0
- package/src/sections/AssignmentSubmission/AssignmentSubmission.tsx +37 -1
- package/src/sections/AssignmentSubmission/types.ts +6 -0
- package/src/sections/CertificateViewer/CertificateViewer.tsx +29 -227
- package/src/sections/CertificateViewer/certificate-variants.tsx +170 -0
- package/src/sections/CertificateViewer/types.ts +6 -0
- package/src/sections/ContentAuthoringStudio/ContentAuthoringStudio.tsx +289 -0
- package/src/sections/ContentAuthoringStudio/block-editor-item.tsx +487 -0
- package/src/sections/ContentAuthoringStudio/block-type-picker.tsx +123 -0
- package/src/sections/ContentAuthoringStudio/types.ts +67 -0
- package/src/sections/CourseCatalog/CourseCatalog.tsx +220 -0
- package/src/sections/CourseCatalog/types.ts +76 -0
- package/src/sections/CourseOutline/CourseOutline.tsx +41 -0
- package/src/sections/CourseOutline/types.ts +6 -0
- package/src/sections/DiscussionThread/DiscussionThread.tsx +42 -1
- package/src/sections/DiscussionThread/types.ts +6 -0
- package/src/sections/EnrollmentWizard/EnrollmentWizard.tsx +343 -0
- package/src/sections/EnrollmentWizard/types.ts +65 -0
- package/src/sections/ExamSession/ExamSession.tsx +100 -94
- package/src/sections/ExamSession/types.ts +6 -0
- package/src/sections/FlashcardStudySession/FlashcardStudySession.tsx +53 -36
- package/src/sections/FlashcardStudySession/types.ts +6 -0
- package/src/sections/ForumBoard/ForumBoard.tsx +67 -7
- package/src/sections/ForumBoard/types.ts +14 -0
- package/src/sections/GradebookTable/GradebookTable.tsx +54 -1
- package/src/sections/GradebookTable/types.ts +14 -0
- package/src/sections/LecturePlayer/LecturePlayer.tsx +63 -37
- package/src/sections/LecturePlayer/types.ts +8 -0
- package/src/sections/LessonPage/LessonPage.tsx +34 -6
- package/src/sections/LessonPage/types.ts +6 -0
- package/src/sections/PracticeQuiz/PracticeQuiz.tsx +106 -74
- package/src/sections/PracticeQuiz/types.ts +6 -0
- package/src/sections/ProgressDashboard/ProgressDashboard.tsx +64 -10
- package/src/sections/ProgressDashboard/types.ts +6 -0
- package/src/sections/QuizSession/QuizSession.tsx +71 -82
- package/src/sections/QuizSession/types.ts +6 -0
- package/src/sections/RequirementsChecklist/RequirementsChecklist.tsx +41 -1
- package/src/sections/RequirementsChecklist/types.ts +6 -0
- package/src/sections/ResourceLibrary/ResourceLibrary.tsx +64 -8
- package/src/sections/ResourceLibrary/types.ts +15 -1
- package/src/sections/RubricView/RubricView.tsx +37 -1
- package/src/sections/RubricView/types.ts +6 -0
- package/src/sections/ScrollableQuiz/ScrollableQuiz.tsx +36 -15
- package/src/sections/ScrollableQuiz/types.ts +6 -0
- package/src/sections/StudentProfile/StudentProfile.tsx +279 -0
- package/src/sections/StudentProfile/types.ts +99 -0
- package/src/sections/SurveyForm/SurveyForm.tsx +32 -5
- package/src/sections/SurveyForm/types.ts +6 -0
- package/src/sections/_shared/merge-answers.ts +22 -0
- package/src/sections/_shared/section-shell.tsx +64 -0
- package/src/sections/_shared/use-assessment-session.ts +125 -0
- package/src/sections/index.ts +40 -0
- package/src/social/user-avatar.tsx +9 -5
- package/src/styles/globals.css +39 -41
- package/src/ui/badge.tsx +8 -0
- package/src/ui/index.ts +2 -0
- package/src/ui/progress.tsx +4 -0
- package/src/ui/rich-text-editor.tsx +10 -0
- package/src/ui/rich-text-toolbar.tsx +2 -1
- package/src/ui/toast.tsx +170 -0
- package/src/utils/debounce.ts +8 -2
- package/src/utils/pick-palette-color.ts +33 -0
- package/src/video/types.ts +16 -0
- package/src/video/video-player.tsx +27 -6
- package/dist/ForumBoard-CHXU3mjC.js +0 -2207
- package/dist/ForumBoard-d1w5-r6n.cjs +0 -1
- package/dist/tabs-DRM2Iq_J.cjs +0 -172
- package/dist/tabs-Wf3h_Cx3.js +0 -21580
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import type { ReactNode } from "react";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Status of a single node in the learning path.
|
|
5
|
+
* - `locked` — prerequisites not met, node is inaccessible
|
|
6
|
+
* - `available` — prerequisites met, learner can start
|
|
7
|
+
* - `in_progress` — learner is currently working on this node
|
|
8
|
+
* - `completed` — learner finished but below mastery threshold
|
|
9
|
+
* - `mastered` — learner finished and reached the mastery threshold
|
|
10
|
+
* - `skipped` — node was bypassed by the adaptive engine
|
|
11
|
+
*/
|
|
12
|
+
export type PathNodeStatus =
|
|
13
|
+
| "locked"
|
|
14
|
+
| "available"
|
|
15
|
+
| "in_progress"
|
|
16
|
+
| "completed"
|
|
17
|
+
| "mastered"
|
|
18
|
+
| "skipped";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The type of learning activity a path node represents.
|
|
22
|
+
* Aligns with LearningObjectIcon type strings.
|
|
23
|
+
*/
|
|
24
|
+
export type PathNodeType =
|
|
25
|
+
| "lesson"
|
|
26
|
+
| "quiz"
|
|
27
|
+
| "assignment"
|
|
28
|
+
| "video"
|
|
29
|
+
| "discussion"
|
|
30
|
+
| "document"
|
|
31
|
+
| "assessment"
|
|
32
|
+
| "audio"
|
|
33
|
+
| "link";
|
|
34
|
+
|
|
35
|
+
/** A skill or competency area that the learning path develops. */
|
|
36
|
+
export interface PathSkill {
|
|
37
|
+
uid: string;
|
|
38
|
+
name: string;
|
|
39
|
+
/** Current proficiency level 0–100 */
|
|
40
|
+
proficiency: number;
|
|
41
|
+
/** Target proficiency level 0–100 */
|
|
42
|
+
targetProficiency?: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** A milestone marker along the learning path. */
|
|
46
|
+
export interface PathMilestone {
|
|
47
|
+
uid: string;
|
|
48
|
+
title: string;
|
|
49
|
+
description?: string;
|
|
50
|
+
/** Whether the milestone has been reached */
|
|
51
|
+
reached: boolean;
|
|
52
|
+
/** Index of the node after which this milestone appears (zero-based) */
|
|
53
|
+
afterNodeIndex: number;
|
|
54
|
+
variant?: "default" | "gold" | "silver" | "bronze";
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** A single node in the adaptive learning path. */
|
|
58
|
+
export interface PathNode {
|
|
59
|
+
uid: string;
|
|
60
|
+
title: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
/** Learning activity type — used for icon selection via LearningObjectIcon */
|
|
63
|
+
type: PathNodeType;
|
|
64
|
+
status: PathNodeStatus;
|
|
65
|
+
/** Estimated duration in seconds */
|
|
66
|
+
estimatedDuration?: number;
|
|
67
|
+
/** Performance score if completed (0–100) */
|
|
68
|
+
score?: number;
|
|
69
|
+
/** Whether this node is recommended as the next step */
|
|
70
|
+
recommended?: boolean;
|
|
71
|
+
/** Skill UIDs that this node develops */
|
|
72
|
+
skillUids?: string[];
|
|
73
|
+
/** UIDs of prerequisite nodes */
|
|
74
|
+
prerequisites?: string[];
|
|
75
|
+
/** Optional custom icon (overrides type-based icon) */
|
|
76
|
+
icon?: ReactNode;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** A branch point where the adaptive engine may redirect the learner. */
|
|
80
|
+
export interface PathBranch {
|
|
81
|
+
uid: string;
|
|
82
|
+
/** UID of the node where the branch originates */
|
|
83
|
+
fromNodeUid: string;
|
|
84
|
+
/** Label for this branch (e.g., "Review Fundamentals") */
|
|
85
|
+
label: string;
|
|
86
|
+
/** UIDs of nodes in this branch path */
|
|
87
|
+
nodeUids: string[];
|
|
88
|
+
/** Whether this branch is the active/chosen branch */
|
|
89
|
+
active?: boolean;
|
|
90
|
+
/** Condition description (e.g., "Score below 70%") */
|
|
91
|
+
condition?: string;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Overall progress summary for the path. */
|
|
95
|
+
export interface PathProgress {
|
|
96
|
+
/** Percentage of path completed (0–100) */
|
|
97
|
+
completionPercentage: number;
|
|
98
|
+
completedNodes: number;
|
|
99
|
+
totalNodes: number;
|
|
100
|
+
/** Total time spent in seconds */
|
|
101
|
+
totalTimeSpent: number;
|
|
102
|
+
/** Average score across completed nodes (0–100) */
|
|
103
|
+
averageScore?: number;
|
|
104
|
+
/** Current streak in days */
|
|
105
|
+
currentStreak?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* AdaptiveLearningPath section — a premium visualization of a personalized
|
|
110
|
+
* learning sequence that adapts based on learner performance.
|
|
111
|
+
*
|
|
112
|
+
* Shows a visual path map with nodes, connectors, milestones, skill bars,
|
|
113
|
+
* and summary stats. Each node represents a learning activity with status,
|
|
114
|
+
* score, and recommended-next indicators.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* <AdaptiveLearningPath
|
|
118
|
+
* title="React Mastery Path"
|
|
119
|
+
* description="A personalized journey for mastering React"
|
|
120
|
+
* nodes={pathNodes}
|
|
121
|
+
* progress={pathProgress}
|
|
122
|
+
* onNodeClick={(uid) => navigate(`/activity/${uid}`)}
|
|
123
|
+
* onNodeStart={(uid) => startActivity(uid)}
|
|
124
|
+
* />
|
|
125
|
+
*/
|
|
126
|
+
export interface AdaptiveLearningPathProps {
|
|
127
|
+
/** Path title */
|
|
128
|
+
title: string;
|
|
129
|
+
/** Optional path description */
|
|
130
|
+
description?: string;
|
|
131
|
+
/** Difficulty level displayed in the header */
|
|
132
|
+
difficulty?: "beginner" | "intermediate" | "advanced";
|
|
133
|
+
/** Ordered list of learning path nodes */
|
|
134
|
+
nodes: PathNode[];
|
|
135
|
+
/** Overall path progress data */
|
|
136
|
+
progress: PathProgress;
|
|
137
|
+
/** Skill/competency areas covered by this path */
|
|
138
|
+
skills?: PathSkill[];
|
|
139
|
+
/** Milestones along the path */
|
|
140
|
+
milestones?: PathMilestone[];
|
|
141
|
+
/** Branch points for adaptive routing */
|
|
142
|
+
branches?: PathBranch[];
|
|
143
|
+
/** Called when the user clicks a node */
|
|
144
|
+
onNodeClick?: (nodeUid: string) => void;
|
|
145
|
+
/** Called when the user starts a recommended or available activity */
|
|
146
|
+
onNodeStart?: (nodeUid: string) => void;
|
|
147
|
+
/** Called when the user clicks a skill */
|
|
148
|
+
onSkillClick?: (skillUid: string) => void;
|
|
149
|
+
/** When true, disables all interactive elements. @default false */
|
|
150
|
+
readOnly?: boolean;
|
|
151
|
+
/** Render skeleton placeholders instead of content */
|
|
152
|
+
isLoading?: boolean;
|
|
153
|
+
/** Error message — renders an error state with optional retry */
|
|
154
|
+
error?: string | null;
|
|
155
|
+
/** Called when the user clicks retry in the error state */
|
|
156
|
+
onRetry?: () => void;
|
|
157
|
+
className?: string;
|
|
158
|
+
style?: React.CSSProperties;
|
|
159
|
+
}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
|
-
import { Pin } from "lucide-react";
|
|
2
|
+
import { AlertCircle, Pin } from "lucide-react";
|
|
3
3
|
import { UserAvatar } from "../../social";
|
|
4
4
|
import { EmptyState } from "../../common";
|
|
5
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
5
6
|
import { Badge } from "../../ui/badge";
|
|
6
7
|
import { Button } from "../../ui/button";
|
|
7
8
|
import { Card, CardContent } from "../../ui/card";
|
|
8
9
|
import type { AnnouncementFeedProps } from "./types";
|
|
9
10
|
import { cn } from "../../lib/utils";
|
|
10
11
|
import { formatTimestamp } from "../../utils/format-timestamp";
|
|
12
|
+
import { Pagination } from "../../common/pagination";
|
|
11
13
|
|
|
12
14
|
export function AnnouncementFeed({
|
|
13
15
|
announcements,
|
|
@@ -17,6 +19,13 @@ export function AnnouncementFeed({
|
|
|
17
19
|
previewLines = 3,
|
|
18
20
|
emptyMessage = "No announcements yet",
|
|
19
21
|
readOnly = false,
|
|
22
|
+
isLoading,
|
|
23
|
+
error,
|
|
24
|
+
onRetry,
|
|
25
|
+
pageSize,
|
|
26
|
+
currentPage = 1,
|
|
27
|
+
totalItems,
|
|
28
|
+
onPageChange,
|
|
20
29
|
className,
|
|
21
30
|
style,
|
|
22
31
|
}: AnnouncementFeedProps) {
|
|
@@ -41,6 +50,42 @@ export function AnnouncementFeed({
|
|
|
41
50
|
}
|
|
42
51
|
}
|
|
43
52
|
|
|
53
|
+
if (isLoading) {
|
|
54
|
+
return (
|
|
55
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
56
|
+
{Array.from({ length: 3 }).map((_, i) => (
|
|
57
|
+
<div key={i} className="flex gap-3 items-start">
|
|
58
|
+
<Skeleton className="h-10 w-10 rounded-full shrink-0" />
|
|
59
|
+
<div className="flex-1 space-y-2">
|
|
60
|
+
<Skeleton className="h-5 w-48" />
|
|
61
|
+
<Skeleton className="h-4 w-full" />
|
|
62
|
+
<Skeleton className="h-4 w-full" />
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
))}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (error) {
|
|
71
|
+
return (
|
|
72
|
+
<div className={cn("py-12", className)} style={style}>
|
|
73
|
+
<EmptyState
|
|
74
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
75
|
+
title="Something went wrong"
|
|
76
|
+
description={error}
|
|
77
|
+
action={
|
|
78
|
+
onRetry ? (
|
|
79
|
+
<Button variant="outline" onClick={onRetry}>
|
|
80
|
+
Retry
|
|
81
|
+
</Button>
|
|
82
|
+
) : undefined
|
|
83
|
+
}
|
|
84
|
+
/>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
44
89
|
if (sorted.length === 0) {
|
|
45
90
|
return (
|
|
46
91
|
<div className={className} style={style}>
|
|
@@ -51,7 +96,10 @@ export function AnnouncementFeed({
|
|
|
51
96
|
|
|
52
97
|
return (
|
|
53
98
|
<div className={cn("flex flex-col gap-2", className)} style={style}>
|
|
54
|
-
{
|
|
99
|
+
{(onPageChange && pageSize
|
|
100
|
+
? sorted.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
101
|
+
: sorted
|
|
102
|
+
).map((a) => {
|
|
55
103
|
const isExpanded = expandedUids.has(a.uid);
|
|
56
104
|
|
|
57
105
|
return (
|
|
@@ -91,9 +139,9 @@ export function AnnouncementFeed({
|
|
|
91
139
|
<span className="block text-xs text-muted-foreground mb-1">
|
|
92
140
|
{a.author.displayName} · {formatTimestamp(a.createdAt)}
|
|
93
141
|
</span>
|
|
94
|
-
<
|
|
142
|
+
<div
|
|
95
143
|
className={cn(
|
|
96
|
-
"text-sm text-foreground",
|
|
144
|
+
"text-sm text-foreground [&_p]:mb-2 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:list-decimal [&_ol]:pl-5",
|
|
97
145
|
!isExpanded && "line-clamp-(--preview-lines) overflow-hidden",
|
|
98
146
|
)}
|
|
99
147
|
style={
|
|
@@ -101,10 +149,9 @@ export function AnnouncementFeed({
|
|
|
101
149
|
? { "--preview-lines": previewLines } as React.CSSProperties
|
|
102
150
|
: undefined
|
|
103
151
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
{!isExpanded && a.content.length > 200 && (
|
|
152
|
+
dangerouslySetInnerHTML={{ __html: a.content }}
|
|
153
|
+
/>
|
|
154
|
+
{!isExpanded && a.content.replace(/<[^>]*>/g, "").length > 200 && (
|
|
108
155
|
<Button
|
|
109
156
|
variant="link"
|
|
110
157
|
size="xs"
|
|
@@ -123,6 +170,15 @@ export function AnnouncementFeed({
|
|
|
123
170
|
</Card>
|
|
124
171
|
);
|
|
125
172
|
})}
|
|
173
|
+
|
|
174
|
+
{onPageChange && pageSize && sorted.length > 0 && (
|
|
175
|
+
<Pagination
|
|
176
|
+
currentPage={currentPage}
|
|
177
|
+
totalPages={Math.ceil((totalItems ?? sorted.length) / pageSize)}
|
|
178
|
+
onPageChange={onPageChange}
|
|
179
|
+
className="mt-4"
|
|
180
|
+
/>
|
|
181
|
+
)}
|
|
126
182
|
</div>
|
|
127
183
|
);
|
|
128
184
|
}
|
|
@@ -26,6 +26,20 @@ export interface AnnouncementFeedProps {
|
|
|
26
26
|
emptyMessage?: string;
|
|
27
27
|
/** When true, disables interactions */
|
|
28
28
|
readOnly?: boolean;
|
|
29
|
+
/** Render skeleton placeholders instead of content */
|
|
30
|
+
isLoading?: boolean;
|
|
31
|
+
/** Error message — renders an error state with optional retry */
|
|
32
|
+
error?: string | null;
|
|
33
|
+
/** Called when the user clicks retry in the error state */
|
|
34
|
+
onRetry?: () => void;
|
|
35
|
+
/** Number of items per page (enables pagination when set with onPageChange) */
|
|
36
|
+
pageSize?: number;
|
|
37
|
+
/** Current page (1-indexed) */
|
|
38
|
+
currentPage?: number;
|
|
39
|
+
/** Total number of items (for server-side pagination) */
|
|
40
|
+
totalItems?: number;
|
|
41
|
+
/** Called when the user navigates to a different page */
|
|
42
|
+
onPageChange?: (page: number) => void;
|
|
29
43
|
/** CSS class name for the root element */
|
|
30
44
|
className?: string;
|
|
31
45
|
/** Inline styles for the root element */
|
|
@@ -37,7 +51,7 @@ export interface Announcement {
|
|
|
37
51
|
uid: string;
|
|
38
52
|
/** Announcement title */
|
|
39
53
|
title: string;
|
|
40
|
-
/** Announcement body content */
|
|
54
|
+
/** Announcement body content. May contain HTML from a rich-text editor. */
|
|
41
55
|
content: string;
|
|
42
56
|
/** Author information */
|
|
43
57
|
author: { displayName: string; avatarUrl?: string; role?: string };
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
+
import { AlertCircle } from "lucide-react";
|
|
2
3
|
import { QuestionRenderer } from "../../questions";
|
|
3
4
|
import type { QuestionData, SessionAnswer } from "../../questions/types";
|
|
4
5
|
import { Badge } from "../../ui/badge";
|
|
5
6
|
import { Card, CardContent } from "../../ui/card";
|
|
6
7
|
import { Separator } from "../../ui/separator";
|
|
8
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
9
|
+
import { Button } from "../../ui/button";
|
|
10
|
+
import { EmptyState } from "../../common/empty-state";
|
|
7
11
|
import { cn } from "../../lib/utils";
|
|
8
12
|
import type {
|
|
9
13
|
AssessmentReviewProps,
|
|
@@ -140,9 +144,42 @@ export function AssessmentReview({
|
|
|
140
144
|
score,
|
|
141
145
|
questionGroups,
|
|
142
146
|
showCorrectAnswers = true,
|
|
147
|
+
isLoading,
|
|
148
|
+
error,
|
|
149
|
+
onRetry,
|
|
143
150
|
className,
|
|
144
151
|
style,
|
|
145
152
|
}: AssessmentReviewProps) {
|
|
153
|
+
if (isLoading) {
|
|
154
|
+
return (
|
|
155
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
156
|
+
<Skeleton className="h-16 w-full" />
|
|
157
|
+
<Skeleton className="h-24 w-full" />
|
|
158
|
+
<Skeleton className="h-24 w-full" />
|
|
159
|
+
<Skeleton className="h-24 w-full" />
|
|
160
|
+
</div>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (error) {
|
|
165
|
+
return (
|
|
166
|
+
<div className={cn("py-12", className)} style={style}>
|
|
167
|
+
<EmptyState
|
|
168
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
169
|
+
title="Something went wrong"
|
|
170
|
+
description={error}
|
|
171
|
+
action={
|
|
172
|
+
onRetry ? (
|
|
173
|
+
<Button variant="outline" onClick={onRetry}>
|
|
174
|
+
Retry
|
|
175
|
+
</Button>
|
|
176
|
+
) : undefined
|
|
177
|
+
}
|
|
178
|
+
/>
|
|
179
|
+
</div>
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
146
183
|
return (
|
|
147
184
|
<div className={cn(className)} style={style}>
|
|
148
185
|
{score && <ScoreHeader score={score} />}
|
|
@@ -34,6 +34,12 @@ export interface AssessmentReviewProps {
|
|
|
34
34
|
* @default true
|
|
35
35
|
*/
|
|
36
36
|
showCorrectAnswers?: boolean;
|
|
37
|
+
/** Render skeleton placeholders instead of content */
|
|
38
|
+
isLoading?: boolean;
|
|
39
|
+
/** Error message — renders an error state with optional retry */
|
|
40
|
+
error?: string | null;
|
|
41
|
+
/** Called when the user clicks retry in the error state */
|
|
42
|
+
onRetry?: () => void;
|
|
37
43
|
/** CSS class name for the root element */
|
|
38
44
|
className?: string;
|
|
39
45
|
/** Inline styles for the root element */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState } from "react";
|
|
2
|
-
import { Send, Save } from "lucide-react";
|
|
2
|
+
import { Send, Save, AlertCircle } from "lucide-react";
|
|
3
3
|
import { StatusBadge, DueDateDisplay } from "../../common";
|
|
4
4
|
import { FileUploadZone } from "../../content";
|
|
5
5
|
import { Button } from "../../ui/button";
|
|
@@ -9,6 +9,9 @@ import { Separator } from "../../ui/separator";
|
|
|
9
9
|
import { Card, CardContent } from "../../ui/card";
|
|
10
10
|
import { Alert, AlertDescription } from "../../ui/alert";
|
|
11
11
|
import { Tabs, TabsList, TabsTrigger, TabsContent } from "../../ui/tabs";
|
|
12
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
13
|
+
import { EmptyState } from "../../common/empty-state";
|
|
14
|
+
import { cn } from "../../lib/utils";
|
|
12
15
|
import type { AssignmentSubmissionProps, SubmissionData } from "./types";
|
|
13
16
|
|
|
14
17
|
export function AssignmentSubmission({
|
|
@@ -25,6 +28,9 @@ export function AssignmentSubmission({
|
|
|
25
28
|
grade,
|
|
26
29
|
isSubmitting = false,
|
|
27
30
|
readOnly = false,
|
|
31
|
+
isLoading,
|
|
32
|
+
error,
|
|
33
|
+
onRetry,
|
|
28
34
|
className,
|
|
29
35
|
style,
|
|
30
36
|
}: AssignmentSubmissionProps) {
|
|
@@ -33,6 +39,36 @@ export function AssignmentSubmission({
|
|
|
33
39
|
const [url, setUrl] = useState(existingSubmission?.url ?? "");
|
|
34
40
|
const [activeTab, setActiveTab] = useState<"text" | "file" | "url">(submissionTypes[0]);
|
|
35
41
|
|
|
42
|
+
if (isLoading) {
|
|
43
|
+
return (
|
|
44
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
45
|
+
<Skeleton className="h-8 w-64" />
|
|
46
|
+
<Skeleton className="h-6 w-20" />
|
|
47
|
+
<Skeleton className="h-32 w-full" />
|
|
48
|
+
<Skeleton className="h-10 w-32" />
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (error) {
|
|
54
|
+
return (
|
|
55
|
+
<div className={cn("py-12", className)} style={style}>
|
|
56
|
+
<EmptyState
|
|
57
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
58
|
+
title="Something went wrong"
|
|
59
|
+
description={error}
|
|
60
|
+
action={
|
|
61
|
+
onRetry ? (
|
|
62
|
+
<Button variant="outline" onClick={onRetry}>
|
|
63
|
+
Retry
|
|
64
|
+
</Button>
|
|
65
|
+
) : undefined
|
|
66
|
+
}
|
|
67
|
+
/>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
36
72
|
const isEditable = !readOnly && !["submitted", "graded"].includes(status);
|
|
37
73
|
|
|
38
74
|
function getSubmissionData(): SubmissionData {
|
|
@@ -44,6 +44,12 @@ export interface AssignmentSubmissionProps {
|
|
|
44
44
|
isSubmitting?: boolean;
|
|
45
45
|
/** When true, disables all interactions */
|
|
46
46
|
readOnly?: boolean;
|
|
47
|
+
/** Render skeleton placeholders instead of content */
|
|
48
|
+
isLoading?: boolean;
|
|
49
|
+
/** Error message — renders an error state with optional retry */
|
|
50
|
+
error?: string | null;
|
|
51
|
+
/** Called when the user clicks retry in the error state */
|
|
52
|
+
onRetry?: () => void;
|
|
47
53
|
/** CSS class name for the root element */
|
|
48
54
|
className?: string;
|
|
49
55
|
/** Inline styles for the root element */
|