Skip to content

Commit

Permalink
Merge pull request #761 from geonetwork/DH-add-record-thumbnail
Browse files Browse the repository at this point in the history
feat(DH): Add basiclightbox for thumbnail preview
  • Loading branch information
Angi-Kinas committed Jan 24, 2024
2 parents 05d3ea3 + 1ba7227 commit 177cac3
Show file tree
Hide file tree
Showing 17 changed files with 187 additions and 8 deletions.
14 changes: 14 additions & 0 deletions apps/datahub-e2e/src/e2e/datasetDetailPage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ describe('dataset pages', () => {
expect(text).not.to.equal('')
})
})
it.only('should display the thumbnail image and magnify', () => {
cy.get('datahub-record-metadata')
.find('[id="about"]')
.find('gn-ui-image-overlay-preview')
.as('overlay')
.should('have.length', 1)
cy.get('@overlay').find('gn-ui-button').click()
cy.get('[class="basicLightbox__placeholder"]')
.as('lightbox')
.find('img')
.should('have.length', 1)
cy.get('body').click()
cy.get('@lightbox').should('have.length', 0)
})
it('should display the contact details', () => {
cy.get('datahub-record-metadata')
.find('[id="about"]')
Expand Down
1 change: 1 addition & 0 deletions apps/datahub/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"tailwind.base.css",
"apps/datahub/src/styles.css",
"node_modules/tippy.js/dist/tippy.css",
"node_modules/basiclightbox/dist/basicLightbox.min.css",
"node_modules/ol/ol.css",
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,21 @@
[metadataQualityDisplay]="metadataQualityDisplay"
></gn-ui-metadata-quality>
</div>
<gn-ui-metadata-contact
(organizationClick)="onOrganizationClick($event)"
[metadata]="facade.metadata$ | async"
<gn-ui-image-overlay-preview
[imageUrl]="thumbnailUrl$ | async"
(isPlaceholderShown)="showOverlay = !$event"
*ngIf="showOverlay"
>
</gn-ui-metadata-contact>
<gn-ui-metadata-catalog [sourceLabel]="sourceLabel$ | async">
</gn-ui-metadata-catalog>
</gn-ui-image-overlay-preview>
<div>
<gn-ui-metadata-contact
(organizationClick)="onOrganizationClick($event)"
[metadata]="facade.metadata$ | async"
>
</gn-ui-metadata-contact>
<gn-ui-metadata-catalog [sourceLabel]="sourceLabel$ | async">
</gn-ui-metadata-catalog>
</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,15 @@ export class MockMetadataCatalogComponent {
export class MockRecordApiFormComponent {
@Input() apiLink: DatasetServiceDistribution
}
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'gn-ui-image-overlay-preview',
template: '<div></div>',
})
export class MockImgOverlayPreviewComponent {
@Input() imageUrl: string
@Output() isPlaceholderShown = new EventEmitter<boolean>()
}

describe('RecordMetadataComponent', () => {
let component: RecordMetadataComponent
Expand All @@ -172,6 +181,7 @@ describe('RecordMetadataComponent', () => {
MockMetadataCatalogComponent,
MockMetadataContactComponent,
MockRecordApiFormComponent,
MockImgOverlayPreviewComponent,
],
schemas: [NO_ERRORS_SCHEMA],
imports: [TranslateModule.forRoot()],
Expand Down Expand Up @@ -267,6 +277,56 @@ describe('RecordMetadataComponent', () => {
fixture.debugElement.query(By.directive(MockMetadataCatalogComponent))
).toBeFalsy()
})
it('does not display the image overlay preview', () => {
expect(
fixture.debugElement.query(
By.directive(MockImgOverlayPreviewComponent)
)
).toBeFalsy()
})
})
describe('Image Overlay Preview', () => {
describe('if metadata without overview', () => {
let imgOverlayPreview: MockImgOverlayPreviewComponent
beforeEach(() => {
facade.isPresent$.next(true)
facade.metadata$.next({})
fixture.detectChanges()
imgOverlayPreview = fixture.debugElement.query(
By.directive(MockImgOverlayPreviewComponent)
).componentInstance
})
it('should send undefined as imageUrl to imgOverlayPreview component', () => {
expect(imgOverlayPreview).toBeTruthy()
expect(imgOverlayPreview.imageUrl).toBe(undefined)
})
})
describe('if metadata with overview', () => {
let imgOverlayPreview: MockImgOverlayPreviewComponent
beforeEach(() => {
facade.isPresent$.next(true)
fixture.detectChanges()
imgOverlayPreview = fixture.debugElement.query(
By.directive(MockImgOverlayPreviewComponent)
).componentInstance
})
describe('and url defined', () => {
it('should send the imageUrl to imgOverlayPreview component', () => {
expect(imgOverlayPreview).toBeTruthy()
expect(imgOverlayPreview.imageUrl).toBeDefined()
})
})
describe('and url undefined', () => {
beforeEach(() => {
facade.metadata$.next({ overviews: [] })
fixture.detectChanges()
})
it('should send the imagUrl as null to imgOverlayPreview component', () => {
expect(imgOverlayPreview).toBeTruthy()
expect(imgOverlayPreview.imageUrl).toBeNull()
})
})
})
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,21 @@ export class RecordMetadataComponent {
errorTypes = ErrorType
selectedTabIndex$ = new BehaviorSubject(0)

thumbnailUrl$ = this.facade.metadata$.pipe(
map((metadata) => {
// in order to differentiate between metadata not loaded yet
// and url not defined
// the content-ghost of image-overlay-preview relies on this differentiation
if (metadata?.overviews === undefined) {
return undefined
} else {
return metadata?.overviews?.[0]?.url ?? null
}
})
)

showOverlay = true

constructor(
public facade: MdViewFacade,
private searchService: SearchService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class Gn4MetadataMapper extends MetadataBaseMapper<Gn4Record> {
useLimitations: [],
spatialExtents: [],
temporalExtents: [],
overviews: [],
}
const record: CatalogRecord = Object.keys(_source).reduce(
(prev, fieldName) =>
Expand Down
1 change: 1 addition & 0 deletions libs/ui/elements/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ export * from './lib/search-results-error/search-results-error.component'
export * from './lib/user-preview/user-preview.component'
export * from './lib/record-api-form/record-api-form.component'
export * from './lib/markdown-parser/markdown-parser.component'
export * from './lib/image-overlay-preview/image-overlay-preview.component'
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<gn-ui-content-ghost
[showContent]="imageUrl !== undefined"
ghostClass="h-36 mb-3"
>
<div
*ngIf="imageUrl"
data-cy="record-thumbnail"
class="flex-shrink-0 bg-gray-100 rounded-lg overflow-hidden w-full border border-gray-300 h-36 group-hover:shadow-xl group-hover:border-0 mb-3"
>
<gn-ui-thumbnail
class="relative h-full w-full"
[thumbnailUrl]="imageUrl"
fit="cover"
(placeholderShown)="isPlaceholderShown.emit($event)"
></gn-ui-thumbnail>
<div class="relative">
<gn-ui-button
class="absolute bottom-0 right-0 z-10 mr-2 mb-2"
[type]="'outline'"
[extraClass]="'!py-2 !px-0'"
(buttonClick)="openLightbox(imageUrl)"
>
<mat-icon class="material-symbols-outlined font-extralight"
>zoom_out_map</mat-icon
>
</gn-ui-button>
</div>
</div>
</gn-ui-content-ghost>
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'

import { ImageOverlayPreviewComponent } from './image-overlay-preview.component'

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

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [ImageOverlayPreviewComponent],
})
fixture = TestBed.createComponent(ImageOverlayPreviewComponent)
component = fixture.componentInstance
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'
import * as basicLightbox from 'basiclightbox'

@Component({
selector: 'gn-ui-image-overlay-preview',
templateUrl: './image-overlay-preview.component.html',
styleUrls: ['./image-overlay-preview.component.css'],
})
export class ImageOverlayPreviewComponent {
@Input() imageUrl: string
@Output() isPlaceholderShown = new EventEmitter<boolean>()
openLightbox(src: string) {
basicLightbox.create(`<img src="${src}"/>`).show()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
(click)="onOrganizationClick()"
data-cy="organization-name"
>
{{ shownOrganization.name }}
{{ shownOrganization?.name }}
</div>
</div>
<div *ngIf="shownOrganization?.website">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<div class="h-52 bg-gray-100">
<gn-ui-thumbnail
class="h-52 w-full object-cover"
[thumbnailUrl]="record.overviews?.[0].url.toString()"
[thumbnailUrl]="record.overviews?.[0]?.url.toString()"
></gn-ui-thumbnail>
</div>
<div class="flex flex-col justify-between h-44 px-5 pt-4 pb-6">
Expand Down
4 changes: 4 additions & 0 deletions libs/ui/elements/src/lib/thumbnail/thumbnail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
Optional,
SimpleChanges,
ViewChild,
Output,
EventEmitter,
} from '@angular/core'

export const THUMBNAIL_PLACEHOLDER = new InjectionToken<string>(
Expand All @@ -36,6 +38,7 @@ export class ThumbnailComponent implements OnInit, OnChanges {
@Input() fit: FitOptions | FitOptions[] = 'cover'
@ViewChild('imageElement') imgElement: ElementRef<HTMLImageElement>
@ViewChild('containerElement') containerElement: ElementRef<HTMLDivElement>
@Output() placeholderShown = new EventEmitter<boolean>()
imgUrl: string
imgFit: FitOptions
placeholderUrl = this.optionalPlaceholderUrl || DEFAULT_PLACEHOLDER
Expand Down Expand Up @@ -85,6 +88,7 @@ export class ThumbnailComponent implements OnInit, OnChanges {
private setNewSrcImage(image: ThumbnailImageObject) {
this.imgFit = image.fit
this.imgUrl = image.url
this.placeholderShown.emit(this.isPlaceholder)
}

private setPlaceholder(): void {
Expand Down
3 changes: 3 additions & 0 deletions libs/ui/elements/src/lib/ui-elements.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import { PaginationButtonsComponent } from './pagination-buttons/pagination-butt
import { MaxLinesComponent } from './max-lines/max-lines.component'
import { RecordApiFormComponent } from './record-api-form/record-api-form.component'
import { MarkdownParserComponent } from './markdown-parser/markdown-parser.component'
import { ImageOverlayPreviewComponent } from './image-overlay-preview/image-overlay-preview.component'

@NgModule({
imports: [
Expand Down Expand Up @@ -67,6 +68,7 @@ import { MarkdownParserComponent } from './markdown-parser/markdown-parser.compo
MaxLinesComponent,
RecordApiFormComponent,
MarkdownParserComponent,
ImageOverlayPreviewComponent,
],
exports: [
MetadataInfoComponent,
Expand All @@ -88,6 +90,7 @@ import { MarkdownParserComponent } from './markdown-parser/markdown-parser.compo
PaginationButtonsComponent,
RecordApiFormComponent,
MarkdownParserComponent,
ImageOverlayPreviewComponent,
],
})
export class UiElementsModule {}
6 changes: 6 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
"@rgrove/parse-xml": "~4.0.1",
"alasql": "^3.1.0",
"axios": "^1.6.0",
"basiclightbox": "^5.0.4",
"chart.js": "^4.2.0",
"chroma-js": "^2.1.2",
"cypress-browser-permissions": "^1.1.0",
Expand Down

0 comments on commit 177cac3

Please sign in to comment.