Skip to content

Commit ac94394

Browse files
committed
feat: add concept list and item components for track page
Implement the `ConceptList` and `ConceptListItem` components to display sorted concepts on the track page. Introduce a new SVG icon for visual representation. Update the card layout for better spacing and remove an unused SVG. These changes enhance the user interface and improve the organization of concept information.
1 parent f49b5b7 commit ac94394

File tree

10 files changed

+156
-3
lines changed

10 files changed

+156
-3
lines changed

app/components/track-page/card.hbs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
{{#if @isComplete}}
3232
{{svg-jar "check-circle" class="w-8 h-8 fill-current text-teal-500"}}
3333
{{else if (and @logoImageUrl @logoImageAltText)}}
34-
<img src={{@logoImageUrl}} alt={{@logoImageAltText}} class="w-8 md:w-12 transform scale-100 group-hover:scale-105 transition-all" />
34+
<img src={{@logoImageUrl}} alt={{@logoImageAltText}} class="w-8 transform scale-100 group-hover:scale-105 transition-all" />
3535
{{/if}}
3636
</div>
3737
</div>

app/components/track-page/course-card.hbs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
</:afterTitle>
1515

1616
<:default>
17-
<div class="leading-6 prose dark:prose-invert mb-6">
17+
<div class="leading-6 prose dark:prose-invert mb-4 pr-8">
1818
{{markdown-to-html this.introductionMarkdown}}
1919
</div>
2020

@@ -53,7 +53,7 @@
5353
</div>
5454
{{/if}}
5555

56-
<div class="leading-6 prose dark:prose-invert mb-6 pr-8 md:pr-12">
56+
<div class="leading-6 prose dark:prose-invert mb-4 pr-8">
5757
{{markdown-to-html this.introductionMarkdown}}
5858
</div>
5959

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<LinkTo
2+
@route="concept"
3+
@models={{array @concept.slug}}
4+
class="block hover:bg-gray-50 dark:hover:bg-gray-700/50 py-1.5 -mx-1.5 px-1.5 rounded"
5+
data-test-concept-list-item
6+
...attributes
7+
>
8+
<div class="flex items-center justify-between">
9+
<div class="flex items-center">
10+
<div class="w-2 h-2 {{if @isComplete 'bg-teal-500' 'bg-gray-200 dark:bg-gray-700'}} rounded-full mr-2"></div>
11+
12+
{{! TODO: Qualify all heroicons with solid/outline }}
13+
{{svg-jar "book-open-outline" class="w-6 mr-2 text-gray-400 dark:text-gray-600"}}
14+
15+
<div class="prose dark:prose-invert prose-sm">
16+
{{@concept.title}}
17+
</div>
18+
</div>
19+
20+
{{#if @isComplete}}
21+
{{svg-jar "check" class="ml-1 w-5 text-teal-500"}}
22+
{{else}}
23+
<div class="items-center gap-1 pl-4 hidden sm:flex flex-shrink-0">
24+
{{svg-jar "clock" class="w-4 fill-current text-gray-300 dark:text-gray-700"}}
25+
26+
<span class="text-xs text-gray-400 dark:text-gray-600">
27+
{{@concept.estimatedReadingTimeInMinutes}}
28+
mins
29+
</span>
30+
</div>
31+
{{/if}}
32+
</div>
33+
</LinkTo>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import Component from '@glimmer/component';
2+
import type AuthenticatorService from 'codecrafters-frontend/services/authenticator';
3+
import type ConceptModel from 'codecrafters-frontend/models/concept';
4+
import { service } from '@ember/service';
5+
6+
interface Signature {
7+
Element: HTMLAnchorElement;
8+
9+
Args: {
10+
isComplete: boolean;
11+
concept: ConceptModel;
12+
};
13+
}
14+
15+
export default class ConceptListItemComponent extends Component<Signature> {
16+
@service declare authenticator: AuthenticatorService;
17+
}
18+
19+
declare module '@glint/environment-ember-loose/registry' {
20+
export default interface Registry {
21+
'TrackPage::PrimerConceptGroupCard::ConceptListItem': typeof ConceptListItemComponent;
22+
}
23+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{{#each this.sortedConcepts as |concept|}}
2+
<TrackPage::PrimerConceptGroupCard::ConceptListItem @concept={{concept}} @isComplete={{false}} />
3+
{{/each}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import Component from '@glimmer/component';
2+
import ConceptGroupModel from 'codecrafters-frontend/models/concept-group';
3+
import ConceptModel from 'codecrafters-frontend/models/concept';
4+
import Store from '@ember-data/store';
5+
import { inject as service } from '@ember/service';
6+
7+
interface Signature {
8+
Element: HTMLDivElement;
9+
10+
Args: {
11+
conceptGroup: ConceptGroupModel;
12+
};
13+
}
14+
15+
export default class TrackPagePrimerConceptGroupCardConceptListComponent extends Component<Signature> {
16+
@service declare store: Store;
17+
18+
get sortedConcepts() {
19+
return this.args.conceptGroup.conceptSlugs.reduce((acc, slug) => {
20+
const concept = this.store.peekAll('concept').find((concept) => concept.slug === slug);
21+
22+
if (concept) {
23+
acc.push(concept);
24+
}
25+
26+
return acc;
27+
}, [] as ConceptModel[]);
28+
}
29+
}
30+
31+
declare module '@glint/environment-ember-loose/registry' {
32+
export default interface Registry {
33+
'TrackPage::PrimerConceptGroupCard::ConceptList': typeof TrackPagePrimerConceptGroupCardConceptListComponent;
34+
}
35+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<TrackPage::Card
2+
@isComplete={{false}}
3+
@logoImageAltText={{@language.name}}
4+
@logoImageUrl={{@language.colorLogoUrl}}
5+
@title="Rust Primer"
6+
@recentParticipants={{array}}
7+
...attributes
8+
>
9+
<:afterTitle>
10+
<Pill @color="green">
11+
FREE
12+
</Pill>
13+
</:afterTitle>
14+
15+
<:default>
16+
<div class="leading-6 prose dark:prose-invert mb-4">
17+
New to Rust? Start with our interactive concepts that cover the basics.
18+
</div>
19+
20+
<TrackPage::PrimerConceptGroupCard::ConceptList @conceptGroup={{@conceptGroup}} />
21+
</:default>
22+
</TrackPage::Card>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import Component from '@glimmer/component';
2+
import ConceptGroupModel from 'codecrafters-frontend/models/concept-group';
3+
import LanguageModel from 'codecrafters-frontend/models/language';
4+
5+
interface Signature {
6+
Element: HTMLDivElement;
7+
8+
Args: {
9+
language: LanguageModel;
10+
conceptGroup: ConceptGroupModel;
11+
};
12+
}
13+
14+
export default class TrackPagePrimerConceptGroupCardComponent extends Component<Signature> {}
15+
16+
declare module '@glint/environment-ember-loose/registry' {
17+
export default interface Registry {
18+
'TrackPage::PrimerConceptGroupCard': typeof TrackPagePrimerConceptGroupCardComponent;
19+
}
20+
}

app/templates/track.hbs

+17
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,23 @@
1010
<div class="container mx-auto lg:max-w-screen-lg px-3 md:px-6 py-6 md:py-10">
1111
<div class="flex items-start">
1212
<div class="flex-grow">
13+
{{#if this.trackPrimerConceptGroup}}
14+
<TrackPage::PrimerConceptGroupCard @language={{@model.language}} @conceptGroup={{this.trackPrimerConceptGroup}} class="w-full mb-6" />
15+
16+
<div class="border-b pb-1 mb-4 flex">
17+
<div class="text-2xl font-semibold text-gray-800 dark:text-gray-200">
18+
{{@model.language.name}}
19+
Projects
20+
</div>
21+
</div>
22+
23+
<div class="prose dark:prose-invert mb-4">
24+
<p>
25+
Ready to get your hands dirty? Here are some projects you can build.
26+
</p>
27+
</div>
28+
{{/if}}
29+
1330
<TrackPage::CourseCardList @language={{@model.language}} @courses={{this.sortedCourses}} class="w-full mb-4" />
1431
</div>
1532

0 commit comments

Comments
 (0)