diff --git a/package.json b/package.json index b5d828b..a68d2bd 100644 --- a/package.json +++ b/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", diff --git a/src/apis/index.php b/src/apis/index.php index ad3015e..b91173e 100644 --- a/src/apis/index.php +++ b/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(); diff --git a/src/app/about/about.component.scss b/src/app/about/about.component.scss index a0eb681..22ceada 100644 --- a/src/app/about/about.component.scss +++ b/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; diff --git a/src/app/app-layout/app-layout.component.html b/src/app/app-layout/app-layout.component.html index 89a86da..e46bcfe 100644 --- a/src/app/app-layout/app-layout.component.html +++ b/src/app/app-layout/app-layout.component.html @@ -1,5 +1,7 @@ - - +
+ + - + +
diff --git a/src/app/app-layout/app-layout.component.scss b/src/app/app-layout/app-layout.component.scss index e69de29..0d2866d 100644 --- a/src/app/app-layout/app-layout.component.scss +++ b/src/app/app-layout/app-layout.component.scss @@ -0,0 +1,3 @@ +main { + overflow: hidden; +} diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 453d579..d21da2f 100644 --- a/src/app/app-routing.module.ts +++ b/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 }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index ae96ec7..cf7935c 100644 --- a/src/app/app.module.ts +++ b/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, diff --git a/src/app/detail/detail.component.html b/src/app/detail/detail.component.html index 53457f7..488b0f3 100644 --- a/src/app/detail/detail.component.html +++ b/src/app/detail/detail.component.html @@ -4,6 +4,12 @@

{{details.title}}

+
+ from + on + {{details.date_from | date}} + to {{details.date_to | date}} +
-
- from - on - {{details.date_from | date}} - to {{details.date_to | date}} -
-
@@ -52,19 +51,18 @@ Exhibitions: {{exhibition.title}} Works: {{work.title}}
- + + diff --git a/src/app/detail/detail.component.scss b/src/app/detail/detail.component.scss index 246b883..86015ae 100644 --- a/src/app/detail/detail.component.scss +++ b/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; diff --git a/src/app/detail/detail.component.ts b/src/app/detail/detail.component.ts index f2d3553..00d9403 100644 --- a/src/app/detail/detail.component.ts +++ b/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) } diff --git a/src/app/header/header.component.ts b/src/app/header/header.component.ts index e4c7522..c4638d6 100644 --- a/src/app/header/header.component.ts +++ b/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 { diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html new file mode 100644 index 0000000..2a92674 --- /dev/null +++ b/src/app/home/home.component.html @@ -0,0 +1,31 @@ +
+ + +
+
+
+ loading + +
+ {{item.title}} + {{item.type}} + +
+
+ from + on + {{item.date_from | date}} +
+
+ to {{item.date_to | date}} +
+
+ + {{item.tags}} +
+
+
+
+
+ + diff --git a/src/app/home/home.component.scss b/src/app/home/home.component.scss new file mode 100644 index 0000000..8c0ef20 --- /dev/null +++ b/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;} +} diff --git a/src/app/home/home.component.spec.ts b/src/app/home/home.component.spec.ts new file mode 100644 index 0000000..490e81b --- /dev/null +++ b/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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ HomeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts new file mode 100644 index 0000000..131f80e --- /dev/null +++ b/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' + } + } + } +} diff --git a/src/app/portfolio/portfolio.component.html b/src/app/portfolio/portfolio.component.html index f384422..dc8c0fd 100644 --- a/src/app/portfolio/portfolio.component.html +++ b/src/app/portfolio/portfolio.component.html @@ -1,29 +1,29 @@
-
-
-
-
- loading - -
- {{item.title}} - {{item.type}} +
+
+
+ loading + +
+ {{item.title}} + {{item.type}} -
-
- from - on - {{item.date_from | date}} -
-
- to {{item.date_to | date}} -
+
+
+ from + on + {{item.date_from | date}} +
+
+ to {{item.date_to | date}}
- - {{item.tags}}
+ + {{item.tags}}
+ + diff --git a/src/app/portfolio/portfolio.component.scss b/src/app/portfolio/portfolio.component.scss index 6a6f4ac..ab9be70 100644 --- a/src/app/portfolio/portfolio.component.scss +++ b/src/app/portfolio/portfolio.component.scss @@ -1,119 +1,134 @@ @import "../../assets/scss/variables"; .component-portfolio { - padding-top: 140px; + padding: 160px 0 80px 0; - .box { + .row-container { position: relative; - display: flex; - background: $black-alpha; - border-radius: 10px; - overflow: hidden; - margin: 10px 0; - padding: 40px 20px; - min-height: 250px; - cursor: pointer; - transition: transform .4s, background .4s; - -webkit-backface-visibility: hidden; - - .image { - position: absolute; - top: 50%; - left: 50%; - height: 100%; - width: 100%; - object-fit: cover; - transform: translate(-50%, -50%); - opacity: .9; - filter: grayscale(100%) brightness(.4); - transition: opacity .4s, filter .4s; + transform: skew(-2deg, -2deg) rotate(-2deg); + width: calc(100% - 50px); + max-width: 1400px; + margin: auto; + z-index: 1; + + .box { + position: relative; + display: flex; + border-radius: 4px; + overflow: hidden; + background: $black-alpha; + margin: 6px; + padding: 40px 20px; + min-height: 250px; + cursor: pointer; + transform: skew(6deg, -6deg) rotate(6deg); + transition: transform .4s, background .4s, box-shadow .4s; -webkit-backface-visibility: hidden; - z-index: 0; - } - - .text { - display: block; - margin: auto; - text-align: center; - transform: translate(0%, 0%); - color: $yellow; - //transition: color .4s; - -webkit-backface-visibility: hidden; - z-index: 1; - .title { - display: block; - font-size: $font-20; - text-transform: uppercase; - font-weight: bold; + .image { + position: absolute; + top: 50%; + left: 50%; + height: 100%; + width: 100%; + object-fit: cover; + transform: translate(-50%, -50%); + opacity: .9; + filter: grayscale(100%) brightness(.4); + transition: opacity .4s, filter .4s; + -webkit-backface-visibility: hidden; + z-index: 0; } - .type { - display: block; - font-size: $font-16; - font-weight: bold; + .loader { + position: absolute; + top: 50%; + left: 50%; + height: 100%; + width: 100%; + object-fit: cover; + transform: translate(-50%, -50%); + z-index: 0; } - .tags { + .text { display: block; - font-size: $font-12; - text-transform: uppercase; - font-weight: bold; - padding-top: 10px; - } + margin: auto; + text-align: center; + transform: translate(0%, 0%); + color: $yellow; + //transition: color .4s; + -webkit-backface-visibility: hidden; + z-index: 1; + + .title { + display: block; + font-size: $font-20; + text-transform: uppercase; + font-weight: bold; + } - .date-container { - display: inline-flex; - flex-wrap: wrap; + .type { + display: block; + font-size: $font-16; + font-weight: bold; + } - .date-row { + .tags { display: block; - width: 100%; + font-size: $font-12; + text-transform: uppercase; + font-weight: bold; + padding-top: 10px; + } - .date { - display: inline-flex; - margin: auto; - font-size: $font-20; - } + .date-container { + display: inline-flex; + flex-wrap: wrap; - .date-indication { - margin: 2px 5px auto 5px; - font-size: $font-12; - } + .date-row { + display: block; + width: 100%; - &:nth-of-type(2) { - margin-top: -12px; + .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; + } } } - } - - } - @each $angle in 0,1,2,3,4,5,6 { - &.skew-#{$angle} { - transform: skew(#{$angle - 3}deg, #{$angle - 3}deg); } - } - &:hover { - background: $black; - z-index: 50; + &: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; - } - .text { - //color: $yellow; + .image { + filter: grayscale(0%) brightness(1); + opacity: .7; + } } } } } +@media (min-width: map-get($grid-breakpoints, 'md')) { + .component-portfolio { + .row-container { + width: calc(100% - 100px); + } + } +} diff --git a/src/app/portfolio/portfolio.component.ts b/src/app/portfolio/portfolio.component.ts index cf63720..f7f2c66 100644 --- a/src/app/portfolio/portfolio.component.ts +++ b/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) } } diff --git a/src/app/services/apis.service.ts b/src/app/services/apis.service.ts index 31e6ab1..47887ba 100644 --- a/src/app/services/apis.service.ts +++ b/src/app/services/apis.service.ts @@ -16,8 +16,8 @@ export class ApisService extends BaseService { super() } - getPortfolio(section): Observable { - let urlApi = `${this.restApi}?query=${section}` + getPortfolio(section, randon = false): Observable { + let urlApi = `${this.restApi}?query=${section}&random=${randon}` return this.http.get(urlApi).pipe( catchError(this.handleError) ) diff --git a/src/app/spinner/spinner.component.html b/src/app/spinner/spinner.component.html new file mode 100644 index 0000000..91af365 --- /dev/null +++ b/src/app/spinner/spinner.component.html @@ -0,0 +1,2 @@ + +
diff --git a/src/app/spinner/spinner.component.scss b/src/app/spinner/spinner.component.scss new file mode 100644 index 0000000..ded7d41 --- /dev/null +++ b/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; +} diff --git a/src/app/spinner/spinner.component.ts b/src/app/spinner/spinner.component.ts new file mode 100644 index 0000000..2def854 --- /dev/null +++ b/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 + } + } +} diff --git a/src/assets/images/loader.svg b/src/assets/images/loader.svg new file mode 100644 index 0000000..a656b7e --- /dev/null +++ b/src/assets/images/loader.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/scss/variables.scss b/src/assets/scss/variables.scss index dd99a70..743424d 100644 --- a/src/assets/scss/variables.scss +++ b/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 diff --git a/src/index.html b/src/index.html index b5d7d53..229698c 100644 --- a/src/index.html +++ b/src/index.html @@ -4,7 +4,7 @@ DslakWebsite - + diff --git a/src/main.ts b/src/main.ts index c7b673c..5f26277 100644 --- a/src/main.ts +++ b/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(); }