Browse Source

Merge branch 'feature/loader' into develop

hotfix/class_typo
Dslak 5 years ago
parent
commit
1435cb1cfb
  1. 2
      package.json
  2. 3
      src/apis/index.php
  3. 4
      src/app/about/about.component.scss
  4. 2
      src/app/app-layout/app-layout.component.html
  5. 3
      src/app/app-layout/app-layout.component.scss
  6. 3
      src/app/app-routing.module.ts
  7. 6
      src/app/app.module.ts
  8. 22
      src/app/detail/detail.component.html
  9. 2
      src/app/detail/detail.component.scss
  10. 13
      src/app/detail/detail.component.ts
  11. 6
      src/app/header/header.component.ts
  12. 31
      src/app/home/home.component.html
  13. 185
      src/app/home/home.component.scss
  14. 25
      src/app/home/home.component.spec.ts
  15. 129
      src/app/home/home.component.ts
  16. 10
      src/app/portfolio/portfolio.component.html
  17. 55
      src/app/portfolio/portfolio.component.scss
  18. 17
      src/app/portfolio/portfolio.component.ts
  19. 4
      src/app/services/apis.service.ts
  20. 2
      src/app/spinner/spinner.component.html
  21. 15
      src/app/spinner/spinner.component.scss
  22. 56
      src/app/spinner/spinner.component.ts
  23. 11
      src/assets/images/loader.svg
  24. 1
      src/assets/scss/variables.scss
  25. 2
      src/index.html
  26. 2
      src/main.ts

2
package.json

@ -7,6 +7,7 @@
"dev": "ng serve",
"build": "ng build",
"prod": "ng build --prod --configuration production",
"deploy": "sh ./deploy.sh",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
@ -23,6 +24,7 @@
"@angular/router": "~9.1.7",
"@kolkov/angular-editor": "^1.1.4",
"bootstrap": "^4.5.3",
"hammerjs": "^2.0.8",
"ng-particles": "^2.1.11",
"ngx-image-gallery": "^2.0.5",
"rxjs": "~6.5.4",

3
src/apis/index.php

@ -15,7 +15,8 @@ if(isset($_GET['query'])) {
case "performances":
case "workshops":
if($_GET['query'] == 'portfolio') {$filter = '';} else {$filter = "WHERE type='".$_GET['query']."'";}
$qe = mysqli_query($conn,"SELECT * FROM `works` $filter ORDER BY id DESC");
if($_GET['random']) {$order = 'ORDER BY RAND()';} else {$order = "ORDER BY id DESC";}
$qe = mysqli_query($conn,"SELECT * FROM `works` $filter $order");
if(mysqli_num_rows($qe) > 0) {
$content = null;
$content->items = array();

4
src/app/about/about.component.scss

@ -1,8 +1,6 @@
@import "../../assets/scss/variables";
.component-about {
z-index: 0;
.content {
position: relative;
margin: 150px auto 80px auto;
@ -13,6 +11,8 @@
color: $black;
box-shadow: 0px 0px 25px $white-alpha;
border-radius: 10px;
z-index: 1;
.about-links {
color: $black;

2
src/app/app-layout/app-layout.component.html

@ -1,5 +1,7 @@
<main>
<app-header *ngIf="page != '/admin'"></app-header>
<router-outlet></router-outlet>
<Particles class="particles" *ngIf="particlesEnabled && page != '/admin'"
[id]="id" [options]="particlesOptions" (particlesLoaded)="particlesLoaded($event)"></Particles>
</main>

3
src/app/app-layout/app-layout.component.scss

@ -0,0 +1,3 @@
main {
overflow: hidden;
}

3
src/app/app-routing.module.ts

@ -4,6 +4,7 @@ import { AppLayoutComponent } from './app-layout/app-layout.component'
import { AboutComponent } from './about/about.component'
import { PortfolioComponent } from './portfolio/portfolio.component'
import { DetailComponent } from './detail/detail.component'
import { HomeComponent } from './home/home.component'
import { AdminComponent } from './admin/admin.component'
const routes: Routes = [
@ -12,7 +13,7 @@ const routes: Routes = [
component: AppLayoutComponent,
children: [
//{ path: '', redirectTo: '/portfolio', pathMatch: 'full' },
{ path: '', component: PortfolioComponent },
{ path: '', component: HomeComponent },
{ path: 'about', component: AboutComponent },
{ path: 'portfolio', component: PortfolioComponent },
{ path: 'exhibitions', component: PortfolioComponent },

6
src/app/app.module.ts

@ -14,6 +14,8 @@ import { AboutComponent } from './about/about.component';
import { PortfolioComponent } from './portfolio/portfolio.component';
import { DetailComponent } from './detail/detail.component';
import { AdminComponent } from './admin/admin.component';
import { HomeComponent } from './home/home.component';
import { SpinnerComponent } from './spinner/spinner.component';
@NgModule({
declarations: [
@ -23,7 +25,9 @@ import { AdminComponent } from './admin/admin.component';
AboutComponent,
PortfolioComponent,
DetailComponent,
AdminComponent
AdminComponent,
HomeComponent,
SpinnerComponent
],
imports: [
BrowserModule,

22
src/app/detail/detail.component.html

@ -4,6 +4,12 @@
<button class="back icon-back" (click)="back()"></button>
<h2 class="title">{{details.title}}</h2>
<div class="date-container" *ngIf="section == 'exhibitions'">
<span class="date-indication" *ngIf="details.date_from != details.date_to">from</span>
<span class="date-indication" *ngIf="details.date_from == details.date_to">on</span>
<span class="date">{{details.date_from | date}}</span>
<span class="date" *ngIf="details.date_from != details.date_to"> <span class="date-indication">to</span> {{details.date_to | date}}</span>
</div>
<div class="row no-gutters gallery" *ngIf="galleryImages.length">
<div class="col-12" *ngFor="let image of galleryImages; let i = index"
@ -12,19 +18,12 @@
'col-md-3': galleryImages.length >= 3}">
<div class="gallery-container">
<span class="gallery-title">{{image.title}}</span>
<img class="image" *ngIf="loadedImages[i]" src="/assets/images/loader.webp" alt="loading">
<img class="image" *ngIf="loadedImages[i]" src="/assets/images/loader.svg" alt="loading">
<img class="image" [hidden]="loadedImages[i]" (load)="onLoad(i)" [src]="image.url" (click)="openGallery(i)">
</div>
</div>
</div>
<div class="date-container" *ngIf="section == 'exhibitions'">
<span class="date-indication" *ngIf="details.date_from != details.date_to">from</span>
<span class="date-indication" *ngIf="details.date_from == details.date_to">on</span>
<span class="date">{{details.date_from | date}}</span>
<span class="date" *ngIf="details.date_from != details.date_to"> <span class="date-indication">to</span> {{details.date_to | date}}</span>
</div>
<div class="text" [innerHTML]="details.content"></div>
<div class="row videos" *ngIf="details.videos && details.videos.length">
@ -52,19 +51,18 @@
<span class="links" *ngIf="details.exhibitions && details.exhibitions.length"><b>Exhibitions:</b>
<span class="link" *ngFor="let exhibition of details.exhibitions"
(click)="showDetails('exhibitions', exhibition.id)"
(click)="showDetails('exhibitions', exhibition.id, exhibition.title)"
routerLink="/detail/exhibitions/{{exhibition.id}}">{{exhibition.title}} </span>
</span>
<span class="links" *ngIf="details.works && details.works.length"><b>Works:</b>
<span class="link" *ngFor="let work of details.works"
(click)="showDetails('works', work.id)"
(click)="showDetails('works', work.id, work.title)"
routerLink="/detail/works/{{work.id}}">{{work.title}} </span>
</span>
</div>
</div>
<ngx-image-gallery
[images]="galleryImages"
[conf]="conf"
@ -74,3 +72,5 @@
(onImageChange)="galleryImageChanged($event)"
(onDelete)="deleteImage($event)"
></ngx-image-gallery>
<app-spinner [show]="!loaded"></app-spinner>

2
src/app/detail/detail.component.scss

@ -1,7 +1,6 @@
@import "../../assets/scss/variables";
.component-detail {
z-index: 0;
.content {
position: relative;
@ -11,6 +10,7 @@
color: $black;
box-shadow: 0px 0px 25px $white-alpha;
border-radius: 10px;
z-index: 1;
.title {
margin: 0;

13
src/app/detail/detail.component.ts

@ -15,6 +15,8 @@ import { environment } from '../../environments/environment'
export class DetailComponent implements OnInit {
public basePath = `${environment.BASE_PATH}`
public loaded = false
public init = false
@ViewChild(NgxImageGalleryComponent) ngxImageGallery: NgxImageGalleryComponent
@ -46,11 +48,15 @@ export class DetailComponent implements OnInit {
this.showDetails(this.section, this.id)
}
showDetails(section, id): void {
ngAfterContentInit() {
this.init = true
}
showDetails(section, id, title = ''): void {
this.galleryImages = []
this.apisService.getDetails(section, id).toPromise().then((response) => {
if(this.history[this.history.length - 1] != `/detail/${section}/${id}`) {
this.history.push(`/detail/${section}/${id}`)
this.history.push(`/detail/${section}/${id}/${title.toLowerCase().replace(/[^a-zA-Z0-9]/g, '_')}`)
}
const detail = response.item
@ -83,6 +89,8 @@ export class DetailComponent implements OnInit {
this.loadedImages.push(true)
}
})
this.loaded = !this.loadedImages.length
this.details = detail
},(error) => {
@ -108,6 +116,7 @@ export class DetailComponent implements OnInit {
onLoad(index): void {
this.loadedImages[index] = false
this.loaded = this.init && this.loadedImages.every( (val) => !val)
}

6
src/app/header/header.component.ts

@ -9,7 +9,7 @@ import { DOCUMENT } from '@angular/common'
})
export class HeaderComponent implements OnInit {
public isSticky: boolean = false
public isSticky: boolean = true
public isMenuOpen: boolean = false
public isFirstScroll: boolean = true
@ -22,7 +22,7 @@ export class HeaderComponent implements OnInit {
}
ngOnInit(): void {
this.isSticky = this.router.url != '/'
//this.isSticky = this.router.url != '/'
}
@HostListener('window:scroll', ['$event'])
@ -32,7 +32,7 @@ export class HeaderComponent implements OnInit {
|| document.body.scrollTop || 0
this.isFirstScroll = this.router.url == '/'
this.isSticky = this.isFirstScroll ? this.isMenuOpen || verticalOffset > 10 : true
//this.isSticky = this.isFirstScroll ? this.isMenuOpen || verticalOffset > 10 : true
}
toggleMenu(): void {

31
src/app/home/home.component.html

@ -0,0 +1,31 @@
<div class="component-home">
<button class="goto-prev" (click)="scroll('prev')" (mouseover)="paused=true"><span class="icon icon-back"></span></button>
<button class="goto-next" (click)="scroll('next')" (mouseover)="paused=true"><span class="icon icon-back"></span></button>
<div class="content" #scrollContent (touchstart)="swipe($event, 'start')" (touchend)="swipe($event, 'end')">
<div [ngClass]="'slide-' + item.width" *ngFor="let item of homeItems">
<div class="box" [ngClass]="'skew-' + (item.id % 6)" (click)="showDetails(item.id, item.title)" (mouseover)="paused=true" (mouseout)="paused=false">
<img class="image" *ngIf="item.loading" src="/assets/images/loader.svg" alt="loading">
<img class="image" [hidden]="item.loading" (load)="onLoad(item.id)" [src]="basePath+item.image">
<div class="text">
<span class="title">{{item.title}}</span>
<span class="type" *ngIf="section != 'exhibitions'">{{item.type}}</span>
<div class="date-container" *ngIf="section == 'exhibitions'">
<div class="date-row">
<span class="date-indication" *ngIf="item.date_from != item.date_to">from</span>
<span class="date-indication" *ngIf="item.date_from == item.date_to">on</span>
<span class="date">{{item.date_from | date}}</span>
</div>
<div class="date-row">
<span class="date" *ngIf="item.date_from != item.date_to"> <span class="date-indication">to</span> {{item.date_to | date}}</span>
</div>
</div>
<span class="tags">{{item.tags}}</span>
</div>
</div>
</div>
</div>
</div>
<app-spinner [show]="!loaded"></app-spinner>

185
src/app/home/home.component.scss

@ -0,0 +1,185 @@
@import "../../assets/scss/variables";
.component-home {
display: flex;
padding-top: 100px;
height: 100vh;
transform: skew(-15deg) rotate(-15deg);
z-index: 1;
.goto-prev,
.goto-next {
position: absolute;
height: 40px;
width: 60px;
border: none;
background: none;
color: $black;
font-size: $font-40;
appearance: none;
margin: 0;
padding: 5px;
cursor: pointer;
z-index: 2;
.icon {
&:before {
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
left: 50%;
}
}
}
.goto-prev {
top: 60px;
left: 20px;
}
.goto-next {
top: calc(80vh + 10px);
right: 20px;
.icon {
&:before {
transform: translate(-50%, -50%) rotate(180deg);
}
}
}
.content {
display: inline-flex;
margin: 0;
margin-left: -50px;
//animation: slide 150s linear infinite;
transition: margin-left .5s;
@each $width in 1,2,3,4,5,6 {
.slide-#{$width} {
width: #{($width+2)*100}px;
}
}
.box {
position: relative;
display: flex;
background: $black-alpha2;
border-radius: 5px;
overflow: hidden;
margin: auto 0;
padding: 40px 20px;
height: calc(80vh - 90px);
min-height: 250px;
//max-height: 700px;
cursor: pointer;
transform: skew(-6deg, -6deg) rotate(6deg);
transition: transform .4s, background .4s, opacity .4s;
-webkit-backface-visibility: hidden;
.image {
position: absolute;
top: 50%;
left: 50%;
height: 100%;
width: 100%;
object-fit: cover;
transform: translate(-50%, -50%);
opacity: .8;
filter: grayscale(100%) contrast(3);
transition: opacity .4s, filter .4s;
-webkit-backface-visibility: hidden;
z-index: 0;
}
.text {
display: block;
margin: auto;
text-align: center;
transform: translate(0%, 0%);
color: $yellow;
-webkit-backface-visibility: hidden;
z-index: 1;
.title {
display: block;
font-size: $font-20;
text-transform: uppercase;
font-weight: bold;
}
.type {
display: block;
font-size: $font-16;
font-weight: bold;
}
.tags {
display: block;
font-size: $font-12;
text-transform: uppercase;
font-weight: bold;
padding-top: 10px;
}
.date-container {
display: inline-flex;
flex-wrap: wrap;
.date-row {
display: block;
width: 100%;
.date {
display: inline-flex;
margin: auto;
font-size: $font-20;
}
.date-indication {
margin: 2px 5px auto 5px;
font-size: $font-12;
}
&:nth-of-type(2) {
margin-top: -12px;
}
}
}
}
&:hover {
background: $black;
transform: scale(1.4) rotate(14deg) skew(14deg, 0deg);
z-index: 50;
.image {
filter: grayscale(0%);
opacity: .5;
}
}
}
&:hover,
&.paused {
//animation: none;
animation-play-state: paused;
}
}
}
@media (min-width: map-get($grid-breakpoints, 'md')) {
.component-home {
.goto-prev {
left: 50px;
}
.goto-next {
right: 50px;
}
}
}
@keyframes slide {
0% {margin-left: 0;}
50% {margin-left: -100%;}
100% {margin-left: 0;}
}

25
src/app/home/home.component.spec.ts

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HomeComponent } from './home.component';
describe('HomeComponent', () => {
let component: HomeComponent;
let fixture: ComponentFixture<HomeComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ HomeComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomeComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

129
src/app/home/home.component.ts

@ -0,0 +1,129 @@
import { Component, OnInit, ViewChild, ElementRef, Renderer2 } from '@angular/core'
import { Router, NavigationEnd } from '@angular/router'
import { ApisService } from '../services/apis.service'
import { environment } from '../../environments/environment'
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnInit {
@ViewChild('scrollContent') scrollContent: ElementRef
public basePath = `${environment.BASE_PATH}`
public loaded = false
public init = false
public homeItems: any = []
public section: string = 'portfolio'
public paused: boolean = false
private scrollPos: number = 0
private swipeCoord?: [number, number]
private swipeTime?: number
constructor(
private apisService: ApisService,
private router: Router,
private renderer: Renderer2
) { }
ngOnInit(): void {
this.apisService.getPortfolio(this.section, true).toPromise().then((response) => {
this.homeItems = response.items
let cnt = 0
let width = 0
let tot = 0
this.homeItems.forEach((e) => {
e.loading = true
e.width = Math.floor(Math.random()*4)+1
cnt++
})
},(error) => {
console.error('getPortfolio ERROR', error)
}).catch((e) => {
console.error('getPortfolio CATCH', e)
})
}
ngAfterContentInit() {
this.init = true
setInterval( () => {
if(!this.paused) {
const scrollWidth = 300
const scrollPos = parseInt(this.scrollContent.nativeElement.style.marginLeft) || 0
this.scrollPos = scrollPos - scrollWidth <= -(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) ?
-(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) : scrollPos - scrollWidth
this.scrollContent.nativeElement.style.marginLeft = this.scrollPos + 'px'
}
},2000)
}
showDetails(id, title = ''): void {
const section = this.section == 'exhibitions' ? 'exhibitions' : 'works'
this.router.navigate([`/detail/${section}/${id}/${title.toLowerCase().replace(/[^a-zA-Z0-9]/g, '_')}`])
}
onLoad(id): void {
this.homeItems.filter(item => item.id == id)[0].loading = false
this.loaded = this.init && this.homeItems.every( (val) => !val.loading)
}
scroll(dir): void {
const scrollWidth = document.body.clientWidth / 3
const scrollPos = parseInt(this.scrollContent.nativeElement.style.marginLeft) || 0
this.paused = true
switch(dir) {
case 'prev':
this.scrollPos = scrollPos + scrollWidth >= 0 ? 0 : scrollPos + scrollWidth
break;
case 'next':
this.scrollPos = scrollPos - scrollWidth <= -(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) ?
-(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) : scrollPos - scrollWidth
break;
}
this.scrollContent.nativeElement.style.marginLeft = this.scrollPos + 'px'
}
swipe(e: TouchEvent, when: string): void {
const coord: [number, number] = [e.changedTouches[0].clientX, e.changedTouches[0].clientY]
const time = new Date().getTime()
const scrollWidth = document.body.clientWidth
const scrollPos = parseInt(this.scrollContent.nativeElement.style.marginLeft) || 0
this.paused = true
if (when === 'start') {
this.swipeCoord = coord
this.swipeTime = time
} else if (when === 'end') {
const direction = [coord[0] - this.swipeCoord[0], coord[1] - this.swipeCoord[1]]
const duration = time - this.swipeTime
if (duration < 1000
&& Math.abs(direction[0]) > 30
&& Math.abs(direction[0]) > Math.abs(direction[1] * 3)) {
const swipe = direction[0] < 0 ? 'next' : 'prev'
switch(swipe) {
case 'prev':
this.scrollPos = scrollPos + scrollWidth >= 0 ? 0 : scrollPos + scrollWidth
break;
case 'next':
this.scrollPos = scrollPos - scrollWidth <= -(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) ?
-(this.scrollContent.nativeElement.offsetWidth - document.body.clientWidth) : scrollPos - scrollWidth
break;
}
this.scrollContent.nativeElement.style.marginLeft = this.scrollPos + 'px'
}
}
}
}

10
src/app/portfolio/portfolio.component.html

@ -1,9 +1,8 @@
<div class="component-portfolio">
<div class="container">
<div class="row">
<div class="row no-gutters row-container">
<div class="col-12 col-sm-6 mx-auto" [ngClass]="'col-md-' + item.width" *ngFor="let item of portfolioItems">
<div class="box" [ngClass]="'skew-' + (item.id % 6)" (click)="showDetails(item.id)">
<img class="image" *ngIf="item.loading" src="/assets/images/loader.webp" alt="loading">
<div class="box" (click)="showDetails(item.id, item.title)">
<img class="loader" *ngIf="item.loading" src="/assets/images/loader.svg" alt="loading">
<img class="image" [hidden]="item.loading" (load)="onLoad(item.id)" [src]="basePath+item.image">
<div class="text">
<span class="title">{{item.title}}</span>
@ -26,4 +25,5 @@
</div>
</div>
</div>
</div>
<app-spinner [show]="!loaded"></app-spinner>

55
src/app/portfolio/portfolio.component.scss

@ -1,19 +1,28 @@
@import "../../assets/scss/variables";
.component-portfolio {
padding-top: 140px;
padding: 160px 0 80px 0;
.row-container {
position: relative;
transform: skew(-2deg, -2deg) rotate(-2deg);
width: calc(100% - 50px);
max-width: 1400px;
margin: auto;
z-index: 1;
.box {
position: relative;
display: flex;
background: $black-alpha;
border-radius: 10px;
border-radius: 4px;
overflow: hidden;
margin: 10px 0;
background: $black-alpha;
margin: 6px;
padding: 40px 20px;
min-height: 250px;
cursor: pointer;
transition: transform .4s, background .4s;
transform: skew(6deg, -6deg) rotate(6deg);
transition: transform .4s, background .4s, box-shadow .4s;
-webkit-backface-visibility: hidden;
.image {
@ -31,6 +40,17 @@
z-index: 0;
}
.loader {
position: absolute;
top: 50%;
left: 50%;
height: 100%;
width: 100%;
object-fit: cover;
transform: translate(-50%, -50%);
z-index: 0;
}
.text {
display: block;
margin: auto;
@ -89,31 +109,26 @@
}
@each $angle in 0,1,2,3,4,5,6 {
&.skew-#{$angle} {
transform: skew(#{$angle - 3}deg, #{$angle - 3}deg);
}
}
&:hover {
box-shadow: 0 0 20px $white-alpha2;
background: $black;
z-index: 50;
@each $angle in 0,1,2,3,4,5,6 {
&.skew-#{$angle} {
//transform: scale(1.4) rotate(2deg) skew(#{3 - $angle}deg, #{3 - $angle}deg);
transform: scale(1.4) rotate(0deg) skew(0deg, 0deg);
}
}
transform: scale(1.4) rotate(4deg) skew(3deg);
.image {
filter: grayscale(0%) brightness(1);
opacity: .5;
opacity: .7;
}
.text {
//color: $yellow;
}
}
}
}
@media (min-width: map-get($grid-breakpoints, 'md')) {
.component-portfolio {
.row-container {
width: calc(100% - 100px);
}
}
}

17
src/app/portfolio/portfolio.component.ts

@ -11,6 +11,8 @@ import { environment } from '../../environments/environment'
export class PortfolioComponent implements OnInit {
public basePath = `${environment.BASE_PATH}`
public loaded = false
public init = false
public portfolioItems: any = []
public section: string = ''
@ -42,7 +44,6 @@ export class PortfolioComponent implements OnInit {
case 1:
width = Math.floor(Math.random()*3)+3
cnt++
if(tot + width > 9) {
width = 12 - tot
tot = 0
@ -50,7 +51,6 @@ export class PortfolioComponent implements OnInit {
} else {
tot = tot + width
}
break;
case 2:
width = 12 - tot
@ -58,11 +58,7 @@ export class PortfolioComponent implements OnInit {
cnt = 0
break;
}
e.width = width
//((e.id % 5)+3)
//Math.floor((Math.random()*3)+1)+2
})
},(error) => {
console.error('getPortfolio ERROR', error)
@ -71,13 +67,18 @@ export class PortfolioComponent implements OnInit {
})
}
showDetails(id): void {
ngAfterContentInit() {
this.init = true
}
showDetails(id, title = ''): void {
const section = this.section == 'exhibitions' ? 'exhibitions' : 'works'
this.router.navigate([`/detail/${section}/${id}`])
this.router.navigate([`/detail/${section}/${id}/${title.toLowerCase().replace(/[^a-zA-Z0-9]/g, '_')}`])
}
onLoad(id): void {
this.portfolioItems.filter(item => item.id == id)[0].loading = false
this.loaded = this.init && this.portfolioItems.every( (val) => !val.loading)
}
}

4
src/app/services/apis.service.ts

@ -16,8 +16,8 @@ export class ApisService extends BaseService {
super()
}
getPortfolio(section): Observable<any> {
let urlApi = `${this.restApi}?query=${section}`
getPortfolio(section, randon = false): Observable<any> {
let urlApi = `${this.restApi}?query=${section}&random=${randon}`
return this.http.get<any>(urlApi).pipe(
catchError(this.handleError)
)

2
src/app/spinner/spinner.component.html

@ -0,0 +1,2 @@
<div class="spinner" #spinner></div>

15
src/app/spinner/spinner.component.scss

@ -0,0 +1,15 @@
@import "../../assets/scss/variables";
.spinner {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 100vw;
background: $yellow-alpha;
background-image: url('/assets/images/loader.svg');
background-size: 200px 200px;
background-repeat: no-repeat;
background-position: center center;
z-index: 100;
}

56
src/app/spinner/spinner.component.ts

@ -0,0 +1,56 @@
import { Component, OnInit, Input, ViewChild, ElementRef, SimpleChanges } from '@angular/core'
@Component({
selector: 'app-spinner',
templateUrl: './spinner.component.html',
styleUrls: ['./spinner.component.scss']
})
export class SpinnerComponent implements OnInit {
@ViewChild('spinner') spinner: ElementRef
@Input() show: boolean = false
ngOnInit(): void {
}
ngOnChanges(changes: SimpleChanges) {
if(changes.show && changes.show.firstChange) {
this.loader(changes.show.currentValue ? 'show' : 'hide')
}
}
loader(action) {
let op = 0
let timer = null
switch(action) {
case 'show':
op = 1
timer = setInterval(() => {
if(op <= 0.1){
clearInterval(timer)
this.spinner.nativeElement.style.display = 'none'
}
this.spinner.nativeElement.style.opacity = op
this.spinner.nativeElement.style.filter = 'alpha(opacity=' + op * 100 + ")"
op -= op * 0.1
}, 20)
break
case 'hide':
op = 0.1
this.spinner.nativeElement.style.display = 'block'
timer = setInterval(() => {
if(op >= 1){
clearInterval(timer)
}
this.spinner.nativeElement.style.opacity = op
this.spinner.nativeElement.style.filter = 'alpha(opacity=' + op * 100 + ")"
op += op * 0.1
}, 20)
break
}
}
}

11
src/assets/images/loader.svg

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto; background: rgba(0, 0, 0, 0) none repeat scroll 0% 0%; display: block; shape-rendering: auto;" width="414px" height="414px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="50" cy="50" r="0" fill="none" stroke="#a2dc02" stroke-width="2">
<animate attributeName="r" repeatCount="indefinite" dur="1s" values="0;20" keyTimes="0;1" keySplines="0 0.2 0.8 1" calcMode="spline" begin="-0.5s"></animate>
<animate attributeName="opacity" repeatCount="indefinite" dur="1s" values="1;0" keyTimes="0;1" keySplines="0.2 0 0.8 1" calcMode="spline" begin="-0.5s"></animate>
</circle>
<circle cx="50" cy="50" r="0" fill="none" stroke="#ffffff" stroke-width="2">
<animate attributeName="r" repeatCount="indefinite" dur="1s" values="0;20" keyTimes="0;1" keySplines="0 0.2 0.8 1" calcMode="spline"></animate>
<animate attributeName="opacity" repeatCount="indefinite" dur="1s" values="1;0" keyTimes="0;1" keySplines="0.2 0 0.8 1" calcMode="spline"></animate>
</circle>
<!-- [ldio] generated by https://loading.io/ --></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

1
src/assets/scss/variables.scss

@ -34,6 +34,7 @@ $yellow: #a2dc02;
$white-alpha: rgba(255, 255, 255, 0.8);
$white-alpha2: rgba(255, 255, 255, 0.4);
$black-alpha: rgba(0, 0, 0, 0.8);
$black-alpha2: rgba(0, 0, 0, 0.4);
$yellow-alpha: rgba(160, 220, 0, 0.8);
// Fonts

2
src/index.html

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>DslakWebsite</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, user-scalable=no,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0">
<link rel="icon" type="image/x-icon" href="assets/images/favicon.png">
</head>
<body>

2
src/main.ts

@ -4,6 +4,8 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import 'hammerjs';
if (environment.production) {
enableProdMode();
}

Loading…
Cancel
Save