mirror of
https://github.com/CaramelFur/Picsur.git
synced 2025-11-02 10:15:47 +01:00
add snackbars
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
|
import { SnackBarType } from 'src/app/models/snack-bar-type';
|
||||||
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'copy-field',
|
selector: 'copy-field',
|
||||||
@@ -11,11 +13,18 @@ export class CopyFieldComponent {
|
|||||||
@Input() label: string = 'Loading...';
|
@Input() label: string = 'Loading...';
|
||||||
@Input() value: string = 'Loading...';
|
@Input() value: string = 'Loading...';
|
||||||
|
|
||||||
constructor(private snackBar: MatSnackBar) {}
|
constructor(private utilService: UtilService) {}
|
||||||
|
|
||||||
public copy() {
|
public copy() {
|
||||||
|
try {
|
||||||
navigator.clipboard.writeText(this.value);
|
navigator.clipboard.writeText(this.value);
|
||||||
|
} catch (e) {
|
||||||
|
return this.utilService.showSnackBar(
|
||||||
|
'Copying to clipboard failed',
|
||||||
|
SnackBarType.Error
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.snackBar.open(`Copied ${this.label}!`);
|
this.utilService.showSnackBar(`Copied ${this.label}!`, SnackBarType.Info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { CopyFieldComponent } from './copy-field.component';
|
|||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
import { UtilModule } from 'src/app/util/util.module';
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [CopyFieldComponent],
|
declarations: [CopyFieldComponent],
|
||||||
imports: [
|
imports: [
|
||||||
@@ -12,7 +12,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|||||||
MatInputModule,
|
MatInputModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatSnackBarModule,
|
UtilModule,
|
||||||
],
|
],
|
||||||
exports: [CopyFieldComponent],
|
exports: [CopyFieldComponent],
|
||||||
})
|
})
|
||||||
|
|||||||
7
frontend/src/app/models/snack-bar-type.ts
Normal file
7
frontend/src/app/models/snack-bar-type.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export enum SnackBarType {
|
||||||
|
Success = 'snack-success',
|
||||||
|
Error = 'snack-error',
|
||||||
|
Warning = 'snack-warning',
|
||||||
|
Info = 'snack-info',
|
||||||
|
Default = 'snack-default',
|
||||||
|
}
|
||||||
@@ -2,10 +2,6 @@ import { NgModule } from '@angular/core';
|
|||||||
import { RouterModule, Routes } from '@angular/router';
|
import { RouterModule, Routes } from '@angular/router';
|
||||||
import { UploadComponent } from '../routes/upload/upload.component';
|
import { UploadComponent } from '../routes/upload/upload.component';
|
||||||
import { NgxDropzoneModule } from 'ngx-dropzone';
|
import { NgxDropzoneModule } from 'ngx-dropzone';
|
||||||
import {
|
|
||||||
MatSnackBarModule,
|
|
||||||
MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
|
||||||
} from '@angular/material/snack-bar';
|
|
||||||
import { ProcessingComponent } from '../routes/processing/processing.component';
|
import { ProcessingComponent } from '../routes/processing/processing.component';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { ApiModule } from '../api/api.module';
|
import { ApiModule } from '../api/api.module';
|
||||||
@@ -14,6 +10,7 @@ import { PageNotFoundComponent } from '../components/pagenotfound/pagenotfound.c
|
|||||||
import { ViewComponent } from '../routes/view/view.component';
|
import { ViewComponent } from '../routes/view/view.component';
|
||||||
import { CopyFieldModule } from '../components/copy-field/copy-field.module';
|
import { CopyFieldModule } from '../components/copy-field/copy-field.module';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
|
import { UtilModule } from '../util/util.module';
|
||||||
|
|
||||||
const routes: Routes = [
|
const routes: Routes = [
|
||||||
{ path: '', component: UploadComponent },
|
{ path: '', component: UploadComponent },
|
||||||
@@ -28,7 +25,7 @@ const routes: Routes = [
|
|||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
NgxDropzoneModule,
|
NgxDropzoneModule,
|
||||||
MatSnackBarModule,
|
UtilModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
PageNotFoundModule,
|
PageNotFoundModule,
|
||||||
@@ -37,16 +34,6 @@ const routes: Routes = [
|
|||||||
RouterModule.forRoot(routes),
|
RouterModule.forRoot(routes),
|
||||||
],
|
],
|
||||||
declarations: [UploadComponent, ProcessingComponent, ViewComponent],
|
declarations: [UploadComponent, ProcessingComponent, ViewComponent],
|
||||||
providers: [
|
|
||||||
{
|
|
||||||
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
|
||||||
useValue: {
|
|
||||||
duration: 2500,
|
|
||||||
horizontalPosition: 'left',
|
|
||||||
panelClass: ['mat-toolbar', 'mat-primary'],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
exports: [RouterModule],
|
exports: [RouterModule],
|
||||||
})
|
})
|
||||||
export class AppRouterModule {}
|
export class AppRouterModule {}
|
||||||
|
|||||||
@@ -3,27 +3,30 @@ import { Router } from '@angular/router';
|
|||||||
import { ProcessingViewMetadata } from 'src/app/models/processing-view-metadata';
|
import { ProcessingViewMetadata } from 'src/app/models/processing-view-metadata';
|
||||||
import { ImageService } from 'src/app/api/image.service';
|
import { ImageService } from 'src/app/api/image.service';
|
||||||
import { HasFailed } from 'picsur-shared/dist/types';
|
import { HasFailed } from 'picsur-shared/dist/types';
|
||||||
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
templateUrl: './processing.component.html',
|
templateUrl: './processing.component.html',
|
||||||
styleUrls: ['./processing.component.scss'],
|
styleUrls: ['./processing.component.scss'],
|
||||||
})
|
})
|
||||||
export class ProcessingComponent implements OnInit {
|
export class ProcessingComponent implements OnInit {
|
||||||
constructor(private router: Router, private imageService: ImageService) {}
|
constructor(
|
||||||
|
private router: Router,
|
||||||
|
private imageService: ImageService,
|
||||||
|
private utilService: UtilService
|
||||||
|
) {}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const state = history.state as ProcessingViewMetadata;
|
const state = history.state as ProcessingViewMetadata;
|
||||||
if (!state) {
|
if (!state) {
|
||||||
this.router.navigate(['/'], { replaceUrl: true });
|
return this.utilService.quitError('Error');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
history.replaceState(null, '');
|
history.replaceState(null, '');
|
||||||
|
|
||||||
const hash = await this.imageService.UploadImage(state.imageFile);
|
const hash = await this.imageService.UploadImage(state.imageFile);
|
||||||
if (HasFailed(hash)) {
|
if (HasFailed(hash)) {
|
||||||
this.router.navigate(['/'], { replaceUrl: true });
|
return this.utilService.quitError(hash.getReason());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.router.navigate([`/view/`, hash], { replaceUrl: true });
|
this.router.navigate([`/view/`, hash], { replaceUrl: true });
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Component, OnInit } from '@angular/core';
|
|||||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { NgxDropzoneChangeEvent } from 'ngx-dropzone';
|
import { NgxDropzoneChangeEvent } from 'ngx-dropzone';
|
||||||
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -9,10 +10,10 @@ import { ProcessingViewMetadata } from '../../models/processing-view-metadata';
|
|||||||
styleUrls: ['./upload.component.scss'],
|
styleUrls: ['./upload.component.scss'],
|
||||||
})
|
})
|
||||||
export class UploadComponent {
|
export class UploadComponent {
|
||||||
constructor(private snackBar: MatSnackBar, private router: Router) {}
|
constructor(private utilService: UtilService, private router: Router) {}
|
||||||
onSelect(event: NgxDropzoneChangeEvent) {
|
onSelect(event: NgxDropzoneChangeEvent) {
|
||||||
if (event.addedFiles.length > 1) {
|
if (event.addedFiles.length > 1) {
|
||||||
this.snackBar.open(
|
this.utilService.showSnackBar(
|
||||||
'You uploaded multiple images, only one has been uploaded'
|
'You uploaded multiple images, only one has been uploaded'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
.uploadedimage {
|
.uploadedimage {
|
||||||
|
max-width: 100%;
|
||||||
border-radius: 20px;
|
border-radius: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.content-border {
|
.content-border {
|
||||||
padding: 2rem;
|
padding: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { isHash } from 'class-validator';
|
|||||||
import { HasFailed } from 'picsur-shared/dist/types';
|
import { HasFailed } from 'picsur-shared/dist/types';
|
||||||
import { ImageService } from 'src/app/api/image.service';
|
import { ImageService } from 'src/app/api/image.service';
|
||||||
import { ImageLinks } from 'picsur-shared/dist/dto/imagelinks.dto';
|
import { ImageLinks } from 'picsur-shared/dist/dto/imagelinks.dto';
|
||||||
|
import { UtilService } from 'src/app/util/util.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-view',
|
selector: 'app-view',
|
||||||
@@ -15,7 +16,8 @@ export class ViewComponent implements OnInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
private imageService: ImageService
|
private imageService: ImageService,
|
||||||
|
private utilService: UtilService
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
public imageUrl: string;
|
public imageUrl: string;
|
||||||
@@ -25,14 +27,12 @@ export class ViewComponent implements OnInit {
|
|||||||
const params = this.route.snapshot.paramMap;
|
const params = this.route.snapshot.paramMap;
|
||||||
const hash = params.get('hash') ?? '';
|
const hash = params.get('hash') ?? '';
|
||||||
if (!isHash(hash, 'sha256')) {
|
if (!isHash(hash, 'sha256')) {
|
||||||
this.router.navigate(['/'], { replaceUrl: true });
|
return this.utilService.quitError('Invalid image link');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageMeta = await this.imageService.GetImageMeta(hash);
|
const imageMeta = await this.imageService.GetImageMeta(hash);
|
||||||
if (HasFailed(imageMeta)) {
|
if (HasFailed(imageMeta)) {
|
||||||
this.router.navigate(['/'], { replaceUrl: true });
|
return this.utilService.quitError(imageMeta.getReason());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.imageUrl = this.imageService.GetImageURL(hash);
|
this.imageUrl = this.imageService.GetImageURL(hash);
|
||||||
|
|||||||
24
frontend/src/app/util/util.module.ts
Normal file
24
frontend/src/app/util/util.module.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { UtilService } from './util.service';
|
||||||
|
import {
|
||||||
|
MatSnackBarModule,
|
||||||
|
MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
||||||
|
} from '@angular/material/snack-bar';
|
||||||
|
import { RouterModule } from '@angular/router';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [],
|
||||||
|
providers: [
|
||||||
|
UtilService,
|
||||||
|
{
|
||||||
|
provide: MAT_SNACK_BAR_DEFAULT_OPTIONS,
|
||||||
|
useValue: {
|
||||||
|
duration: 4000,
|
||||||
|
horizontalPosition: 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
imports: [CommonModule, MatSnackBarModule, RouterModule],
|
||||||
|
})
|
||||||
|
export class UtilModule {}
|
||||||
25
frontend/src/app/util/util.service.ts
Normal file
25
frontend/src/app/util/util.service.ts
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { SnackBarType } from '../models/snack-bar-type';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class UtilService {
|
||||||
|
constructor(private snackBar: MatSnackBar, private router: Router) {}
|
||||||
|
|
||||||
|
public quitError(message: string) {
|
||||||
|
this.showSnackBar(message, SnackBarType.Error);
|
||||||
|
this.router.navigate(['/']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public showSnackBar(
|
||||||
|
message: string,
|
||||||
|
type: SnackBarType = SnackBarType.Default
|
||||||
|
) {
|
||||||
|
this.snackBar.open(message, '', {
|
||||||
|
panelClass: ['mat-toolbar', 'snackbar', type],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
2
frontend/src/scss/index.scss
Normal file
2
frontend/src/scss/index.scss
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
@import "./personal.scss";
|
||||||
|
@import "./snackbar.scss";
|
||||||
24
frontend/src/scss/snackbar.scss
Normal file
24
frontend/src/scss/snackbar.scss
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
.snackbar {
|
||||||
|
background: #272727;
|
||||||
|
color: white;
|
||||||
|
|
||||||
|
&.snack-success {
|
||||||
|
background: #4d9a51;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.snack-error {
|
||||||
|
background: #d74545;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.snack-warning {
|
||||||
|
background: #f68a1c;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.snack-info {
|
||||||
|
background: #1d95d6;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.snack-default {
|
||||||
|
background: #272727;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -281,4 +281,4 @@ html {
|
|||||||
transition: 0.2s;
|
transition: 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@import "./styles.personal";
|
@import "./scss";
|
||||||
|
|||||||
Reference in New Issue
Block a user