@hydralms/components 0.1.3 → 0.3.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/dist/StudentProfile-BVfZMbnV.cjs +1 -0
- package/dist/StudentProfile-DeMxdrL3.js +3275 -0
- package/dist/assessment-toolbar/assessment-toolbar.d.ts +1 -1
- package/dist/assessment-toolbar/index.d.ts +5 -1
- package/dist/assessment-toolbar/question-header-bar.d.ts +2 -0
- package/dist/assessment-toolbar/question-materials-drawer.d.ts +2 -0
- package/dist/assessment-toolbar/question-navigator.d.ts +1 -1
- package/dist/assessment-toolbar/timer-display.d.ts +1 -1
- package/dist/assessment-toolbar/types.d.ts +52 -4
- package/dist/assessment-toolbar/use-countdown.d.ts +43 -0
- package/dist/common/index.d.ts +3 -1
- package/dist/common/pagination.d.ts +26 -0
- package/dist/common/stepper.d.ts +6 -0
- package/dist/common/types.d.ts +38 -0
- package/dist/components.css +1 -1
- package/dist/content/attachment-list.d.ts +6 -0
- package/dist/content/audio-player.d.ts +22 -0
- package/dist/content/code-block.d.ts +30 -0
- package/dist/content/content-block.d.ts +1 -1
- package/dist/content/embed-block.d.ts +28 -0
- package/dist/content/index.d.ts +8 -1
- package/dist/content/types.d.ts +63 -0
- package/dist/curriculum/course-card.d.ts +51 -0
- package/dist/curriculum/curriculum-item.d.ts +1 -1
- 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 +597 -308
- 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 +3 -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 +5 -0
- package/dist/modules/AssignmentModule/types.d.ts +69 -0
- package/dist/modules/CertificateModule/CertificateModule.d.ts +5 -0
- package/dist/modules/CertificateModule/types.d.ts +51 -0
- 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 +5 -0
- package/dist/modules/DiscussionModule/types.d.ts +47 -0
- package/dist/modules/ExamModule/ExamModule.d.ts +5 -0
- package/dist/modules/ExamModule/types.d.ts +55 -0
- 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 +5 -0
- package/dist/modules/GradeCenterModule/types.d.ts +56 -0
- package/dist/modules/QuizModule/QuizModule.d.ts +4 -1
- package/dist/modules/QuizModule/types.d.ts +10 -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 +5 -0
- package/dist/modules/SurveyModule/types.d.ts +51 -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 +18 -0
- package/dist/modules.cjs +1 -0
- package/dist/modules.js +1834 -0
- package/dist/progress/achievement-badge.d.ts +6 -0
- package/dist/progress/activity-timeline.d.ts +6 -0
- package/dist/progress/index.d.ts +4 -1
- package/dist/progress/stat-card.d.ts +1 -1
- package/dist/progress/streak-badge.d.ts +6 -0
- package/dist/progress/types.d.ts +99 -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 +2 -2
- package/dist/questions/fill-in-the-blank.d.ts +1 -1
- package/dist/questions/hotspot.d.ts +21 -0
- package/dist/questions/index.d.ts +11 -1
- package/dist/questions/inline-choice.d.ts +21 -0
- package/dist/questions/matching.d.ts +22 -0
- package/dist/questions/multiple-choice.d.ts +1 -1
- package/dist/questions/numeric.d.ts +11 -0
- package/dist/questions/ordering.d.ts +12 -0
- package/dist/questions/question-renderer.d.ts +1 -1
- package/dist/questions/scenario.d.ts +23 -0
- package/dist/questions/scoring.d.ts +22 -0
- package/dist/questions/spreadsheet.d.ts +29 -0
- package/dist/questions/true-false.d.ts +1 -1
- package/dist/questions/types.d.ts +106 -1
- package/dist/questions/use-drag-reorder.d.ts +17 -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 +13 -5
- 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 +12 -1
- 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 +8 -0
- package/dist/sections/ForumBoard/types.d.ts +78 -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 +12 -1
- package/dist/sections/RequirementsChecklist/RequirementsChecklist.d.ts +8 -0
- package/dist/sections/RequirementsChecklist/types.d.ts +43 -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 +9 -0
- package/dist/sections/RubricView/types.d.ts +56 -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 +13 -1
- package/dist/sections.cjs +1 -1
- package/dist/sections.js +282 -1786
- package/dist/social/post-card.d.ts +1 -1
- package/dist/tabs-BsfVo2Bl.cjs +173 -0
- package/dist/tabs-BuY1iNJE.js +22305 -0
- package/dist/ui/alert.d.ts +1 -1
- package/dist/ui/badge.d.ts +1 -1
- package/dist/ui/button.d.ts +1 -1
- package/dist/ui/drawer.d.ts +84 -0
- package/dist/ui/index.d.ts +5 -0
- package/dist/ui/progress.d.ts +1 -1
- package/dist/ui/rich-text-editor.d.ts +32 -0
- package/dist/ui/rich-text-toolbar.d.ts +8 -0
- package/dist/ui/toast.d.ts +43 -0
- package/dist/utils/array-utils.d.ts +4 -0
- package/dist/utils/debounce.d.ts +5 -1
- package/dist/utils/flatten-leaves.d.ts +6 -0
- package/dist/utils/format-file-size.d.ts +1 -0
- package/dist/utils/format-timestamp.d.ts +1 -0
- package/dist/utils/is-empty-html.d.ts +5 -0
- package/dist/utils/pick-palette-color.d.ts +19 -0
- package/dist/utils/shuffle.d.ts +1 -0
- package/dist/utils/string-utils.d.ts +12 -0
- package/dist/video/types.d.ts +15 -0
- package/dist/video/video-bookmark.d.ts +1 -1
- package/dist/video/video-player.d.ts +1 -1
- package/dist/video/video-playlist-item.d.ts +1 -1
- package/dist/withProGate-BWqcKdPM.js +137 -0
- package/dist/withProGate-DX6XqKLp.cjs +1 -0
- package/package.json +40 -137
- package/src/assessment-toolbar/assessment-toolbar.tsx +54 -49
- package/src/assessment-toolbar/index.ts +6 -0
- package/src/assessment-toolbar/question-header-bar.tsx +61 -0
- package/src/assessment-toolbar/question-materials-drawer.tsx +55 -0
- package/src/assessment-toolbar/question-navigator.tsx +13 -36
- package/src/assessment-toolbar/timer-display.tsx +6 -5
- package/src/assessment-toolbar/types.ts +54 -4
- package/src/assessment-toolbar/use-countdown.ts +153 -0
- package/src/common/empty-state.tsx +1 -0
- package/src/common/index.ts +5 -0
- package/src/common/pagination.tsx +135 -0
- package/src/common/search-input.tsx +8 -6
- package/src/common/stepper.tsx +100 -0
- package/src/common/types.ts +41 -0
- package/src/content/attachment-list.tsx +92 -0
- package/src/content/audio-player.tsx +196 -0
- package/src/content/code-block.tsx +113 -0
- package/src/content/content-block.tsx +68 -2
- package/src/content/embed-block.tsx +78 -0
- package/src/content/file-upload-zone.tsx +11 -6
- package/src/content/index.ts +9 -0
- package/src/content/types.ts +46 -0
- package/src/curriculum/course-card.tsx +199 -0
- package/src/curriculum/curriculum-item.tsx +9 -5
- package/src/curriculum/curriculum-tree.tsx +20 -13
- package/src/curriculum/index.ts +2 -0
- package/src/curriculum/types.ts +2 -2
- package/src/feedback/feedback-banner.tsx +12 -14
- package/src/flashcards/flashcard-deck.tsx +1 -9
- package/src/flashcards/flashcard.tsx +29 -9
- 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 +24 -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 +314 -0
- package/src/modules/AssignmentModule/types.ts +77 -0
- package/src/modules/CertificateModule/CertificateModule.tsx +173 -0
- package/src/modules/CertificateModule/types.ts +49 -0
- package/src/modules/CourseCatalogModule/CourseCatalogModule.tsx +126 -0
- package/src/modules/CourseCatalogModule/types.ts +47 -0
- package/src/modules/CoursePlayer/CoursePlayer.tsx +80 -69
- package/src/modules/DiscussionModule/DiscussionModule.tsx +145 -0
- package/src/modules/DiscussionModule/types.ts +54 -0
- package/src/modules/ExamModule/ExamModule.tsx +151 -0
- package/src/modules/ExamModule/types.ts +57 -0
- package/src/modules/FlashcardLab/FlashcardLab.tsx +39 -21
- package/src/modules/FlashcardLab/types.ts +2 -0
- package/src/modules/GradeCenterModule/GradeCenterModule.tsx +174 -0
- package/src/modules/GradeCenterModule/types.ts +65 -0
- package/src/modules/QuizModule/QuizModule.tsx +58 -178
- package/src/modules/QuizModule/types.ts +10 -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 +185 -0
- package/src/modules/SurveyModule/types.ts +53 -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 +33 -0
- package/src/progress/achievement-badge.tsx +52 -0
- package/src/progress/activity-timeline.tsx +84 -0
- package/src/progress/grade-indicator.tsx +9 -1
- package/src/progress/index.ts +7 -0
- package/src/progress/progress-ring.tsx +2 -1
- package/src/progress/stat-card.tsx +37 -18
- package/src/progress/streak-badge.tsx +35 -0
- package/src/progress/types.ts +103 -0
- package/src/provider/HydraProvider.tsx +15 -6
- package/src/questions/choice.tsx +19 -14
- package/src/questions/confidence-indicator.tsx +107 -0
- package/src/questions/essay.tsx +28 -28
- package/src/questions/fill-in-the-blank.tsx +20 -19
- package/src/questions/hotspot.tsx +154 -0
- package/src/questions/index.ts +18 -0
- package/src/questions/inline-choice.tsx +152 -0
- package/src/questions/matching.tsx +229 -0
- package/src/questions/multiple-choice.tsx +19 -14
- package/src/questions/numeric.tsx +106 -0
- package/src/questions/ordering.tsx +167 -0
- package/src/questions/question-renderer.tsx +24 -2
- package/src/questions/scenario.tsx +140 -0
- package/src/questions/scoring.ts +201 -0
- package/src/questions/spreadsheet.tsx +260 -0
- package/src/questions/true-false.tsx +19 -14
- package/src/questions/types.ts +123 -1
- package/src/questions/use-drag-reorder.ts +80 -0
- package/src/sections/AnnouncementFeed/AnnouncementFeed.tsx +66 -23
- package/src/sections/AnnouncementFeed/types.ts +15 -1
- package/src/sections/AssessmentReview/AssessmentReview.tsx +50 -2
- package/src/sections/AssessmentReview/types.ts +6 -0
- package/src/sections/AssignmentSubmission/AssignmentSubmission.tsx +44 -6
- package/src/sections/AssignmentSubmission/types.ts +6 -0
- package/src/sections/CertificateViewer/CertificateViewer.tsx +215 -60
- package/src/sections/CertificateViewer/certificate-variants.tsx +170 -0
- package/src/sections/CertificateViewer/types.ts +19 -5
- package/src/sections/CourseCatalog/CourseCatalog.tsx +220 -0
- package/src/sections/CourseCatalog/types.ts +76 -0
- package/src/sections/CourseOutline/CourseOutline.tsx +45 -14
- package/src/sections/CourseOutline/types.ts +6 -0
- package/src/sections/DiscussionThread/DiscussionThread.tsx +55 -11
- 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 +125 -82
- package/src/sections/ExamSession/types.ts +12 -1
- package/src/sections/FlashcardStudySession/FlashcardStudySession.tsx +53 -36
- package/src/sections/FlashcardStudySession/types.ts +6 -0
- package/src/sections/ForumBoard/ForumBoard.tsx +342 -0
- package/src/sections/ForumBoard/types.ts +81 -0
- package/src/sections/GradebookTable/GradebookTable.tsx +55 -2
- 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 +40 -13
- package/src/sections/LessonPage/types.ts +6 -0
- package/src/sections/PracticeQuiz/PracticeQuiz.tsx +119 -98
- package/src/sections/PracticeQuiz/types.ts +6 -0
- package/src/sections/ProgressDashboard/ProgressDashboard.tsx +121 -67
- package/src/sections/ProgressDashboard/types.ts +6 -0
- package/src/sections/QuizSession/QuizSession.tsx +115 -67
- package/src/sections/QuizSession/types.ts +12 -1
- package/src/sections/RequirementsChecklist/RequirementsChecklist.tsx +147 -0
- package/src/sections/RequirementsChecklist/types.ts +44 -0
- package/src/sections/ResourceLibrary/ResourceLibrary.tsx +68 -17
- package/src/sections/ResourceLibrary/types.ts +15 -1
- package/src/sections/RubricView/RubricView.tsx +174 -0
- package/src/sections/RubricView/types.ts +58 -0
- package/src/sections/ScrollableQuiz/ScrollableQuiz.tsx +58 -23
- 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 +40 -10
- 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 +42 -1
- package/src/social/post-card.tsx +8 -19
- package/src/social/user-avatar.tsx +10 -5
- package/src/styles/globals.css +52 -41
- package/src/ui/badge.tsx +8 -0
- package/src/ui/drawer.tsx +600 -0
- package/src/ui/index.ts +21 -0
- package/src/ui/progress.tsx +4 -0
- package/src/ui/rich-text-editor.tsx +119 -0
- package/src/ui/rich-text-toolbar.tsx +157 -0
- package/src/ui/toast.tsx +170 -0
- package/src/utils/array-utils.ts +17 -0
- package/src/utils/debounce.ts +8 -2
- package/src/utils/flatten-leaves.ts +17 -0
- package/src/utils/format-file-size.ts +5 -0
- package/src/utils/format-timestamp.ts +13 -0
- package/src/utils/is-empty-html.ts +7 -0
- package/src/utils/pick-palette-color.ts +33 -0
- package/src/utils/shuffle.ts +8 -0
- package/src/utils/string-utils.ts +30 -0
- package/src/video/types.ts +16 -0
- package/src/video/video-bookmark.tsx +4 -3
- package/src/video/video-chapter-list.tsx +9 -4
- package/src/video/video-player.tsx +24 -5
- package/src/video/video-playlist-item.tsx +8 -3
- package/src/video/video-thumbnail-card.tsx +4 -0
- package/src/video/video-transcript.tsx +8 -5
- package/dist/table-BrS5cDQu.js +0 -2510
- package/dist/table-D6AkBBEo.cjs +0 -1
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { useMemo, useState } from "react";
|
|
2
|
+
import { AlertCircle, Grid, List as ListIcon, GraduationCap } from "lucide-react";
|
|
3
|
+
import { CourseCard } from "../../curriculum/course-card";
|
|
4
|
+
import { SearchInput, EmptyState } from "../../common";
|
|
5
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
6
|
+
import { Button } from "../../ui/button";
|
|
7
|
+
import { Tabs, TabsList, TabsTrigger } from "../../ui/tabs";
|
|
8
|
+
import { Tooltip, TooltipTrigger, TooltipContent } from "../../ui/tooltip";
|
|
9
|
+
import { Pagination } from "../../common/pagination";
|
|
10
|
+
import type { CourseCatalogProps } from "./types";
|
|
11
|
+
import { cn } from "../../lib/utils";
|
|
12
|
+
|
|
13
|
+
export function CourseCatalog({
|
|
14
|
+
courses = [],
|
|
15
|
+
categories,
|
|
16
|
+
onCourseClick,
|
|
17
|
+
onEnroll,
|
|
18
|
+
viewMode: initialViewMode = "grid",
|
|
19
|
+
allowViewToggle = true,
|
|
20
|
+
showSearch = true,
|
|
21
|
+
emptyMessage = "No courses found",
|
|
22
|
+
readOnly = false,
|
|
23
|
+
isLoading,
|
|
24
|
+
error,
|
|
25
|
+
onRetry,
|
|
26
|
+
pageSize,
|
|
27
|
+
currentPage = 1,
|
|
28
|
+
totalItems,
|
|
29
|
+
onPageChange,
|
|
30
|
+
className,
|
|
31
|
+
style,
|
|
32
|
+
}: CourseCatalogProps) {
|
|
33
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
34
|
+
const [activeCategoryUid, setActiveCategoryUid] = useState<string | null>(null);
|
|
35
|
+
const [viewMode, setViewMode] = useState(initialViewMode);
|
|
36
|
+
|
|
37
|
+
const filtered = useMemo(() => {
|
|
38
|
+
let result = courses;
|
|
39
|
+
if (activeCategoryUid) {
|
|
40
|
+
result = result.filter((c) => c.categoryUid === activeCategoryUid);
|
|
41
|
+
}
|
|
42
|
+
if (searchQuery.trim()) {
|
|
43
|
+
const q = searchQuery.toLowerCase();
|
|
44
|
+
result = result.filter(
|
|
45
|
+
(c) =>
|
|
46
|
+
c.title.toLowerCase().includes(q) ||
|
|
47
|
+
c.description?.toLowerCase().includes(q) ||
|
|
48
|
+
c.instructor?.displayName.toLowerCase().includes(q),
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
52
|
+
}, [courses, activeCategoryUid, searchQuery]);
|
|
53
|
+
|
|
54
|
+
if (isLoading) {
|
|
55
|
+
return (
|
|
56
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
57
|
+
<Skeleton className="h-9 w-full" />
|
|
58
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
59
|
+
{Array.from({ length: 6 }).map((_, i) => (
|
|
60
|
+
<Skeleton key={i} className="h-64 w-full rounded-lg" />
|
|
61
|
+
))}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (error) {
|
|
68
|
+
return (
|
|
69
|
+
<div className={cn("py-12", className)} style={style}>
|
|
70
|
+
<EmptyState
|
|
71
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
72
|
+
title="Something went wrong"
|
|
73
|
+
description={error}
|
|
74
|
+
action={
|
|
75
|
+
onRetry ? (
|
|
76
|
+
<Button variant="outline" onClick={onRetry}>
|
|
77
|
+
Retry
|
|
78
|
+
</Button>
|
|
79
|
+
) : undefined
|
|
80
|
+
}
|
|
81
|
+
/>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const paginatedItems =
|
|
87
|
+
onPageChange && pageSize
|
|
88
|
+
? filtered.slice((currentPage - 1) * pageSize, currentPage * pageSize)
|
|
89
|
+
: filtered;
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<div className={className} style={style}>
|
|
93
|
+
{/* Toolbar */}
|
|
94
|
+
<div className="flex gap-2 items-center mb-2">
|
|
95
|
+
{showSearch && (
|
|
96
|
+
<div className="flex-1 max-w-80">
|
|
97
|
+
<SearchInput
|
|
98
|
+
value={searchQuery}
|
|
99
|
+
onChange={setSearchQuery}
|
|
100
|
+
placeholder="Search courses..."
|
|
101
|
+
size="small"
|
|
102
|
+
/>
|
|
103
|
+
</div>
|
|
104
|
+
)}
|
|
105
|
+
{allowViewToggle && (
|
|
106
|
+
<div className="flex gap-0.5">
|
|
107
|
+
<Tooltip>
|
|
108
|
+
<TooltipTrigger>
|
|
109
|
+
<Button
|
|
110
|
+
variant="ghost"
|
|
111
|
+
size="icon-xs"
|
|
112
|
+
aria-label="Grid view"
|
|
113
|
+
className={cn(viewMode === "grid" && "text-primary")}
|
|
114
|
+
onClick={() => setViewMode("grid")}
|
|
115
|
+
>
|
|
116
|
+
<Grid size={18} />
|
|
117
|
+
</Button>
|
|
118
|
+
</TooltipTrigger>
|
|
119
|
+
<TooltipContent>Grid view</TooltipContent>
|
|
120
|
+
</Tooltip>
|
|
121
|
+
<Tooltip>
|
|
122
|
+
<TooltipTrigger>
|
|
123
|
+
<Button
|
|
124
|
+
variant="ghost"
|
|
125
|
+
size="icon-xs"
|
|
126
|
+
aria-label="List view"
|
|
127
|
+
className={cn(viewMode === "list" && "text-primary")}
|
|
128
|
+
onClick={() => setViewMode("list")}
|
|
129
|
+
>
|
|
130
|
+
<ListIcon size={18} />
|
|
131
|
+
</Button>
|
|
132
|
+
</TooltipTrigger>
|
|
133
|
+
<TooltipContent>List view</TooltipContent>
|
|
134
|
+
</Tooltip>
|
|
135
|
+
</div>
|
|
136
|
+
)}
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
{/* Category tabs */}
|
|
140
|
+
{categories && categories.length > 0 && (
|
|
141
|
+
<Tabs
|
|
142
|
+
value={activeCategoryUid ?? "all"}
|
|
143
|
+
onValueChange={(v) => setActiveCategoryUid(v === "all" ? null : v)}
|
|
144
|
+
className="mb-2"
|
|
145
|
+
>
|
|
146
|
+
<TabsList>
|
|
147
|
+
<TabsTrigger value="all">All</TabsTrigger>
|
|
148
|
+
{categories.map((cat) => (
|
|
149
|
+
<TabsTrigger key={cat.uid} value={cat.uid}>{cat.label}</TabsTrigger>
|
|
150
|
+
))}
|
|
151
|
+
</TabsList>
|
|
152
|
+
</Tabs>
|
|
153
|
+
)}
|
|
154
|
+
|
|
155
|
+
{/* Course grid/list */}
|
|
156
|
+
{filtered.length === 0 ? (
|
|
157
|
+
<EmptyState
|
|
158
|
+
icon={<GraduationCap />}
|
|
159
|
+
title={emptyMessage}
|
|
160
|
+
description="Try adjusting your search or filter."
|
|
161
|
+
/>
|
|
162
|
+
) : viewMode === "grid" ? (
|
|
163
|
+
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-4">
|
|
164
|
+
{paginatedItems.map((course) => (
|
|
165
|
+
<CourseCard
|
|
166
|
+
key={course.uid}
|
|
167
|
+
uid={course.uid}
|
|
168
|
+
title={course.title}
|
|
169
|
+
description={course.description}
|
|
170
|
+
thumbnailUrl={course.thumbnailUrl}
|
|
171
|
+
instructor={course.instructor}
|
|
172
|
+
progress={course.progress}
|
|
173
|
+
enrollmentStatus={course.enrollmentStatus}
|
|
174
|
+
studentCount={course.studentCount}
|
|
175
|
+
duration={course.duration}
|
|
176
|
+
layout="vertical"
|
|
177
|
+
onClick={readOnly ? undefined : () => onCourseClick(course)}
|
|
178
|
+
onEnroll={
|
|
179
|
+
onEnroll && !readOnly ? () => onEnroll(course) : undefined
|
|
180
|
+
}
|
|
181
|
+
className={cn(readOnly && "opacity-70")}
|
|
182
|
+
/>
|
|
183
|
+
))}
|
|
184
|
+
</div>
|
|
185
|
+
) : (
|
|
186
|
+
<div className="flex flex-col gap-2">
|
|
187
|
+
{paginatedItems.map((course) => (
|
|
188
|
+
<CourseCard
|
|
189
|
+
key={course.uid}
|
|
190
|
+
uid={course.uid}
|
|
191
|
+
title={course.title}
|
|
192
|
+
description={course.description}
|
|
193
|
+
thumbnailUrl={course.thumbnailUrl}
|
|
194
|
+
instructor={course.instructor}
|
|
195
|
+
progress={course.progress}
|
|
196
|
+
enrollmentStatus={course.enrollmentStatus}
|
|
197
|
+
studentCount={course.studentCount}
|
|
198
|
+
duration={course.duration}
|
|
199
|
+
layout="horizontal"
|
|
200
|
+
onClick={readOnly ? undefined : () => onCourseClick(course)}
|
|
201
|
+
onEnroll={
|
|
202
|
+
onEnroll && !readOnly ? () => onEnroll(course) : undefined
|
|
203
|
+
}
|
|
204
|
+
className={cn(readOnly && "opacity-70")}
|
|
205
|
+
/>
|
|
206
|
+
))}
|
|
207
|
+
</div>
|
|
208
|
+
)}
|
|
209
|
+
|
|
210
|
+
{onPageChange && pageSize && filtered.length > 0 && (
|
|
211
|
+
<Pagination
|
|
212
|
+
currentPage={currentPage}
|
|
213
|
+
totalPages={Math.ceil((totalItems ?? filtered.length) / pageSize)}
|
|
214
|
+
onPageChange={onPageChange}
|
|
215
|
+
className="mt-4"
|
|
216
|
+
/>
|
|
217
|
+
)}
|
|
218
|
+
</div>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
|
|
2
|
+
/**
|
|
3
|
+
* CourseCatalog section — a searchable, filterable course catalog.
|
|
4
|
+
*
|
|
5
|
+
* Displays courses in a grid or list view with search, category tabs,
|
|
6
|
+
* view mode toggling, and optional pagination.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* <CourseCatalog
|
|
10
|
+
* courses={courses}
|
|
11
|
+
* categories={categories}
|
|
12
|
+
* onCourseClick={(c) => navigate(`/courses/${c.uid}`)}
|
|
13
|
+
* onEnroll={(c) => enroll(c.uid)}
|
|
14
|
+
* />
|
|
15
|
+
*/
|
|
16
|
+
export interface CourseCatalogProps {
|
|
17
|
+
/** Courses to display */
|
|
18
|
+
courses: CourseInfo[];
|
|
19
|
+
/** Optional categories for tab filtering */
|
|
20
|
+
categories?: { uid: string; label: string }[];
|
|
21
|
+
/** Called when the user clicks a course */
|
|
22
|
+
onCourseClick: (course: CourseInfo) => void;
|
|
23
|
+
/** Called when the user clicks enroll on a course */
|
|
24
|
+
onEnroll?: (course: CourseInfo) => void;
|
|
25
|
+
/** Layout view mode */
|
|
26
|
+
viewMode?: "grid" | "list";
|
|
27
|
+
/** Whether the user can toggle between grid and list */
|
|
28
|
+
allowViewToggle?: boolean;
|
|
29
|
+
/** Whether to show search */
|
|
30
|
+
showSearch?: boolean;
|
|
31
|
+
/** Empty state message */
|
|
32
|
+
emptyMessage?: string;
|
|
33
|
+
/** When true, disables interactions */
|
|
34
|
+
readOnly?: boolean;
|
|
35
|
+
/** Render skeleton placeholders instead of content */
|
|
36
|
+
isLoading?: boolean;
|
|
37
|
+
/** Error message — renders an error state with optional retry */
|
|
38
|
+
error?: string | null;
|
|
39
|
+
/** Called when the user clicks retry in the error state */
|
|
40
|
+
onRetry?: () => void;
|
|
41
|
+
/** Number of items per page (enables pagination when set with onPageChange) */
|
|
42
|
+
pageSize?: number;
|
|
43
|
+
/** Current page (1-indexed) */
|
|
44
|
+
currentPage?: number;
|
|
45
|
+
/** Total number of items (for server-side pagination) */
|
|
46
|
+
totalItems?: number;
|
|
47
|
+
/** Called when the user navigates to a different page */
|
|
48
|
+
onPageChange?: (page: number) => void;
|
|
49
|
+
/** CSS class name for the root element */
|
|
50
|
+
className?: string;
|
|
51
|
+
/** Inline styles for the root element */
|
|
52
|
+
style?: React.CSSProperties;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface CourseInfo {
|
|
56
|
+
/** Unique identifier */
|
|
57
|
+
uid: string;
|
|
58
|
+
/** Course title */
|
|
59
|
+
title: string;
|
|
60
|
+
/** Course description */
|
|
61
|
+
description?: string;
|
|
62
|
+
/** Thumbnail image URL */
|
|
63
|
+
thumbnailUrl?: string;
|
|
64
|
+
/** Instructor info */
|
|
65
|
+
instructor?: { displayName: string; avatarUrl?: string };
|
|
66
|
+
/** Category UID for filtering */
|
|
67
|
+
categoryUid?: string;
|
|
68
|
+
/** Progress percentage (0-100) */
|
|
69
|
+
progress?: number;
|
|
70
|
+
/** Enrollment status */
|
|
71
|
+
enrollmentStatus?: "enrolled" | "completed" | "available" | "locked";
|
|
72
|
+
/** Number of enrolled students */
|
|
73
|
+
studentCount?: number;
|
|
74
|
+
/** Estimated duration (e.g. "12 hours") */
|
|
75
|
+
duration?: string;
|
|
76
|
+
}
|
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
+
import { AlertCircle } from "lucide-react";
|
|
2
3
|
import { CurriculumTree } from "../../curriculum";
|
|
3
|
-
import type { CurriculumItem } from "../../curriculum/types";
|
|
4
4
|
import { Progress } from "../../ui/progress";
|
|
5
|
+
import { Separator } from "../../ui/separator";
|
|
6
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
7
|
+
import { Button } from "../../ui/button";
|
|
8
|
+
import { EmptyState } from "../../common/empty-state";
|
|
9
|
+
import { flattenLeaves } from "../../utils/flatten-leaves";
|
|
5
10
|
import type { CourseOutlineProps } from "./types";
|
|
6
11
|
import { cn } from "../../lib/utils";
|
|
7
12
|
|
|
8
|
-
function flattenLeaves(items: CurriculumItem[]): string[] {
|
|
9
|
-
const leaves: string[] = [];
|
|
10
|
-
for (const item of items) {
|
|
11
|
-
if (!item.children || item.children.length === 0) {
|
|
12
|
-
leaves.push(item.uid);
|
|
13
|
-
} else {
|
|
14
|
-
leaves.push(...flattenLeaves(item.children));
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
return leaves;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
13
|
export function CourseOutline({
|
|
21
14
|
items,
|
|
22
15
|
progress,
|
|
@@ -27,6 +20,9 @@ export function CourseOutline({
|
|
|
27
20
|
showDuration = true,
|
|
28
21
|
showIcons = true,
|
|
29
22
|
readOnly = false,
|
|
23
|
+
isLoading,
|
|
24
|
+
error,
|
|
25
|
+
onRetry,
|
|
30
26
|
className,
|
|
31
27
|
style,
|
|
32
28
|
}: CourseOutlineProps) {
|
|
@@ -45,10 +41,44 @@ export function CourseOutline({
|
|
|
45
41
|
};
|
|
46
42
|
}, [items, progress]);
|
|
47
43
|
|
|
44
|
+
if (isLoading) {
|
|
45
|
+
return (
|
|
46
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
47
|
+
<Skeleton className="h-6 w-48" />
|
|
48
|
+
<Skeleton className="h-2 w-full" />
|
|
49
|
+
<Skeleton className="h-8 w-full" />
|
|
50
|
+
<Skeleton className="h-8 w-full ml-6" />
|
|
51
|
+
<Skeleton className="h-8 w-full ml-6" />
|
|
52
|
+
<Skeleton className="h-8 w-full" />
|
|
53
|
+
<Skeleton className="h-8 w-full ml-6" />
|
|
54
|
+
<Skeleton className="h-8 w-full" />
|
|
55
|
+
</div>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (error) {
|
|
60
|
+
return (
|
|
61
|
+
<div className={cn("py-12", className)} style={style}>
|
|
62
|
+
<EmptyState
|
|
63
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
64
|
+
title="Something went wrong"
|
|
65
|
+
description={error}
|
|
66
|
+
action={
|
|
67
|
+
onRetry ? (
|
|
68
|
+
<Button variant="outline" onClick={onRetry}>
|
|
69
|
+
Retry
|
|
70
|
+
</Button>
|
|
71
|
+
) : undefined
|
|
72
|
+
}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
48
78
|
return (
|
|
49
79
|
<div className={cn(className)} style={style}>
|
|
50
80
|
{(courseTitle || showOverallProgress) && (
|
|
51
|
-
<div className="px-2 pt-2 pb-
|
|
81
|
+
<div className="px-2 pt-2 pb-2">
|
|
52
82
|
{courseTitle && (
|
|
53
83
|
<p className={cn("font-semibold text-sm text-foreground", showOverallProgress && "mb-1")}>
|
|
54
84
|
{courseTitle}
|
|
@@ -64,6 +94,7 @@ export function CourseOutline({
|
|
|
64
94
|
)}
|
|
65
95
|
</div>
|
|
66
96
|
)}
|
|
97
|
+
{(courseTitle || showOverallProgress) && <Separator />}
|
|
67
98
|
<CurriculumTree
|
|
68
99
|
items={items}
|
|
69
100
|
progress={progress}
|
|
@@ -46,6 +46,12 @@ export interface CourseOutlineProps {
|
|
|
46
46
|
showIcons?: boolean;
|
|
47
47
|
/** When true, disables all click interactions */
|
|
48
48
|
readOnly?: boolean;
|
|
49
|
+
/** Render skeleton placeholders instead of content */
|
|
50
|
+
isLoading?: boolean;
|
|
51
|
+
/** Error message — renders an error state with optional retry */
|
|
52
|
+
error?: string | null;
|
|
53
|
+
/** Called when the user clicks retry in the error state */
|
|
54
|
+
onRetry?: () => void;
|
|
49
55
|
/** CSS class name for the root element */
|
|
50
56
|
className?: string;
|
|
51
57
|
/** Inline styles for the root element */
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
|
-
import { CheckCircle, Heart, MessageSquare, Reply } from "lucide-react";
|
|
2
|
+
import { AlertCircle, CheckCircle, Heart, MessageSquare, Reply } from "lucide-react";
|
|
3
|
+
import { Skeleton } from "../../ui/skeleton";
|
|
4
|
+
import { EmptyState } from "../../common/empty-state";
|
|
3
5
|
import { PostCard } from "../../social";
|
|
4
6
|
import { Button } from "../../ui/button";
|
|
5
|
-
import {
|
|
7
|
+
import { RichTextEditor } from "../../ui/rich-text-editor";
|
|
8
|
+
import { isEmptyHtml } from "../../utils/is-empty-html";
|
|
9
|
+
import { Badge } from "../../ui/badge";
|
|
6
10
|
import { Separator } from "../../ui/separator";
|
|
7
11
|
import { Card, CardContent } from "../../ui/card";
|
|
8
12
|
import { Tooltip, TooltipTrigger, TooltipContent } from "../../ui/tooltip";
|
|
@@ -21,6 +25,9 @@ export function DiscussionThread({
|
|
|
21
25
|
allowReplies = true,
|
|
22
26
|
sortOrder = "oldest",
|
|
23
27
|
readOnly = false,
|
|
28
|
+
isLoading,
|
|
29
|
+
error,
|
|
30
|
+
onRetry,
|
|
24
31
|
className,
|
|
25
32
|
style,
|
|
26
33
|
}: DiscussionThreadProps) {
|
|
@@ -47,9 +54,45 @@ export function DiscussionThread({
|
|
|
47
54
|
return childrenMap;
|
|
48
55
|
}, [replies, rootPost.uid, sortOrder]);
|
|
49
56
|
|
|
57
|
+
if (isLoading) {
|
|
58
|
+
return (
|
|
59
|
+
<div className={cn("space-y-4", className)} style={style}>
|
|
60
|
+
<Skeleton className="h-7 w-64" />
|
|
61
|
+
<div className="flex items-start gap-3">
|
|
62
|
+
<Skeleton className="h-8 w-8 rounded-full shrink-0" />
|
|
63
|
+
<Skeleton className="h-32 w-full" />
|
|
64
|
+
</div>
|
|
65
|
+
{Array.from({ length: 2 }).map((_, i) => (
|
|
66
|
+
<div key={i} className="ml-8">
|
|
67
|
+
<Skeleton className="h-20 w-full" />
|
|
68
|
+
</div>
|
|
69
|
+
))}
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (error) {
|
|
75
|
+
return (
|
|
76
|
+
<div className={cn("py-12", className)} style={style}>
|
|
77
|
+
<EmptyState
|
|
78
|
+
icon={<AlertCircle className="size-10 text-destructive" />}
|
|
79
|
+
title="Something went wrong"
|
|
80
|
+
description={error}
|
|
81
|
+
action={
|
|
82
|
+
onRetry ? (
|
|
83
|
+
<Button variant="outline" onClick={onRetry}>
|
|
84
|
+
Retry
|
|
85
|
+
</Button>
|
|
86
|
+
) : undefined
|
|
87
|
+
}
|
|
88
|
+
/>
|
|
89
|
+
</div>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
|
|
50
93
|
function handleSubmitReply(parentUid: string) {
|
|
51
|
-
if (
|
|
52
|
-
onReply(parentUid, replyContent
|
|
94
|
+
if (isEmptyHtml(replyContent)) return;
|
|
95
|
+
onReply(parentUid, replyContent);
|
|
53
96
|
setReplyContent("");
|
|
54
97
|
setReplyingToUid(null);
|
|
55
98
|
}
|
|
@@ -132,18 +175,19 @@ export function DiscussionThread({
|
|
|
132
175
|
className="mb-2"
|
|
133
176
|
style={{ marginLeft: `${(effectiveDepth + 1) * 16}px` }}
|
|
134
177
|
>
|
|
135
|
-
<CardContent className="
|
|
136
|
-
<
|
|
178
|
+
<CardContent className="py-4">
|
|
179
|
+
<RichTextEditor
|
|
137
180
|
className="min-h-15 mb-2"
|
|
138
181
|
placeholder="Write a reply..."
|
|
139
182
|
value={replyContent}
|
|
140
|
-
onChange={(
|
|
183
|
+
onChange={(html) => setReplyContent(html)}
|
|
184
|
+
variant="minimal"
|
|
141
185
|
/>
|
|
142
186
|
<div className="flex items-center gap-2">
|
|
143
187
|
<Button
|
|
144
188
|
size="sm"
|
|
145
189
|
onClick={() => handleSubmitReply(post.uid)}
|
|
146
|
-
disabled={
|
|
190
|
+
disabled={isEmptyHtml(replyContent)}
|
|
147
191
|
>
|
|
148
192
|
Post Reply
|
|
149
193
|
</Button>
|
|
@@ -170,12 +214,12 @@ export function DiscussionThread({
|
|
|
170
214
|
|
|
171
215
|
return (
|
|
172
216
|
<div className={className} style={style}>
|
|
173
|
-
<div className="flex items-center gap-
|
|
217
|
+
<div className="flex items-center gap-2 mb-2">
|
|
174
218
|
<MessageSquare size={20} className="text-foreground shrink-0" />
|
|
175
219
|
<span className="text-lg font-semibold text-foreground">{title}</span>
|
|
176
|
-
<
|
|
220
|
+
<Badge variant="muted" className="text-xs">
|
|
177
221
|
{replies.length} {replies.length === 1 ? "reply" : "replies"}
|
|
178
|
-
</
|
|
222
|
+
</Badge>
|
|
179
223
|
</div>
|
|
180
224
|
|
|
181
225
|
<Separator className="mb-2" />
|
|
@@ -38,6 +38,12 @@ export interface DiscussionThreadProps {
|
|
|
38
38
|
sortOrder?: "newest" | "oldest" | "most_liked";
|
|
39
39
|
/** When true, disables interactions */
|
|
40
40
|
readOnly?: boolean;
|
|
41
|
+
/** Render skeleton placeholders instead of content */
|
|
42
|
+
isLoading?: boolean;
|
|
43
|
+
/** Error message — renders an error state with optional retry */
|
|
44
|
+
error?: string | null;
|
|
45
|
+
/** Called when the user clicks retry in the error state */
|
|
46
|
+
onRetry?: () => void;
|
|
41
47
|
/** CSS class name for the root element */
|
|
42
48
|
className?: string;
|
|
43
49
|
/** Inline styles for the root element */
|