* deploy added
* semantic-ui removed * image display reworked
This commit is contained in:
parent
87f6ca9ddb
commit
8f98dcb5e1
@ -19,7 +19,6 @@
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../semantic/dist/semantic.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
@ -41,7 +40,6 @@
|
||||
"tsconfig": "tsconfig.app-ssr.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../semantic/dist/semantic.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
|
||||
73
deploy.php
Normal file
73
deploy.php
Normal file
@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
namespace Deployer;
|
||||
require 'recipe/common.php';
|
||||
|
||||
set('ssh_type', 'native');
|
||||
set('ssh_multiplexing', true);
|
||||
|
||||
// Configuration
|
||||
|
||||
// set('repository', 'git@domain.com:username/repository.git');
|
||||
set('shared_files', []);
|
||||
set('shared_dirs', []);
|
||||
set('writable_dirs', []);
|
||||
set('keep_releases', 3);
|
||||
set('default_stage', 'production');
|
||||
|
||||
// Servers
|
||||
server('alfheim', 'alfheim.ragnarok.yvan.hu')
|
||||
->stage('production')
|
||||
->user('yvan')
|
||||
->identityFile()
|
||||
->set('ng_target', 'production')
|
||||
->set('ng_environment', 'prod')
|
||||
->set('env_vars', 'NODE_ENV=production')
|
||||
->set('deploy_path', '/var/www/photos/frontend');
|
||||
|
||||
// Tasks
|
||||
desc('Prepare release');
|
||||
task('deploy:ng-prepare', function() {
|
||||
runLocally("ng build --target={{ng_target}} --environment={{ng_environment}}");
|
||||
runLocally("ng build --target={{ng_target}} --environment={{ng_environment}} --app ssr --output-hashing=none");
|
||||
runLocally("tar -cJf dist.tar.xz dist dist-ssr render.js package.json pm2.json");
|
||||
});
|
||||
|
||||
desc('Upload release');
|
||||
task('deploy:ng-upload', function() {
|
||||
upload("dist.tar.xz", "{{release_path}}/dist.tar.xz");
|
||||
run("tar -C {{release_path}} -xJf {{release_path}}/dist.tar.xz");
|
||||
within("{{release_path}}", function () {
|
||||
run("npm install --production");
|
||||
run("npm install express --production");
|
||||
});
|
||||
run("rm -f {{release_path}}/dist.tar.xz");
|
||||
runLocally("rm -rf dist.tar.xz dist dist-ssr");
|
||||
});
|
||||
|
||||
desc('Start app server');
|
||||
task('deploy:node-restart', function() {
|
||||
within("{{release_path}}", function () {
|
||||
run("pm2 stop --silent gallery-frontend");
|
||||
run("pm2 delete --silent gallery-frontend");
|
||||
|
||||
run("pm2 start pm2.json");
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
desc('Deploy your project');
|
||||
task('deploy', [
|
||||
'deploy:prepare',
|
||||
'deploy:lock',
|
||||
'deploy:release',
|
||||
'deploy:ng-prepare',
|
||||
'deploy:ng-upload',
|
||||
'deploy:shared',
|
||||
'deploy:clear_paths',
|
||||
'deploy:symlink',
|
||||
'deploy:node-restart',
|
||||
'deploy:unlock',
|
||||
'cleanup',
|
||||
]);
|
||||
after('deploy', 'success');
|
||||
3385
package-lock.json
generated
3385
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -24,8 +24,8 @@
|
||||
"@angular/platform-server": "^4.3.3",
|
||||
"@angular/router": "^4.2.4",
|
||||
"core-js": "^2.4.1",
|
||||
"pm2": "^2.6.1",
|
||||
"rxjs": "^5.4.2",
|
||||
"semantic-ui": "^2.2.13",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
13
pm2.json
Normal file
13
pm2.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"apps" : [{
|
||||
"name" : "gallery-frontend",
|
||||
"script" : "./render.js",
|
||||
"watch" : true,
|
||||
"env": {
|
||||
"NODE_ENV": "development"
|
||||
},
|
||||
"env_production" : {
|
||||
"NODE_ENV": "production"
|
||||
}
|
||||
}]
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
const PORT = 4000;
|
||||
|
||||
require('reflect-metadata');
|
||||
//require('reflect-metadata');
|
||||
require('zone.js/dist/zone-node');
|
||||
const { renderModuleFactory } = require('@angular/platform-server');
|
||||
const { enableProdMode } = require('@angular/core');
|
||||
@ -23,7 +23,7 @@ app.engine('html', (_, options, callback) => {
|
||||
});
|
||||
|
||||
app.set('view engine', 'html');
|
||||
app.set('views', 'src')
|
||||
app.set('views', 'dist')
|
||||
|
||||
app.get('*.*', express.static(join(__dirname, 'dist')));
|
||||
app.get('*', (req, res) => {
|
||||
|
||||
@ -1,22 +0,0 @@
|
||||
{
|
||||
"base": "semantic/",
|
||||
"paths": {
|
||||
"source": {
|
||||
"config": "src/theme.config",
|
||||
"definitions": "src/definitions/",
|
||||
"site": "src/site/",
|
||||
"themes": "src/themes/"
|
||||
},
|
||||
"output": {
|
||||
"packaged": "dist/",
|
||||
"uncompressed": "dist/components/",
|
||||
"compressed": "dist/components/",
|
||||
"themes": "dist/themes/"
|
||||
},
|
||||
"clean": "dist/"
|
||||
},
|
||||
"permission": false,
|
||||
"autoInstall": true,
|
||||
"rtl": false,
|
||||
"version": "2.2.13"
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
<div class="image">
|
||||
<img src="{{image}}">
|
||||
</div>
|
||||
<div class="extra content">
|
||||
<a>
|
||||
<i class="image icon"></i>
|
||||
{{item.path}}
|
||||
</a>
|
||||
</div>
|
||||
@ -1,27 +0,0 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {Image} from "../shared/image.model";
|
||||
|
||||
import { environment } from "../../../environments/environment";
|
||||
|
||||
@Component({
|
||||
selector: 'app-album-item,[app-album-item]',
|
||||
templateUrl: './album-item.component.html',
|
||||
styleUrls: ['./album-item.component.css']
|
||||
})
|
||||
export class AlbumItemComponent implements OnInit {
|
||||
|
||||
@Input() slug: string = "";
|
||||
@Input() item: Image = new Image();
|
||||
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get image(): string {
|
||||
try {
|
||||
return environment.apiUrl + `/image/${this.slug}/${this.item.path}/thumb`;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
.main.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 510px;
|
||||
}
|
||||
@ -1,6 +1,22 @@
|
||||
<div class="ui main fullwide-container">
|
||||
<div class="ui special cards">
|
||||
<div app-album-item class="ui link card" *ngFor="let item of album.images" [item]="item" [slug]="album.slug" (click)="imageClick(album.slug, item.path)"></div>
|
||||
<div class="main container">
|
||||
<h1>{{album.name}}</h1>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsLeft"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
(click)="imageClick(album.slug, thumbnail.path)"></app-thumbnail>
|
||||
</div>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsMiddle"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
(click)="imageClick(album.slug, thumbnail.path)"></app-thumbnail>
|
||||
</div>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsRight"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
(click)="imageClick(album.slug, thumbnail.path)"></app-thumbnail>
|
||||
</div>
|
||||
</div>
|
||||
<app-display-image (imageChange)="switchImage($event)"></app-display-image>
|
||||
@ -4,24 +4,29 @@ import {Album} from "../shared/album.model";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {Title} from "@angular/platform-browser";
|
||||
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";
|
||||
|
||||
@Component({
|
||||
selector: 'app-album',
|
||||
templateUrl: './album.component.html',
|
||||
styleUrls: ['./album.component.css']
|
||||
styleUrls: ['./album.component.css'],
|
||||
})
|
||||
export class AlbumComponent implements OnInit {
|
||||
|
||||
public album: Album = new Album();
|
||||
private thumbnails: Array<Thumbnail>;
|
||||
|
||||
constructor(private titleService: Title,
|
||||
private route: ActivatedRoute,
|
||||
private displayImageService: DisplayImageService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('Album');
|
||||
this.route.data.subscribe((data: { albums: Array<Album>}) => {
|
||||
this.album = data.albums.find(album => album.slug == this.route.snapshot.params.slug);
|
||||
this.titleService.setTitle(`${this.album.name} - photos.yvan.hu`);
|
||||
this.thumbnails = this.initThumbnails();
|
||||
if(this.route.snapshot.params.image) {
|
||||
this.imageClick(
|
||||
this.route.snapshot.params.slug,
|
||||
@ -31,8 +36,52 @@ export class AlbumComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private initThumbnails(): Array<Thumbnail> {
|
||||
return this.album.images.map(image => <Thumbnail>{
|
||||
slug: '',
|
||||
image: this.imageUrl(image),
|
||||
path: image.path,
|
||||
label: {
|
||||
title: image.path,
|
||||
extraRight: '',
|
||||
extraLeft: '',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
get thumbnailsLeft(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=0;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
get thumbnailsMiddle(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=1;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
get thumbnailsRight(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=2;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
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.displayImageService.activate(slug, path, this.album.name);
|
||||
}
|
||||
|
||||
public switchImage(evnt:{direction: string, currentPath: string}) {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
background: rgba(0, 0, 0, 0.75);
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 150ms ease-in;
|
||||
@ -13,5 +13,7 @@
|
||||
}
|
||||
|
||||
.modal-container .image {
|
||||
display: flex;
|
||||
margin: auto;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
@ -8,7 +8,7 @@ import { DisplayImageService } from "./display-image.service";
|
||||
@Component({
|
||||
selector: 'app-display-image',
|
||||
templateUrl: './display-image.component.html',
|
||||
styleUrls: ['./display-image.component.css']
|
||||
styleUrls: ['./display-image.component.css'],
|
||||
})
|
||||
export class DisplayImageComponent implements OnInit {
|
||||
@Output()
|
||||
@ -16,6 +16,7 @@ export class DisplayImageComponent implements OnInit {
|
||||
|
||||
private slug: string = "";
|
||||
private image: string = "";
|
||||
private extitle: string = "";
|
||||
|
||||
private visible: boolean = false;
|
||||
|
||||
@ -25,9 +26,7 @@ export class DisplayImageComponent implements OnInit {
|
||||
displayImageService.activate = this.activate.bind(this);
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
this.titleService.setTitle('Image');
|
||||
}
|
||||
public ngOnInit() {}
|
||||
|
||||
public get modalStyle(): any {
|
||||
return {
|
||||
@ -48,8 +47,8 @@ export class DisplayImageComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
public activate(slug = "", image = "") {
|
||||
this.init(slug, image);
|
||||
public activate(slug = "", image = "", extitle = "") {
|
||||
this.init(slug, image, extitle);
|
||||
|
||||
this.locationService.go(`/album/${this.slug}/${this.image}`);
|
||||
|
||||
@ -58,12 +57,14 @@ export class DisplayImageComponent implements OnInit {
|
||||
});
|
||||
}
|
||||
|
||||
private init(slug, image) {
|
||||
private init(slug, image, extitle) {
|
||||
this.slug = slug;
|
||||
this.image = image;
|
||||
this.extitle = 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);
|
||||
@ -71,6 +72,7 @@ export class DisplayImageComponent implements OnInit {
|
||||
|
||||
private hide() {
|
||||
this.visible = false;
|
||||
this.titleService.setTitle(`${this.extitle} - photos.yvan.hu`);
|
||||
this.locationService.go(`/album/${this.slug}`);
|
||||
}
|
||||
|
||||
@ -107,4 +109,11 @@ export class DisplayImageComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
@HostListener('click')
|
||||
public handleClick() {
|
||||
if(this.visible) {
|
||||
this.nextImage();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,6 +4,6 @@ import { Injectable } from '@angular/core';
|
||||
export class DisplayImageService {
|
||||
|
||||
constructor() { }
|
||||
activate: (message?: string, title?: string) => Promise<boolean>;
|
||||
activate: (message?: string, title?: string, extitle? :string) => Promise<boolean>;
|
||||
|
||||
}
|
||||
|
||||
@ -1,15 +0,0 @@
|
||||
<div class="image">
|
||||
<img src="{{coverImage}}">
|
||||
</div>
|
||||
<div class="content">
|
||||
<a class="header">{{item.name}}</a>
|
||||
<div class="meta">
|
||||
<span class="date">{{item.date}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="extra content">
|
||||
<a>
|
||||
<i class="image icon"></i>
|
||||
{{imageCount}} photos
|
||||
</a>
|
||||
</div>
|
||||
@ -1,25 +0,0 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GalleryItemComponent } from './gallery-item.component';
|
||||
|
||||
describe('GalleryItemComponent', () => {
|
||||
let component: GalleryItemComponent;
|
||||
let fixture: ComponentFixture<GalleryItemComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ GalleryItemComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GalleryItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@ -1,30 +0,0 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
import {Album} from "../shared/album.model";
|
||||
|
||||
import { environment } from "../../../environments/environment";
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-item,[app-gallery-item]',
|
||||
templateUrl: './gallery-item.component.html',
|
||||
styleUrls: ['./gallery-item.component.css']
|
||||
})
|
||||
export class GalleryItemComponent implements OnInit {
|
||||
|
||||
@Input() item: Album = new Album();
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
get imageCount(): number {
|
||||
return this.item.images.length;
|
||||
}
|
||||
|
||||
get coverImage(): string {
|
||||
try {
|
||||
return environment.apiUrl + `/image/${this.item.slug}/${this.item.coverImage.path}/thumb`;
|
||||
} catch (e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,9 +6,8 @@ import { GalleryComponent } from './gallery/gallery.component';
|
||||
import { AlbumComponent } from './album/album.component';
|
||||
import { DisplayImageComponent } from './display-image/display-image.component';
|
||||
import { GalleryRoutingModule } from "./gallery-routing.module";
|
||||
import { GalleryItemComponent } from './gallery-item/gallery-item.component';
|
||||
import { AlbumItemComponent } from './album-item/album-item.component';
|
||||
import { DisplayImageService } from './display-image/display-image.service';
|
||||
import { ThumbnailComponent } from './thumbnail/thumbnail.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -23,8 +22,7 @@ import { DisplayImageService } from './display-image/display-image.service';
|
||||
GalleryComponent,
|
||||
AlbumComponent,
|
||||
DisplayImageComponent,
|
||||
GalleryItemComponent,
|
||||
AlbumItemComponent,
|
||||
ThumbnailComponent,
|
||||
],
|
||||
providers: [ GalleryService, DisplayImageService ]
|
||||
})
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
.main.container {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.row {
|
||||
display: block;
|
||||
float: left;
|
||||
width: 510px;
|
||||
}
|
||||
@ -1,5 +1,21 @@
|
||||
<div class="ui main container">
|
||||
<div class="ui special cards">
|
||||
<div app-gallery-item class="ui link card" *ngFor="let item of albums" [item]="item" [routerLink]="['/album', item.slug]"></div>
|
||||
<div class="main container">
|
||||
<h1>Albums</h1>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsLeft"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
[routerLink]="['/album', thumbnail.slug]"></app-thumbnail>
|
||||
</div>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsMiddle"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
[routerLink]="['/album', thumbnail.slug]"></app-thumbnail>
|
||||
</div>
|
||||
<div class="row images">
|
||||
<app-thumbnail *ngFor="let thumbnail of thumbnailsRight"
|
||||
[image]="thumbnail.image"
|
||||
[label]="thumbnail.label"
|
||||
[routerLink]="['/album', thumbnail.slug]"></app-thumbnail>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,24 +1,74 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from "@angular/platform-browser";
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {Title} from "@angular/platform-browser";
|
||||
|
||||
import { Album } from "../shared";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
import {Album} from "../shared";
|
||||
import {ActivatedRoute} from "@angular/router";
|
||||
import {environment} from "../../../environments/environment";
|
||||
import {Thumbnail} from "../shared/thumbnail.model";
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery',
|
||||
templateUrl: './gallery.component.html',
|
||||
styleUrls: ['./gallery.component.css']
|
||||
styleUrls: ['./gallery.component.css'],
|
||||
})
|
||||
export class GalleryComponent implements OnInit {
|
||||
|
||||
public albums: Array<Album> = [];
|
||||
private thumbnails: Array<Thumbnail>;
|
||||
|
||||
constructor(private titleService: Title,
|
||||
private route: ActivatedRoute) {}
|
||||
private route: ActivatedRoute) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('Albums');
|
||||
this.route.data.subscribe((data: { albums: Array<Album>}) => this.albums = data.albums);
|
||||
this.titleService.setTitle('Albums - photos.yvan.hu');
|
||||
this.route.data.subscribe((data: { albums: Array<Album> }) => {
|
||||
this.albums = data.albums;
|
||||
this.thumbnails = this.initThumbnails();
|
||||
});
|
||||
}
|
||||
|
||||
private initThumbnails(): Array<Thumbnail> {
|
||||
return this.albums.map(album => <Thumbnail>{
|
||||
slug: album.slug,
|
||||
image: this.imageUrl(album),
|
||||
label: {
|
||||
title: album.name,
|
||||
extraRight: album.images.length + ' images',
|
||||
extraLeft: album.date,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
get thumbnailsLeft(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=0;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
get thumbnailsMiddle(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=1;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
get thumbnailsRight(): Array<Thumbnail> {
|
||||
let thumbs = [];
|
||||
for (let i=2;i<this.thumbnails.length; i=i+3) {
|
||||
thumbs.push(this.thumbnails[i]);
|
||||
|
||||
}
|
||||
return thumbs;
|
||||
}
|
||||
|
||||
private imageUrl(album: Album): string {
|
||||
return environment.apiUrl + `/image/${album.slug}/${album.coverImage.path}/thumb`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
5
src/app/gallery/shared/thumb-label.model.ts
Normal file
5
src/app/gallery/shared/thumb-label.model.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export class ThumbLabel {
|
||||
public title: string = "";
|
||||
public extraLeft: string = "";
|
||||
public extraRight: string = "";
|
||||
}
|
||||
8
src/app/gallery/shared/thumbnail.model.ts
Normal file
8
src/app/gallery/shared/thumbnail.model.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import {ThumbLabel} from "./thumb-label.model";
|
||||
|
||||
export class Thumbnail {
|
||||
public slug: string = '';
|
||||
public image: string = '';
|
||||
public path: string = '';
|
||||
public label: ThumbLabel = new ThumbLabel();
|
||||
}
|
||||
37
src/app/gallery/thumbnail/thumbnail.component.css
Normal file
37
src/app/gallery/thumbnail/thumbnail.component.css
Normal file
@ -0,0 +1,37 @@
|
||||
.thumbnail {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.thumbnail img.image {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.thumbnail > div.label {
|
||||
padding-left: 14px;
|
||||
padding-right: 14px;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
transform-origin: 50% 100%;
|
||||
transition-property: transform;
|
||||
transition-duration: 0.15s;
|
||||
transition-timing-function: ease-out;
|
||||
transform: scaleY(0);
|
||||
}
|
||||
|
||||
.thumbnail:hover > div.label {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
|
||||
.align.right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.align.left {
|
||||
float: left;
|
||||
}
|
||||
7
src/app/gallery/thumbnail/thumbnail.component.html
Normal file
7
src/app/gallery/thumbnail/thumbnail.component.html
Normal file
@ -0,0 +1,7 @@
|
||||
<a class="thumbnail">
|
||||
<img class="image" src="{{image}}">
|
||||
<div class="label" *ngIf="label">
|
||||
<h1 class="title">{{label.title}}</h1>
|
||||
<h2 class="extra">{{label.extraLeft}}<span class="align right">{{label.extraRight}}</span></h2>
|
||||
</div>
|
||||
</a>
|
||||
@ -1,20 +1,20 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AlbumItemComponent } from './album-item.component';
|
||||
import { ThumbnailComponent } from './thumbnail.component';
|
||||
|
||||
describe('AlbumItemComponent', () => {
|
||||
let component: AlbumItemComponent;
|
||||
let fixture: ComponentFixture<AlbumItemComponent>;
|
||||
describe('ThumbnailComponent', () => {
|
||||
let component: ThumbnailComponent;
|
||||
let fixture: ComponentFixture<ThumbnailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AlbumItemComponent ]
|
||||
declarations: [ ThumbnailComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AlbumItemComponent);
|
||||
fixture = TestBed.createComponent(ThumbnailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
20
src/app/gallery/thumbnail/thumbnail.component.ts
Normal file
20
src/app/gallery/thumbnail/thumbnail.component.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import {Component, Input, OnInit} from '@angular/core';
|
||||
|
||||
import {ThumbLabel} from "../shared/thumb-label.model";
|
||||
|
||||
@Component({
|
||||
selector: 'app-thumbnail',
|
||||
templateUrl: './thumbnail.component.html',
|
||||
styleUrls: ['./thumbnail.component.css']
|
||||
})
|
||||
export class ThumbnailComponent implements OnInit {
|
||||
|
||||
@Input() image: string = "";
|
||||
@Input() label: ThumbLabel = null;
|
||||
@Input() target: any = {};
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit() {}
|
||||
|
||||
}
|
||||
@ -1,12 +1,65 @@
|
||||
/* 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;
|
||||
}
|
||||
.main.container,
|
||||
.main.fullwide-container {
|
||||
margin-top: 1em;
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
.ui.fullwide-container {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
min-width: 320px;
|
||||
background: #002B36;
|
||||
font-family: "Source Sans Pro", 'Helvetica Neue', Arial, Helvetica, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 1.4285em;
|
||||
color: #839496;
|
||||
}
|
||||
|
||||
a {
|
||||
cursor: pointer;
|
||||
color: #2AA198;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #2AA198;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
|
||||
/* app style */
|
||||
@media screen and (min-width: 600px) {
|
||||
.main.container {
|
||||
width: 540px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1200px) {
|
||||
.main.container {
|
||||
width: 1060px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1600px) {
|
||||
.main.container {
|
||||
width: 1580px;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user