fix: refactor course layout

feat/course
Arik Chakma 3 weeks ago
parent ca0708ab46
commit cf26debab4
  1. 39
      src/components/Course/ChallengeView.tsx
  2. 5
      src/components/Course/CourseLayout.tsx
  3. 86
      src/components/Course/CourseView.tsx
  4. 33
      src/components/Course/LessonQuizView.tsx
  5. 21
      src/components/Course/LessonView.tsx
  6. 41
      src/pages/learn/[courseId]/[chapterId]/[lessonId].astro

@ -1,39 +0,0 @@
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from '../Resizable';
import { SqlCodeEditor } from '../SqlCodeEditor/SqlCodeEditor';
import type { ReactNode } from 'react';
import type { LessonFileType } from '../../lib/course';
import { LessonView } from './LessonView';
type ChallengeViewProps = {
lesson: LessonFileType;
children: ReactNode;
};
export function ChallengeView(props: ChallengeViewProps) {
const { children, lesson } = props;
const { frontmatter } = lesson;
const { defaultValue, initSteps, expectedResults } = frontmatter;
return (
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={60} minSize={20}>
<LessonView>{children}</LessonView>
</ResizablePanel>
<ResizableHandle withHandle={true} />
<ResizablePanel defaultSize={40} minSize={20}>
<SqlCodeEditor
defaultValue={defaultValue}
initSteps={initSteps}
expectedResults={expectedResults}
/>
</ResizablePanel>
</ResizablePanelGroup>
);
}

@ -12,7 +12,7 @@ import { getPercentage } from '../../helper/number';
import { cn } from '../../lib/classname';
import { CourseNotes } from '../CourseNotes/CourseNotes';
type CourseLayoutProps = {
export type CourseLayoutProps = {
children: React.ReactNode;
} & Omit<CourseSidebarProps, 'completedPercentage'>;
@ -67,7 +67,8 @@ export function CourseLayout(props: CourseLayoutProps) {
const handleCompleteLesson = () => {
if (isCurrentLessonCompleted) {
window.location.href = nextLessonLink;
window.location.href =
nextLessonLink || `/learn/${activeCourseId}/certificate`;
return;
}

@ -0,0 +1,86 @@
import { lazy, type ReactNode } from 'react';
import type { LessonFileType } from '../../lib/course';
import { CourseLayout, type CourseLayoutProps } from './CourseLayout';
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from '../Resizable';
const SqlCodeEditor = lazy(() =>
import('../SqlCodeEditor/SqlCodeEditor').then((module) => ({
default: module.SqlCodeEditor,
})),
);
const QuizView = lazy(() =>
import('./QuizView').then((module) => ({
default: module.QuizView,
})),
);
type CourseViewProps = Omit<CourseLayoutProps, 'children'> & {
lesson: LessonFileType;
children?: ReactNode;
};
export function CourseView(props: CourseViewProps) {
const { lesson, children, ...courseLayoutProps } = props;
const { frontmatter } = lesson;
const lessonType = frontmatter.type;
const { defaultValue, initSteps, expectedResults } = frontmatter;
const isTextualLesson = [
'lesson',
'lesson-challenge',
'lesson-quiz',
].includes(lessonType);
return (
<CourseLayout {...courseLayoutProps}>
<ResizablePanelGroup direction="horizontal">
{children && (isTextualLesson || lessonType === 'challenge') && (
<ResizablePanel
defaultSize={lessonType === 'lesson' ? 100 : 60}
minSize={20}
>
<div className="relative h-full">
<div className="absolute inset-0 overflow-y-auto [scrollbar-color:#3f3f46_#27272a;]">
<div className="mx-auto max-w-xl p-4">
<div className="course-content prose prose-lg prose-invert mt-8 text-zinc-300 prose-headings:mb-3 prose-headings:mt-8 prose-code:text-zinc-100 prose-li:my-1 prose-thead:border-zinc-800 prose-tr:border-zinc-800">
{children}
</div>
</div>
</div>
</div>
</ResizablePanel>
)}
{lessonType !== 'lesson' && (
<>
<ResizableHandle withHandle={true} />
<ResizablePanel
defaultSize={lessonType === 'quiz' ? 100 : 40}
minSize={20}
>
{(lessonType === 'challenge' ||
lessonType === 'lesson-challenge') && (
<SqlCodeEditor
defaultValue={defaultValue}
initSteps={initSteps}
expectedResults={expectedResults}
/>
)}
{(lessonType === 'quiz' || lessonType === 'lesson-quiz') && (
<QuizView lesson={lesson} />
)}
</ResizablePanel>
</>
)}
</ResizablePanelGroup>
</CourseLayout>
);
}

@ -1,33 +0,0 @@
import {
ResizableHandle,
ResizablePanel,
ResizablePanelGroup,
} from '../Resizable';
import { SqlCodeEditor } from '../SqlCodeEditor/SqlCodeEditor';
import type { ReactNode } from 'react';
import type { LessonFileType } from '../../lib/course';
import { LessonView } from './LessonView';
import { QuizView } from './QuizView';
type LessonQuizViewProps = {
lesson: LessonFileType;
children: ReactNode;
};
export function LessonQuizView(props: LessonQuizViewProps) {
const { children, lesson } = props;
return (
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={50} minSize={20}>
<LessonView>{children}</LessonView>
</ResizablePanel>
<ResizableHandle withHandle={true} />
<ResizablePanel defaultSize={50} minSize={20}>
<QuizView lesson={lesson} />
</ResizablePanel>
</ResizablePanelGroup>
);
}

@ -1,21 +0,0 @@
import { type ReactNode } from 'react';
type LessonViewProps = {
children: ReactNode;
};
export function LessonView(props: LessonViewProps) {
const { children } = props;
return (
<div className="relative h-full">
<div className="absolute inset-0 overflow-y-auto [scrollbar-color:#3f3f46_#27272a;]">
<div className="mx-auto max-w-xl p-4">
<div className="course-content prose prose-lg prose-invert mt-8 text-zinc-300 prose-headings:mb-3 prose-headings:mt-8 prose-code:text-zinc-100 prose-li:my-1 prose-thead:border-zinc-800 prose-tr:border-zinc-800">
{children}
</div>
</div>
</div>
</div>
);
}

@ -1,9 +1,5 @@
---
import { ChallengeView } from '../../../../components/Course/ChallengeView';
import { LessonView } from '../../../../components/Course/LessonView';
import { QuizView } from '../../../../components/Course/QuizView';
import { LessonQuizView } from '../../../../components/Course/LessonQuizView';
import { CourseLayout } from '../../../../components/Course/CourseLayout';
import { CourseView } from '../../../../components/Course/CourseView';
import SkeletonLayout from '../../../../layouts/SkeletonLayout.astro';
import {
getAllCourses,
@ -72,7 +68,7 @@ const { course, chapter, lesson } = Astro.props;
---
<SkeletonLayout title={course.frontmatter.title}>
<CourseLayout
<CourseView
activeCourseId={courseId}
activeChapterId={chapterId}
activeLessonId={lesson.id}
@ -81,35 +77,6 @@ const { course, chapter, lesson } = Astro.props;
chapters={course.chapters}
client:load
>
{
(lesson.frontmatter.type === 'challenge' ||
lesson.frontmatter.type === 'lesson-challenge') && (
<ChallengeView lesson={lesson} client:load>
<lesson.Content />
</ChallengeView>
)
}
{
lesson.frontmatter.type === 'lesson' && (
<LessonView client:load>
<lesson.Content />
</LessonView>
)
}
{
lesson.frontmatter.type === 'quiz' && (
<QuizView lesson={lesson} client:load />
)
}
{
lesson.frontmatter.type === 'lesson-quiz' && (
<LessonQuizView lesson={lesson} client:load>
<lesson.Content />
</LessonQuizView>
)
}
</CourseLayout>
<lesson.Content />
</CourseView>
</SkeletonLayout>

Loading…
Cancel
Save