From d6abfa5f08c11a06c2b7320b7ddadb9a65d86d65 Mon Sep 17 00:00:00 2001 From: Paul Kuruvilla Date: Fri, 31 Oct 2025 00:00:42 -0700 Subject: [PATCH 01/12] refactor: split introduction and FAQ into separate components Remove the combined IntroductionAndStages component and create a new IntroductionAndFaq component to render the course description and FAQ. Update templates to use IntroductionAndFaq and Stages separately for better separation of concerns and improved maintainability. --- .../introduction-and-faq.hbs | 14 ++++++ .../introduction-and-faq.ts | 18 +++++++ .../introduction-and-stages.ts | 48 ------------------- ...introduction-and-stages.hbs => stages.hbs} | 11 ----- app/components/course-overview-page/stages.ts | 20 ++++++++ app/templates/course-overview.hbs | 3 +- app/templates/join-course.hbs | 3 +- 7 files changed, 56 insertions(+), 61 deletions(-) create mode 100644 app/components/course-overview-page/introduction-and-faq.hbs create mode 100644 app/components/course-overview-page/introduction-and-faq.ts delete mode 100644 app/components/course-overview-page/introduction-and-stages.ts rename app/components/course-overview-page/{introduction-and-stages.hbs => stages.hbs} (56%) create mode 100644 app/components/course-overview-page/stages.ts diff --git a/app/components/course-overview-page/introduction-and-faq.hbs b/app/components/course-overview-page/introduction-and-faq.hbs new file mode 100644 index 0000000000..d03c00fa28 --- /dev/null +++ b/app/components/course-overview-page/introduction-and-faq.hbs @@ -0,0 +1,14 @@ +
+
+
+ {{markdown-to-html @course.descriptionMarkdown}} +
+ + {{#if (gt @course.frequentlyAskedQuestions.length 0)}} + {{! Extra if convinces typescript that frequentlyAskedQuestions is not null }} + {{#if @course.frequentlyAskedQuestions}} + + {{/if}} + {{/if}} +
+
\ No newline at end of file diff --git a/app/components/course-overview-page/introduction-and-faq.ts b/app/components/course-overview-page/introduction-and-faq.ts new file mode 100644 index 0000000000..8e2517553c --- /dev/null +++ b/app/components/course-overview-page/introduction-and-faq.ts @@ -0,0 +1,18 @@ +import Component from '@glimmer/component'; +import type CourseModel from 'codecrafters-frontend/models/course'; + +interface Signature { + Element: HTMLDivElement; + + Args: { + course: CourseModel; + }; +} + +export default class CourseOverviewPageIntroductionAndFaq extends Component {} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'CourseOverviewPage::IntroductionAndFaq': typeof CourseOverviewPageIntroductionAndFaq; + } +} diff --git a/app/components/course-overview-page/introduction-and-stages.ts b/app/components/course-overview-page/introduction-and-stages.ts deleted file mode 100644 index 9dd32cc074..0000000000 --- a/app/components/course-overview-page/introduction-and-stages.ts +++ /dev/null @@ -1,48 +0,0 @@ -import Component from '@glimmer/component'; -import type CourseModel from 'codecrafters-frontend/models/course'; -import type CourseStageModel from 'codecrafters-frontend/models/course-stage'; - -export type Faq = { - query: string; - answerMarkdown: string; -}; - -interface Signature { - Element: HTMLDivElement; - - Args: { - course: CourseModel; - completedStages?: CourseStageModel[]; - }; -} - -export default class CourseOverviewPageIntroductionAndStages extends Component { - faqs: Faq[] = [ - { - query: 'How long does this course take?', - answerMarkdown: - 'This course typically takes 2-4 weeks to complete, depending on your experience level and time commitment. Each stage is designed to be completed in 1-2 hours.', - }, - { - query: 'What will I learn in this course?', - answerMarkdown: - "You'll learn the fundamental concepts and implementation details behind building your own version of this technology. This includes understanding the core algorithms, data structures, and design patterns used in real-world systems.", - }, - { - query: 'Do I need prior experience?', - answerMarkdown: - 'Some programming experience is recommended, but the course is designed to be accessible to developers with basic knowledge of your chosen programming language. Each stage includes detailed explanations and guidance.', - }, - { - query: 'What programming languages are supported?', - answerMarkdown: - 'This course supports multiple programming languages including Python, JavaScript, Go, Rust, Java, C++, and more. You can switch languages at any time during the course.', - }, - ]; -} - -declare module '@glint/environment-ember-loose/registry' { - export default interface Registry { - 'CourseOverviewPage::IntroductionAndStages': typeof CourseOverviewPageIntroductionAndStages; - } -} diff --git a/app/components/course-overview-page/introduction-and-stages.hbs b/app/components/course-overview-page/stages.hbs similarity index 56% rename from app/components/course-overview-page/introduction-and-stages.hbs rename to app/components/course-overview-page/stages.hbs index 49a15ad188..ecf76154bb 100644 --- a/app/components/course-overview-page/introduction-and-stages.hbs +++ b/app/components/course-overview-page/stages.hbs @@ -1,16 +1,5 @@
-
- {{markdown-to-html @course.descriptionMarkdown}} -
- - {{#if (gt @course.frequentlyAskedQuestions.length 0)}} - {{! Extra if convinces typescript that frequentlyAskedQuestions is not null }} - {{#if @course.frequentlyAskedQuestions}} - - {{/if}} - {{/if}} -

Stages diff --git a/app/components/course-overview-page/stages.ts b/app/components/course-overview-page/stages.ts new file mode 100644 index 0000000000..c505846509 --- /dev/null +++ b/app/components/course-overview-page/stages.ts @@ -0,0 +1,20 @@ +import Component from '@glimmer/component'; +import type CourseModel from 'codecrafters-frontend/models/course'; +import type CourseStageModel from 'codecrafters-frontend/models/course-stage'; + +interface Signature { + Element: HTMLDivElement; + + Args: { + course: CourseModel; + completedStages?: CourseStageModel[]; + }; +} + +export default class CourseOverviewPageStages extends Component {} + +declare module '@glint/environment-ember-loose/registry' { + export default interface Registry { + 'CourseOverviewPage::Stages': typeof CourseOverviewPageStages; + } +} diff --git a/app/templates/course-overview.hbs b/app/templates/course-overview.hbs index cc75671f47..bf7921bfae 100644 --- a/app/templates/course-overview.hbs +++ b/app/templates/course-overview.hbs @@ -6,7 +6,8 @@
- + +

-
+
{{markdown-to-html @descriptionMarkdown}}
From 061809ca4d52037464530e0f5d08ea2f5f390c5d Mon Sep 17 00:00:00 2001 From: Paul Kuruvilla Date: Fri, 31 Oct 2025 17:50:05 -0700 Subject: [PATCH 12/12] feat(course-overview): add collapsible stage list cards Make stage list cards collapsible with a default collapsed state for extensions. This introduces an expand button overlay to reveal full content when collapsed, preventing excessive initial content height. Update titles to conditionally show "Base Stages" only if extensions are present, otherwise show "Stages". This improves clarity and UI consistency for courses with and without extensions. --- .../course-overview-page/stage-list-card-list.hbs | 7 ++++++- .../course-overview-page/stage-list-card.hbs | 13 ++++++++++++- .../course-overview-page/stage-list-card.ts | 12 +++++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/components/course-overview-page/stage-list-card-list.hbs b/app/components/course-overview-page/stage-list-card-list.hbs index cf46c85b42..63e7a215d6 100644 --- a/app/components/course-overview-page/stage-list-card-list.hbs +++ b/app/components/course-overview-page/stage-list-card-list.hbs @@ -1,11 +1,16 @@
- + {{#each @course.sortedExtensions as |extension|}} {{/each}}
\ No newline at end of file diff --git a/app/components/course-overview-page/stage-list-card.hbs b/app/components/course-overview-page/stage-list-card.hbs index b6d099c2aa..c49f700d4f 100644 --- a/app/components/course-overview-page/stage-list-card.hbs +++ b/app/components/course-overview-page/stage-list-card.hbs @@ -1,5 +1,6 @@
@@ -15,4 +16,14 @@
+ + {{#unless this.isExpanded}} +
+ + Click to expand + +
+ {{/unless}}
\ No newline at end of file diff --git a/app/components/course-overview-page/stage-list-card.ts b/app/components/course-overview-page/stage-list-card.ts index c6bdd88aa2..fc30bf3f09 100644 --- a/app/components/course-overview-page/stage-list-card.ts +++ b/app/components/course-overview-page/stage-list-card.ts @@ -1,5 +1,7 @@ import Component from '@glimmer/component'; import type CourseStageModel from 'codecrafters-frontend/models/course-stage'; +import { tracked } from '@glimmer/tracking'; +import { action } from '@ember/object'; interface Signature { Element: HTMLDivElement; @@ -8,10 +10,18 @@ interface Signature { title: string; descriptionMarkdown: string; stages: CourseStageModel[]; + isCollapsedByDefault?: boolean; }; } -export default class CourseOverviewPageStageListCard extends Component {} +export default class CourseOverviewPageStageListCard extends Component { + @tracked isExpanded = !this.args.isCollapsedByDefault; + + @action + handleExpandClick() { + this.isExpanded = true; + } +} declare module '@glint/environment-ember-loose/registry' { export default interface Registry {