Updated gallery
This commit is contained in:
16
src/app/components/carousel/carousel.component.html
Normal file
16
src/app/components/carousel/carousel.component.html
Normal file
@ -0,0 +1,16 @@
|
||||
<div class="carousel-container" [style.height]="height" style="background: #282d31">
|
||||
<div class="carousel-previous" (click)="previous()">
|
||||
<mat-icon>keyboard_arrow_left</mat-icon>
|
||||
</div>
|
||||
<div *ngIf="loading" class="carousel-loading">
|
||||
<div class="lds-ring"><div></div><div></div><div></div><div></div></div>
|
||||
</div>
|
||||
<img class="carousel-image" [src]="photos[index].src" [alt]="photos[index].alt || 'slide ' + index" (load)="loading = false">
|
||||
<div class="carousel-next" (click)="next()">
|
||||
<mat-icon>keyboard_arrow_right</mat-icon>
|
||||
</div>
|
||||
<div *ngIf="!disableAutoplay" class="carousel-pause" (click)="pause = !pause">
|
||||
<mat-icon *ngIf="!pause">pause</mat-icon>
|
||||
<mat-icon *ngIf="pause">play_arrow</mat-icon>
|
||||
</div>
|
||||
</div>
|
117
src/app/components/carousel/carousel.component.scss
Normal file
117
src/app/components/carousel/carousel.component.scss
Normal file
@ -0,0 +1,117 @@
|
||||
.carousel-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.carousel-background {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
filter: blur(10px);
|
||||
-webkit-filter: blur(10px);
|
||||
}
|
||||
|
||||
.carousel-loading {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
.lds-ring {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.lds-ring div {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 8px;
|
||||
border: 8px solid #fff;
|
||||
border-radius: 50%;
|
||||
animation: lds-ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
border-color: #fff transparent transparent transparent;
|
||||
}
|
||||
.lds-ring div:nth-child(1) {
|
||||
animation-delay: -0.45s;
|
||||
}
|
||||
.lds-ring div:nth-child(2) {
|
||||
animation-delay: -0.3s;
|
||||
}
|
||||
.lds-ring div:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
}
|
||||
@keyframes lds-ring {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-image {
|
||||
display: block;
|
||||
max-width: 70%;
|
||||
max-height: 90%;
|
||||
object-fit: cover;
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.carousel-next, .carousel-previous {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
filter: drop-shadow(3px 3px 5px black);
|
||||
cursor: pointer;
|
||||
transition: 0.25s;
|
||||
border-radius: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
||||
&.carousel-next {
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&.carousel-previous {
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
background: rgba(0,0,0,0.25);
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
|
||||
.carousel-pause {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
height: 56px;
|
||||
width: 56px;
|
||||
transform: translate(-50%, -50%);
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
filter: drop-shadow(3px 3px 5px black);
|
||||
cursor: pointer;
|
||||
padding: 1rem;
|
||||
border-radius: 50%;
|
||||
transition: 0.25s;
|
||||
|
||||
&:hover {
|
||||
color: white;
|
||||
background: rgba(0,0,0,0.25);
|
||||
filter: none;
|
||||
}
|
||||
}
|
||||
}
|
51
src/app/components/carousel/carousel.component.ts
Normal file
51
src/app/components/carousel/carousel.component.ts
Normal file
@ -0,0 +1,51 @@
|
||||
import {AfterViewInit, Component, Input, OnDestroy, OnInit} from '@angular/core';
|
||||
import {Photo} from '../models/photo';
|
||||
|
||||
@Component({
|
||||
selector: 'xxx-carousel',
|
||||
templateUrl: './carousel.component.html',
|
||||
styleUrls: ['./carousel.component.scss']
|
||||
})
|
||||
export class CarouselComponent implements OnDestroy, OnInit, AfterViewInit {
|
||||
private timer?: any;
|
||||
|
||||
loading = true;
|
||||
|
||||
@Input() background = true;
|
||||
@Input() photos: Photo[] = [];
|
||||
@Input() speed = 5000;
|
||||
@Input() pause = false;
|
||||
@Input() disableAutoplay = false;
|
||||
@Input() index = ~~(Math.random() * this.photos.length);
|
||||
@Input() height = '100%';
|
||||
|
||||
ngOnInit() {
|
||||
if(this.disableAutoplay) this.pause = true;
|
||||
}
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.timer = setInterval(() => {
|
||||
if(!this.pause) this.next(false);
|
||||
}, this.speed);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if(this.timer) {
|
||||
clearInterval(this.timer);
|
||||
this.timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
next(pause = true) {
|
||||
this.loading = true;
|
||||
this.pause = pause;
|
||||
this.index++;
|
||||
if(this.index >= this.photos.length) this.index = 0;
|
||||
}
|
||||
|
||||
previous(pause = true) {
|
||||
this.loading = true;
|
||||
this.pause = pause;
|
||||
this.index = this.index > 0 ? this.index - 1 : this.photos.length - 1;
|
||||
}
|
||||
}
|
41
src/app/components/image-viewer/image-viewer.component.ts
Normal file
41
src/app/components/image-viewer/image-viewer.component.ts
Normal file
@ -0,0 +1,41 @@
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog';
|
||||
import {Photo} from '../models/photo';
|
||||
|
||||
export interface ImageViewerOptions {
|
||||
photos: Photo[],
|
||||
index?: number;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'xxx-viewer',
|
||||
styles: [`
|
||||
.close {
|
||||
position: absolute;
|
||||
top: 1rem;
|
||||
right: 1rem;
|
||||
z-index: 100000;
|
||||
}
|
||||
::ng-deep .cdk-overlay-pane {
|
||||
max-width: 100% !important;
|
||||
}
|
||||
::ng-deep mat-dialog-container {
|
||||
padding: 0 !important;
|
||||
}
|
||||
`],
|
||||
template: `
|
||||
<button class="close" mat-icon-button aria-label="close dialog" mat-dialog-close>
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
<xxx-carousel [photos]="photos" [index]="index" [disableAutoplay]="true"></xxx-carousel>
|
||||
`
|
||||
})
|
||||
export class ImageViewerComponent {
|
||||
index!: number;
|
||||
photos!: Photo[];
|
||||
|
||||
constructor(public ref: MatDialogRef<ImageViewerComponent>, @Inject(MAT_DIALOG_DATA) data: ImageViewerOptions) {
|
||||
this.index = data.index || 0;
|
||||
this.photos = data.photos || [];
|
||||
}
|
||||
}
|
4
src/app/components/models/photo.ts
Normal file
4
src/app/components/models/photo.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export interface Photo {
|
||||
alt: string;
|
||||
src: string;
|
||||
}
|
43
src/app/components/placeholder/placeholder.component.ts
Normal file
43
src/app/components/placeholder/placeholder.component.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'xxx-placeholder',
|
||||
styles: [`
|
||||
.placeholder {
|
||||
position: relative;
|
||||
background-color: #bbbbbb;
|
||||
background: linear-gradient(to right, #eeeeee 8%, #bbbbbb 18%, #eeeeee 33%);
|
||||
background-size: 400% 100%;
|
||||
min-height: 100px;
|
||||
min-width: 200px;
|
||||
|
||||
animation-duration: 3s;
|
||||
animation-fill-mode: forwards;
|
||||
animation-iteration-count: infinite;
|
||||
animation-name: placeHolderShimmer;
|
||||
animation-timing-function: linear;
|
||||
|
||||
@keyframes placeHolderShimmer {
|
||||
0% {
|
||||
background-position: 200% 0;
|
||||
}
|
||||
100% {
|
||||
background-position: -200% 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
`],
|
||||
template: `
|
||||
<div *ngIf="loading" class="placeholder" [style.height]="height" [style.width]="width"></div>
|
||||
<img [src]="src" [alt]="alt" [style]="style" [style.height]="height" [style.width]="width" loading="lazy" (load)="loading = false" />
|
||||
`
|
||||
})
|
||||
export class PlaceholderComponent {
|
||||
loading = true;
|
||||
|
||||
@Input() alt?: string;
|
||||
@Input() src!: string;
|
||||
@Input() style!: string;
|
||||
@Input() height: string = 'auto';
|
||||
@Input() width: string = 'auto';
|
||||
}
|
Reference in New Issue
Block a user