From a831810487b07d1137a144ad6c7719249a752a59 Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Wed, 16 Oct 2024 21:55:23 +0600 Subject: [PATCH] wip --- src/components/Course/ChallengeView.tsx | 60 ++++++----- src/components/Course/Chapter.tsx | 87 +++++++++++++--- src/components/Course/CourseLayout.tsx | 8 +- src/components/Course/CourseSidebar.tsx | 20 +++- src/components/Course/LessonView.tsx | 29 +++++- src/components/Course/QuizView.tsx | 99 +++++++------------ .../introduction/lessons/challenge-1.md | 4 +- .../chapters/introduction/lessons/quiz-1.md | 67 +++++++++++++ src/layouts/SkeletonLayout.astro | 2 +- src/lib/course.ts | 10 ++ .../[courseId]/[chapterId]/[lessonId].astro | 56 ++++++++++- src/pages/learn-sql/index.astro | 27 ----- 12 files changed, 321 insertions(+), 148 deletions(-) create mode 100644 src/data/courses/sql/chapters/introduction/lessons/quiz-1.md delete mode 100644 src/pages/learn-sql/index.astro diff --git a/src/components/Course/ChallengeView.tsx b/src/components/Course/ChallengeView.tsx index 5938d8e68..af32ad66f 100644 --- a/src/components/Course/ChallengeView.tsx +++ b/src/components/Course/ChallengeView.tsx @@ -3,36 +3,46 @@ import { ResizablePanel, ResizablePanelGroup, } from '../Resizable'; -import { CourseSidebar, type CourseSidebarProps } from './CourseSidebar'; +import { CourseSidebar } from './CourseSidebar'; import { CourseLayout } from './CourseLayout'; -import { - SqlCodeEditor, - type SqlCodeEditorProps, -} from '../SqlCodeEditor/SqlCodeEditor'; +import { SqlCodeEditor } from '../SqlCodeEditor/SqlCodeEditor'; import type { ReactNode } from 'react'; +import type { + ChapterFileType, + CourseFileType, + LessonFileType, +} from '../../lib/course'; + +type ChallengeViewProps = { + courseId: string; + chapterId: string; + lessonId: string; -type ChallengeViewProps = SqlCodeEditorProps & - CourseSidebarProps & { - children: ReactNode; + title: string; + course: CourseFileType & { + chapters: ChapterFileType[]; }; + lesson: LessonFileType; + children: ReactNode; +}; export function ChallengeView(props: ChallengeViewProps) { - const { - children, - title, - chapters, - completedPercentage, - ...sqlCodeEditorProps - } = props; + const { children, title, course, lesson, courseId, lessonId, chapterId } = + props; + const { chapters } = course; - return ( - - + const { frontmatter } = lesson; + const { defaultValue, initSteps, expectedResults } = frontmatter; + return ( +
@@ -45,7 +55,11 @@ export function ChallengeView(props: ChallengeViewProps) { - + diff --git a/src/components/Course/Chapter.tsx b/src/components/Course/Chapter.tsx index 756283d86..22447115b 100644 --- a/src/components/Course/Chapter.tsx +++ b/src/components/Course/Chapter.tsx @@ -1,17 +1,16 @@ import { Check } from 'lucide-react'; import { cn } from '../../lib/classname'; -import type { - ChallengeFileType, - ChapterFileType, - LessonFileType, - QuizFileType, -} from '../../lib/course'; +import type { ChapterFileType, LessonFileType } from '../../lib/course'; +import { useMemo } from 'react'; type ChapterProps = ChapterFileType & { index: number; isActive?: boolean; isCompleted?: boolean; + courseId: string; + chapterId: string; + lessonId?: string; onChapterClick?: () => void; }; @@ -20,12 +19,35 @@ export function Chapter(props: ChapterProps) { index, frontmatter, lessons, - exercises, isActive = false, onChapterClick, + + courseId, + chapterId, + lessonId, } = props; const { title } = frontmatter; + const exercises = useMemo( + () => + lessons + ?.filter( + (lesson) => + lesson.frontmatter.type === 'quiz' || + lesson.frontmatter.type === 'challenge', + ) + ?.sort((a, b) => a.frontmatter.order - b.frontmatter.order) || [], + [lessons], + ); + + const filteredLessons = useMemo( + () => + lessons + ?.filter((lesson) => lesson.frontmatter.type === 'lesson') + ?.sort((a, b) => a.frontmatter.order - b.frontmatter.order) || [], + [lessons], + ); + return (
)} @@ -68,21 +112,34 @@ export function Chapter(props: ChapterProps) { ); } -type LessonProps = (LessonFileType | QuizFileType | ChallengeFileType) & { +type LessonProps = LessonFileType & { + courseId: string; + chapterId: string; + isActive?: boolean; isCompleted?: boolean; }; export function Lesson(props: LessonProps) { - const { frontmatter, isCompleted, isActive } = props; + const { + frontmatter, + isCompleted, + isActive, + courseId, + chapterId, + id: lessonId, + } = props; const { title } = frontmatter; + const href = `/courses/${courseId}/${chapterId}/${lessonId}`; + return (
{isCompleted && } diff --git a/src/components/Course/CourseLayout.tsx b/src/components/Course/CourseLayout.tsx index e0e35d149..838c91156 100644 --- a/src/components/Course/CourseLayout.tsx +++ b/src/components/Course/CourseLayout.tsx @@ -1,12 +1,16 @@ +import { CourseSidebar, type CourseSidebarProps } from './CourseSidebar'; + type CourseLayoutProps = { children: React.ReactNode; -}; +} & CourseSidebarProps; export function CourseLayout(props: CourseLayoutProps) { - const { children } = props; + const { children, ...sidebarProps } = props; return (
+ + {children}
); diff --git a/src/components/Course/CourseSidebar.tsx b/src/components/Course/CourseSidebar.tsx index b13a4cb3f..91d1a902f 100644 --- a/src/components/Course/CourseSidebar.tsx +++ b/src/components/Course/CourseSidebar.tsx @@ -3,6 +3,10 @@ import type { ChapterFileType } from '../../lib/course'; import { Chapter } from './Chapter'; export type CourseSidebarProps = { + courseId: string; + chapterId: string; + lessonId: string; + title: string; chapters: ChapterFileType[]; @@ -10,9 +14,16 @@ export type CourseSidebarProps = { }; export function CourseSidebar(props: CourseSidebarProps) { - const { title, chapters, completedPercentage } = props; + const { + title, + chapters, + completedPercentage, + chapterId, + lessonId, + courseId, + } = props; - const [activeChapterId, setActiveChapterId] = useState(''); + const [activeChapterId, setActiveChapterId] = useState(chapterId); return (