Skip to content

Commit

Permalink
Merge pull request #70 from NuGetTrends/feat/loading-indicator
Browse files Browse the repository at this point in the history
Add loading indicator
  • Loading branch information
bruno-garcia authored Oct 5, 2019
2 parents 96cfa43 + 9bdf1d6 commit f01db4c
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 11 deletions.
1 change: 1 addition & 0 deletions src/NuGetTrends.Spa/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@
<router-outlet></router-outlet>
</div>
<app-footer></app-footer>
<app-loading></app-loading>
8 changes: 8 additions & 0 deletions src/NuGetTrends.Spa/src/app/shared/components/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export * from './loading-indicator/loading-indicator.component';
export * from './loading-indicator/loading-indicator.interceptor';

export * from './package-list/package-list.component';
export * from './search-input/search-input.component';
export * from './search-period/search-period.component';
export * from './search-type/search-type.component';

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<div class="loading-screen-wrapper">
<div class="loading-screen-icon">
<div class="loadchart">
<div class="loadchart__bar"></div>
<div class="loadchart__bar"></div>
<div class="loadchart__bar"></div>
<div class="loadchart__bar"></div>
<div class="loadchart__bar"></div>
<div class="loadchart__ball"></div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
@import '../../../../colors';

.loading-screen-wrapper {
background-color: rgba(51,51,51,0.8);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 99999 !important;
}

.loading-screen-icon {
top: 50%;
left: 50%;
margin: 0;
position: absolute;
transform: translate(-50%, -50%);
}

.loadchart {

position: relative;
width: 75px;
height: 100px;

&__bar {
position: absolute;
bottom: 0;
width: 10px;
height: 50%;
background: $chart-loading-icon;
transform-origin: center bottom;
box-shadow: 1px 1px 0 rgba(0,0,0,.2);

@for $i from 1 through 5 {
&:nth-child(#{$i}) {
left: ($i - 1) * 15px;
transform: scale(1,$i*.2);
animation: barUp#{$i} 4s infinite;
}
}

}

&__ball {
position: absolute;
bottom: 10px;
left: 0;
width: 10px;
height: 10px;
background: $chart-loading-icon;
border-radius: 50%;
animation: ball 4s infinite;
}
}

@keyframes ball {
0% {
transform: translate(0, 0);
}
5% {
transform: translate(8px, -14px);
}
10% {
transform: translate(15px, -10px)
}
17% {
transform: translate(23px, -24px)
}
20% {
transform: translate(30px, -20px)
}
27% {
transform: translate(38px, -34px)
}
30% {
transform: translate(45px, -30px)
}
37% {
transform: translate(53px, -44px)
}
40% {
transform: translate(60px, -40px)
}
50% {
transform: translate(60px, 0)
}
57% {
transform: translate(53px, -14px)
}
60% {
transform: translate(45px, -10px)
}
67% {
transform: translate(37px, -24px)
}
70% {
transform: translate(30px, -20px)
}
77% {
transform: translate(22px, -34px)
}
80% {
transform: translate(15px, -30px)
}
87% {
transform: translate(7px, -44px)
}
90% {
transform: translate(0, -40px)
}
100% {
transform: translate(0, 0);
}
}

@keyframes barUp1 {
0% {
transform: scale(1, .2);
}
40%{
transform: scale(1, .2);
}
50% {
transform: scale(1, 1);
}
90% {
transform: scale(1,1);
}
100% {
transform: scale(1,.2);
}
}
@keyframes barUp2 {
0% {
transform: scale(1, .4);
}
40% {
transform: scale(1, .4);
}
50% {
transform: scale(1, .8);
}
90% {
transform: scale(1, .8);
}
100% {
transform: scale(1, .4);
}
}
@keyframes barUp3 {
0% {
transform: scale(1, .6);
}
100% {
transform: scale(1, .6);
}
}
@keyframes barUp4 {
0% {
transform: scale(1, .8);
}
40% {
transform: scale(1, .8);
}
50% {
transform: scale(1, .4);
}
90% {
transform: scale(1, .4);
}
100% {
transform: scale(1, .8);
}
}
@keyframes barUp5 {
0% {
transform: scale(1, 1);
}
40% {
transform: scale(1, 1);
}
50% {
transform: scale(1, .2);
}
90% {
transform: scale(1, .2);
}
100% {
transform: scale(1, 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { LoadingIndicatorComponent } from './loading-indicator.component';

describe('LoadingIndicatorComponent', () => {
let component: LoadingIndicatorComponent;
let fixture: ComponentFixture<LoadingIndicatorComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoadingIndicatorComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(LoadingIndicatorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Component, OnDestroy, AfterViewInit, ElementRef, ChangeDetectorRef } from '@angular/core';
import { Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';

import { LoadingIndicatorService } from './loading-indicator.service';

@Component({
selector: 'app-loading',
templateUrl: './loading-indicator.component.html',
styleUrls: ['./loading-indicator.component.scss']
})
export class LoadingIndicatorComponent implements AfterViewInit, OnDestroy {

loadingSubscription: Subscription;

constructor(
private _elmRef: ElementRef,
private _changeDetectorRef: ChangeDetectorRef,
private loadingIndicatorService: LoadingIndicatorService) { }

ngAfterViewInit(): void {
this._elmRef.nativeElement.style.display = 'none';
this.loadingSubscription = this.loadingIndicatorService.loadingSubject$
.pipe(debounceTime(200))
.subscribe((isLoading: boolean) => {
this._elmRef.nativeElement.style.display = isLoading ? 'block' : 'none';
this._changeDetectorRef.detectChanges();
});
}

ngOnDestroy() {
this.loadingSubscription.unsubscribe();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { Injectable } from '@angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';

import { LoadingIndicatorService } from './loading-indicator.service';


@Injectable()
export class LoadingIndicatorInterceptor implements HttpInterceptor {

activeRequests = 0;

constructor(private loadingIndicatorService: LoadingIndicatorService) {
}

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (this.activeRequests === 0) {
this.loadingIndicatorService.show();
}

this.activeRequests++;
return next.handle(request).pipe(
finalize(() => {
this.activeRequests--;
if (this.activeRequests === 0) {
this.loadingIndicatorService.hide();
}
})
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

@Injectable({
providedIn: 'root',
})
export class LoadingIndicatorService {

loadingSubject$ = new Subject<boolean>();
show() {
this.loadingSubject$.next(true);
}
hide() {
this.loadingSubject$.next(false);
}
}
35 changes: 25 additions & 10 deletions src/NuGetTrends.Spa/src/app/shared/shared.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { NgModule } from '@angular/core';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { MatAutocompleteModule } from '@angular/material/autocomplete';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ToastrModule } from 'ngx-toastr';

import { SearchInputComponent } from './components/search-input/search-input.component';
import { PackageListComponent } from './components/package-list/package-list.component';
import { SearchTypeComponent } from './components/search-type/search-type.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { SearchPeriodComponent } from './components/search-period/search-period.component';
import {
SearchInputComponent,
PackageListComponent,
SearchTypeComponent,
SearchPeriodComponent,
LoadingIndicatorComponent,
LoadingIndicatorInterceptor
} from './components';

@NgModule({
imports: [
Expand All @@ -20,14 +25,15 @@ import { SearchPeriodComponent } from './components/search-period/search-period.
preventDuplicates: true,
}),
ReactiveFormsModule,
BrowserAnimationsModule],

BrowserAnimationsModule
],
declarations: [
SearchInputComponent,
PackageListComponent,
SearchTypeComponent,
SearchPeriodComponent],

SearchPeriodComponent,
LoadingIndicatorComponent
],
exports: [
CommonModule,
FormsModule,
Expand All @@ -36,7 +42,16 @@ import { SearchPeriodComponent } from './components/search-period/search-period.
SearchInputComponent,
PackageListComponent,
SearchTypeComponent,
SearchPeriodComponent]
SearchPeriodComponent,
LoadingIndicatorComponent
],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: LoadingIndicatorInterceptor,
multi: true
}
],
})
export class SharedModule {
}
Loading

0 comments on commit f01db4c

Please sign in to comment.