* framework done
This commit is contained in:
parent
908a75834b
commit
87f6ca9ddb
@ -19,6 +19,7 @@
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../semantic/dist/semantic.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
@ -27,6 +28,29 @@
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "ssr",
|
||||
"root": "src",
|
||||
"outDir": "dist-ssr",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"main": "main-ssr.ts",
|
||||
"tsconfig": "tsconfig.app-ssr.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"../semantic/dist/semantic.css",
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
},
|
||||
"platform": "server"
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
# See http://help.github.com/ignore-files/ for more about ignoring files.
|
||||
|
||||
# compiled output
|
||||
/dist-ssr
|
||||
/dist
|
||||
/tmp
|
||||
/out-tsc
|
||||
|
||||
3275
package-lock.json
generated
3275
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -8,7 +8,8 @@
|
||||
"build": "ng build",
|
||||
"test": "ng test",
|
||||
"lint": "ng lint",
|
||||
"e2e": "ng e2e"
|
||||
"e2e": "ng e2e",
|
||||
"sbuild": "ng build --aot && ng build --aot --app ssr"
|
||||
},
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
@ -20,9 +21,11 @@
|
||||
"@angular/http": "^4.2.4",
|
||||
"@angular/platform-browser": "^4.2.4",
|
||||
"@angular/platform-browser-dynamic": "^4.2.4",
|
||||
"@angular/platform-server": "^4.3.3",
|
||||
"@angular/router": "^4.2.4",
|
||||
"core-js": "^2.4.1",
|
||||
"rxjs": "^5.4.2",
|
||||
"semantic-ui": "^2.2.13",
|
||||
"zone.js": "^0.8.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
35
render.js
Normal file
35
render.js
Normal file
@ -0,0 +1,35 @@
|
||||
const PORT = 4000;
|
||||
|
||||
require('reflect-metadata');
|
||||
require('zone.js/dist/zone-node');
|
||||
const { renderModuleFactory } = require('@angular/platform-server');
|
||||
const { enableProdMode } = require('@angular/core');
|
||||
const { join } = require('path');
|
||||
const express = require('express');
|
||||
const fs = require('fs');
|
||||
|
||||
const { AppServerModuleNgFactory } = require('./dist-ssr/main.bundle');
|
||||
|
||||
|
||||
enableProdMode();
|
||||
const app = express();
|
||||
let template = fs.readFileSync('dist/index.html', 'utf8');
|
||||
|
||||
app.engine('html', (_, options, callback) => {
|
||||
renderModuleFactory(AppServerModuleNgFactory, {
|
||||
document: template,
|
||||
url: options.req.url
|
||||
}).then(html => callback(null, html));
|
||||
});
|
||||
|
||||
app.set('view engine', 'html');
|
||||
app.set('views', 'src')
|
||||
|
||||
app.get('*.*', express.static(join(__dirname, 'dist')));
|
||||
app.get('*', (req, res) => {
|
||||
res.render('index', { req });
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`listening on http://localhost:${PORT}!`);
|
||||
});
|
||||
22
semantic.json
Normal file
22
semantic.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"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,12 +1,7 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: []
|
||||
}
|
||||
];
|
||||
const routes: Routes = [];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forRoot(routes)],
|
||||
|
||||
@ -1,21 +1 @@
|
||||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<div style="text-align:center">
|
||||
<h1>
|
||||
Welcome to {{title}}!
|
||||
</h1>
|
||||
<img width="300" src="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4NCjwhLS0gR2VuZXJhdG9yOiBBZG9iZSBJbGx1c3RyYXRvciAxOS4xLjAsIFNWRyBFeHBvcnQgUGx1Zy1JbiAuIFNWRyBWZXJzaW9uOiA2LjAwIEJ1aWxkIDApICAtLT4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iTGF5ZXJfMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiDQoJIHZpZXdCb3g9IjAgMCAyNTAgMjUwIiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNTAgMjUwOyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KCS5zdDB7ZmlsbDojREQwMDMxO30NCgkuc3Qxe2ZpbGw6I0MzMDAyRjt9DQoJLnN0MntmaWxsOiNGRkZGRkY7fQ0KPC9zdHlsZT4NCjxnPg0KCTxwb2x5Z29uIGNsYXNzPSJzdDAiIHBvaW50cz0iMTI1LDMwIDEyNSwzMCAxMjUsMzAgMzEuOSw2My4yIDQ2LjEsMTg2LjMgMTI1LDIzMCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAJIi8+DQoJPHBvbHlnb24gY2xhc3M9InN0MSIgcG9pbnRzPSIxMjUsMzAgMTI1LDUyLjIgMTI1LDUyLjEgMTI1LDE1My40IDEyNSwxNTMuNCAxMjUsMjMwIDEyNSwyMzAgMjAzLjksMTg2LjMgMjE4LjEsNjMuMiAxMjUsMzAgCSIvPg0KCTxwYXRoIGNsYXNzPSJzdDIiIGQ9Ik0xMjUsNTIuMUw2Ni44LDE4Mi42aDBoMjEuN2gwbDExLjctMjkuMmg0OS40bDExLjcsMjkuMmgwaDIxLjdoMEwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMUwxMjUsNTIuMQ0KCQlMMTI1LDUyLjF6IE0xNDIsMTM1LjRIMTA4bDE3LTQwLjlMMTQyLDEzNS40eiIvPg0KPC9nPg0KPC9zdmc+DQo=">
|
||||
</div>
|
||||
<h2>Here are some links to help you start: </h2>
|
||||
<ul>
|
||||
<li>
|
||||
<h2><a target="_blank" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" href="https://github.com/angular/angular-cli/wiki">CLI Documentation</a></h2>
|
||||
</li>
|
||||
<li>
|
||||
<h2><a target="_blank" href="https://blog.angular.io//">Angular blog</a></h2>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@ -3,16 +3,21 @@ import { NgModule } from '@angular/core';
|
||||
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppComponent } from './app.component';
|
||||
import { GalleryModule } from "./gallery/gallery.module";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
AppRoutingModule
|
||||
BrowserModule.withServerTransition({
|
||||
appId: 'angullary'
|
||||
}),
|
||||
AppRoutingModule,
|
||||
GalleryModule,
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
14
src/app/app.server.module.ts
Normal file
14
src/app/app.server.module.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ServerModule } from '@angular/platform-server';
|
||||
import { AppComponent } from './app.component';
|
||||
import { AppModule } from './app.module';
|
||||
@NgModule({
|
||||
imports: [
|
||||
AppModule,
|
||||
ServerModule
|
||||
],
|
||||
bootstrap: [
|
||||
AppComponent
|
||||
]
|
||||
})
|
||||
export class AppServerModule {}
|
||||
0
src/app/gallery/album-item/album-item.component.css
Normal file
0
src/app/gallery/album-item/album-item.component.css
Normal file
9
src/app/gallery/album-item/album-item.component.html
Normal file
9
src/app/gallery/album-item/album-item.component.html
Normal file
@ -0,0 +1,9 @@
|
||||
<div class="image">
|
||||
<img src="{{image}}">
|
||||
</div>
|
||||
<div class="extra content">
|
||||
<a>
|
||||
<i class="image icon"></i>
|
||||
{{item.path}}
|
||||
</a>
|
||||
</div>
|
||||
25
src/app/gallery/album-item/album-item.component.spec.ts
Normal file
25
src/app/gallery/album-item/album-item.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AlbumItemComponent } from './album-item.component';
|
||||
|
||||
describe('AlbumItemComponent', () => {
|
||||
let component: AlbumItemComponent;
|
||||
let fixture: ComponentFixture<AlbumItemComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AlbumItemComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AlbumItemComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
27
src/app/gallery/album-item/album-item.component.ts
Normal file
27
src/app/gallery/album-item/album-item.component.ts
Normal file
@ -0,0 +1,27 @@
|
||||
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
src/app/gallery/album/album.component.css
Normal file
0
src/app/gallery/album/album.component.css
Normal file
6
src/app/gallery/album/album.component.html
Normal file
6
src/app/gallery/album/album.component.html
Normal file
@ -0,0 +1,6 @@
|
||||
<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>
|
||||
</div>
|
||||
<app-display-image (imageChange)="switchImage($event)"></app-display-image>
|
||||
25
src/app/gallery/album/album.component.spec.ts
Normal file
25
src/app/gallery/album/album.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { AlbumComponent } from './album.component';
|
||||
|
||||
describe('AlbumComponent', () => {
|
||||
let component: AlbumComponent;
|
||||
let fixture: ComponentFixture<AlbumComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ AlbumComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AlbumComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
68
src/app/gallery/album/album.component.ts
Normal file
68
src/app/gallery/album/album.component.ts
Normal file
@ -0,0 +1,68 @@
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
|
||||
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";
|
||||
|
||||
@Component({
|
||||
selector: 'app-album',
|
||||
templateUrl: './album.component.html',
|
||||
styleUrls: ['./album.component.css']
|
||||
})
|
||||
export class AlbumComponent implements OnInit {
|
||||
|
||||
public album: Album = new Album();
|
||||
|
||||
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);
|
||||
if(this.route.snapshot.params.image) {
|
||||
this.imageClick(
|
||||
this.route.snapshot.params.slug,
|
||||
this.route.snapshot.params.image
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public imageClick(slug: string, path: string) {
|
||||
this.displayImageService.activate(slug, path);
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
17
src/app/gallery/display-image/display-image.component.css
Normal file
17
src/app/gallery/display-image/display-image.component.css
Normal file
@ -0,0 +1,17 @@
|
||||
.modal-container {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: -1;
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 150ms ease-in;
|
||||
-moz-transition: opacity 150ms ease-in;
|
||||
transition: opacity 150ms ease-in;
|
||||
}
|
||||
|
||||
.modal-container .image {
|
||||
margin: auto;
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
<div class="modal-container" [ngStyle]="modalStyle">
|
||||
<img *ngIf="hasImage" class="ui centered image" src="{{imageUrl}}">
|
||||
</div>
|
||||
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { DisplayImageComponent } from './display-image.component';
|
||||
|
||||
describe('DisplayImageComponent', () => {
|
||||
let component: DisplayImageComponent;
|
||||
let fixture: ComponentFixture<DisplayImageComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ DisplayImageComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DisplayImageComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
110
src/app/gallery/display-image/display-image.component.ts
Normal file
110
src/app/gallery/display-image/display-image.component.ts
Normal file
@ -0,0 +1,110 @@
|
||||
import { Component, EventEmitter, HostListener, OnInit, Output } from '@angular/core';
|
||||
import { Location } from "@angular/common";
|
||||
|
||||
import { environment } from "../../../environments/environment";
|
||||
import { Title } from "@angular/platform-browser";
|
||||
import { DisplayImageService } from "./display-image.service";
|
||||
|
||||
@Component({
|
||||
selector: 'app-display-image',
|
||||
templateUrl: './display-image.component.html',
|
||||
styleUrls: ['./display-image.component.css']
|
||||
})
|
||||
export class DisplayImageComponent implements OnInit {
|
||||
@Output()
|
||||
private imageChange: EventEmitter<any> = new EventEmitter();
|
||||
|
||||
private slug: string = "";
|
||||
private image: string = "";
|
||||
|
||||
private visible: boolean = false;
|
||||
|
||||
public constructor(private titleService: Title,
|
||||
private locationService: Location,
|
||||
private displayImageService: DisplayImageService) {
|
||||
displayImageService.activate = this.activate.bind(this);
|
||||
}
|
||||
|
||||
public ngOnInit() {
|
||||
this.titleService.setTitle('Image');
|
||||
}
|
||||
|
||||
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 = "") {
|
||||
this.init(slug, image);
|
||||
|
||||
this.locationService.go(`/album/${this.slug}/${this.image}`);
|
||||
|
||||
return new Promise<boolean>(resolve => {
|
||||
this.show(resolve);
|
||||
});
|
||||
}
|
||||
|
||||
private init(slug, image) {
|
||||
this.slug = slug;
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
private show(resolve: (boolean) => any) {
|
||||
let habbidyn = (e: any) => resolve(true);
|
||||
this.visible = true;
|
||||
return habbidyn(null);
|
||||
}
|
||||
|
||||
private hide() {
|
||||
this.visible = false;
|
||||
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'])
|
||||
public 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
15
src/app/gallery/display-image/display-image.service.spec.ts
Normal file
15
src/app/gallery/display-image/display-image.service.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { DisplayImageService } from './display-image.service';
|
||||
|
||||
describe('DisplayImageService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [DisplayImageService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([DisplayImageService], (service: DisplayImageService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
9
src/app/gallery/display-image/display-image.service.ts
Normal file
9
src/app/gallery/display-image/display-image.service.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class DisplayImageService {
|
||||
|
||||
constructor() { }
|
||||
activate: (message?: string, title?: string) => Promise<boolean>;
|
||||
|
||||
}
|
||||
15
src/app/gallery/gallery-item/gallery-item.component.html
Normal file
15
src/app/gallery/gallery-item/gallery-item.component.html
Normal file
@ -0,0 +1,15 @@
|
||||
<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>
|
||||
25
src/app/gallery/gallery-item/gallery-item.component.spec.ts
Normal file
25
src/app/gallery/gallery-item/gallery-item.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
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();
|
||||
});
|
||||
});
|
||||
30
src/app/gallery/gallery-item/gallery-item.component.ts
Normal file
30
src/app/gallery/gallery-item/gallery-item.component.ts
Normal file
@ -0,0 +1,30 @@
|
||||
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 '';
|
||||
}
|
||||
}
|
||||
}
|
||||
52
src/app/gallery/gallery-routing.module.ts
Normal file
52
src/app/gallery/gallery-routing.module.ts
Normal file
@ -0,0 +1,52 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
import { GalleryComponent } from "./gallery/gallery.component";
|
||||
import { GalleryService } from "./shared/gallery.service";
|
||||
import { AlbumComponent } from "./album/album.component";
|
||||
import { DisplayImageComponent } from "./display-image/display-image.component";
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
children: [],
|
||||
component: GalleryComponent,
|
||||
resolve: {
|
||||
albums: GalleryService,
|
||||
},
|
||||
}, {
|
||||
path: 'galleries',
|
||||
children: [],
|
||||
component: GalleryComponent,
|
||||
resolve: {
|
||||
albums: GalleryService,
|
||||
},
|
||||
}, {
|
||||
path: 'album/:slug',
|
||||
children: [],
|
||||
component: AlbumComponent,
|
||||
resolve: {
|
||||
albums: GalleryService,
|
||||
},
|
||||
}, {
|
||||
path: 'album/:slug/:image',
|
||||
children: [],
|
||||
component: AlbumComponent,
|
||||
resolve: {
|
||||
albums: GalleryService,
|
||||
},
|
||||
}, {
|
||||
path: 'image/:slug/:image',
|
||||
children: [],
|
||||
component: DisplayImageComponent,
|
||||
resolve: {
|
||||
albums: GalleryService,
|
||||
},
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule]
|
||||
})
|
||||
export class GalleryRoutingModule { }
|
||||
31
src/app/gallery/gallery.module.ts
Normal file
31
src/app/gallery/gallery.module.ts
Normal file
@ -0,0 +1,31 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { HttpModule } from "@angular/http";
|
||||
import { GalleryService } from './shared/gallery.service';
|
||||
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';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
HttpModule,
|
||||
GalleryRoutingModule,
|
||||
],
|
||||
exports: [
|
||||
GalleryComponent,
|
||||
],
|
||||
declarations: [
|
||||
GalleryComponent,
|
||||
AlbumComponent,
|
||||
DisplayImageComponent,
|
||||
GalleryItemComponent,
|
||||
AlbumItemComponent,
|
||||
],
|
||||
providers: [ GalleryService, DisplayImageService ]
|
||||
})
|
||||
export class GalleryModule { }
|
||||
0
src/app/gallery/gallery/gallery.component.css
Normal file
0
src/app/gallery/gallery/gallery.component.css
Normal file
5
src/app/gallery/gallery/gallery.component.html
Normal file
5
src/app/gallery/gallery/gallery.component.html
Normal file
@ -0,0 +1,5 @@
|
||||
<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>
|
||||
</div>
|
||||
25
src/app/gallery/gallery/gallery.component.spec.ts
Normal file
25
src/app/gallery/gallery/gallery.component.spec.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { GalleryComponent } from './gallery.component';
|
||||
|
||||
describe('GalleryComponent', () => {
|
||||
let component: GalleryComponent;
|
||||
let fixture: ComponentFixture<GalleryComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ GalleryComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(GalleryComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
24
src/app/gallery/gallery/gallery.component.ts
Normal file
24
src/app/gallery/gallery/gallery.component.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { Title } from "@angular/platform-browser";
|
||||
|
||||
import { Album } from "../shared";
|
||||
import { ActivatedRoute } from "@angular/router";
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery',
|
||||
templateUrl: './gallery.component.html',
|
||||
styleUrls: ['./gallery.component.css']
|
||||
})
|
||||
export class GalleryComponent implements OnInit {
|
||||
|
||||
public albums: Array<Album> = [];
|
||||
|
||||
constructor(private titleService: Title,
|
||||
private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.titleService.setTitle('Albums');
|
||||
this.route.data.subscribe((data: { albums: Array<Album>}) => this.albums = data.albums);
|
||||
}
|
||||
|
||||
}
|
||||
15
src/app/gallery/shared/album.model.ts
Normal file
15
src/app/gallery/shared/album.model.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { Image } from "./image.model";
|
||||
|
||||
export const IMAGE_STANDARD = 0;
|
||||
export const IMAGE_PANORAMA = 1;
|
||||
|
||||
export class Album {
|
||||
public slug: string = "";
|
||||
public name: string = "";
|
||||
public date: string = "";
|
||||
public coverImage: Image;
|
||||
public type: number = IMAGE_STANDARD;
|
||||
public isNew: boolean = false;
|
||||
public isPublic: boolean = true;
|
||||
public images: Array<Image> = [];
|
||||
}
|
||||
15
src/app/gallery/shared/gallery.service.spec.ts
Normal file
15
src/app/gallery/shared/gallery.service.spec.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import { TestBed, inject } from '@angular/core/testing';
|
||||
|
||||
import { GalleryService } from './gallery.service';
|
||||
|
||||
describe('GalleryService', () => {
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
providers: [GalleryService]
|
||||
});
|
||||
});
|
||||
|
||||
it('should be created', inject([GalleryService], (service: GalleryService) => {
|
||||
expect(service).toBeTruthy();
|
||||
}));
|
||||
});
|
||||
45
src/app/gallery/shared/gallery.service.ts
Normal file
45
src/app/gallery/shared/gallery.service.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Http } from "@angular/http";
|
||||
import { ActivatedRouteSnapshot, Resolve } from "@angular/router";
|
||||
import { Observable } from "rxjs/Observable";
|
||||
import 'rxjs/Rx';
|
||||
|
||||
import { environment } from "../../../environments/environment";
|
||||
import { Album, Image } from ".";
|
||||
|
||||
@Injectable()
|
||||
export class GalleryService implements Resolve<Array<Album>> {
|
||||
|
||||
public albums: Array<Album> = [];
|
||||
|
||||
constructor(
|
||||
private httpService: Http,
|
||||
) {}
|
||||
|
||||
public listGalleries(): Observable<Array<Album>> {
|
||||
return this.httpService.get(environment.apiUrl + '/api/galleries').map(res => res.json());
|
||||
}
|
||||
|
||||
// public listGalleryImages(gallerySlug: string): Observable<Image> {
|
||||
// return this.httpService.get(environment.apiUrl + '/api/gallery/' + gallerySlug).map(res => res.json());
|
||||
// }
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ActivatedRouteSnapshot} route
|
||||
* @returns {Promise<Array<Album>>}
|
||||
* @todo add some cache ttl to albums?
|
||||
*/
|
||||
public resolve(route: ActivatedRouteSnapshot): Promise<Array<Album>> {
|
||||
if(this.albums.length) {
|
||||
return Promise.resolve(this.albums);
|
||||
}
|
||||
return this.listGalleries().toPromise().then(result => {
|
||||
if(result) {
|
||||
this.albums = result;
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
4
src/app/gallery/shared/image.model.ts
Normal file
4
src/app/gallery/shared/image.model.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export class Image {
|
||||
public label: string = "";
|
||||
public path: string = "";
|
||||
}
|
||||
3
src/app/gallery/shared/index.ts
Normal file
3
src/app/gallery/shared/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export * from './album.model';
|
||||
export * from './gallery.service';
|
||||
export * from './image.model';
|
||||
@ -1,3 +1,4 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
production: true,
|
||||
apiUrl: 'http://photos-api.yvan.hu',
|
||||
};
|
||||
|
||||
@ -4,5 +4,6 @@
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
production: false,
|
||||
apiUrl: 'http://localhost:8888',
|
||||
};
|
||||
|
||||
@ -2,13 +2,22 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Frontend</title>
|
||||
<title>Gallery</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
<app-root>
|
||||
<div class="ui main container">
|
||||
<div class="ui visible massive floating icon message">
|
||||
<i class="notched circle loading icon"></i>
|
||||
<div class="content">
|
||||
<div class="header">Loading ...</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
1
src/main-ssr.ts
Normal file
1
src/main-ssr.ts
Normal file
@ -0,0 +1 @@
|
||||
export { AppServerModule } from './app/app.server.module';
|
||||
@ -1 +1,12 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
body {
|
||||
background-color: #FFFFFF;
|
||||
}
|
||||
.main.container,
|
||||
.main.fullwide-container {
|
||||
margin-top: 1em;
|
||||
}
|
||||
.ui.fullwide-container {
|
||||
margin-left: 1em;
|
||||
margin-right: 1em;
|
||||
}
|
||||
|
||||
16
src/tsconfig.app-ssr.json
Normal file
16
src/tsconfig.app-ssr.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
],
|
||||
"angularCompilerOptions": {
|
||||
"entryModule": "app/app.server.module#AppServerModule"
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user