1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2026-05-16 09:21:12 +02:00

Refactor uploader UI #1118

This commit is contained in:
Patrik J. Braun
2026-01-19 21:14:09 +01:00
parent b961fd0b24
commit 4a01356165
6 changed files with 121 additions and 94 deletions
@@ -81,32 +81,3 @@ app-gallery-map {
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
}
}
.upload-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
.upload-overlay-content {
background: var(--bs-body-bg);
padding: 2em;
text-align: center;
border: 2px dashed var(--bs-primary);
}
.upload-progress-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 300px;
z-index: 10001;
}
@@ -25,36 +25,8 @@
<app-gallery-navbar navbar-appendix></app-gallery-navbar>
<div body class="container-fluid app-gallery-body" *ngIf="ContentWrapper"
[class.upload-over]="isOver">
<div class="upload-overlay" *ngIf="isOver">
<div class="upload-overlay-content rounded">
<div class="upload-overlay-icon">
<ng-icon name="ionCloudUploadOutline" size="4em"></ng-icon>
</div>
<div class="upload-overlay-text" i18n>Drop files to upload</div>
</div>
</div>
<div class="upload-progress-container" *ngIf="uploaderService.uploadProgress.length > 0">
<div class="card mb-2" *ngFor="let item of uploaderService.uploadProgress">
<div *ngIf="item.lastUpdate > Date.now() - 3000" class="card-body p-2">
<div class="d-flex justify-content-between align-items-center mb-1">
<small class="text-truncate me-2" [title]="item.name">{{ item.name }}</small>
<small *ngIf="!item.error">{{ item.progress }}%</small>
<small *ngIf="item.error" class="text-danger" [title]="item.error" i18n>Error</small>
</div>
<div *ngIf="item.error" class="d-flex justify-content-between align-items-center mb-1">
<small class="text-danger">{{item.error}}</small>
</div>
<div class="progress" style="height: 5px;">
<div class="progress-bar" role="progressbar"
[class.bg-danger]="item.error"
[class.bg-success]="item.done && !item.error"
[ngStyle]="{'width': item.progress + '%'}"></div>
</div>
</div>
</div>
</div>
<div body class="container-fluid app-gallery-body" *ngIf="ContentWrapper">
<app-gallery-uploader [isUploadOver]="isUploadOver"></app-gallery-uploader>
<ng-container *ngIf="ContentWrapper.error">
<div class="alert alert-danger" role="alert">
{{ ContentWrapper.error }}
@@ -34,6 +34,7 @@ import {SearchQueryUtils} from '../../../../common/SearchQueryUtils';
import {UploaderService} from './uploader.service';
import {GalleryService} from './gallery.service';
import {NgIconComponent} from '@ng-icons/core';
import {UploaderComponent} from './upload-progress/upload-progress.gallery.component';
@Component({
selector: 'app-gallery',
@@ -43,8 +44,6 @@ import {NgIconComponent} from '@ng-icons/core';
GalleryLightboxComponent,
FrameComponent,
NgIf,
NgFor,
NgStyle,
RandomQueryBuilderGalleryComponent,
PhotoFrameBuilderGalleryComponent,
GalleryNavigatorComponent,
@@ -55,7 +54,7 @@ import {NgIconComponent} from '@ng-icons/core';
GPXFilesFilterPipe,
PhotoFilterPipe,
MediaButtonModalComponent,
NgIconComponent
UploaderComponent
]
})
export class GalleryComponent implements OnInit, OnDestroy {
@@ -77,7 +76,6 @@ export class GalleryComponent implements OnInit, OnDestroy {
} = null;
public readonly mapEnabled: boolean;
public directoryContent: GroupedDirectoryContent;
public isOver = false;
private $counter: Observable<number>;
private subscription: { [key: string]: Subscription } = {
content: null,
@@ -85,6 +83,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
timer: null,
sorting: null,
};
public isUploadOver = false;
constructor(
public contentLoader: ContentLoaderService,
@@ -187,36 +186,6 @@ export class GalleryComponent implements OnInit, OnDestroy {
}
}
@HostListener('dragover', ['$event'])
onDragOver(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isOver = true;
}
}
@HostListener('dragleave', ['$event'])
onDragLeave(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isOver = false;
}
}
@HostListener('drop', ['$event'])
onDrop(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isOver = false;
const files = event.dataTransfer.files;
if (files.length > 0) {
this.uploaderService.uploadFiles(files);
}
}
}
private onRoute = async (params: Params): Promise<void> => {
const searchQuery = SearchQueryUtils.parseURLifiedQuery(params[QueryParams.gallery.search.query]);
@@ -270,5 +239,38 @@ export class GalleryComponent implements OnInit, OnDestroy {
}
}
};
protected readonly Date = Date;
@HostListener('dragover', ['$event'])
onDragOver(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isUploadOver = true;
}
}
@HostListener('dragleave', ['$event'])
onDragLeave(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isUploadOver = false;
}
}
@HostListener('drop', ['$event'])
onDrop(event: DragEvent): void {
if (this.uploaderService.canUpload()) {
event.preventDefault();
event.stopPropagation();
this.isUploadOver = false;
const files = event.dataTransfer.files;
if (files.length > 0) {
this.uploaderService.uploadFiles(files);
}
}
}
}
@@ -0,0 +1,29 @@
.upload-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 10000;
display: flex;
justify-content: center;
align-items: center;
pointer-events: none;
}
.upload-overlay-content {
background: var(--bs-body-bg);
padding: 2em;
text-align: center;
border: 2px dashed var(--bs-primary);
}
.upload-progress-container {
position: fixed;
bottom: 20px;
right: 20px;
width: 300px;
z-index: 10001;
}
@@ -0,0 +1,28 @@
<div class="upload-overlay" *ngIf="isUploadOver">
<div class="upload-overlay-content rounded">
<div class="upload-overlay-icon">
<ng-icon name="ionCloudUploadOutline" size="4em"></ng-icon>
</div>
<div class="upload-overlay-text" i18n>Drop files to upload</div>
</div>
</div>
<div class="upload-progress-container" *ngIf="uploaderService.uploadProgress.length > 0">
<div class="card mb-2" *ngFor="let item of uploaderService.uploadProgress">
<div *ngIf="item.lastUpdate > Date.now() - 3000" class="card-body p-2">
<div class="d-flex justify-content-between align-items-center mb-1">
<small class="text-truncate me-2" [title]="item.name">{{ item.name }}</small>
<small *ngIf="!item.error">{{ item.progress }}%</small>
<small *ngIf="item.error" class="text-danger" [title]="item.error" i18n>Error</small>
</div>
<div *ngIf="item.error" class="d-flex justify-content-between align-items-center mb-1">
<small class="text-danger">{{item.error}}</small>
</div>
<div class="progress" style="height: 5px;">
<div class="progress-bar" role="progressbar"
[class.bg-danger]="item.error"
[class.bg-success]="item.done && !item.error"
[ngStyle]="{'width': item.progress + '%'}"></div>
</div>
</div>
</div>
</div>
@@ -0,0 +1,25 @@
import {Component, HostListener, Input} from '@angular/core';
import {NgFor, NgIf, NgStyle} from '@angular/common';
import {NgIconComponent} from '@ng-icons/core';
import {UploaderService} from '../uploader.service';
@Component({
selector: 'app-gallery-uploader',
templateUrl: './upload-progress.gallery.component.html',
styleUrls: ['./upload-progress.gallery.component.css'],
imports: [
NgIf,
NgFor,
NgIconComponent,
NgStyle,
]
})
export class UploaderComponent {
public readonly Date = Date;
@Input() isUploadOver: boolean;
constructor(public uploaderService: UploaderService) {
}
}