Skip to content

Commit

Permalink
chore: demo
Browse files Browse the repository at this point in the history
  • Loading branch information
vapkse committed Jul 8, 2024
1 parent 98d61d9 commit b0aa584
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 7 deletions.
2 changes: 1 addition & 1 deletion .hintrc
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
}
]
}
}
}
6 changes: 6 additions & 0 deletions projects/demo-app/src/app/app.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ <h1 class="demo-app-name">hug/ngx-components Demo</h1>
<span mat-line>Overlay</span>
</mat-list-item>
</mat-nav-list>
<mat-nav-list>
<mat-list-item title="Snackbar" routerLink="/snackbar" routerLinkActive="active">
<mat-icon mat-list-icon>home</mat-icon>
<span mat-line>Snackbar</span>
</mat-list-item>
</mat-nav-list>
</mat-sidenav>

<mat-sidenav-content>
Expand Down
1 change: 1 addition & 0 deletions projects/demo-app/src/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ export const appRoutes: Routes = [
{ path: 'message-box', loadComponent: () => import('./message-box/message-box-demo.component').then(m => m.MessageBoxDemoComponent), data: { title: 'Message Box' } },
{ path: 'numeric-stepper', loadComponent: () => import('./numeric-stepper/numeric-stepper-demo.component').then(m => m.NumericStepperDemoComponent), data: { title: 'Numeric Stepper' } },
{ path: 'overlay', loadComponent: () => import('./overlay/overlay-demo.component').then(m => m.OverlayDemoComponent), data: { title: 'Overlay' } },
{ path: 'snackbar', loadComponent: () => import('./snackbar/snackbar-demo.component').then(m => m.SnackbarDemoComponent), data: { title: 'Snackbar' } },
{ path: '**', redirectTo: 'message-box', pathMatch: 'prefix' }
];
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { MatTabsModule } from '@angular/material/tabs';
import { MatToolbarModule } from '@angular/material/toolbar';
import { Destroy } from '@hug/ngx-core';
import { NumericStepperComponent } from '@hug/ngx-numeric-stepper';
import { Subject, debounceTime, distinctUntilChanged, map, takeUntil } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, Subject, takeUntil } from 'rxjs';

interface NumberFormControls {
numberValue3: FormControl<number>;
Expand All @@ -17,7 +17,7 @@ interface NumberFormControls {
numberValue6: FormControl<number>;
}

const numberValidator = (control: AbstractControl): Array<string> | null => {
const numberValidator = (control: AbstractControl): string[] | null => {
const val = +control.value;
if (isNaN(val)) {
return ['Not a number'];
Expand Down Expand Up @@ -68,7 +68,7 @@ export class NumericStepperDemoComponent extends Destroy {
super();

this.numberForm = this.formBuilder.group({
numberValue3: this.formBuilder.control({ value: this.value3, disabled: false}, { validators: numberValidator, nonNullable: true }),
numberValue3: this.formBuilder.control({ value: this.value3, disabled: false }, { validators: numberValidator, nonNullable: true }),
numberValue4: this.formBuilder.control(this.value4, { validators: [Validators.required, numberValidator], nonNullable: true }),
numberValue5: this.formBuilder.control(this.value5, { validators: numberValidator, nonNullable: true }),
numberValue6: this.formBuilder.control(this.value6, { validators: numberValidator, nonNullable: true })
Expand Down
119 changes: 119 additions & 0 deletions projects/demo-app/src/app/snackbar/snackbar-demo.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
<mat-tab-group [selectedIndex]="tabIndex" (selectedTabChange)="tabIndex = $event.index">
<!--<mat-tab label="OVERVIEW">-->
<!--<mat-card class="demo-card demo-basic">-->
<!--TODO-->
<!--</mat-card>-->
<!--</mat-tab>-->
<mat-tab label="API REFERENCE"></mat-tab>
<mat-tab label="EXAMPLES"></mat-tab>
</mat-tab-group>

<mat-card class="demo-card demo-basic" *ngIf="tabIndex === 0">
<!-- <markdown [url]="'https://raw.githubusercontent.com/DSI-HUG/dejajs-components/develop/projects/js/component/snackbar/readme.md'"></markdown> -->
</mat-card>

<div class="demo-card" *ngIf="tabIndex === 1">
<!--
important:
using web-animations-js polyfill is mandatory for IE & Safari because
they don't implement the Web Animation API natively
note:
the graphic representation of the snackbar has no link with it's implementation beside it's size (see impl)
the graphic impl proposed here may be impl in the future as a separate component
it may be something that looks like a mat-card but with context property defining the context (danger, warning, success, info, simple)
which will be translated to it's color and z index
-->

<!--
todo
check body position if scrollHeight > viewportHeight
check if html container but !outerContainerElement => position on viewport
-->

<div class="btn-container">
<button mat-raised-button background="danger" (click)="push.emit('danger')">Danger</button>
<button mat-raised-button background="warning" (click)="push.emit('warning')">Warning</button>
<button mat-raised-button background="success" (click)="push.emit('success')">Success</button>
<button mat-raised-button background="info" (click)="push.emit('info')">Info</button>
<button mat-raised-button (click)="simpleGate = true">Simple</button>
</div>

<!-- simple use case, single snackbar -->
<snackbar *ngIf="simpleGate" alignment="top left" [duration]="2000" (onAnimationDone)="simpleGate = false">
<message-box type="primary" horizontal>Hello world ! I'm a simple snackbar.</message-box>
</snackbar>

<!-- event driven from UI -->
<!-- this behavior is to be used to react to user behavior on the UI, snackbars MUST be disposed using user interraction -->

<!--inside a container-->
<section #containerEl class="container" [style.position]="'relative'">
<ng-template ngFor let-message [ngForOf]="infos$ | async">
<snackbar *ngIf="message.gate" alignment="right" [outerContainerElement]="containerEl">
<message-box type="primary" horizontal>
{{ message.content }}
<ng-template #actionsTemplate>
<button mat-icon-button class="action-button" [color]="'blank'" (click)="message.gate = false">
<mat-icon>clear</mat-icon>
</button>
</ng-template>
</message-box>
</snackbar>
</ng-template>
</section>

<!--on the viewport-->
<ng-template ngFor let-message [ngForOf]="successes$ | async">
<snackbar *ngIf="message.gate" alignment="bottom left">
<message-box type="success" horizontal>
{{ message.content }}
<ng-template #actionsTemplate>
<button mat-icon-button class="action-button" [color]="'blank'" (click)="message.gate = false">
<mat-icon>clear</mat-icon>
</button>
</ng-template>
</message-box>
</snackbar>
</ng-template>

<ng-template ngFor let-message [ngForOf]="warnings$ | async">
<snackbar *ngIf="message.gate" alignment="bottom">
<message-box type="warn" horizontal>
{{ message.content }}
<ng-template #actionsTemplate>
<button mat-icon-button class="action-button" [color]="'blank'" (click)="message.gate = false">
<mat-icon>clear</mat-icon>
</button>
</ng-template>
</message-box>
</snackbar>
</ng-template>

<ng-template ngFor let-message [ngForOf]="dangers$ | async">
<snackbar *ngIf="message.gate" alignment="bottom right">
<message-box type="danger" horizontal>
{{ message.content }}
<ng-template #actionsTemplate>
<button mat-icon-button class="action-button" [color]="'blank'" (click)="message.gate = false">
<mat-icon>clear</mat-icon>
</button>
</ng-template>
</message-box>
</snackbar>
</ng-template>

<section class="push-section">
<!-- server push like feed -->
<!-- this behavior is to be used to push message to the client for example, snackbars MUST be displosed by themself -->
<!-- to do so, define duration @Input and negate flag used for disposal using the onAnimationDone @Output -->
<ng-template ngFor let-message [ngForOf]="messages$ | async">
<snackbar *ngIf="message.gate" alignment="left" [duration]="5000" (onAnimationDone)="message.gate = false">
<message-box type="primary" horizontal>
{{ message.content }}
</message-box>
</snackbar>
</ng-template>
</section>
</div>
45 changes: 45 additions & 0 deletions projects/demo-app/src/app/snackbar/snackbar-demo.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
@use '@angular/material' as mat;

:host {
.container {
display: block;
margin: auto;
max-width: 800px;
max-height: 800px;
min-height: 400px;
box-sizing: border-box;
border: solid rgba(0, 0, 0, 1) 1px;
}

.btn-container {
width: 500px;
margin: auto;
margin-bottom: 12px;

[background='danger'] {
background: mat.get-color-from-palette(mat.$red-palette, 400);
}

[background='warning'] {
background: mat.get-color-from-palette(mat.$orange-palette, 400);
}

[background='success'] {
background: mat.get-color-from-palette(mat.$green-palette, 400);
}

[background='info'] {
background: mat.get-color-from-palette(mat.$blue-palette, 400);
}

[background='default'] {
background: mat.get-color-from-palette(mat.$grey-palette, 900);
}
}

.push-section {
width: 400px;
height: 4000px;
border: red solid 1px;
}
}
81 changes: 81 additions & 0 deletions projects/demo-app/src/app/snackbar/snackbar-demo.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { AsyncPipe, NgFor, NgIf } from '@angular/common';
import { ChangeDetectionStrategy, Component, EventEmitter } from '@angular/core';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatIconModule } from '@angular/material/icon';
import { MatTabsModule } from '@angular/material/tabs';
import { MessageBoxComponent } from '@hug/ngx-message-box';
import { SnackbarComponent } from '@hug/ngx-snackbar';
import { Observable, defaultIfEmpty, filter, from, interval, map, scan } from 'rxjs';

class Message {
public constructor(public content = 'Some snackbar', public gate = true) { }
}

@Component({
selector: 'app-snackbar-demo',
styleUrls: ['./snackbar-demo.component.scss'],
templateUrl: './snackbar-demo.component.html',
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [
AsyncPipe,
MatButtonModule,
MatCardModule,
MatIconModule,
MatTabsModule,
MessageBoxComponent,
NgIf,
NgFor,
SnackbarComponent
]
})
export class SnackbarDemoComponent {
public tabIndex = 1;

/*
The example below demonstrate how you can dynamically add snackbars using *ngFor structural directive.
Here the Observable simulate items being push from the server
*/
public messages$: Observable<Message[]>;

public dangers$: Observable<Message[]>;
public warnings$: Observable<Message[]>;
public successes$: Observable<Message[]>;
public infos$: Observable<Message[]>;

public push = new EventEmitter<string>();

public simpleGate = false;

public constructor() {
this.dangers$ = from(this.push).pipe(
filter(type => type === 'danger'),
map(() => new Message('Danger snackbar')),
scan((acc, curr) => [...acc, curr], [] as Message[]),
defaultIfEmpty([] as Message[]));

this.warnings$ = from(this.push).pipe(
filter(type => type === 'warning'),
map(() => new Message('Warning snackbar')),
scan((acc, curr) => [...acc, curr], [] as Message[]),
defaultIfEmpty([] as Message[]));

this.successes$ = from(this.push).pipe(
filter(type => type === 'success'),
map(() => new Message('Success snackbar')),
scan((acc, curr) => [...acc, curr], [] as Message[]),
defaultIfEmpty([] as Message[]));

this.infos$ = from(this.push).pipe(
filter(type => type === 'info'),
map(() => new Message('Info snackbar')),
scan((acc, curr) => [...acc, curr], [] as Message[]),
defaultIfEmpty([] as Message[]));

this.messages$ = interval(2000).pipe(
map(() => new Message('Server push snackbar')),
scan((acc, curr) => [...acc, curr], [] as Message[]),
defaultIfEmpty([] as Message[]));
}
}
4 changes: 1 addition & 3 deletions projects/message-box/src/message-box.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ message-box {
> .mat-card-actions {
margin: 0;
padding: 0;
position: absolute;
right: 0;
top: 0;
flex: 0 0 auto;

[mat-icon-button] {
mat-icon {
Expand Down

0 comments on commit b0aa584

Please sign in to comment.