From 0abddab41402639f5a09d5a07e6c429fc703d7ae Mon Sep 17 00:00:00 2001 From: Arik Chakma Date: Sat, 19 Oct 2024 00:46:22 +0600 Subject: [PATCH] fix: refactor layout --- package.json | 1 + pnpm-lock.yaml | 18 ++ src/components/Course/ChallengeView.tsx | 61 ++----- src/components/Course/LessonView.tsx | 41 +---- src/components/Course/QuizView.tsx | 158 ++++++++---------- .../SqlCodeEditor/sql-code-editor-theme.ts | 9 +- .../introduction/lessons/challenge-1.md | 12 +- .../[courseId]/[chapterId]/[lessonId].astro | 82 ++++----- src/stores/query-client.ts | 11 ++ 9 files changed, 171 insertions(+), 222 deletions(-) create mode 100644 src/stores/query-client.ts diff --git a/package.json b/package.json index ba683956e..967fc9d42 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 088a3325b..4ea0f9ea1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -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 diff --git a/src/components/Course/ChallengeView.tsx b/src/components/Course/ChallengeView.tsx index 83c0118c3..32e66bded 100644 --- a/src/components/Course/ChallengeView.tsx +++ b/src/components/Course/ChallengeView.tsx @@ -3,65 +3,40 @@ 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 ( - - - -
-
-
{children}
-
+ + +
+
+
{children}
- +
+
- + - - - -
- + + + + ); } diff --git a/src/components/Course/LessonView.tsx b/src/components/Course/LessonView.tsx index cd6ef2840..49c8f3238 100644 --- a/src/components/Course/LessonView.tsx +++ b/src/components/Course/LessonView.tsx @@ -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 ( - -
-
-
{children}
-
+
+
+
{children}
- +
); } diff --git a/src/components/Course/QuizView.tsx b/src/components/Course/QuizView.tsx index 6002e695d..f932a8066 100644 --- a/src/components/Course/QuizView.tsx +++ b/src/components/Course/QuizView.tsx @@ -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,85 +31,75 @@ export function QuizView(props: QuizViewProps) { }).length; return ( - -
-
-
-

- SQL Quiz: Intermediate -

- -
- {questions.map((question) => { - return ( - { - const selectedOptionId = selectedOptions?.[question.id]; - - let optionStatus: QuizOptionStatus = 'default'; - if (option.isCorrectOption && isSubmitted) { - optionStatus = 'correct'; - } else if (selectedOptionId === option.id) { - optionStatus = isSubmitted ? 'wrong' : 'selected'; - } - - return { - ...option, - status: optionStatus, - }; - })} - onOptionSelectChange={(id, optionId) => { - setSelectedOptions((prev) => ({ - ...prev, - [id]: optionId, - })); - }} - selectedOptionId={selectedOptions?.[question.id]} - /> - ); - })} -
- -
- -
+
+
+
+

+ SQL Quiz: Intermediate +

+ +
+ {questions.map((question) => { + return ( + { + const selectedOptionId = selectedOptions?.[question.id]; + + let optionStatus: QuizOptionStatus = 'default'; + if (option.isCorrectOption && isSubmitted) { + optionStatus = 'correct'; + } else if (selectedOptionId === option.id) { + optionStatus = isSubmitted ? 'wrong' : 'selected'; + } + + return { + ...option, + status: optionStatus, + }; + })} + onOptionSelectChange={(id, optionId) => { + setSelectedOptions((prev) => ({ + ...prev, + [id]: optionId, + })); + }} + selectedOptionId={selectedOptions?.[question.id]} + /> + ); + })} +
- {isSubmitted && ( -
- - You got {correctAnswerCount} out of {questions.length}{' '} - questions right - - - - Move to Next Lesson - -
- )} +
+
+ + {isSubmitted && ( +
+ + You got {correctAnswerCount} out of {questions.length} questions + right + + + + Move to Next Lesson + +
+ )}
- +
); } diff --git a/src/components/SqlCodeEditor/sql-code-editor-theme.ts b/src/components/SqlCodeEditor/sql-code-editor-theme.ts index 38eef5163..18c65545d 100644 --- a/src/components/SqlCodeEditor/sql-code-editor-theme.ts +++ b/src/components/SqlCodeEditor/sql-code-editor-theme.ts @@ -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, diff --git a/src/data/courses/sql/chapters/introduction/lessons/challenge-1.md b/src/data/courses/sql/chapters/introduction/lessons/challenge-1.md index 9e1f220db..b5b024b1b 100644 --- a/src/data/courses/sql/chapters/introduction/lessons/challenge-1.md +++ b/src/data/courses/sql/chapters/introduction/lessons/challenge-1.md @@ -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 COUNT(*) FROM orders; + SELECT + * + FROM + orders; + + SELECT + COUNT(*) + FROM + orders; initSteps: - CREATE TABLE orders ( id INTEGER PRIMARY KEY, diff --git a/src/pages/learn/[courseId]/[chapterId]/[lessonId].astro b/src/pages/learn/[courseId]/[chapterId]/[lessonId].astro index d3aa4f639..2e69cbdd1 100644 --- a/src/pages/learn/[courseId]/[chapterId]/[lessonId].astro +++ b/src/pages/learn/[courseId]/[chapterId]/[lessonId].astro @@ -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,53 +71,40 @@ const { course, chapter, lesson } = Astro.props; --- - { - lesson.frontmatter.type === 'challenge' && ( - -
- -
-
- ) - } + + { + lesson.frontmatter.type === 'challenge' && ( + +
+ +
+
+ ) + } - { - lesson.frontmatter.type === 'lesson' && ( - -
- -
-
- ) - } + { + lesson.frontmatter.type === 'lesson' && ( + +
+ +
+
+ ) + } - { - lesson.frontmatter.type === 'quiz' && ( - - ) - } + { + lesson.frontmatter.type === 'quiz' && ( + + ) + } +
diff --git a/src/stores/query-client.ts b/src/stores/query-client.ts new file mode 100644 index 000000000..210d1d733 --- /dev/null +++ b/src/stores/query-client.ts @@ -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, + }, + }, +});