Skeleton loader WIP
This commit is contained in:
parent
cb3f1e3eea
commit
6702aea4e3
@ -42,3 +42,23 @@ $sides: (top, bottom, left, right);
|
||||
flex: #{$n};
|
||||
}
|
||||
}
|
||||
|
||||
/* SKELETON LINES */
|
||||
|
||||
/* sk-w-${n} (in pixels) */
|
||||
|
||||
$skeleton-widths: (120, 200, 250, 340);
|
||||
@each $w in $skeleton-widths {
|
||||
.sk-w-#{$w} {
|
||||
max-width: #{$w}px;
|
||||
}
|
||||
}
|
||||
|
||||
/* sk-h-${n} */
|
||||
|
||||
$skeleton-heights: (12, 20, 24);
|
||||
@each $h in $skeleton-heights {
|
||||
.sk-h-#{$h} {
|
||||
height: #{$h}px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatLegacyProgressSpinnerModule as MatProgressSpinnerModule } from '@angular/material/legacy-progress-spinner';
|
||||
import { SortByPipe } from './sorting';
|
||||
import { CommonUiOptions, IqserAppConfig, ModuleWithOptions } from './utils';
|
||||
import { HiddenActionComponent, LogoComponent, ToastComponent } from './shared';
|
||||
import { HiddenActionComponent, ToastComponent } from './shared';
|
||||
import { ConnectionStatusComponent, FullPageErrorComponent } from './error';
|
||||
import { IqserListingModule } from './listing';
|
||||
import { IqserFiltersModule } from './filtering';
|
||||
@ -24,6 +24,7 @@ import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/le
|
||||
import { ApiPathInterceptor, IqserConfigService, IqserUserPreferenceService } from './services';
|
||||
import { DefaultUserPreferenceService } from './services/default-user-preference.service';
|
||||
import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
|
||||
import { IqserSkeletonModule } from './skeleton/skeleton.module';
|
||||
|
||||
const matModules = [
|
||||
MatIconModule,
|
||||
@ -42,16 +43,10 @@ const modules = [
|
||||
IqserInputsModule,
|
||||
IqserScrollbarModule,
|
||||
IqserEmptyStatesModule,
|
||||
IqserSkeletonModule,
|
||||
HttpClientModule,
|
||||
];
|
||||
const components = [
|
||||
ConnectionStatusComponent,
|
||||
FullPageErrorComponent,
|
||||
LogoComponent,
|
||||
HiddenActionComponent,
|
||||
ConfirmationDialogComponent,
|
||||
ToastComponent,
|
||||
];
|
||||
const components = [ConnectionStatusComponent, FullPageErrorComponent, HiddenActionComponent, ConfirmationDialogComponent, ToastComponent];
|
||||
|
||||
const pipes = [SortByPipe];
|
||||
|
||||
|
||||
@ -2,15 +2,20 @@ import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } fro
|
||||
import { Injectable, InjectionToken, Injector } from '@angular/core';
|
||||
import { firstValueFrom, from, of } from 'rxjs';
|
||||
import { LoadingService } from '../loading';
|
||||
import { SkeletonService } from './skeleton.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class CompositeRouteGuard implements CanActivate {
|
||||
constructor(protected readonly _injector: Injector, private readonly _loadingService: LoadingService) {}
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _skeletonService: SkeletonService,
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
this._loadingService.start();
|
||||
this.#preChecks(route);
|
||||
|
||||
const routeGuards = <InjectionToken<CanActivate>[]>route.data['routeGuards'];
|
||||
|
||||
@ -27,14 +32,30 @@ export class CompositeRouteGuard implements CanActivate {
|
||||
|
||||
const result = await firstValueFrom(canActivateResult);
|
||||
if (!result) {
|
||||
this._loadingService.stop();
|
||||
this.#postChecks(route);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._loadingService.stop();
|
||||
|
||||
this.#postChecks(route);
|
||||
return true;
|
||||
}
|
||||
|
||||
#preChecks(route: ActivatedRouteSnapshot): void {
|
||||
const skeleton = route.data['skeleton'];
|
||||
if (skeleton) {
|
||||
this._skeletonService.setType(skeleton);
|
||||
} else {
|
||||
this._loadingService.start();
|
||||
}
|
||||
}
|
||||
|
||||
#postChecks(route: ActivatedRouteSnapshot): void {
|
||||
if (route.data['skeleton']) {
|
||||
this._skeletonService.clear();
|
||||
} else {
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -9,3 +9,4 @@ export * from './iqser-user-preference.service';
|
||||
export * from './language.service';
|
||||
export * from './iqser-config.service';
|
||||
export * from './api-path.interceptor';
|
||||
export * from './skeleton.service';
|
||||
|
||||
17
src/lib/services/skeleton.service.ts
Normal file
17
src/lib/services/skeleton.service.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SkeletonService {
|
||||
type$ = new BehaviorSubject<string | null>(null);
|
||||
|
||||
clear() {
|
||||
this.type$.next(null);
|
||||
}
|
||||
|
||||
setType(type: string) {
|
||||
this.type$.next(type);
|
||||
}
|
||||
}
|
||||
@ -1,13 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { SideNavComponent, SmallChipComponent, StatusBarComponent } from './index';
|
||||
import { LogoComponent, SideNavComponent, SmallChipComponent, StatusBarComponent } from './index';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { MatLegacyTooltipModule as MatTooltipModule } from '@angular/material/legacy-tooltip';
|
||||
import { IqserIconsModule } from '../icons';
|
||||
|
||||
const components = [SmallChipComponent, StatusBarComponent, SideNavComponent];
|
||||
const components = [SmallChipComponent, StatusBarComponent, SideNavComponent, LogoComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
imports: [CommonModule, MatTooltipModule],
|
||||
imports: [CommonModule, MatTooltipModule, IqserIconsModule],
|
||||
})
|
||||
export class IqserSharedModule {}
|
||||
|
||||
12
src/lib/skeleton/skeleton.module.ts
Normal file
12
src/lib/skeleton/skeleton.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SkeletonComponent } from './skeleton/skeleton.component';
|
||||
import { IqserSharedModule } from '../shared';
|
||||
import { IqserUsersModule } from '../users';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SkeletonComponent],
|
||||
exports: [SkeletonComponent],
|
||||
imports: [CommonModule, IqserSharedModule, IqserUsersModule],
|
||||
})
|
||||
export class IqserSkeletonModule {}
|
||||
3
src/lib/skeleton/skeleton/skeleton.component.html
Normal file
3
src/lib/skeleton/skeleton/skeleton.component.html
Normal file
@ -0,0 +1,3 @@
|
||||
<ng-container *ngIf="type$ | async as type">
|
||||
<ng-container *ngTemplateOutlet="templates[type]"></ng-container>
|
||||
</ng-container>
|
||||
5
src/lib/skeleton/skeleton/skeleton.component.scss
Normal file
5
src/lib/skeleton/skeleton/skeleton.component.scss
Normal file
@ -0,0 +1,5 @@
|
||||
:host {
|
||||
position: absolute;
|
||||
width: 100vw;
|
||||
z-index: 2;
|
||||
}
|
||||
29
src/lib/skeleton/skeleton/skeleton.component.ts
Normal file
29
src/lib/skeleton/skeleton/skeleton.component.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { ChangeDetectionStrategy, Component, HostBinding, Input, TemplateRef } from '@angular/core';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { SkeletonService } from '../../services';
|
||||
|
||||
@Component({
|
||||
selector: 'iqser-skeleton [templates]',
|
||||
templateUrl: './skeleton.component.html',
|
||||
styleUrls: ['./skeleton.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SkeletonComponent {
|
||||
x$ = new BehaviorSubject<string | null>('Dashboard');
|
||||
@HostBinding('style.display') display = 'block';
|
||||
|
||||
@Input() templates: Record<string, TemplateRef<unknown>> = {};
|
||||
|
||||
// @HostBinding('style.display') display = 'none';
|
||||
|
||||
constructor(private readonly _skeletonService: SkeletonService) {
|
||||
// this._skeletonService.type$.subscribe(type => {
|
||||
// this.display = type ? 'block' : 'none';
|
||||
// });
|
||||
}
|
||||
|
||||
get type$(): BehaviorSubject<string | null> {
|
||||
return this.x$;
|
||||
// return this._skeletonService.type$;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user