Skip to content

Commit 6024ad9

Browse files
committed
extract anime-rate-section component
1 parent acdaa1b commit 6024ad9

File tree

8 files changed

+182
-163
lines changed

8 files changed

+182
-163
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<div
2+
class="anime-rate-section__label"
3+
(ngxVisibility)="onSectionVisible($event)"
4+
>
5+
<ion-text class="anime-rate-section__text">
6+
{{ label() | transloco | uppercase }}
7+
8+
@if (isLoaded()) {
9+
<span class="anime-rate-section__counter">({{ ratesCount() }})</span>
10+
}
11+
</ion-text>
12+
13+
<ion-button
14+
fill="clear"
15+
size="small"
16+
color="medium"
17+
(click)="onToggleHidden()"
18+
>
19+
<ion-icon
20+
class="anime-rate-section__icon"
21+
slot="icon-only"
22+
[name]="isHidden() ? 'chevron-down' : 'chevron-up'"
23+
/>
24+
</ion-button>
25+
</div>
26+
27+
<app-card-grid
28+
class="anime-rate-section__grid"
29+
[class.ion-hide]="isHidden()"
30+
[userAnimeRates]="rates()"
31+
[isLoading]="!isLoaded()"
32+
(ngxVisibility)="onSectionVisible($event)"
33+
/>
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
.anime-rate-section {
2+
&__label {
3+
margin: 0 0 1rem;
4+
padding: 5px 1rem;
5+
display: flex;
6+
justify-content: space-between;
7+
align-items: center;
8+
9+
color: var(--ion-color-dark-tint);
10+
background-color: var(--ion-color-light-tint);
11+
}
12+
13+
&__text {
14+
font-weight: bold;
15+
font-size: 15px;
16+
}
17+
18+
&__icon {
19+
font-size: 25px;
20+
cursor: pointer;
21+
}
22+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {
2+
ChangeDetectionStrategy,
3+
Component,
4+
ViewEncapsulation,
5+
computed,
6+
input,
7+
output,
8+
} from '@angular/core';
9+
import { IonButton, IonIcon, IonText } from '@ionic/angular/standalone';
10+
import { NgxVisibilityDirective } from 'ngx-visibility';
11+
import { TranslocoPipe } from '@jsverse/transloco';
12+
import { UpperCasePipe } from '@angular/common';
13+
14+
import { CardGridComponent } from '@app/modules/home/components/card-grid';
15+
import { UserAnimeRate } from '@app/shared/types/shikimori/user-anime-rate';
16+
17+
@Component({
18+
selector: 'app-anime-rate-section',
19+
imports: [
20+
NgxVisibilityDirective,
21+
TranslocoPipe,
22+
IonIcon,
23+
IonButton,
24+
IonText,
25+
UpperCasePipe,
26+
CardGridComponent,
27+
],
28+
templateUrl: './anime-rate-section.component.html',
29+
styleUrl: './anime-rate-section.component.scss',
30+
encapsulation: ViewEncapsulation.None,
31+
changeDetection: ChangeDetectionStrategy.OnPush,
32+
host: {
33+
'class': 'anime-rate-section',
34+
'[id]': 'status()',
35+
'[class.ion-hide]': 'isSectionHidden(isLoaded(), rates())',
36+
},
37+
})
38+
export class AnimeRateSectionComponent {
39+
label = input.required<string>();
40+
status = input.required<string>();
41+
rates = input.required<UserAnimeRate[]>();
42+
isHidden = input(false);
43+
isLoaded = input(false);
44+
45+
visible = output();
46+
toggleHidden = output();
47+
48+
ratesCount = computed(() => this.rates()?.length || 0);
49+
50+
isSectionHidden(isLoaded: boolean, rates: UserAnimeRate[]): boolean {
51+
return isLoaded && !rates?.length;
52+
}
53+
54+
onSectionVisible(isVisible: boolean): void {
55+
if (isVisible) {
56+
this.visible.emit();
57+
}
58+
}
59+
60+
onToggleHidden(): void {
61+
this.toggleHidden.emit();
62+
}
63+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { AnimeRateSectionComponent } from './anime-rate-section.component';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { CardGridComponent } from './card-grid.component';
Lines changed: 10 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,16 @@
1-
<ion-content [fullscreen]="true" class="page-content">
1+
<ion-content [fullscreen]="true" class="page-content ion-padding">
22
@for (status of animeStatusOrder(); track status) {
33
@let grid = animeGridMap.get(status);
44

5-
<ng-template
6-
[ngTemplateOutlet]="animeRatesGrid"
7-
[ngTemplateOutletContext]="{
8-
label: 'HOME_MODULE.HOME_PAGE.GRIDS.' + (status | uppercase),
9-
status,
10-
rates: grid.rates | async,
11-
isLoaded: grid.isLoaded | async
12-
}"
5+
<app-anime-rate-section
6+
class="home-page__anime-rates"
7+
[label]="'HOME_MODULE.HOME_PAGE.GRIDS.' + (status | uppercase)"
8+
[status]="status"
9+
[rates]="grid.rates | async"
10+
[isLoaded]="grid.isLoaded | async"
11+
[isHidden]="getHiddenGridStatus(status)"
12+
(visible)="onSectionVisibilityChange(status)"
13+
(toggleHidden)="toggleHiddenGridStatus(status)"
1314
/>
1415
}
1516
</ion-content>
16-
17-
<ng-template
18-
#animeRatesGrid
19-
let-label="label"
20-
let-status="status"
21-
let-rates="rates"
22-
let-isLoaded="isLoaded"
23-
>
24-
<section
25-
class="anime-rates"
26-
[id]="status"
27-
[class.ion-hide]="isSectionHidden(isLoaded, rates)"
28-
(ngxVisibility)="onSectionVisibilityChange(status, $event)"
29-
>
30-
<div class="anime-rates__label">
31-
<ion-text class="anime-rates__text">
32-
{{ label | transloco | uppercase }}
33-
34-
@if (isLoaded) {
35-
<span class="anime-rates__counter">({{ rates?.length || 0 }})</span>
36-
}
37-
</ion-text>
38-
39-
<ion-button
40-
[fill]="'clear'"
41-
[size]="'small'"
42-
[color]="'medium'"
43-
(click)="toggleHiddenGridStatus(status)"
44-
>
45-
<ion-icon
46-
class="anime-rates__icon"
47-
slot="icon-only"
48-
[name]="getHiddenGridStatus(status) ? 'chevron-down' : 'chevron-up'"
49-
/>
50-
</ion-button>
51-
</div>
52-
53-
<app-card-grid
54-
class="anime-rates__grid"
55-
[class.ion-hide]="getHiddenGridStatus(status)"
56-
[userAnimeRates]="rates"
57-
[isLoading]="!isLoaded"
58-
/>
59-
</section>
60-
</ng-template>
Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,25 @@
11
@use 'src/scss/mixins' as *;
22

3-
.anime-rates {
4-
padding: 0;
5-
margin: 0;
3+
.home-page {
64

7-
@include media-breakpoint-up('sm') {
8-
margin: .5rem;
9-
}
10-
11-
@include media-breakpoint-up('md') {
12-
margin: 1.25rem;
13-
}
14-
15-
@include media-breakpoint-up('lg') {
16-
margin: 1.5rem 5rem;
17-
}
18-
19-
@include media-breakpoint-up('xl') {
20-
margin: 1.5rem 10rem;
21-
}
22-
23-
&__label {
24-
margin: 0 0 1rem;
25-
padding: 5px 1rem;
5+
&__anime-rates {
266
display: flex;
27-
justify-content: space-between;
28-
align-items: center;
7+
flex-direction: column;
298

30-
color: var(--ion-color-dark-tint);
31-
background-color: var(--ion-color-light-tint);
32-
}
9+
@include media-breakpoint-up('sm') {
10+
margin: .5rem;
11+
}
3312

34-
&__text {
35-
font-weight: bold;
36-
font-size: 15px;
37-
}
13+
@include media-breakpoint-up('md') {
14+
margin: 1.25rem;
15+
}
16+
17+
@include media-breakpoint-up('lg') {
18+
margin: 1.5rem 5rem;
19+
}
3820

39-
&__icon {
40-
font-size: 25px;
41-
cursor: pointer;
21+
@include media-breakpoint-up('xl') {
22+
margin: 1.5rem 10rem;
23+
}
4224
}
4325
}

0 commit comments

Comments
 (0)