Skip to content

Commit 2b5aaa8

Browse files
Francesco MautoAndrea Barbasso
authored andcommitted
Merged in task/dspace-cris-2024_02_x/DSC-2308 (pull request DSpace#5007)
[DSC-2308] add: skeleton loader on browse elements sub components Approved-by: Andrea Barbasso
2 parents bc8a0ea + 95bdb0e commit 2b5aaa8

4 files changed

Lines changed: 94 additions & 21 deletions

File tree

src/app/shared/browse-most-elements/abstract-browse-elements.component.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isPlatformServer } from '@angular/common';
1+
import { isPlatformBrowser } from '@angular/common';
22
import {
33
Component,
44
inject,
@@ -12,6 +12,7 @@ import {
1212
mergeMap,
1313
Observable,
1414
} from 'rxjs';
15+
import { tap } from 'rxjs/operators';
1516

1617
import { APP_CONFIG } from '../../../config/app-config.interface';
1718
import { SearchManager } from '../../core/browse/search-manager';
@@ -88,12 +89,18 @@ export abstract class AbstractBrowseElementsComponent implements OnInit, OnChang
8889

8990
searchResultArray$: Observable<DSpaceObject[]>;
9091

92+
isLoading = true;
93+
94+
isBrowser: boolean;
95+
9196
ngOnChanges() {
9297
this.paginatedSearchOptions$?.next(this.paginatedSearchOptions);
9398
}
9499

95100
ngOnInit() {
96-
if (isPlatformServer(this.platformId)) {
101+
this.isBrowser = isPlatformBrowser(this.platformId);
102+
103+
if (!this.isBrowser) {
97104
return;
98105
}
99106
const followLinks = [];
@@ -121,6 +128,9 @@ export abstract class AbstractBrowseElementsComponent implements OnInit, OnChang
121128
toDSpaceObjectListRD(),
122129
getRemoteDataPayload(),
123130
getPaginatedListPayload(),
131+
tap(() => {
132+
this.isLoading = false;
133+
}),
124134
);
125135
}
126136

Lines changed: 33 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,36 @@
11
<div class="m-2">
2-
<ng-container *ngIf="(searchResults$ | async) as searchResults">
3-
<ul *ngIf="searchResults?.hasSucceeded" class="list-unstyled">
4-
<li *ngFor="let object of searchResults?.payload?.page; let i = index; let last = last" class="mt-4 mb-4 d-flex" [class.border-bottom]="last !== true">
5-
<ds-listable-object-component-loader [context]="context"
6-
[index]="i"
7-
[listID]="paginatedSearchOptions.configuration"
8-
[object]="object"
9-
[showMetrics]="showMetrics"
10-
[showLabel]="showLabel"
11-
[showThumbnails]="showThumbnails"
12-
[viewMode]="paginatedSearchOptions.view"></ds-listable-object-component-loader>
13-
</li>
14-
</ul>
15-
<div *ngIf="searchResults?.hasFailed">
16-
{{ 'remote.error' | translate }}
17-
</div>
2+
<ng-container *ngIf="(searchResults$ | async) as searchResults; else skeleton">
3+
<ul *ngIf="searchResults?.hasSucceeded" class="list-unstyled">
4+
<li *ngFor="let object of searchResults?.payload?.page; let i = index; let last = last" class="mt-4 mb-4 d-flex" [class.border-bottom]="last !== true">
5+
<ds-listable-object-component-loader [context]="context"
6+
[index]="i"
7+
[listID]="paginatedSearchOptions.configuration"
8+
[object]="object"
9+
[showMetrics]="showMetrics"
10+
[showLabel]="showLabel"
11+
[showThumbnails]="showThumbnails"
12+
[viewMode]="paginatedSearchOptions.view"></ds-listable-object-component-loader>
13+
</li>
14+
</ul>
15+
<div *ngIf="searchResults?.hasFailed">
16+
{{ 'remote.error' | translate }}
17+
</div>
1818
</ng-container>
19-
<ds-loading *ngIf="(searchResults$ | async) === null || (searchResults$ | async) === undefined"></ds-loading>
19+
<ng-template #skeleton>
20+
<div *ngFor="let item of skeletonItems" class="skeleton-row row my-4">
21+
<div *ngIf="showThumbnails" class="col-3 col-md-2">
22+
<div class="thumbnail-skeleton">
23+
<ngx-skeleton-loader></ngx-skeleton-loader>
24+
</div>
25+
</div>
26+
<div [class.col-9]="showThumbnails" [class.col-md-10]="showThumbnails" [class.col-12]="!showThumbnails">
27+
<div class="badge-skeleton">
28+
<ngx-skeleton-loader></ngx-skeleton-loader>
29+
</div>
30+
<div class="text-skeleton">
31+
<ngx-skeleton-loader [count]="2"></ngx-skeleton-loader>
32+
</div>
33+
</div>
34+
</div>
35+
</ng-template>
2036
</div>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
:host ::ng-deep {
2+
.skeleton-row {
3+
border-bottom: 1px solid var(--bs-border-color, #dee2e6);
4+
padding-bottom: 1rem;
5+
}
6+
7+
.thumbnail-skeleton {
8+
max-width: var(--ds-thumbnail-max-width, 100%);
9+
height: 100%;
10+
11+
ngx-skeleton-loader .skeleton-loader {
12+
border-radius: 0;
13+
height: 80px;
14+
width: 100%;
15+
}
16+
}
17+
18+
.badge-skeleton {
19+
ngx-skeleton-loader .skeleton-loader {
20+
height: var(--ds-search-skeleton-text-height, 20px);
21+
width: var(--ds-search-skeleton-badge-width, 75px);
22+
}
23+
}
24+
25+
.text-skeleton {
26+
margin-top: 0.5rem;
27+
28+
ngx-skeleton-loader .skeleton-loader {
29+
height: var(--ds-search-skeleton-text-height, 20px);
30+
}
31+
}
32+
33+
ngx-skeleton-loader .skeleton-loader {
34+
background-color: var(--bs-light, #f8f9fa);
35+
box-shadow: none;
36+
}
37+
}

src/app/shared/browse-most-elements/default-browse-elements/default-browse-elements.component.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ import {
99
OnInit,
1010
} from '@angular/core';
1111
import { TranslateModule } from '@ngx-translate/core';
12+
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
1213

13-
import { ThemedLoadingComponent } from '../../loading/themed-loading.component';
1414
import { ListableObjectComponentLoaderComponent } from '../../object-collection/shared/listable-object/listable-object-component-loader.component';
1515
import { AbstractBrowseElementsComponent } from '../abstract-browse-elements.component';
1616

@@ -22,7 +22,7 @@ import { AbstractBrowseElementsComponent } from '../abstract-browse-elements.com
2222
imports: [
2323
ListableObjectComponentLoaderComponent,
2424
TranslateModule,
25-
ThemedLoadingComponent,
25+
NgxSkeletonLoaderModule,
2626
AsyncPipe,
2727
NgIf,
2828
NgForOf,
@@ -33,9 +33,19 @@ export class DefaultBrowseElementsComponent extends AbstractBrowseElementsCompon
3333
protected followMetricsLink: boolean;
3434
protected followThumbnailLink: boolean;
3535

36+
/**
37+
* Array used to render skeleton placeholder items.
38+
* Length matches the configured page size.
39+
*/
40+
skeletonItems: number[];
41+
3642
ngOnInit() {
3743
this.followMetricsLink = this.showMetrics ?? this.appConfig.browseBy.showMetrics;
3844
this.followThumbnailLink = this.showThumbnails ?? this.appConfig.browseBy.showThumbnails;
45+
this.skeletonItems = Array.from(
46+
{ length: this.paginatedSearchOptions?.pagination?.pageSize ?? 5 },
47+
(_, i) => i,
48+
);
3949
super.ngOnInit();
4050
}
4151
}

0 commit comments

Comments
 (0)