-
Notifications
You must be signed in to change notification settings - Fork 18
feat: add Rust language support and concept group handling #2672
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
2195670
1e7a2bf
7894d20
fb8444b
5ad4450
f8f8a0c
c55dd1c
9b3b339
ee325c6
7856172
7b7df65
eaf5b41
4dc1eac
405abc6
3d4b614
58a5138
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
<LinkTo | ||
@route="concept" | ||
@models={{array @concept.slug}} | ||
class="block hover:bg-gray-50 dark:hover:bg-gray-700/50 py-1.5 -mx-1.5 px-1.5 rounded" | ||
data-test-concept-list-item | ||
...attributes | ||
> | ||
<div class="flex items-center justify-between"> | ||
<div class="flex items-center"> | ||
<div class="w-2 h-2 {{if @isComplete 'bg-teal-500' 'bg-gray-200 dark:bg-gray-700'}} rounded-full mr-2"></div> | ||
|
||
{{! TODO: Qualify all heroicons with solid/outline }} | ||
{{svg-jar "book-open-outline" class="w-6 mr-2 text-gray-400 dark:text-gray-600"}} | ||
|
||
<div class="prose dark:prose-invert prose-sm"> | ||
{{@concept.title}} | ||
</div> | ||
</div> | ||
|
||
{{#if @isComplete}} | ||
{{svg-jar "check" class="ml-1 w-5 text-teal-500"}} | ||
{{else}} | ||
<div class="flex items-center gap-1 pl-4 flex-shrink-0"> | ||
<span class="text-xs text-gray-400 dark:text-gray-600"> | ||
{{@concept.estimatedReadingTimeInMinutes}} | ||
mins | ||
</span> | ||
|
||
{{svg-jar "clock" class="w-4 fill-current text-gray-300 dark:text-gray-700"}} | ||
</div> | ||
{{/if}} | ||
|
||
<EmberTooltip @text={{@concept.descriptionMarkdown}} /> | ||
</div> | ||
</LinkTo> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import Component from '@glimmer/component'; | ||
import type AuthenticatorService from 'codecrafters-frontend/services/authenticator'; | ||
import type ConceptModel from 'codecrafters-frontend/models/concept'; | ||
import { service } from '@ember/service'; | ||
|
||
interface Signature { | ||
Element: HTMLAnchorElement; | ||
|
||
Args: { | ||
isComplete: boolean; | ||
concept: ConceptModel; | ||
}; | ||
} | ||
|
||
export default class ConceptListItemComponent extends Component<Signature> { | ||
@service declare authenticator: AuthenticatorService; | ||
} | ||
|
||
declare module '@glint/environment-ember-loose/registry' { | ||
export default interface Registry { | ||
'TrackPage::PrimerConceptGroupSection::ConceptListItem': typeof ConceptListItemComponent; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{{#each this.sortedConcepts as |concept|}} | ||
<TrackPage::PrimerConceptGroupSection::ConceptListItem @concept={{concept}} @isComplete={{false}} /> | ||
{{/each}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import Component from '@glimmer/component'; | ||
import ConceptGroupModel from 'codecrafters-frontend/models/concept-group'; | ||
import ConceptModel from 'codecrafters-frontend/models/concept'; | ||
import Store from '@ember-data/store'; | ||
import { inject as service } from '@ember/service'; | ||
|
||
interface Signature { | ||
Element: HTMLDivElement; | ||
|
||
Args: { | ||
conceptGroup: ConceptGroupModel; | ||
}; | ||
} | ||
|
||
export default class ConceptListComponent extends Component<Signature> { | ||
@service declare store: Store; | ||
|
||
get sortedConcepts() { | ||
return this.args.conceptGroup.conceptSlugs.reduce((acc, slug) => { | ||
const concept = this.store.peekAll('concept').find((concept) => concept.slug === slug); | ||
|
||
if (concept) { | ||
acc.push(concept); | ||
} | ||
|
||
return acc; | ||
}, [] as ConceptModel[]); | ||
} | ||
} | ||
|
||
declare module '@glint/environment-ember-loose/registry' { | ||
export default interface Registry { | ||
'TrackPage::PrimerConceptGroupSection::ConceptList': typeof ConceptListComponent; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
{{! template-lint-disable no-invalid-interactive }} | ||
<div | ||
class="relative group/concept-group-section {{unless this.conceptListIsExpanded 'cursor-pointer'}}" | ||
{{on "click" this.handleSectionClick}} | ||
role={{if this.conceptListIsExpanded "region" "button"}} | ||
...attributes | ||
data-test-primer-concept-group-section | ||
> | ||
<div class="border-b pb-1 mb-4 flex items-center gap-2 {{unless this.conceptListIsExpanded 'group-hover/concept-group-section:border-gray-300'}}"> | ||
<div class="text-2xl font-semibold text-gray-800 dark:text-gray-200"> | ||
{{@language.name}} | ||
Basics | ||
</div> | ||
<Pill @color="green"> | ||
FREE | ||
<EmberTooltip @text="These interactive guides are 100% free to access." /> | ||
</Pill> | ||
</div> | ||
|
||
<div class="prose dark:prose-invert mb-4"> | ||
<p> | ||
New to | ||
{{@language.name}}? Start with our interactive byte-sized guides that cover the basics. | ||
</p> | ||
</div> | ||
|
||
<div class={{if this.conceptListIsExpanded "" "h-60 overflow-hidden"}}> | ||
<TrackPage::PrimerConceptGroupSection::ConceptList @conceptGroup={{@conceptGroup}} /> | ||
|
||
{{#if this.conceptListIsExpanded}} | ||
<div class="flex items-center justify-center mt-2"> | ||
<PrimaryButton {{on "click" this.handleCollapseButtonClick}}> | ||
↑ Collapse ↑ | ||
</PrimaryButton> | ||
</div> | ||
{{else}} | ||
<div class="absolute top-20 bottom-0 left-0 right-0 vertical-mask dark:vertical-mask-gray-850 rounded-b-md p-4 flex items-end justify-center"> | ||
{{#if this.authenticator.isAuthenticated}} | ||
<PrimaryButton class="mb-4 group-hover/concept-group-section:bg-teal-600 w-full sm:w-auto"> | ||
↓ Show all ↓ | ||
</PrimaryButton> | ||
{{else}} | ||
<PrimaryButton class="mb-4 group-hover/concept-group-section:bg-teal-600 w-full sm:w-auto"> | ||
<span>Start learning →</span> | ||
</PrimaryButton> | ||
{{/if}} | ||
</div> | ||
{{/if}} | ||
</div> | ||
</div> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import Component from '@glimmer/component'; | ||
import ConceptGroupModel from 'codecrafters-frontend/models/concept-group'; | ||
import LanguageModel from 'codecrafters-frontend/models/language'; | ||
import { tracked } from '@glimmer/tracking'; | ||
import { action } from '@ember/object'; | ||
import { next } from '@ember/runloop'; | ||
import { service } from '@ember/service'; | ||
import type AuthenticatorService from 'codecrafters-frontend/services/authenticator'; | ||
import type RouterService from '@ember/routing/router-service'; | ||
|
||
interface Signature { | ||
Element: HTMLDivElement; | ||
|
||
Args: { | ||
language: LanguageModel; | ||
conceptGroup: ConceptGroupModel; | ||
}; | ||
} | ||
|
||
export default class TrackPagePrimerConceptGroupSectionComponent extends Component<Signature> { | ||
@service declare authenticator: AuthenticatorService; | ||
@service declare router: RouterService; | ||
|
||
@tracked conceptListIsExpanded = false; | ||
|
||
Comment on lines
+20
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent ❓ Verification inconclusiveAdd tests for component state management. The
🏁 Script executed: #!/bin/bash
# Check if test file exists
fd -t f "primer-concept-group-section-test.ts" app/components/track-page/ Length of output: 73 Add tests for component state management in TrackPagePrimerConceptGroupSectionComponent. It appears that the test file (
🧰 Tools🪛 GitHub Check: codecov/patch[warning] 25-25: app/components/track-page/primer-concept-group-section/index.ts#L25 |
||
@action | ||
handleCollapseButtonClick() { | ||
next(() => { | ||
this.conceptListIsExpanded = false; | ||
}); | ||
} | ||
|
||
@action | ||
handleSectionClick() { | ||
if (this.conceptListIsExpanded) { | ||
return; | ||
} | ||
|
||
if (this.authenticator.isAuthenticated) { | ||
this.conceptListIsExpanded = true; | ||
} else { | ||
this.router.transitionTo('concept', this.args.conceptGroup.conceptSlugs[0]!); | ||
} | ||
} | ||
Comment on lines
+33
to
+44
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainAdd comprehensive tests for section click handler. The
🏁 Script executed: #!/bin/bash
# Description: Check test coverage for authentication paths
# Look for existing tests covering authentication scenarios
rg -l "authenticator\.isAuthenticated.*conceptListIsExpanded" app/components/track-page/
rg -l "router\.transitionTo.*concept" app/components/track-page/ Length of output: 221 Enhance Test Coverage for The
These tests will safeguard the action's functionality and ensure robust handling of different authentication states. 🧰 Tools🪛 GitHub Check: codecov/patch[warning] 37-37: app/components/track-page/primer-concept-group-section/index.ts#L37 [warning] 41-41: app/components/track-page/primer-concept-group-section/index.ts#L41 [warning] 43-43: app/components/track-page/primer-concept-group-section/index.ts#L43 |
||
} | ||
|
||
declare module '@glint/environment-ember-loose/registry' { | ||
export default interface Registry { | ||
'TrackPage::PrimerConceptGroupSection': typeof TrackPagePrimerConceptGroupSectionComponent; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use findAll() instead of peekAll() for reliable data fetching.
The current implementation has potential issues:
peekAll()
only returns already loaded records, which could miss concepts if they haven't been loaded yet.Consider this implementation:
The static analysis indicates missing test coverage. Let's add tests:
🧰 Tools
🪛 GitHub Check: codecov/patch
[warning] 20-21: app/components/track-page/primer-concept-group-section/concept-list.ts#L20-L21
Added lines #L20 - L21 were not covered by tests
[warning] 24-24: app/components/track-page/primer-concept-group-section/concept-list.ts#L24
Added line #L24 was not covered by tests
[warning] 27-27: app/components/track-page/primer-concept-group-section/concept-list.ts#L27
Added line #L27 was not covered by tests