Skip to content

Commit 6b342ac

Browse files
FrancescoMolinaroAndrea Barbasso
authored andcommitted
Merged in task/ux-plus-2023_02_x/UXP-205 (pull request #28)
[UXP-205] port glam implementation for grid section bg, adapt tests Approved-by: Andrea Barbasso
2 parents 9886cb0 + c2c80f7 commit 6b342ac

6 files changed

Lines changed: 236 additions & 58 deletions

File tree

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,31 @@
1-
<div class="grid-container">
2-
<div style="grid-area: title" class="bg-light p-5 border border-dark position-relative">
3-
<p class="mb-3 text-muted main-content-badge">{{maincontentBadge}}</p>
4-
<h1 class="text-muted main-content-title">
5-
{{maincontentTitle}}
6-
</h1>
7-
<h1 class="text-dark main-content-subtitle">
8-
{{maincontentSubtitle}}
9-
</h1>
10-
<p class="mt-3 pl-0 text-muted col-8">
11-
{{maincontentAbstract}}
12-
</p>
13-
<button type="button" (click)="goToMainContentLink()" class="btn btn-dark position-absolute m-5">{{'explore.grid-section.seeAll' | translate}}</button>
1+
<div class="grid-container py-5">
2+
<div class="cris-section-element-background path-title">
3+
<div class="inner-container d-flex flex-column justify-content-center gap-3 h-100">
4+
<div class="main-content-badge mb-3">{{maincontentBadge | translate}}</div>
5+
<h2>
6+
<div class="main-content-title-1">
7+
{{ maincontentTitle | translate }}
8+
</div>
9+
<div class="main-content-title-2">
10+
{{ maincontentSubtitle | translate }}
11+
</div>
12+
</h2>
13+
<p class="main-content-text text-muted">
14+
{{ maincontentAbstract | translate }}
15+
</p>
16+
<div class="align-self-end">
17+
<button type="button" class="btn btn-dark" (click)="goToMainContentLink()">
18+
{{'explore.grid-section.seeAll' | translate}}
19+
</button>
20+
</div>
21+
</div>
1422
</div>
15-
<div class="bg-light text-center position-relative border border-dark d-flex flex-column
16-
justify-content-between align-items-center"
23+
<div class="cris-section-element-background text-center position-relative d-flex flex-column
24+
justify-content-between align-items-center path-item"
25+
[dsBackgroundImage]="(itemToImageHrefMap$ | async).get(item.indexableObject?.uuid)"
1726
*ngFor="let item of searchResults | slice:0:8; index as i">
18-
<ds-thumbnail [thumbnail]="item.indexableObject?.thumbnail | async" [limitWidth]="false"
19-
[defaultImage]="'assets/images/replacement_image.svg'"
20-
[alt]="'menu.header.image.logo' | translate" [keepAspectRatio]="true">
21-
</ds-thumbnail>
22-
<h5 class="text-dark text-truncate position-absolute py-3 px-1">{{item.indexableObject?.firstMetadataValue('dc.title')}}</h5>
27+
<a [routerLink]="[getItemPageRoute(item.indexableObject)]" class="mw-100 p-3">
28+
<p class="text-center m-0 text-truncate">{{item.indexableObject?.firstMetadataValue('dc.title')}}</p>
29+
</a>
2330
</div>
2431
</div>
Lines changed: 88 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,102 @@
1+
.main-content {
2+
&-title, &-subtitle {
3+
font-weight: var(--ds-home-page-title-size);
4+
}
5+
6+
&-text {
7+
overflow: hidden; // TODO find better solution
8+
font-size: 1.15rem;
9+
}
10+
11+
&-badge {
12+
font-size: 1.2rem;
13+
}
14+
15+
&-title-1 {
16+
color: var(--bs-headings-color)
17+
}
18+
19+
&-title-2 {
20+
color: var(--bs-body-color)
21+
}
22+
23+
&-badge, &-title-1, &-title-2 {
24+
font-weight: 900;
25+
}
26+
27+
}
28+
129
.grid-container {
230
width: 100%;
331
display: grid;
4-
grid-gap: 1em;
5-
6-
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
7-
grid-template-rows: repeat(6, 1fr);
8-
grid-template-areas:
9-
"title title"
10-
"title title"
11-
"item-0 item-1"
12-
"item-2 item-3"
13-
"item-4 item-5"
14-
"item-6 item-7";
15-
16-
@include media-breakpoint-up(lg) {
17-
grid-template-columns: repeat(4, minmax(0, 1fr));
18-
grid-template-rows: repeat(3, 1fr);
19-
grid-template-areas:
20-
"title title item-0 item-1"
21-
"title title item-2 item-3"
22-
"item-4 item-5 item-6 item-7";
32+
grid-gap: 24px;
33+
34+
.path-title {
35+
border: 1px solid var(--bs-link-hover-color) !important;
36+
padding: 4rem;
37+
}
38+
39+
@include media-breakpoint-up(xl) {
40+
grid-template-columns: repeat(4, minmax(240px, 1fr));
41+
.path-title, .path-item {
42+
aspect-ratio: 1;
43+
}
44+
.path-title {
45+
grid-row-end: span 2;
46+
grid-column-end: span 2;
47+
}
48+
}
49+
50+
@include media-breakpoint-between(md, lg) {
51+
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
52+
.path-title, .path-item {
53+
aspect-ratio: 1;
54+
}
55+
.path-title {
56+
grid-row-end: span 2;
57+
grid-column-end: span 2;
58+
}
59+
}
60+
61+
@include media-breakpoint-down(sm) {
62+
grid-template-columns: 1fr;
63+
.path-title {
64+
aspect-ratio: unset;
65+
}
66+
.path-item {
67+
aspect-ratio: 1;
68+
}
69+
}
70+
71+
@media (min-width: 4000px) {
72+
// when the screen is zoomed out to 25%
73+
grid-template-columns: repeat(auto-fit, minmax(60px, 1fr));
74+
75+
.path-title {
76+
aspect-ratio: 0;
77+
}
78+
79+
.path-title {
80+
grid-row-end: span 1;
81+
grid-column-end: span 1;
82+
}
2383
}
2484
}
2585

26-
h5 {
86+
a {
87+
position: absolute;
2788
bottom: 0.5em;
28-
background-color: white;
2989
width: 90%;
90+
background-color: rgba(255, 255, 255, .7);
91+
padding: .6em;
92+
border-radius: $border-radius;
93+
z-index: 2;
3094
}
3195

32-
.main-content-badge, .main-content-title, .main-content-subtitle {
96+
.main-content-badge, .main-content-title-1, .main-content-title-2 {
3397
font-weight: 900;
3498
}
3599

36-
button {
37-
bottom: 0;
38-
right: 0;
100+
.main-content-title-1, .main-content-title-2 {
101+
font-size: var(--ds-cris-path-section-title-font-size);
39102
}

src/app/shared/explore/section-component/grid-section/grid-section.component.spec.ts

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { CommonModule } from '@angular/common';
2-
import { NO_ERRORS_SCHEMA } from '@angular/core';
2+
import { ChangeDetectorRef, NO_ERRORS_SCHEMA } from '@angular/core';
33
import { ComponentFixture, inject, TestBed, waitForAsync } from '@angular/core/testing';
44
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
55
import { BrowserModule } from '@angular/platform-browser';
@@ -17,6 +17,17 @@ import { createSuccessfulRemoteDataObject$ } from '../../../remote-data.utils';
1717
import { LocaleService } from '../../../../core/locale/locale.service';
1818
import { Site } from '../../../../core/shared/site.model';
1919
import { of } from 'rxjs';
20+
import { ObjectCacheService } from '../../../../core/cache/object-cache.service';
21+
import { getMockObjectCacheService } from '../../../mocks/object-cache.service.mock';
22+
import { UUIDService } from '../../../../core/shared/uuid.service';
23+
import { getMockUUIDService } from '../../../mocks/uuid.service.mock';
24+
import { provideMockStore } from '@ngrx/store/testing';
25+
import { RemoteDataBuildService } from '../../../../core/cache/builders/remote-data-build.service';
26+
import { getMockRemoteDataBuildService } from '../../../mocks/remote-data-build.service.mock';
27+
import { HALEndpointService } from '../../../../core/shared/hal-endpoint.service';
28+
import { DSOChangeAnalyzer } from '../../../../core/data/dso-change-analyzer.service';
29+
import { BitstreamFormatDataService } from '../../../../core/data/bitstream-format-data.service';
30+
import { NotificationsService } from '../../../notifications/notifications.service';
2031

2132
describe('GridSectionComponent', () => {
2233
let component: GridSectionComponent;
@@ -32,7 +43,6 @@ describe('GridSectionComponent', () => {
3243
});
3344

3445
const firstSearchResult = Object.assign(new SearchResult(), {
35-
_embedded: {
3646
indexableObject: Object.assign(new DSpaceObject(), {
3747
id: 'd317835d-7b06-4219-91e2-1191900cb897',
3848
uuid: 'd317835d-7b06-4219-91e2-1191900cb897',
@@ -46,11 +56,9 @@ describe('GridSectionComponent', () => {
4656
return '';
4757
},
4858
})
49-
}
5059
});
5160

5261
const secondSearchResult = Object.assign(new SearchResult(), {
53-
_embedded: {
5462
indexableObject: Object.assign(new DSpaceObject(), {
5563
id: '0c34d491-b5ed-4a78-8b29-83d0bad80e5a',
5664
uuid: '0c34d491-b5ed-4a78-8b29-83d0bad80e5a',
@@ -59,7 +67,6 @@ describe('GridSectionComponent', () => {
5967
return '';
6068
},
6169
})
62-
}
6370
});
6471

6572
beforeEach(waitForAsync(() => {
@@ -81,6 +88,19 @@ describe('GridSectionComponent', () => {
8188
providers: [GridSectionComponent,
8289
{ provide: SearchService, useValue: searchServiceStub },
8390
{ provide: LocaleService, useValue: mockLocaleService },
91+
{ provide: ObjectCacheService, useValue: getMockObjectCacheService() },
92+
{ provide: UUIDService, useValue: getMockUUIDService() },
93+
{ provide: RemoteDataBuildService, useValue: getMockRemoteDataBuildService() },
94+
{ provide: HALEndpointService, useValue: {} },
95+
{ provide: DSOChangeAnalyzer, useValue: {} },
96+
{ provide: BitstreamFormatDataService, useValue: {} },
97+
{ provide: NotificationsService, useValue: {} },
98+
{
99+
provide: ChangeDetectorRef, useValue: {
100+
detectChanges: () => fixture.detectChanges()
101+
}
102+
},
103+
provideMockStore({ core: { auth: { loading: false } } } as any),
84104
],
85105
schemas: [NO_ERRORS_SCHEMA]
86106
}).compileComponents();

src/app/shared/explore/section-component/grid-section/grid-section.component.ts

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { LayoutModeEnum, GridSection } from '../../../../core/layout/models/section.model';
2-
import { Component, Input, OnInit } from '@angular/core';
1+
import { GridSection } from '../../../../core/layout/models/section.model';
2+
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
33

44
import { SortDirection, SortOptions } from '../../../../core/cache/models/sort-options.model';
55
import { PaginationComponentOptions } from '../../../pagination/pagination-component-options.model';
@@ -16,6 +16,13 @@ import { Site } from '../../../../core/shared/site.model';
1616
import { LocaleService } from '../../../../core/locale/locale.service';
1717
import { Router } from '@angular/router';
1818
import { TranslateService } from '@ngx-translate/core';
19+
import { BehaviorSubject, filter, from, map, mergeMap, scan, switchMap, take } from 'rxjs';
20+
import { BitstreamDataService } from 'src/app/core/data/bitstream-data.service';
21+
import { Item } from 'src/app/core/shared/item.model';
22+
import { Bitstream } from 'src/app/core/shared/bitstream.model';
23+
import { BitstreamFormat } from 'src/app/core/shared/bitstream-format.model';
24+
import { hasValue } from 'src/app/shared/empty.util';
25+
import { getItemPageRoute } from 'src/app/item-page/item-page-routing-paths';
1926

2027
/**
2128
* Component representing the Grid component section.
@@ -41,8 +48,6 @@ export class GridSectionComponent implements OnInit {
4148

4249
paginatedSearchOptions: PaginatedSearchOptions;
4350

44-
layoutMode: LayoutModeEnum = LayoutModeEnum.CARD;
45-
4651
maincontentBadge: string;
4752

4853
maincontentTitle: string;
@@ -53,13 +58,17 @@ export class GridSectionComponent implements OnInit {
5358

5459
maincontentLink: string;
5560

56-
searchResults;
61+
searchResults: SearchResult<DSpaceObject>[];
62+
63+
itemToImageHrefMap$ = new BehaviorSubject<Map<string, string>>(new Map<string, string>());
5764

5865
constructor(
5966
private searchService: SearchService,
6067
private locale: LocaleService,
6168
private router: Router,
62-
private translateService: TranslateService
69+
private translateService: TranslateService,
70+
private bitstreamDataService: BitstreamDataService,
71+
private cdr: ChangeDetectorRef
6372
) {
6473
}
6574

@@ -111,11 +120,55 @@ export class GridSectionComponent implements OnInit {
111120
.pipe(getFirstCompletedRemoteData())
112121
.subscribe(
113122
(response: RemoteData<PaginatedList<SearchResult<DSpaceObject>>>) => {
114-
this.searchResults = response.payload.page as any;
123+
this.searchResults = response.payload.page;
124+
this.getAllBitstreams();
115125
}
116126
);
117127
}
118128

129+
private getAllBitstreams() {
130+
from(this.searchResults).pipe(
131+
map((itemSR) => itemSR.indexableObject),
132+
mergeMap((item: Item) => this.bitstreamDataService.showableByItem(
133+
item.uuid, 'ORIGINAL', [], {}, true, true, followLink('format')
134+
).pipe(
135+
getFirstCompletedRemoteData(),
136+
switchMap((rd: RemoteData<PaginatedList<Bitstream>>) => rd.hasSucceeded ? rd.payload.page : []),
137+
mergeMap((bitstream: Bitstream) => bitstream.format.pipe(
138+
getFirstCompletedRemoteData(),
139+
filter((formatRemoteData: RemoteData<BitstreamFormat>) =>
140+
formatRemoteData.hasSucceeded && hasValue(formatRemoteData.payload) && hasValue(bitstream) &&
141+
formatRemoteData.payload.mimetype.includes('image/')
142+
),
143+
map(() => bitstream)
144+
)),
145+
take(1),
146+
map((bitstream: Bitstream) => {
147+
return [item.uuid, bitstream._links.content.href];
148+
})
149+
)
150+
),
151+
scan((acc: Map<string, string>, value: [string, string]) => {
152+
acc.set(value[0], value[1]);
153+
return acc;
154+
}, new Map<string, string>())
155+
).subscribe((res) => {
156+
this.itemToImageHrefMap$.next(res);
157+
this.cdr.detectChanges();
158+
});
159+
160+
}
161+
162+
163+
/**
164+
* to get the route of the item
165+
* @param item
166+
* @returns route to the item as a string
167+
*/
168+
getItemPageRoute(item: DSpaceObject) {
169+
return getItemPageRoute(item as Item);
170+
}
171+
119172
goToMainContentLink() {
120173
this.router.navigateByUrl(this.maincontentLink);
121174
}

src/app/shared/shared.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,7 @@ import { CardsBrowseElementsComponent } from './browse-most-elements/cards-brows
364364
import {
365365
ThemedCardsBrowseElementsComponent
366366
} from './browse-most-elements/cards-browse-elements/themed-cards-browse-elements.component';
367+
import { BackgroundImageDirective } from './utils/background-image.directive';
367368

368369
const MODULES = [
369370
CommonModule,
@@ -637,7 +638,8 @@ const DIRECTIVES = [
637638
ContextHelpDirective,
638639
EntityIconDirective,
639640
MarkdownDirective,
640-
StickyPopoverDirective
641+
StickyPopoverDirective,
642+
BackgroundImageDirective
641643
];
642644

643645
@NgModule({

0 commit comments

Comments
 (0)