diff --git a/.angular-cli.json b/.angular-cli.json index 8b7aab4..ae1c448 100644 --- a/.angular-cli.json +++ b/.angular-cli.json @@ -19,6 +19,7 @@ "testTsconfig": "tsconfig.spec.json", "prefix": "app", "styles": [ + "../node_modules/normalize.css/normalize.css", "assets/css/font-awesome.css", "styles.css" ], @@ -41,6 +42,7 @@ "tsconfig": "tsconfig.app-ssr.json", "prefix": "app", "styles": [ + "../node_modules/normalize.css/normalize.css", "assets/css/font-awesome.css", "styles.css" ], diff --git a/package-lock.json b/package-lock.json index 0e66b11..70d9a4c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5273,6 +5273,11 @@ "sort-keys": "1.1.2" } }, + "normalize.css": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-7.0.0.tgz", + "integrity": "sha1-q/sd2CRwZ04DIrU86xqvQSk45L8=" + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", diff --git a/package.json b/package.json index 3f7f4fe..d004d89 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@angular/platform-server": "^4.3.3", "@angular/router": "^4.2.4", "core-js": "^2.4.1", + "normalize.css": "^7.0.0", "pm2": "^2.6.1", "rxjs": "^5.4.2", "zone.js": "^0.8.14" diff --git a/src/app/animations/fade-in.animation.ts b/src/app/animations/fade-in.animation.ts new file mode 100644 index 0000000..1604fd6 --- /dev/null +++ b/src/app/animations/fade-in.animation.ts @@ -0,0 +1,14 @@ +import {trigger, state, animate, transition, style} from '@angular/animations'; + +export const fadeInAnimation = + trigger('fadeInAnimation', [ + // route 'enter' transition + transition(':enter', [ + + // styles at start of transition + style({opacity: 0}), + + // animation and styles at end of transition + animate('3s', style({opacity: 1})) + ]), + ]); diff --git a/src/app/animations/index.ts b/src/app/animations/index.ts new file mode 100644 index 0000000..893db99 --- /dev/null +++ b/src/app/animations/index.ts @@ -0,0 +1,2 @@ +export * from './fade-in.animation'; +export * from './slide-in-out.animation'; diff --git a/src/app/animations/slide-in-out.animation.ts b/src/app/animations/slide-in-out.animation.ts new file mode 100644 index 0000000..dec25ca --- /dev/null +++ b/src/app/animations/slide-in-out.animation.ts @@ -0,0 +1,51 @@ +import {trigger, state, animate, transition, style} from '@angular/animations'; + +export const slideInOutAnimation = + trigger('slideInOutAnimation', [ + + // end state styles for route container (host) + state('*', style({ + // the view covers the whole screen with a semi tranparent background + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + // backgroundColor: 'rgba(0, 0, 0, 0.8)' + })), + + // route 'enter' transition + transition(':enter', [ + + // styles at start of transition + style({ + // start with the content positioned off the right of the screen, + // -400% is required instead of -100% because the negative position adds to the width of the element + top: '-100%', + + // start with background opacity set to 0 (invisible) + // backgroundColor: 'rgba(0, 0, 0, 0)' + }), + + // animation and styles at end of transition + animate('.5s ease-in-out', style({ + // transition the right position to 0 which slides the content into view + top: 0, + + // transition the background opacity to 0.8 to fade it in + // backgroundColor: 'rgba(0, 0, 0, 0.8)' + })) + ]), + + // route 'leave' transition + transition(':leave', [ + // animation and styles at end of transition + animate('.5s ease-in-out', style({ + // transition the right position to -400% which slides the content out of view + top: '-100%', + + // transition the background opacity to 0 to fade it out + // backgroundColor: 'rgba(0, 0, 0, 0)' + })) + ]) + ]); diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 171987f..13afbf8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,4 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from "@angular/platform-browser/animations" import { NgModule } from '@angular/core'; import { AppRoutingModule } from './app-routing.module'; @@ -13,6 +14,7 @@ import { GalleryModule } from "./gallery/gallery.module"; BrowserModule.withServerTransition({ appId: 'angullary' }), + BrowserAnimationsModule, AppRoutingModule, GalleryModule, ], diff --git a/src/app/gallery/album/album.component.css b/src/app/gallery/album/album.component.css index 72d23c8..da2b2d0 100644 --- a/src/app/gallery/album/album.component.css +++ b/src/app/gallery/album/album.component.css @@ -20,4 +20,4 @@ h1 { padding-right: 15px; -} \ No newline at end of file +} diff --git a/src/app/gallery/album/album.component.ts b/src/app/gallery/album/album.component.ts index 147d544..cbf1c74 100644 --- a/src/app/gallery/album/album.component.ts +++ b/src/app/gallery/album/album.component.ts @@ -1,12 +1,12 @@ -import {Component, OnInit} from '@angular/core'; -import {ActivatedRoute} from "@angular/router"; -import {Title} from "@angular/platform-browser"; +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from "@angular/router"; +import { Title } from "@angular/platform-browser"; -import {Album} from "../shared/album.model"; -import {DisplayImageService} from "../display-image/display-image.service"; -import {environment} from "../../../environments/environment"; -import {Image} from "../shared/image.model"; -import {Thumbnail} from "../shared/thumbnail.model"; +import { Album } from "../shared/album.model"; +import { DisplayImageService } from "../display-image/display-image.service"; +import { environment } from "../../../environments/environment"; +import { Image } from "../shared/image.model"; +import { Thumbnail } from "../shared/thumbnail.model"; const IDX_LEFT = 0; const IDX_MIDDLE = 1; @@ -14,111 +14,117 @@ const IDX_RIGHT = 2; const THUMB_MARGIN = 10; @Component({ - selector: 'app-album', - templateUrl: './album.component.html', - styleUrls: ['./album.component.css'], + selector: 'app-album', + templateUrl: './album.component.html', + styleUrls: ['./album.component.css'], }) export class AlbumComponent implements OnInit { - public album: Album = new Album(); + public album: Album = new Album(); - private leftHeight: number = 0; - private middleHeight: number = 0; - private rightHeight: number = 0; + private leftHeight: number = 0; + private middleHeight: number = 0; + private rightHeight: number = 0; - public thumbnailsLeft: Array = []; - public thumbnailsMiddle: Array = []; - public thumbnailsRight: Array = []; + public thumbnailsLeft: Array = []; + public thumbnailsMiddle: Array = []; + public thumbnailsRight: Array = []; - constructor(private titleService: Title, - private route: ActivatedRoute, - private displayImageService: DisplayImageService) {} - - ngOnInit() { - this.route.data.subscribe((data: { albums: Array}) => { - this.album = data.albums.find(album => album.slug == this.route.snapshot.params.slug); - this.titleService.setTitle(`${this.album.name} - photos.yvan.hu`); - this.initThumbnails(); - if(this.route.snapshot.params.image) { - this.imageClick( - this.route.snapshot.params.slug, - this.route.snapshot.params.image - ); - } - }); - } - - private initThumbnails() { - this.album.images.map(image => { - slug: '', - image: this.imageUrl(image), - path: image.path, - label: { - title: image.path, - extraRight: '', - extraLeft: '', - }, - height: image.thumbHeight, - }).map(thumbnail => { - let heights = [this.leftHeight, this.middleHeight, this.rightHeight]; - let idx = heights.reduce((low, nxt, idx) => nxt < heights[low] ? idx : low, 0); - switch(idx) { - case IDX_LEFT: - this.thumbnailsLeft.push(thumbnail); - this.leftHeight += thumbnail.height + THUMB_MARGIN; - break; - case IDX_MIDDLE: - this.thumbnailsMiddle.push(thumbnail); - this.middleHeight += thumbnail.height + THUMB_MARGIN; - break; - case IDX_RIGHT: - this.thumbnailsRight.push(thumbnail); - this.rightHeight += thumbnail.height + THUMB_MARGIN; - break; - } - }); - } - - public get exportUrl(): string { - return environment.apiUrl + `/export-album/${this.album.slug}`; - } - - private imageUrl(image: Image): string { - return environment.apiUrl + `/image/${this.route.snapshot.params.slug}/${image.path}/thumb`; - } - - public imageClick(slug: string, path: string) { - this.displayImageService.activate(slug, path, this.album.name); - } - - public switchImage(evnt:{direction: string, currentPath: string}) { - switch (evnt.direction) { - case 'next': - this.nextImage(evnt.currentPath); - break; - case 'prev': - this.prevImage(evnt.currentPath); - break; + constructor(private titleService: Title, + private route: ActivatedRoute, + private displayImageService: DisplayImageService) { } - } - private nextImage(path: string) { - let currentIndex: number = this.album.images.findIndex(image => image.path == path); - if(this.album.images.length-1 > currentIndex) { - this.displayImageService.activate( - this.album.slug, - this.album.images[currentIndex+1].path - ) + ngOnInit() { + this.route.data.subscribe((data: { albums: Array }) => { + this.album = data.albums.find(album => album.slug == this.route.snapshot.params.slug); + this.titleService.setTitle(`${this.album.name} - photos.yvan.hu`); + this.initThumbnails(); + this.route.params.subscribe((params: { + slug: string, + image: string + }) => { + if (params.image) { + this.imageClick( + params.slug, + params.image + ) + } + }); + }); } - } - private prevImage(path: string) { - let currentIndex: number = this.album.images.findIndex(image => image.path == path); - if(0 < currentIndex) { - this.displayImageService.activate( - this.album.slug, - this.album.images[currentIndex-1].path - ) + private initThumbnails() { + this.album.images.map(image => { + slug: '', + image: this.imageUrl(image), + path: image.path, + label: { + title: image.path, + extraRight: '', + extraLeft: '', + }, + height: image.thumbHeight, + }).map(thumbnail => { + let heights = [this.leftHeight, this.middleHeight, this.rightHeight]; + let idx = heights.reduce((low, nxt, idx) => nxt < heights[low] ? idx : low, 0); + switch (idx) { + case IDX_LEFT: + this.thumbnailsLeft.push(thumbnail); + this.leftHeight += thumbnail.height + THUMB_MARGIN; + break; + case IDX_MIDDLE: + this.thumbnailsMiddle.push(thumbnail); + this.middleHeight += thumbnail.height + THUMB_MARGIN; + break; + case IDX_RIGHT: + this.thumbnailsRight.push(thumbnail); + this.rightHeight += thumbnail.height + THUMB_MARGIN; + break; + } + }); + } + + public get exportUrl(): string { + return environment.apiUrl + `/export-album/${this.album.slug}`; + } + + private imageUrl(image: Image): string { + return environment.apiUrl + `/image/${this.route.snapshot.params.slug}/${image.path}/thumb`; + } + + public imageClick(slug: string, path: string) { + this.displayImageService.activate(slug, path, this.album.name); + } + + public switchImage(evnt: { direction: string, currentPath: string }) { + switch (evnt.direction) { + case 'next': + this.nextImage(evnt.currentPath); + break; + case 'prev': + this.prevImage(evnt.currentPath); + break; + } + } + + private nextImage(path: string) { + let currentIndex: number = this.album.images.findIndex(image => image.path == path); + if (this.album.images.length - 1 > currentIndex) { + this.displayImageService.activate( + this.album.slug, + this.album.images[currentIndex + 1].path + ) + } + } + + private prevImage(path: string) { + let currentIndex: number = this.album.images.findIndex(image => image.path == path); + if (0 < currentIndex) { + this.displayImageService.activate( + this.album.slug, + this.album.images[currentIndex - 1].path + ) + } } - } } diff --git a/src/app/gallery/display-image/display-image.component.ts b/src/app/gallery/display-image/display-image.component.ts index baa4130..30b43e6 100644 --- a/src/app/gallery/display-image/display-image.component.ts +++ b/src/app/gallery/display-image/display-image.component.ts @@ -4,150 +4,149 @@ import { Location } from "@angular/common"; import { environment } from "../../../environments/environment"; import { Title } from "@angular/platform-browser"; import { DisplayImageService } from "./display-image.service"; +import { Router } from "@angular/router"; @Component({ - selector: 'app-display-image', - templateUrl: './display-image.component.html', - styleUrls: ['./display-image.component.css'], + selector: 'app-display-image', + templateUrl: './display-image.component.html', + styleUrls: ['./display-image.component.css'], }) export class DisplayImageComponent implements OnInit { - @Output() - private imageChange: EventEmitter = new EventEmitter(); + @Output() + private imageChange: EventEmitter = new EventEmitter(); - private touchX: number = 0; - private touchY: number = 0; + private touchX: number = 0; + private touchY: number = 0; - private slug: string = ""; - private image: string = ""; - private albumTitle: string = ""; + private slug: string = ""; + private image: string = ""; + private albumTitle: string = ""; - private visible: boolean = false; + private visible: boolean = false; - public constructor(private titleService: Title, - private locationService: Location, - private displayImageService: DisplayImageService) { - displayImageService.activate = this.activate.bind(this); - } - - public ngOnInit() {} - - public get modalStyle(): any { - return { - 'z-index': this.visible ? 9999 : -1, - 'opacity': this.visible ? 1 : 0, - }; - } - - public get hasImage(): boolean { - return this.image.length > 0; - } - - public get imageUrl(): string { - try { - return environment.apiUrl + `/image/${this.slug}/${this.image}`; - } catch (e) { - return ''; - } - } - - public activate(slug = "", image = "", extitle = "") { - this.init(slug, image, extitle); - - this.locationService.go(`/album/${this.slug}/${this.image}`); - - return new Promise(resolve => { - this.show(resolve); - }); - } - - private init(slug, image, extitle) { - this.slug = slug; - this.image = image; - this.albumTitle = extitle; - } - - private show(resolve: (boolean) => any) { - this.titleService.setTitle(`${this.image} - photos.yvan.hu`); - let habbidyn = (e: any) => resolve(true); - this.visible = true; - return habbidyn(null); - } - - private hide() { - this.visible = false; - this.titleService.setTitle(`${this.albumTitle} - photos.yvan.hu`); - this.locationService.go(`/album/${this.slug}`); - } - - private nextImage() { - this.imageChange.emit({ - direction: "next", - currentPath: this.image, - }); - } - - private prevImage() { - this.imageChange.emit({ - direction: "prev", - currentPath: this.image, - }); - } - - @HostListener('document:keyup', ['$event.key']) - private handleKeyPress(keyPressed: string) { - if (this.visible) { - switch (keyPressed) { - case 'Escape': - this.hide(); - break; - case 'ArrowRight': - case ' ': - this.nextImage(); - break; - case 'ArrowLeft': - case 'Backspace': - this.prevImage(); - break; - } - } - } - - @HostListener('click') - private handleClick() { - if(this.visible) { - this.nextImage(); - } - } - - @HostListener('touchstart', ['$event']) - private touchStart(touchEvent: TouchEvent) { - this.touchX = touchEvent.touches[0].clientX; - this.touchY = touchEvent.touches[0].clientY; - } - - @HostListener('touchend', ['$event']) - private touchEnd(touchEvent: TouchEvent) { - let xDiff: number = this.touchX - touchEvent.changedTouches[0].clientX; - let yDiff: number = this.touchY - touchEvent.changedTouches[0].clientY; - - if( Math.abs(xDiff) > Math.abs(yDiff) ) { - if( xDiff>0 ) { - this.prevImage(); - } else { - this.nextImage(); - } - } else { - this.hide(); + public constructor(private titleService: Title, + private router: Router, + private displayImageService: DisplayImageService) { + displayImageService.activate = this.activate.bind(this); } - this.touchX = 0; - this.touchY = 0; - } + public ngOnInit() { + } - @HostListener('touchcancel') - private touchCancel() { - this.touchX = 0; - this.touchY = 0; - } + public get modalStyle(): any { + return { + 'z-index': this.visible ? 9999 : -1, + 'opacity': this.visible ? 1 : 0, + }; + } + + public get hasImage(): boolean { + return this.image.length > 0; + } + + public get imageUrl(): string { + let url = environment.apiUrl + `/image/${this.slug}/${this.image}`; + return url; + } + + public activate(slug = "", image = "", extitle = "") { + this.init(slug, image, extitle); + + this.router.navigate([`/album/${this.slug}/${this.image}`]); + + return new Promise(resolve => { + this.show(resolve); + }); + } + + private init(slug, image, extitle) { + this.slug = slug; + this.image = image; + this.albumTitle = extitle; + } + + private show(resolve: (boolean) => any) { + this.titleService.setTitle(`${this.image} - photos.yvan.hu`); + let habbidyn = (e: any) => resolve(true); + this.visible = true; + return habbidyn(null); + } + + private hide() { + this.visible = false; + this.titleService.setTitle(`${this.albumTitle} - photos.yvan.hu`); + this.router.navigate([`${this.albumTitle} - photos.yvan.hu`]); + } + + private nextImage() { + this.imageChange.emit({ + direction: "next", + currentPath: this.image, + }); + } + + private prevImage() { + this.imageChange.emit({ + direction: "prev", + currentPath: this.image, + }); + } + + @HostListener('document:keyup', ['$event.key']) + private handleKeyPress(keyPressed: string) { + if (this.visible) { + switch (keyPressed) { + case 'Escape': + this.hide(); + break; + case 'ArrowRight': + case ' ': + this.nextImage(); + break; + case 'ArrowLeft': + case 'Backspace': + this.prevImage(); + break; + } + } + } + + @HostListener('click') + private handleClick() { + if (this.visible) { + this.nextImage(); + } + } + + @HostListener('touchstart', ['$event']) + private touchStart(touchEvent: TouchEvent) { + this.touchX = touchEvent.touches[0].clientX; + this.touchY = touchEvent.touches[0].clientY; + } + + @HostListener('touchend', ['$event']) + private touchEnd(touchEvent: TouchEvent) { + let xDiff: number = this.touchX - touchEvent.changedTouches[0].clientX; + let yDiff: number = this.touchY - touchEvent.changedTouches[0].clientY; + + if (Math.abs(xDiff) > Math.abs(yDiff)) { + if (xDiff > 0) { + this.prevImage(); + } else { + this.nextImage(); + } + } else { + this.hide(); + } + + this.touchX = 0; + this.touchY = 0; + } + + @HostListener('touchcancel') + private touchCancel() { + this.touchX = 0; + this.touchY = 0; + } } diff --git a/src/app/gallery/thumbnail/thumbnail.component.css b/src/app/gallery/thumbnail/thumbnail.component.css index d592745..e9a1d24 100644 --- a/src/app/gallery/thumbnail/thumbnail.component.css +++ b/src/app/gallery/thumbnail/thumbnail.component.css @@ -1,3 +1,7 @@ +:host { + display: flex; +} + .thumbnail { position: relative; display: inline-block; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index afaec31..9de6b3a 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -5,5 +5,6 @@ export const environment = { production: false, - apiUrl: 'http://localhost:8888', + // apiUrl: 'http://localhost:8888', + apiUrl: 'http://photos-api.yvan.hu', }; diff --git a/src/styles.css b/src/styles.css index 96bbbd5..0cb6a92 100644 --- a/src/styles.css +++ b/src/styles.css @@ -1,25 +1,10 @@ /* You can add global styles to this file, and also import other style files */ @import url('https://fonts.googleapis.com/css?family=Source Sans Pro:400,700,400italic,700italic&subset=latin'); -*, -*:before, -*:after { - box-sizing: inherit; -} - -html { - box-sizing: border-box; -} - -body { - margin: 0; - background-color: #FFFFFF; -} - -html, -body { - height: 100%; -} +/*html,*/ +/*body {*/ + /*height: 100%;*/ +/*}*/ body { margin: 0; @@ -31,6 +16,7 @@ body { font-size: 14px; line-height: 1.4285em; color: #839496; + user-select: none; } a {