mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Fix: Improve footer responsiveness and download button on the full item page (#4218)
* fix: footer and download button responsiveness * Revert styling changes to the download button on the simple item page * fix: for restrict bitstrream show only lock icon * ix: display download icon consistently across all item pages * fix embargo label responsiveness * Recommit without json5 changes * Recommit without json5 changes * Recommit without json5 changes
This commit is contained in:
@@ -49,8 +49,8 @@
|
||||
<!-- Grid container -->
|
||||
|
||||
<!-- Copyright -->
|
||||
<div class="bottom-footer p-1 d-flex justify-content-center align-items-center text-white">
|
||||
<div class="content-container">
|
||||
<div class="bottom-footer p-1 d-flex flex-column flex-md-row justify-content-center align-items-center text-white">
|
||||
<div class="content-container align-self-center">
|
||||
<p class="m-0">
|
||||
<a class="text-white"
|
||||
href="http://www.dspace.org/" role="link" tabindex="0">{{ 'footer.link.dspace' | translate}}</a>
|
||||
@@ -85,7 +85,7 @@
|
||||
</ul>
|
||||
</div>
|
||||
@if (coarLdnEnabled$ | async) {
|
||||
<div class="notify-enabled text-white">
|
||||
<div class="notify-enabled text-white align-self-end">
|
||||
<a class="coar-notify-support-route" routerLink="info/coar-notify-support" role="link" tabindex="0">
|
||||
<img class="n-coar" src="assets/images/n-coar.svg" [attr.alt]="'menu.header.image.logo' | translate" />
|
||||
{{ 'footer.link.coar-notify-support' | translate }}
|
||||
@@ -94,4 +94,4 @@
|
||||
}
|
||||
</div>
|
||||
<!-- Copyright -->
|
||||
</footer>
|
||||
</footer>
|
@@ -23,9 +23,8 @@
|
||||
|
||||
.bottom-footer {
|
||||
.notify-enabled {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 0;
|
||||
position: relative;
|
||||
margin-top: 4px;
|
||||
|
||||
.coar-notify-support-route {
|
||||
padding: 0 calc(var(--bs-spacer) / 2);
|
||||
@@ -37,7 +36,11 @@
|
||||
margin-bottom: 8.5px;
|
||||
}
|
||||
|
||||
margin-top: 20px;
|
||||
@media screen and (min-width: map-get($grid-breakpoints, md)) {
|
||||
position: absolute;
|
||||
bottom: 4px;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
li {
|
||||
|
@@ -1,84 +1,108 @@
|
||||
<ds-metadata-field-wrapper [label]="label | translate">
|
||||
<div *ngVar="(originals$ | async)?.payload as originals">
|
||||
@if (hasValuesInBundle(originals)) {
|
||||
<div>
|
||||
<h3 class="h5 simple-view-element-header">{{"item.page.filesection.original.bundle" | translate}}</h3>
|
||||
@if (originals?.page?.length > 0) {
|
||||
<ds-pagination
|
||||
[hideGear]="true"
|
||||
[hidePagerWhenSinglePage]="true"
|
||||
[paginationOptions]="originalOptions"
|
||||
[collectionSize]="originals?.totalElements"
|
||||
[retainScrollPosition]="true">
|
||||
@for (file of originals?.page; track file) {
|
||||
<div class="file-section row mb-3">
|
||||
<div class="col-3">
|
||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<dl class="row">
|
||||
<dt class="col-md-4">{{"item.page.filesection.name" | translate}}</dt>
|
||||
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
|
||||
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
||||
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
||||
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
||||
<dd class="col-md-8">{{(file.format | async)?.payload?.description}}</dd>
|
||||
@if (file.hasMetadata('dc.description')) {
|
||||
<dt class="col-md-4">{{"item.page.filesection.description" | translate}}</dt>
|
||||
<dd class="col-md-8">{{file.firstMetadataValue("dc.description")}}</dd>
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<ds-file-download-link [bitstream]="file" [item]="item">
|
||||
{{"item.page.filesection.download" | translate}}
|
||||
</ds-file-download-link>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ds-pagination>
|
||||
<div>
|
||||
<h3 class="h5 simple-view-element-header">
|
||||
{{ "item.page.filesection.original.bundle" | translate }}
|
||||
</h3>
|
||||
@if (originals?.page?.length > 0) {
|
||||
<ds-pagination [hideGear]="true" [hidePagerWhenSinglePage]="true" [paginationOptions]="originalOptions"
|
||||
[collectionSize]="originals?.totalElements" [retainScrollPosition]="true">
|
||||
@for (file of originals?.page; track file) {
|
||||
<div class="file-section row mb-3">
|
||||
<div class="col-3">
|
||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<dl class="row">
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.name" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.size" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">{{ file.sizeBytes | dsFileSize }}</dd>
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.format" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">
|
||||
{{ (file.format | async)?.payload?.description }}
|
||||
</dd>
|
||||
@if (file.hasMetadata('dc.description')) {
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.description" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">
|
||||
{{ file.firstMetadataValue("dc.description") }}
|
||||
</dd>
|
||||
}
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<ds-file-download-link [showIcon]="true" [bitstream]="file" [item]="item" cssClasses="btn btn-outline-primary btn-download">
|
||||
<span class="d-none d-md-inline">
|
||||
{{ "item.page.filesection.download" | translate }}
|
||||
</span>
|
||||
</ds-file-download-link>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ds-pagination>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div *ngVar="(licenses$ | async)?.payload as licenses">
|
||||
@if (hasValuesInBundle(licenses)) {
|
||||
<div>
|
||||
<h3 class="h5 simple-view-element-header">{{"item.page.filesection.license.bundle" | translate}}</h3>
|
||||
@if (licenses?.page?.length > 0) {
|
||||
<ds-pagination
|
||||
[hideGear]="true"
|
||||
[hidePagerWhenSinglePage]="true"
|
||||
[paginationOptions]="licenseOptions"
|
||||
[collectionSize]="licenses?.totalElements"
|
||||
[retainScrollPosition]="true">
|
||||
@for (file of licenses?.page; track file) {
|
||||
<div class="file-section row">
|
||||
<div class="col-3">
|
||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<dl class="row">
|
||||
<dt class="col-md-4">{{"item.page.filesection.name" | translate}}</dt>
|
||||
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
|
||||
<dt class="col-md-4">{{"item.page.filesection.size" | translate}}</dt>
|
||||
<dd class="col-md-8">{{(file.sizeBytes) | dsFileSize }}</dd>
|
||||
<dt class="col-md-4">{{"item.page.filesection.format" | translate}}</dt>
|
||||
<dd class="col-md-8">{{(file.format | async)?.payload?.description}}</dd>
|
||||
<dt class="col-md-4">{{"item.page.filesection.description" | translate}}</dt>
|
||||
<dd class="col-md-8">{{file.firstMetadataValue("dc.description")}}</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<ds-file-download-link [bitstream]="file" [item]="item">
|
||||
{{"item.page.filesection.download" | translate}}
|
||||
</ds-file-download-link>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</ds-pagination>
|
||||
<div>
|
||||
<h3 class="h5 simple-view-element-header">
|
||||
{{ "item.page.filesection.license.bundle" | translate }}
|
||||
</h3>
|
||||
@if (licenses?.page?.length > 0) {
|
||||
<ds-pagination [hideGear]="true" [hidePagerWhenSinglePage]="true" [paginationOptions]="licenseOptions"
|
||||
[collectionSize]="licenses?.totalElements" [retainScrollPosition]="true">
|
||||
@for (file of licenses?.page; track file) {
|
||||
<div class="file-section row">
|
||||
<div class="col-3">
|
||||
<ds-thumbnail [thumbnail]="(file.thumbnail | async)?.payload"></ds-thumbnail>
|
||||
</div>
|
||||
<div class="col-7">
|
||||
<dl class="row">
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.name" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">{{ dsoNameService.getName(file) }}</dd>
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.size" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">{{ file.sizeBytes | dsFileSize }}</dd>
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.format" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">
|
||||
{{ (file.format | async)?.payload?.description }}
|
||||
</dd>
|
||||
<dt class="col-md-4">
|
||||
{{ "item.page.filesection.description" | translate }}
|
||||
</dt>
|
||||
<dd class="col-md-8">
|
||||
{{ file.firstMetadataValue("dc.description") }}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<ds-file-download-link [showIcon]="true" [bitstream]="file" [item]="item" cssClasses="btn btn-outline-primary btn-download">
|
||||
<span class="d-none d-md-inline">
|
||||
{{ "item.page.filesection.download" | translate }}
|
||||
</span>
|
||||
</ds-file-download-link>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ds-pagination>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</ds-metadata-field-wrapper>
|
||||
|
@@ -5,17 +5,29 @@
|
||||
[queryParams]="(bitstreamPath$| async)?.queryParams"
|
||||
[target]="isBlank ? '_blank': '_self'"
|
||||
[ngClass]="cssClasses"
|
||||
[attr.aria-label]="('file-download-link.download' | translate) + dsoNameService.getName(bitstream)"
|
||||
[attr.aria-label]="getDownloadLinkTitle(canDownload$ | async, canDownloadWithToken$ | async, dsoNameService.getName(bitstream))"
|
||||
[title]="getDownloadLinkTitle(canDownload$ | async, canDownloadWithToken$ | async, dsoNameService.getName(bitstream))"
|
||||
role="link"
|
||||
tabindex="0">
|
||||
@if ((canDownload$ | async) === false && (canDownloadWithToken$ | async) === false) {
|
||||
<!-- If the user cannot download the file by auth or token, show a lock icon -->
|
||||
<span role="img" [attr.aria-label]="'file-download-link.restricted' | translate" class="pr-1"><i class="fas fa-lock"></i></span>
|
||||
<span role="img"
|
||||
[attr.aria-label]="'file-download-link.restricted' | translate"
|
||||
[title]="'file-download-link.restricted' | translate"
|
||||
class="pr-1">
|
||||
<i class="fas fa-lock"></i>
|
||||
</span>
|
||||
} @else if ((canDownloadWithToken$ | async) && (canDownload$ | async) === false) {
|
||||
<!-- If the user can download the file by token, and NOT normally show a lock open icon -->
|
||||
<span role="img" [attr.aria-label]="'file-download-link.secure-access' | translate" class="pr-1 request-a-copy-access-icon"><i class="fa-solid fa-lock-open" style=""></i></span>
|
||||
<span role="img"
|
||||
[attr.aria-label]="'file-download-link.secure-access' | translate"
|
||||
[title]="'file-download-link.secure-access' | translate"
|
||||
class="pr-1 request-a-copy-access-icon">
|
||||
<i class="fa-solid fa-lock-open"></i>
|
||||
</span>
|
||||
} @else if (showIcon) {
|
||||
<i class="fas fa-download d-inline"></i>
|
||||
}
|
||||
<!-- Otherwise, show no icon (normal download by authorized user), public access etc. -->
|
||||
<ng-container *ngTemplateOutlet="content"></ng-container>
|
||||
</a>
|
||||
|
||||
|
@@ -1,3 +1,7 @@
|
||||
.request-a-copy-access-icon {
|
||||
color: var(--bs-success);
|
||||
}
|
||||
|
||||
.btn-download{
|
||||
width: fit-content;
|
||||
}
|
||||
|
@@ -12,7 +12,10 @@ import {
|
||||
ActivatedRoute,
|
||||
RouterLink,
|
||||
} from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import {
|
||||
TranslateModule,
|
||||
TranslateService,
|
||||
} from '@ngx-translate/core';
|
||||
import {
|
||||
combineLatest as observableCombineLatest,
|
||||
Observable,
|
||||
@@ -75,6 +78,11 @@ export class FileDownloadLinkComponent implements OnInit {
|
||||
*/
|
||||
@Input() showAccessStatusBadge = true;
|
||||
|
||||
/**
|
||||
* A boolean indicating whether the download icon should be displayed.
|
||||
*/
|
||||
@Input() showIcon = false;
|
||||
|
||||
itemRequest: ItemRequest;
|
||||
|
||||
bitstreamPath$: Observable<{
|
||||
@@ -90,6 +98,7 @@ export class FileDownloadLinkComponent implements OnInit {
|
||||
private authorizationService: AuthorizationDataService,
|
||||
public dsoNameService: DSONameService,
|
||||
private route: ActivatedRoute,
|
||||
private translateService: TranslateService,
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -153,4 +162,9 @@ export class FileDownloadLinkComponent implements OnInit {
|
||||
queryParams: {},
|
||||
};
|
||||
}
|
||||
|
||||
getDownloadLinkTitle(canDownload: boolean,canDownloadWithToken: boolean, bitstreamName: string): string {
|
||||
return (canDownload || canDownloadWithToken ? this.translateService.instant('file-download-link.download') :
|
||||
this.translateService.instant('file-download-link.request-copy')) + bitstreamName;
|
||||
}
|
||||
}
|
||||
|
@@ -29,6 +29,8 @@ export class ThemedFileDownloadLinkComponent extends ThemedComponent<FileDownloa
|
||||
|
||||
@Input() showAccessStatusBadge: boolean;
|
||||
|
||||
@Input() showIcon = false;
|
||||
|
||||
protected inAndOutputNames: (keyof FileDownloadLinkComponent & keyof this)[] = [
|
||||
'bitstream',
|
||||
'item',
|
||||
@@ -36,6 +38,7 @@ export class ThemedFileDownloadLinkComponent extends ThemedComponent<FileDownloa
|
||||
'isBlank',
|
||||
'enableRequestACopy',
|
||||
'showAccessStatusBadge',
|
||||
'showIcon',
|
||||
];
|
||||
|
||||
protected getComponentName(): string {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
@if (showAccessStatus) {
|
||||
@if ({ status: accessStatus$ | async, date: embargoDate$ | async }; as accessStatus) {
|
||||
<span [class]="'badge bg-secondary access-status-list-element-badge ' + accessStatusClass">{{ accessStatus.status | translate: {date: accessStatus.date} }}</span>
|
||||
<span [class]="'badge bg-secondary dont-break-out access-status-list-element-badge ' + accessStatusClass">{{ accessStatus.status | translate: {date: accessStatus.date} }}</span>
|
||||
}
|
||||
}
|
||||
|
@@ -1 +1,3 @@
|
||||
|
||||
span{
|
||||
white-space: normal;
|
||||
}
|
||||
|
@@ -1,25 +1,30 @@
|
||||
<div class="thumbnail" [class.limit-width]="limitWidth">
|
||||
@if (isLoading) {
|
||||
<div class="thumbnail-content outer">
|
||||
<div class="inner">
|
||||
<div class="centered">
|
||||
<ds-loading [spinner]="true"></ds-loading>
|
||||
</div>
|
||||
<div class="thumbnail-content outer">
|
||||
<div class="inner">
|
||||
<div class="centered">
|
||||
<ds-loading [spinner]="true"></ds-loading>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<!-- don't use *ngIf="!isLoading" so the thumbnail can load in while the animation is playing -->
|
||||
@if (src !== null) {
|
||||
<img class="thumbnail-content img-fluid" [ngClass]="{'d-none': isLoading}"
|
||||
[src]="src | dsSafeUrl" [alt]="alt | translate" (error)="errorHandler()" (load)="successHandler()">
|
||||
}
|
||||
@if (src === null && !isLoading) {
|
||||
<div class="thumbnail-content outer">
|
||||
<div class="inner">
|
||||
<div class="thumbnail-placeholder centered lead">
|
||||
{{ placeholder | translate }}
|
||||
</div>
|
||||
<img
|
||||
class="thumbnail-content img-fluid"
|
||||
[ngClass]="{ 'd-none': isLoading }"
|
||||
[src]="src | dsSafeUrl"
|
||||
[alt]="alt | translate"
|
||||
(error)="errorHandler()"
|
||||
(load)="successHandler()"
|
||||
/>
|
||||
} @if (src === null && !isLoading) {
|
||||
<div class="thumbnail-content outer">
|
||||
<div class="inner">
|
||||
<div class="thumbnail-placeholder centered">
|
||||
{{ placeholder | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
@@ -7061,4 +7061,6 @@
|
||||
"embargo.listelement.badge": "Embargo until {{ date }}",
|
||||
|
||||
"metadata-export-search.submit.error.limit-exceeded": "Only the first {{limit}} items will be exported",
|
||||
|
||||
"file-download-link.request-copy": "Request a copy of ",
|
||||
}
|
||||
|
Reference in New Issue
Block a user