Move gallery content viewer to separate component
Signed-off-by: trivernis <trivernis@protonmail.com>pull/4/head
parent
09f3225aa3
commit
47738b392d
@ -0,0 +1 @@
|
||||
<app-image-viewer *ngIf="getContentType() === 'image'" [imageUrl]="contentUrl"></app-image-viewer>
|
@ -0,0 +1,4 @@
|
||||
app-image-viewer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ContentViewerComponent } from './content-viewer.component';
|
||||
|
||||
describe('ContentViewerComponent', () => {
|
||||
let component: ContentViewerComponent;
|
||||
let fixture: ComponentFixture<ContentViewerComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ContentViewerComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ContentViewerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,37 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {SafeResourceUrl} from "@angular/platform-browser";
|
||||
|
||||
type ContentType = "image" | "video" | "text" | "other";
|
||||
|
||||
@Component({
|
||||
selector: 'app-content-viewer',
|
||||
templateUrl: './content-viewer.component.html',
|
||||
styleUrls: ['./content-viewer.component.scss']
|
||||
})
|
||||
export class ContentViewerComponent {
|
||||
|
||||
@Input() contentUrl!: SafeResourceUrl | string;
|
||||
@Input() mimeType: string | undefined;
|
||||
|
||||
constructor() { }
|
||||
|
||||
public getContentType(): ContentType {
|
||||
if (!this.mimeType) {
|
||||
return "other";
|
||||
}
|
||||
let mimeParts = this.mimeType.split("/");
|
||||
const type = mimeParts.shift() ?? "other";
|
||||
const subtype = mimeParts.shift() ?? "*";
|
||||
|
||||
switch (type) {
|
||||
case "image":
|
||||
return "image";
|
||||
case "video":
|
||||
return "video";
|
||||
case "text":
|
||||
return "text";
|
||||
default:
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<div (mouseenter)="this.mouseInImageView = true" (mouseleave)="this.mouseInImageView = false"
|
||||
class="image-full-view-inner">
|
||||
<div class="zoom-slider">
|
||||
<mat-slider (input)="this.imageZoom=$event.value ?? 1" [value]="this.imageZoom" max="4"
|
||||
min="0.5" step="0.1" vertical></mat-slider>
|
||||
<button (click)="this.resetImage()" mat-icon-button>
|
||||
<mat-icon>refresh</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div (cdkDragMoved)="this.onDragMoved($event)"
|
||||
[cdkDragFreeDragPosition]="this.imagePosition" cdkDrag class="image-drag-container">
|
||||
<div [style]="{scale: this.imageZoom}" class="image-scale-container">
|
||||
<app-content-aware-image [imageSrc]="this.imageUrl" decoding="sync"></app-content-aware-image>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,35 @@
|
||||
|
||||
.image-drag-container, .image-scale-container {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.image-scale-container {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.zoom-slider {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
right: 1em;
|
||||
bottom: 1em;
|
||||
z-index: 10;
|
||||
opacity: 0.5;
|
||||
padding: 1em 0.5em;
|
||||
transition-duration: 0.2s;
|
||||
}
|
||||
|
||||
.zoom-slider:hover {
|
||||
opacity: 1;
|
||||
background-color: rgba(0, 0, 0, 0.3);
|
||||
border-radius: 1em;
|
||||
}
|
||||
|
||||
|
||||
.image-full-view-inner {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ImageViewerComponent } from './image-viewer.component';
|
||||
|
||||
describe('ImageViewerComponent', () => {
|
||||
let component: ImageViewerComponent;
|
||||
let fixture: ComponentFixture<ImageViewerComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ImageViewerComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ImageViewerComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,63 @@
|
||||
import {
|
||||
Component,
|
||||
ElementRef,
|
||||
HostListener,
|
||||
Input,
|
||||
OnInit,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import {CdkDragMove} from "@angular/cdk/drag-drop";
|
||||
import {SafeResourceUrl} from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: 'app-image-viewer',
|
||||
templateUrl: './image-viewer.component.html',
|
||||
styleUrls: ['./image-viewer.component.scss']
|
||||
})
|
||||
export class ImageViewerComponent {
|
||||
|
||||
@Input() imageUrl!: SafeResourceUrl | string;
|
||||
public imageZoom = 1;
|
||||
public imagePosition = {x: 0, y: 0};
|
||||
public mouseInImageView = false;
|
||||
|
||||
constructor() { }
|
||||
|
||||
public resetImage() {
|
||||
this.imageZoom = 1;
|
||||
this.imagePosition = {x: 0, y: 0};
|
||||
}
|
||||
|
||||
public onDragMoved($event: CdkDragMove<HTMLDivElement>): void {
|
||||
this.imagePosition.x += $event.delta.x;
|
||||
this.imagePosition.y += $event.delta.y;
|
||||
}
|
||||
|
||||
@HostListener("window:keydown", ["$event"])
|
||||
private async handleKeydownEvent(event: KeyboardEvent) {
|
||||
switch (event.key) {
|
||||
case "Escape":
|
||||
this.resetImage();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener("mousewheel", ["$event"])
|
||||
private handleScroll(event: any) {
|
||||
if (this.mouseInImageView) {
|
||||
const delta = event.wheelDelta ?? event.detail;
|
||||
|
||||
if (delta > 0) {
|
||||
this.imageZoom += 0.2
|
||||
if (this.imageZoom > 4) {
|
||||
this.imageZoom = 4;
|
||||
}
|
||||
} else if (delta < 0) {
|
||||
this.imageZoom -= 0.2
|
||||
if (this.imageZoom < 0.5) {
|
||||
this.imageZoom = 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue