mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
[DURACOM-303] add grid layout, make SSR enabling configurable, minor restyle of skeletons
This commit is contained in:
@@ -25,6 +25,14 @@ ssr:
|
||||
inlineCriticalCss: false
|
||||
# Path prefixes to enable SSR for. By default these are limited to paths of primary DSpace objects.
|
||||
paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ]
|
||||
# Whether to enable rendering of Search component on SSR.
|
||||
# If set to true the component will be included in the HTML returned from the server side rendering.
|
||||
# If set to false the component will not be included in the HTML returned from the server side rendering.
|
||||
enableSearchComponent: false,
|
||||
# Whether to enable rendering of Browse component on SSR.
|
||||
# If set to true the component will be included in the HTML returned from the server side rendering.
|
||||
# If set to false the component will not be included in the HTML returned from the server side rendering.
|
||||
enableBrowseComponent: false,
|
||||
|
||||
# The REST API server settings
|
||||
# NOTE: these settings define which (publicly available) REST API to use. They are usually
|
||||
@@ -84,7 +92,7 @@ cache:
|
||||
anonymousCache:
|
||||
# Maximum number of pages to cache. Default is zero (0) which means anonymous user cache is disabled.
|
||||
# As all pages are cached in server memory, increasing this value will increase memory needs.
|
||||
# Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory.
|
||||
# Individual cached pages are usually small (<100KB), so a value of max=1000 would only require ~100MB of memory.
|
||||
max: 0
|
||||
# Amount of time after which cached pages are considered stale (in ms). After becoming stale, the cached
|
||||
# copy is automatically refreshed on the next request.
|
||||
@@ -394,7 +402,7 @@ vocabularies:
|
||||
vocabulary: 'srsc'
|
||||
enabled: true
|
||||
|
||||
# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query.
|
||||
# Default collection/community sorting order at Advanced search, Create/update community and collection when there are not a query.
|
||||
comcolSelectionSort:
|
||||
sortField: 'dc.title'
|
||||
sortDirection: 'ASC'
|
||||
|
@@ -23,6 +23,7 @@ import { Community } from '../../core/shared/community.model';
|
||||
import { APP_CONFIG, AppConfig } from '../../../config/app-config.interface';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
import { isPlatformServer } from "@angular/common";
|
||||
import { environment } from "../../../environments/environment";
|
||||
|
||||
export const BBM_PAGINATION_ID = 'bbm';
|
||||
|
||||
@@ -147,7 +148,8 @@ export class BrowseByMetadataPageComponent implements OnInit, OnDestroy {
|
||||
currentPage: 1,
|
||||
pageSize: this.appConfig.browseBy.pageSize,
|
||||
});
|
||||
}
|
||||
this.renderOnServerSide = environment.ssr.enableBrowseComponent;
|
||||
}
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Component, Inject, Input, OnInit } from '@angular/core';
|
||||
import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
|
||||
|
||||
import { BehaviorSubject, Observable, of as observableOf } from 'rxjs';
|
||||
import { filter, map, startWith, switchMap, take } from 'rxjs/operators';
|
||||
@@ -43,6 +43,8 @@ export class SearchFilterComponent implements OnInit {
|
||||
*/
|
||||
@Input() scope: string;
|
||||
|
||||
@Output() isVisibilityComputed = new EventEmitter<boolean>();
|
||||
|
||||
/**
|
||||
* True when the filter is 100% collapsed in the UI
|
||||
*/
|
||||
@@ -99,6 +101,9 @@ export class SearchFilterComponent implements OnInit {
|
||||
this.filterService.expand(this.filter.name);
|
||||
}
|
||||
});
|
||||
this.active$.pipe(take(1)).subscribe(() => {
|
||||
this.isVisibilityComputed.emit(true);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -1,11 +1,12 @@
|
||||
<h3>{{"search.filters.head" | translate}}</h3>
|
||||
<div *ngIf="(filters | async)?.hasSucceeded; else skeleton;">
|
||||
<div *ngIf="(filters | async)?.hasSucceeded">
|
||||
<div *ngFor="let filter of (filters | async)?.payload; trackBy: trackUpdate">
|
||||
<ds-search-filter [scope]="currentScope" [filter]="filter" [inPlaceSearch]="inPlaceSearch" [refreshFilters]="refreshFilters"></ds-search-filter>
|
||||
<ds-search-filter (isVisibilityComputed)="countFiltersWithComputedVisibility($event)" [scope]="currentScope" [filter]="filter" [inPlaceSearch]="inPlaceSearch" [refreshFilters]="refreshFilters"></ds-search-filter>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ng-template #skeleton>
|
||||
|
||||
<ng-container *ngIf="filtersWithComputedVisibility !== (filters | async)?.payload?.length">
|
||||
<ngx-skeleton-loader [count]="defaultFilterCount"/>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
<a class="btn btn-primary" [routerLink]="[searchLink]" [queryParams]="clearParams | async" queryParamsHandling="merge" role="button"><i class="fas fa-undo"></i> {{"search.filters.reset" | translate}}</a>
|
||||
|
@@ -61,6 +61,11 @@ export class SearchFiltersComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
searchLink: string;
|
||||
|
||||
/**
|
||||
* Filters for which visibility has been computed
|
||||
*/
|
||||
filtersWithComputedVisibility = 0;
|
||||
|
||||
subs = [];
|
||||
defaultFilterCount: number;
|
||||
|
||||
@@ -114,4 +119,10 @@ export class SearchFiltersComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
countFiltersWithComputedVisibility(computed: boolean) {
|
||||
if (computed) {
|
||||
this.filtersWithComputedVisibility += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,24 +1,36 @@
|
||||
<div class="row flex-nowrap">
|
||||
<div class="info-skeleton mb-2 col-12">
|
||||
<div [class.mb-2]="(viewMode$ | async) === ViewMode.ListElement" class="info-skeleton col-12">
|
||||
<ngx-skeleton-loader/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@for (result of loadingResults; track result) {
|
||||
<div class="row flex-nowrap result-row">
|
||||
@if(showThumbnails) {
|
||||
<div class="thumbnail-skeleton">
|
||||
<ngx-skeleton-loader/>
|
||||
@if((viewMode$ | async) === ViewMode.ListElement) {
|
||||
@for (result of loadingResults; track result) {
|
||||
<div class="row flex-nowrap result-row">
|
||||
@if(showThumbnails) {
|
||||
<div class="thumbnail-skeleton">
|
||||
<ngx-skeleton-loader/>
|
||||
</div>
|
||||
}
|
||||
<div [class.col-9]="showThumbnails" [class.col-md-12]="!showThumbnails">
|
||||
<div class="badge-skeleton">
|
||||
<ngx-skeleton-loader/>
|
||||
</div>
|
||||
<div class="text-skeleton">
|
||||
<ngx-skeleton-loader [count]="textLineCount"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
} @else if ((viewMode$ | async) === ViewMode.GridElement) {
|
||||
<div class="card-columns row">
|
||||
@for (result of loadingResults; track result) {
|
||||
<div class="card-column col col-sm-6 col-lg-4">
|
||||
<div class="card-skeleton">
|
||||
<ngx-skeleton-loader/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<div [class.col-9]="showThumbnails" [class.col-md-12]="!showThumbnails">
|
||||
<div class="badge-skeleton">
|
||||
<ngx-skeleton-loader/>
|
||||
</div>
|
||||
<div class="text-skeleton">
|
||||
<ngx-skeleton-loader [count]="textLineCount"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
@@ -1,4 +1,6 @@
|
||||
:host ::ng-deep {
|
||||
--ds-wrapper-grid-spacing: calc(var(--bs-spacer) / 2);
|
||||
|
||||
.info-skeleton, .badge-skeleton, .text-skeleton{
|
||||
ngx-skeleton-loader .skeleton-loader {
|
||||
height: var(--ds-search-skeleton-text-height);
|
||||
@@ -27,13 +29,31 @@
|
||||
}
|
||||
}
|
||||
|
||||
.card-skeleton {
|
||||
ngx-skeleton-loader .skeleton-loader {
|
||||
height: var(--ds-search-skeleton-card-height);
|
||||
}
|
||||
}
|
||||
|
||||
ngx-skeleton-loader .skeleton-loader {
|
||||
background-color: var(--bs-light);
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.card-columns {
|
||||
margin-left: calc(-1 * var(--ds-wrapper-grid-spacing));
|
||||
margin-right: calc(-1 * var(--ds-wrapper-grid-spacing));
|
||||
column-gap: 0;
|
||||
|
||||
.card-column {
|
||||
padding-left: var(--ds-wrapper-grid-spacing);
|
||||
padding-right: var(--ds-wrapper-grid-spacing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.result-row {
|
||||
margin-right: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
|
@@ -1,10 +1,17 @@
|
||||
import {
|
||||
AsyncPipe,
|
||||
NgForOf,
|
||||
} from '@angular/common';
|
||||
import {
|
||||
Component,
|
||||
Input,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { SearchService } from '../../../../core/shared/search/search.service';
|
||||
import { ViewMode } from '../../../../core/shared/view-mode.model';
|
||||
import { hasValue } from '../../../empty.util';
|
||||
|
||||
@Component({
|
||||
@@ -12,6 +19,8 @@ import { hasValue } from '../../../empty.util';
|
||||
standalone: true,
|
||||
imports: [
|
||||
NgxSkeletonLoaderModule,
|
||||
AsyncPipe,
|
||||
NgForOf,
|
||||
],
|
||||
templateUrl: './search-results-skeleton.component.html',
|
||||
styleUrl: './search-results-skeleton.component.scss',
|
||||
@@ -26,8 +35,16 @@ export class SearchResultsSkeletonComponent implements OnInit {
|
||||
@Input()
|
||||
textLineCount = 2;
|
||||
|
||||
public viewMode$: Observable<ViewMode>;
|
||||
|
||||
public loadingResults: number[];
|
||||
|
||||
protected readonly ViewMode = ViewMode;
|
||||
|
||||
constructor(private searchService: SearchService) {
|
||||
this.viewMode$ = searchService.getViewMode();
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.loadingResults = Array.from({ length: this.numberOfResults }, (_, i) => i + 1);
|
||||
|
||||
|
@@ -1,12 +1,10 @@
|
||||
@if ((filters$ | async).length > 0 && isLoading()) {
|
||||
@if ((activeFilters$ | async).length > 0 && (appliedFilters$ | async).length === 0) {
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="d-flex">
|
||||
@for (filter of (filters$| async); track filter.key) {
|
||||
<div class="filter-badge-skeleton mr-2">
|
||||
<ngx-skeleton-loader/>
|
||||
<div class="filters-badge-skeleton-container">
|
||||
<div class="filter-badge-skeleton">
|
||||
<ngx-skeleton-loader [count]="(activeFilters$ | async).length" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -4,7 +4,14 @@
|
||||
background-color: var(--bs-light);
|
||||
box-shadow: none;
|
||||
width: var(--ds-search-skeleton-filter-badge-width);
|
||||
height: var(--ds-search-skeleton-text-height);
|
||||
height: var(--ds-search-skeleton-badge-height);
|
||||
margin-bottom: 0;
|
||||
margin-right: calc(var(--bs-spacer) / 4);
|
||||
}
|
||||
}
|
||||
|
||||
.filters-badge-skeleton-container {
|
||||
display: flex;
|
||||
max-height: var(--ds-search-skeleton-badge-height);
|
||||
}
|
||||
}
|
||||
|
@@ -14,6 +14,7 @@ import { PaginatedSearchOptions } from '../models/paginated-search-options.model
|
||||
import { SearchFilter } from "../models/search-filter.model";
|
||||
import { Observable } from "rxjs";
|
||||
import { SearchConfigurationService } from "../../../core/shared/search/search-configuration.service";
|
||||
import { SearchService } from "../../../core/shared/search/search.service";
|
||||
|
||||
export interface SelectionConfig {
|
||||
repeatable: boolean;
|
||||
@@ -110,7 +111,10 @@ export class SearchResultsComponent {
|
||||
|
||||
@Output() selectObject: EventEmitter<ListableObject> = new EventEmitter<ListableObject>();
|
||||
|
||||
constructor(private searchConfigService: SearchConfigurationService) {
|
||||
constructor(
|
||||
protected searchConfigService: SearchConfigurationService,
|
||||
protected searchService: SearchService,
|
||||
) {
|
||||
this.filters$ = this.searchConfigService.getCurrentFilters();
|
||||
}
|
||||
|
||||
|
@@ -49,6 +49,7 @@ import { COLLECTION_MODULE_PATH } from '../../collection-page/collection-page-ro
|
||||
import { COMMUNITY_MODULE_PATH } from '../../community-page/community-page-routing-paths';
|
||||
import { AppConfig, APP_CONFIG } from '../../../config/app-config.interface';
|
||||
import { isPlatformServer } from "@angular/common";
|
||||
import { environment } from 'src/environments/environment';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-search',
|
||||
@@ -304,6 +305,7 @@ export class SearchComponent implements OnDestroy, OnInit {
|
||||
@Inject(PLATFORM_ID) public platformId: any,
|
||||
) {
|
||||
this.isXsOrSm$ = this.windowService.isXsOrSm();
|
||||
this.renderOnServerSide = environment.universal.enableSearchComponent;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -10,5 +10,7 @@ export const environment: Partial<BuildConfig> = {
|
||||
time: false,
|
||||
inlineCriticalCss: false,
|
||||
paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ],
|
||||
}
|
||||
enableSearchComponent: false,
|
||||
enableBrowseComponent: false,
|
||||
},
|
||||
};
|
||||
|
@@ -13,6 +13,8 @@ export const environment: BuildConfig = {
|
||||
time: false,
|
||||
inlineCriticalCss: false,
|
||||
paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ],
|
||||
enableSearchComponent: false,
|
||||
enableBrowseComponent: false,
|
||||
},
|
||||
|
||||
// Angular Universal server settings.
|
||||
|
@@ -15,7 +15,9 @@ export const environment: Partial<BuildConfig> = {
|
||||
time: false,
|
||||
inlineCriticalCss: false,
|
||||
paths: [ '/home', '/items/', '/entities/', '/collections/', '/communities/', '/bitstream/', '/bitstreams/', '/handle/' ],
|
||||
}
|
||||
enableSearchComponent: false,
|
||||
enableBrowseComponent: false,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@@ -140,6 +140,7 @@
|
||||
--very-dark-cyan: #215E50; // This variable represents the background color of the save cookies button
|
||||
|
||||
--ds-search-skeleton-text-height: 20px;
|
||||
--ds-search-skeleton-badge-height: 18px;
|
||||
--ds-search-skeleton-thumbnail-height: 125px;
|
||||
--ds-search-skeleton-thumbnail-width: 90px;
|
||||
--ds-search-skeleton-thumbnail-padding: 1em;
|
||||
@@ -148,6 +149,7 @@
|
||||
--ds-search-skeleton-badge-width: 75px;
|
||||
--ds-search-skeleton-filter-badge-width: 200px;
|
||||
--ds-search-skeleton-info-width: 200px;
|
||||
--ds-search-skeleton-card-height: 435px;
|
||||
|
||||
--ds-filters-skeleton-height: 40px;
|
||||
--ds-filters-skeleton-spacing: 12px;
|
||||
|
Reference in New Issue
Block a user