Skip to content
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

feat(paginator): add paginator component #12

Merged
merged 10 commits into from
Sep 18, 2024
1 change: 1 addition & 0 deletions packages/sdg/src/_index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

@forward './lib/breadcrumb/breadcrumb-theme' as breadcrumb-*;
@forward './lib/navigation/navigation-theme' as navigation-*;
@forward './lib/paginator/paginator-theme' as paginator-*;
4 changes: 4 additions & 0 deletions packages/sdg/src/lib/core/theme/_all-theme.scss
Original file line number Diff line number Diff line change
@@ -1,24 +1,28 @@
@use '../style/overrides';
@use '../../breadcrumb/breadcrumb-theme' as breadcrumb;
@use '../../navigation/navigation-theme' as navigation;
@use '../../paginator/paginator-theme' as paginator;

@mixin all-component-themes($theme) {
@include breadcrumb.theme($theme);
@include navigation.theme($theme);
@include paginator.theme($theme);
@include overrides.override-igo2-lib-themes($theme);
@include overrides.override-material-themes($theme);
}

@mixin all-component-colors($theme) {
@include breadcrumb.color($theme);
@include navigation.color($theme);
@include paginator.color($theme);
@include overrides.override-igo2-lib-colors($theme);
@include overrides.override-material-colors($theme);
}

@mixin all-component-densities($theme) {
@include breadcrumb.density($theme);
@include navigation.density($theme);
@include paginator.density($theme);
@include overrides.override-igo2-lib-densities($theme);
@include overrides.override-material-densities($theme);
}
23 changes: 23 additions & 0 deletions packages/sdg/src/lib/paginator/_paginator-theme.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@use 'sass:map';
@use '@angular/material' as mat;

@mixin theme($theme) {
@include color($theme);
@include density($theme);
}

@mixin color($theme) {
}

@mixin density($theme) {
$theme: map.merge(
$theme,
(
density: -2
)
);

sdg-paginator {
@include mat.icon-button-density($theme);
}
}
1 change: 1 addition & 0 deletions packages/sdg/src/lib/paginator/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './paginator.component';
68 changes: 68 additions & 0 deletions packages/sdg/src/lib/paginator/paginator.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<div class="container">
@if (currentPageIndex !== 0) {
<button mat-icon-button class="button" (click)="goToPreviousPage()">
<mat-icon class="chevron" color="primary">chevron_left</mat-icon>
</button>
}
@for (firstPageIndex of firstPagesIndexes; track firstPageIndex) {
<p
class="page"
[class.active]="firstPageIndex === currentPageIndex"
(click)="goToPage(firstPageIndex)"
(keyup.enter)="goToPage(firstPageIndex)"
[tabindex]="firstPageIndex !== currentPageIndex ? '0' : '-1'"
>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Est-ce qu'on pourrait convertir en bouton icone pour améliorer l'accessibilité?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ça pourrait être intéressant, mais du CSS du mat-button à ajuster pour les différents états qui je pense n'est pas idéal. J'ai modifié le html pour ajouté un keyup event et du focus.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, j'ai l'impression qu'avec le <button mat-icon-button ... tu serais arrivé au même résultat mais en utilisant les composantes de bouton.

Copy link
Collaborator Author

@LAMM26 LAMM26 Sep 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

En fait c'est visible en faisant un hover sur les chevrons Previous et Next qui ont une ombre ciculaire au lieu de rectangulaire comme dans le SDG. Peut-être en utilisant un button régulier. Je peux tester.

{{ firstPageIndex + 1 }}
</p>
}
@if (
(!middlePagesIndexes.length && lastPagesIndexes.length === 1) ||
middlePagesIndexes.length
) {
<p class="ellipsis">...</p>
}
@for (middlePageIndex of middlePagesIndexes; track middlePageIndex) {
<p
class="page"
[class.active]="middlePageIndex === currentPageIndex"
(click)="goToPage(middlePageIndex)"
(keyup.enter)="goToPage(middlePageIndex)"
[tabindex]="middlePageIndex !== currentPageIndex ? '0' : '-1'"
>
{{ middlePageIndex + 1 }}
</p>
}
@if (
(!middlePagesIndexes.length && firstPagesIndexes.length === 1) ||
middlePagesIndexes.length
) {
<p class="ellipsis">...</p>
}
@for (lastPageIndex of lastPagesIndexes; track lastPageIndex) {
<p
class="page"
[class.active]="lastPageIndex === currentPageIndex"
(click)="goToPage(lastPageIndex)"
(keyup.enter)="goToPage(lastPageIndex)"
[tabindex]="lastPageIndex !== currentPageIndex ? '0' : '-1'"
>
{{ lastPageIndex + 1 }}
</p>
}
@for (pageIndex of pagesIndexes; track pageIndex) {
<p
class="page"
[class.active]="pageIndex === currentPageIndex"
(click)="goToPage(pageIndex)"
(keyup.enter)="goToPage(pageIndex)"
[tabindex]="pageIndex !== currentPageIndex ? '0' : '-1'"
>
{{ pageIndex + 1 }}
</p>
}
@if (currentPageIndex !== nbOfPages - 1) {
<button mat-icon-button (click)="goToNextPage()">
<mat-icon class="chevron" color="primary">chevron_right</mat-icon>
</button>
}
</div>
54 changes: 54 additions & 0 deletions packages/sdg/src/lib/paginator/paginator.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@use '../core/theme/colors';

.container {
display: flex;
align-items: center;
justify-content: center;
}

.page {
color: colors.$blue-piv;
margin: 0;
line-height: 40px;
cursor: pointer;
min-width: 40px;
height: 40px;
text-align: center;

&:focus {
outline: 2px solid colors.$blue-light;
}

&.active {
color: colors.$blue-dark;
font-weight: bold;
outline: none;
cursor: default;

&:hover {
background-color: transparent;
}
}

&:hover {
background-color: colors.$grey-pale;
}

&:active {
outline: none;
background-color: colors.$blue-pale;
}
}

.ellipsis {
color: colors.$blue-dark;
margin: 0;
line-height: 40px;
min-width: 40px;
height: 40px;
text-align: center;
}

.chevron {
font-variation-settings: 'wght' 400;
}
26 changes: 26 additions & 0 deletions packages/sdg/src/lib/paginator/paginator.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { TEST_CONFIG } from '../../test-config';
import { PaginatorComponent } from './paginator.component';

describe('PaginatorComponent', () => {
let component: PaginatorComponent;
let fixture: ComponentFixture<PaginatorComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [PaginatorComponent],
providers: [...TEST_CONFIG.providers!]
}).compileComponents();

fixture = TestBed.createComponent(PaginatorComponent);
component = fixture.componentInstance;
fixture.componentRef.setInput('listLength', 15);
fixture.componentRef.setInput('pageSize', 10);
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
164 changes: 164 additions & 0 deletions packages/sdg/src/lib/paginator/paginator.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
import { DOCUMENT, NgFor, NgIf, NgStyle } from '@angular/common';
import {
ChangeDetectionStrategy,
Component,
Inject,
Injector,
OnInit,
effect,
inject,
input,
output
} from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatIconModule } from '@angular/material/icon';

import { IgoLanguageModule } from '@igo2/core/language';

@Component({
selector: 'sdg-paginator',
standalone: true,
imports: [
NgIf,
NgFor,
NgStyle,
IgoLanguageModule,
MatButtonModule,
MatIconModule
],
changeDetection: ChangeDetectionStrategy.OnPush,
templateUrl: './paginator.component.html',
styleUrls: ['./paginator.component.scss']
})
export class PaginatorComponent implements OnInit {
constructor(@Inject(DOCUMENT) private document: Document) {
effect(() => {
const pageSize = this.pageSize();
if (!this.initialPageIndexFirstChange) {
this.currentPageIndex = 0;
this.pageChange.emit(this.currentPageIndex);

this.getNbOfPages(pageSize);
} else {
this.initialPageIndexFirstChange = false;
}
});
}
injector = inject(Injector);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Il y a deux manière d'injecter dans Angular et tu utilises les deux dans la même composante, soit injecter dans le constructeur (ex: private document: Document) ou directement comme tu le fais. Il n'y a pas de bonne ou mauvaise mais idéallement on utilise un ou l'autre.


listLength = input.required<number>();
pageSize = input.required<number>();
middlePagesMaxRange = input<number>(1);
initialPageIndex = input<number>(0);
isHandset = input<boolean>();

pageChange = output<number>();

initialPageIndexFirstChange = true;

currentPageIndex = 0;
nbOfPages = 0;

firstPagesIndexes: number[] = [];
middlePagesIndexes: number[] = [];
lastPagesIndexes: number[] = [];
pagesIndexes: number[] = [];
Comment on lines +62 to +65
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Même ces paramètres auraient pu être convertie en computed (Signal). Il y a surement un niveau de complexité vu qu'il y a beaucoup de manipulation et dépendances. Cela pourrait être un nice to have éventuellement...


ngOnInit() {
this.currentPageIndex = this.initialPageIndex();

this.getNbOfPages(this.pageSize());
}

private getNbOfPages(pageSize: number) {
this.nbOfPages = Math.ceil(this.listLength() / pageSize);

this.getPages();
}

private createPagesArray(startIndex: number, finishIndex: number) {
return Array.from(
{ length: finishIndex - startIndex + 1 },
(_, a) => a + startIndex
);
}

private getPages() {
this.firstPagesIndexes = [];
this.middlePagesIndexes = [];
this.lastPagesIndexes = [];
this.pagesIndexes = [];

if (this.nbOfPages > 6) {
this.firstPagesIndexes = this.getFirstPages();
this.middlePagesIndexes = this.getMiddlePages();
this.lastPagesIndexes = this.getLastPages();
} else {
this.pagesIndexes = Array.from({ length: this.nbOfPages }, (v, k) => k);
}

this.document
.getElementsByTagName('sdg-header')
.item(0)
?.scrollIntoView(true);
}

private getFirstPages() {
if (this.currentPageIndex <= 2) {
return this.createPagesArray(0, 2);
} else {
return this.createPagesArray(0, 0);
}
}

private getMiddlePages() {
if (
this.currentPageIndex >= 3 &&
this.currentPageIndex <= this.nbOfPages - 4
) {
return this.createPagesArray(
!this.isHandset() &&
this.currentPageIndex - this.middlePagesMaxRange() > 1
? this.currentPageIndex - this.middlePagesMaxRange()
: this.currentPageIndex - 1,
!this.isHandset() &&
this.currentPageIndex + this.middlePagesMaxRange() <
this.nbOfPages - 2
? this.currentPageIndex + this.middlePagesMaxRange()
: this.currentPageIndex + 1
);
} else {
return [];
}
}

private getLastPages() {
if (this.currentPageIndex >= this.nbOfPages - 3) {
return this.createPagesArray(this.nbOfPages - 3, this.nbOfPages - 1);
} else {
return this.createPagesArray(this.nbOfPages - 1, this.nbOfPages - 1);
}
}

goToPreviousPage() {
if (this.currentPageIndex !== 0) {
this.currentPageIndex -= 1;
this.getPages();
this.pageChange.emit(this.currentPageIndex);
}
}

goToPage(pageIndex: number) {
this.currentPageIndex = pageIndex;
this.getPages();
this.pageChange.emit(this.currentPageIndex);
}

goToNextPage() {
if (this.currentPageIndex !== this.nbOfPages - 1) {
this.currentPageIndex += 1;
this.getPages();
this.pageChange.emit(this.currentPageIndex);
}
}
}
1 change: 1 addition & 0 deletions packages/sdg/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export * from './lib/screen';
export * from './lib/alert';
export * from './lib/notice';
export * from './lib/tile';
export * from './lib/paginator';
export * from './lib/consult';
Loading
Loading