fix: refactor layout

feat/course
Arik Chakma 1 month ago
parent 088d4e2e2d
commit 0abddab414
  1. 1
      package.json
  2. 18
      pnpm-lock.yaml
  3. 29
      src/components/Course/ChallengeView.tsx
  4. 33
      src/components/Course/LessonView.tsx
  5. 32
      src/components/Course/QuizView.tsx
  6. 9
      src/components/SqlCodeEditor/sql-code-editor-theme.ts
  7. 10
      src/data/courses/sql/chapters/introduction/lessons/challenge-1.md
  8. 34
      src/pages/learn/[courseId]/[chapterId]/[lessonId].astro
  9. 11
      src/stores/query-client.ts

@ -43,6 +43,7 @@
"@nanostores/react": "^0.7.2",
"@napi-rs/image": "^1.9.2",
"@resvg/resvg-js": "^2.6.2",
"@tanstack/react-query": "^5.59.15",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"astro": "^4.15.4",

@ -50,6 +50,9 @@ importers:
'@resvg/resvg-js':
specifier: ^2.6.2
version: 2.6.2
'@tanstack/react-query':
specifier: ^5.59.15
version: 5.59.15(react@18.3.1)
'@types/react':
specifier: ^18.3.3
version: 18.3.8
@ -1194,6 +1197,14 @@ packages:
peerDependencies:
tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20'
'@tanstack/query-core@5.59.13':
resolution: {integrity: sha512-Oou0bBu/P8+oYjXsJQ11j+gcpLAMpqW42UlokQYEz4dE7+hOtVO9rVuolJKgEccqzvyFzqX4/zZWY+R/v1wVsQ==}
'@tanstack/react-query@5.59.15':
resolution: {integrity: sha512-QbVlAkTI78wB4Mqgf2RDmgC0AOiJqer2c5k9STOOSXGv1S6ZkY37r/6UpE8DbQ2Du0ohsdoXgFNEyv+4eDoPEw==}
peerDependencies:
react: ^18 || ^19
'@tybys/wasm-util@0.9.0':
resolution: {integrity: sha512-6+7nlbMVX/PVDCwaIQ8nTOPveOcFLSt8GcXdx8hD0bt39uWxYT88uXzqTd4fTvqta7oeUJqudepapKNt2DYJFw==}
@ -4288,6 +4299,13 @@ snapshots:
postcss-selector-parser: 6.0.10
tailwindcss: 3.4.13
'@tanstack/query-core@5.59.13': {}
'@tanstack/react-query@5.59.15(react@18.3.1)':
dependencies:
'@tanstack/query-core': 5.59.13
react: 18.3.1
'@tybys/wasm-util@0.9.0':
dependencies:
tslib: 2.7.0

@ -3,46 +3,22 @@ import {
ResizablePanel,
ResizablePanelGroup,
} from '../Resizable';
import { CourseSidebar } from './CourseSidebar';
import { CourseLayout } from './CourseLayout';
import { SqlCodeEditor } from '../SqlCodeEditor/SqlCodeEditor';
import type { ReactNode } from 'react';
import type {
ChapterFileType,
CourseFileType,
LessonFileType,
} from '../../lib/course';
import type { LessonFileType } from '../../lib/course';
type ChallengeViewProps = {
courseId: string;
chapterId: string;
lessonId: string;
title: string;
course: CourseFileType & {
chapters: ChapterFileType[];
};
lesson: LessonFileType;
children: ReactNode;
};
export function ChallengeView(props: ChallengeViewProps) {
const { children, title, course, lesson, courseId, chapterId } = props;
const { chapters } = course;
const { children, lesson } = props;
const { frontmatter } = lesson;
const { defaultValue, initSteps, expectedResults } = frontmatter;
return (
<CourseLayout
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
lesson={lesson}
title={title}
chapters={chapters}
completedPercentage={0}
>
<ResizablePanelGroup direction="horizontal">
<ResizablePanel defaultSize={60} minSize={20}>
<div className="relative h-full">
@ -62,6 +38,5 @@ export function ChallengeView(props: ChallengeViewProps) {
/>
</ResizablePanel>
</ResizablePanelGroup>
</CourseLayout>
);
}

@ -1,46 +1,17 @@
import { useState, type ReactNode } from 'react';
import { CourseSidebar } from './CourseSidebar';
import { CourseLayout } from './CourseLayout';
import { Circle, CircleCheck, CircleX } from 'lucide-react';
import { cn } from '../../lib/classname';
import type {
ChapterFileType,
CourseFileType,
LessonFileType,
} from '../../lib/course';
import { type ReactNode } from 'react';
type LessonViewProps = {
courseId: string;
chapterId: string;
lessonId: string;
title: string;
course: CourseFileType & {
chapters: ChapterFileType[];
};
lesson: LessonFileType;
children: ReactNode;
};
export function LessonView(props: LessonViewProps) {
const { children, title, course, lesson, courseId, chapterId } = props;
const { chapters } = course;
const { children } = props;
return (
<CourseLayout
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
lesson={lesson}
title={title}
chapters={chapters}
completedPercentage={0}
>
<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">{children}</div>
</div>
</div>
</CourseLayout>
);
}

@ -1,28 +1,14 @@
import { useState } from 'react';
import { CourseLayout } from './CourseLayout';
import { Circle, CircleCheck, CircleX } from 'lucide-react';
import { cn } from '../../lib/classname';
import type {
ChapterFileType,
CourseFileType,
LessonFileType,
} from '../../lib/course';
import type { LessonFileType } from '../../lib/course';
type QuizViewProps = {
courseId: string;
chapterId: string;
lessonId: string;
title: string;
course: CourseFileType & {
chapters: ChapterFileType[];
};
lesson: LessonFileType;
};
export function QuizView(props: QuizViewProps) {
const { title, course, lesson, courseId, lessonId, chapterId } = props;
const { chapters } = course;
const { lesson } = props;
const { frontmatter } = lesson;
const { questions = [] } = frontmatter;
@ -45,15 +31,6 @@ export function QuizView(props: QuizViewProps) {
}).length;
return (
<CourseLayout
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
lesson={lesson}
title={title}
chapters={chapters}
completedPercentage={0}
>
<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 py-10">
@ -111,8 +88,8 @@ export function QuizView(props: QuizViewProps) {
{isSubmitted && (
<div className="mt-8 flex items-center justify-between gap-2 rounded-xl border border-zinc-800 p-4">
<span>
You got {correctAnswerCount} out of {questions.length}{' '}
questions right
You got {correctAnswerCount} out of {questions.length} questions
right
</span>
<a className="disabled:cusror-not-allowed rounded-xl border border-zinc-700 bg-zinc-800 p-2 px-4 text-sm font-medium text-white focus:outline-none">
@ -123,7 +100,6 @@ export function QuizView(props: QuizViewProps) {
</div>
</div>
</div>
</CourseLayout>
);
}

@ -14,8 +14,8 @@ export const editorDarkTheme = EditorView.theme(
'.cm-content': {},
// Line number styles
'.cm-lineNumbers .cm-gutterElement': {
color: '#757575', // Text color for line numbers
paddingRight: '1em',
color: '#757575',
minWidth: '24px',
},
// Scrollbar styles
'.cm-scroller': {
@ -25,7 +25,7 @@ export const editorDarkTheme = EditorView.theme(
'.cm-scroller::-webkit-scrollbar': {},
// Highlight active line
'.cm-activeLine': {
backgroundColor: '#27272a', // Active line background color
backgroundColor: '#27272a',
},
// Cursor styles
'.cm-cursor': {
@ -56,6 +56,9 @@ export const editorDarkTheme = EditorView.theme(
border: 'none',
backgroundColor: 'transparent',
},
'& .cm-foldGutter .cm-gutterElement': {
paddingLeft: '4px',
},
},
{
dark: true,

@ -4,9 +4,15 @@ description: Write a SQL query to find the total number of orders in the `orders
order: 300
type: challenge
defaultValue: |
SELECT * FROM orders;
SELECT
*
FROM
orders;
SELECT COUNT(*) FROM orders;
SELECT
COUNT(*)
FROM
orders;
initSteps:
- CREATE TABLE orders (
id INTEGER PRIMARY KEY,

@ -2,6 +2,7 @@
import { ChallengeView } from '../../../../components/Course/ChallengeView';
import { LessonView } from '../../../../components/Course/LessonView';
import { QuizView } from '../../../../components/Course/QuizView';
import { CourseLayout } from '../../../../components/Course/CourseLayout';
import SkeletonLayout from '../../../../layouts/SkeletonLayout.astro';
import {
getAllCourses,
@ -70,17 +71,19 @@ const { course, chapter, lesson } = Astro.props;
---
<SkeletonLayout title={course.frontmatter.title}>
{
lesson.frontmatter.type === 'challenge' && (
<ChallengeView
<CourseLayout
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
title={course.frontmatter.title}
course={course}
lesson={lesson}
title={course.frontmatter.title}
chapters={course.chapters}
completedPercentage={0}
client:load
>
{
lesson.frontmatter.type === 'challenge' && (
<ChallengeView lesson={lesson} client:load>
<div class='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'>
<lesson.Content />
</div>
@ -90,15 +93,7 @@ const { course, chapter, lesson } = Astro.props;
{
lesson.frontmatter.type === 'lesson' && (
<LessonView
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
title={course.frontmatter.title}
course={course}
lesson={lesson}
client:load
>
<LessonView client:load>
<div class='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'>
<lesson.Content />
</div>
@ -108,15 +103,8 @@ const { course, chapter, lesson } = Astro.props;
{
lesson.frontmatter.type === 'quiz' && (
<QuizView
courseId={courseId}
chapterId={chapterId}
lessonId={lesson.id}
title={course.frontmatter.title}
course={course}
lesson={lesson}
client:load
/>
<QuizView lesson={lesson} client:load />
)
}
</CourseLayout>
</SkeletonLayout>

@ -0,0 +1,11 @@
import { QueryCache, QueryClient } from '@tanstack/react-query';
export const queryClient = new QueryClient({
queryCache: new QueryCache({}),
defaultOptions: {
queries: {
retry: false,
enabled: !import.meta.env.SSR,
},
},
});
Loading…
Cancel
Save