Skip to content

Commit

Permalink
feat(experimental): Skeleton add new directive (#7024)
Browse files Browse the repository at this point in the history
  • Loading branch information
waterplea authored Mar 19, 2024
1 parent aac3883 commit 3785a77
Show file tree
Hide file tree
Showing 21 changed files with 380 additions and 3 deletions.
4 changes: 2 additions & 2 deletions projects/addon-doc/components/main/main.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {TuiThemeNightService, TuiThemeService} from '@taiga-ui/addon-doc/service
import {TUI_DOC_ICONS, TuiDocIcons} from '@taiga-ui/addon-doc/tokens';
import {TuiSwipeService} from '@taiga-ui/cdk';
import {TuiBrightness, TuiModeDirective} from '@taiga-ui/core';
import {distinctUntilChanged, map, share, startWith} from 'rxjs/operators';
import {distinctUntilChanged, map, shareReplay, startWith} from 'rxjs/operators';

@Component({
selector: 'tui-doc-main',
Expand All @@ -35,7 +35,7 @@ export class TuiDocMainComponent {
startWith(null),
map(() => this.night.value),
distinctUntilChanged(),
share(),
shareReplay({bufferSize: 1, refCount: true}),
);

constructor(
Expand Down
2 changes: 1 addition & 1 deletion projects/addon-doc/components/main/main.template.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<tui-theme-night *ngIf="theme.isDefaultTheme && night.useDefaultNightTheme && (night$ | async)"></tui-theme-night>
<tui-root>
<tui-root [attr.tuiTheme]="theme.isDefaultTheme && night.useDefaultNightTheme && (night$ | async) ? 'night' : null">
<div class="tui-doc-page">
<tui-doc-navigation class="tui-doc-navigation">
<ng-content select="tuiDocNavigation"></ng-content>
Expand Down
9 changes: 9 additions & 0 deletions projects/demo/src/modules/app/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,15 @@ export const ROUTES: Routes = [
title: 'Sensitive',
},
},
{
path: 'experimental/skeleton',
loadChildren: async () =>
(await import('../experimental/skeleton/skeleton.module'))
.ExampleTuiSkeletonModule,
data: {
title: 'Skeleton',
},
},
{
path: 'experimental/surface',
loadChildren: async () =>
Expand Down
6 changes: 6 additions & 0 deletions projects/demo/src/modules/app/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -998,6 +998,12 @@ export const pages: TuiDocPages = [
keywords: 'sensitive, pixel, mask, пиксель, маска',
route: '/experimental/sensitive',
},
{
section: 'Experimental',
title: 'Skeleton ',
keywords: 'верстка, markup, скелетон, loader, загрузка, skeleton, shimmer',
route: '/experimental/skeleton',
},
{
section: 'Experimental',
title: 'Surface',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<tui-checkbox-labeled [(ngModel)]="skeleton">Show skeleton</tui-checkbox-labeled>
<p>
<tui-avatar
src="AI"
[tuiSkeleton]="skeleton"
></tui-avatar>
<tui-avatar
src="https://avatars.githubusercontent.com/u/11832552"
[tuiSkeleton]="skeleton"
></tui-avatar>
<tui-avatar
src="❤️"
[tuiSkeleton]="skeleton"
></tui-avatar>
<tui-avatar
appearance="primary"
src="$"
[tuiSkeleton]="skeleton"
></tui-avatar>
</p>
<section
tuiCardLarge
tuiSurface="flat"
[tuiSkeleton]="skeleton"
>
<h2 tuiHeader>
<span tuiTitle>
Card
<span tuiSubtitle>Subtitle</span>
</span>
</h2>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna
aliqua.
</section>
<p>
<button
tuiButton
[tuiSkeleton]="skeleton"
>
Awesome
</button>
<button
appearance="secondary"
tuiButton
[tuiSkeleton]="skeleton"
>
Cool
</button>
</p>
<p>
<tui-chip [tuiSkeleton]="skeleton">Chip</tui-chip>
<tui-badge [tuiSkeleton]="skeleton">Dale</tui-badge>
</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
p {
display: flex;
gap: 1rem;
align-items: center;
justify-content: center;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {Component} from '@angular/core';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';

@Component({
selector: 'tui-skeleton-example-1',
templateUrl: './index.html',
styleUrls: ['./index.less'],
encapsulation,
changeDetection,
})
export class TuiSkeletonExample1 {
skeleton = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<tui-checkbox-labeled [(ngModel)]="skeleton">Show skeleton</tui-checkbox-labeled>
<p>
<span
[tuiSkeleton]="
skeleton
? 'This text serves as the content behind the skeleton and depending on its length, the skeleton will adjust to fit it.'
: ''
"
>
{{ skeleton ? '' : 'This text will be replaced by a placeholder.' }}
</span>
</p>

<span [tuiSkeleton]="skeleton && 20">
{{ skeleton ? '' : 'This text will be replaced by a skeleton made of 20 random length non-breaking spaces.' }}
</span>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {Component} from '@angular/core';
import {changeDetection} from '@demo/emulate/change-detection';
import {encapsulation} from '@demo/emulate/encapsulation';

@Component({
selector: 'tui-skeleton-example-2',
templateUrl: './index.html',
encapsulation,
changeDetection,
})
export class TuiSkeletonExample2 {
skeleton = false;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
```ts
import {NgModule} from '@angular/core';
import {TuiSkeletonModule} from '@taiga-ui/experimental';
// ...

@NgModule({
imports: [
// ...
TuiSkeletonModule,
],
})
export class MyModule {}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```html
<span [tuiSkeleton]="true">Loading..</span>
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import {Component} from '@angular/core';
import {changeDetection} from '@demo/emulate/change-detection';
import {TuiDocExample} from '@taiga-ui/addon-doc';

@Component({
selector: 'skeleton',
templateUrl: './skeleton.template.html',
changeDetection,
})
export class ExampleTuiSkeletonComponent {
readonly import = import('./examples/import/import.md?raw');
readonly template = import('./examples/import/insert.md?raw');

readonly example1: TuiDocExample = {
HTML: import('./examples/1/index.html?raw'),
};

readonly example2: TuiDocExample = {
HTML: import('./examples/2/index.html?raw'),
};
}
43 changes: 43 additions & 0 deletions projects/demo/src/modules/experimental/skeleton/skeleton.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import {CommonModule} from '@angular/common';
import {NgModule} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {tuiGetDocModules} from '@taiga-ui/addon-doc';
import {TuiNotificationModule} from '@taiga-ui/core';
import {
TuiAvatarModule,
TuiBadgeModule,
TuiButtonModule,
TuiCardModule,
TuiChipModule,
TuiHeaderModule,
TuiSkeletonModule,
TuiSurfaceModule,
TuiTitleModule,
} from '@taiga-ui/experimental';
import {TuiCheckboxLabeledModule} from '@taiga-ui/kit';

import {TuiSkeletonExample1} from './examples/1';
import {TuiSkeletonExample2} from './examples/2';
import {ExampleTuiSkeletonComponent} from './skeleton.component';

@NgModule({
imports: [
CommonModule,
FormsModule,
TuiSkeletonModule,
TuiCardModule,
TuiTitleModule,
TuiSurfaceModule,
TuiButtonModule,
TuiChipModule,
TuiBadgeModule,
TuiNotificationModule,
TuiAvatarModule,
TuiHeaderModule,
TuiCheckboxLabeledModule,
tuiGetDocModules(ExampleTuiSkeletonComponent),
],
declarations: [ExampleTuiSkeletonComponent, TuiSkeletonExample1, TuiSkeletonExample2],
exports: [ExampleTuiSkeletonComponent],
})
export class ExampleTuiSkeletonModule {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<tui-doc-page
header="Skeleton"
package="KIT"
type="directives"
>
<ng-template pageTab>
<tui-doc-example
id="components"
heading="Components"
[content]="example1"
>
<tui-skeleton-example-1></tui-skeleton-example-1>
</tui-doc-example>

<tui-doc-example
id="text"
heading="Text"
[content]="example2"
[description]="description"
>
<ng-template #description>
You can pass
<code>boolean</code>
to toggle skeleton for elements. For multi line text you can use
<code>string</code>
to serve as a placeholder underneath the text skeleton or a
<code>number</code>
to generate this many random sized words, while your actual text is loading
</ng-template>
<tui-skeleton-example-2></tui-skeleton-example-2>
</tui-doc-example>
</ng-template>

<ng-template pageTab="Setup">
<ol class="b-demo-steps">
<li>
<p>Import module:</p>

<tui-doc-code
filename="my.module.ts"
[code]="import"
></tui-doc-code>
</li>

<li>
<p>Add to the template:</p>

<tui-doc-code
filename="my.component.html"
[code]="template"
></tui-doc-code>
</li>
</ol>
</ng-template>
</tui-doc-page>
1 change: 1 addition & 0 deletions projects/experimental/directives/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,6 @@ export * from '@taiga-ui/experimental/directives/header';
export * from '@taiga-ui/experimental/directives/icons';
export * from '@taiga-ui/experimental/directives/progress-segmented';
export * from '@taiga-ui/experimental/directives/sensitive';
export * from '@taiga-ui/experimental/directives/skeleton';
export * from '@taiga-ui/experimental/directives/surface';
export * from '@taiga-ui/experimental/directives/title';
3 changes: 3 additions & 0 deletions projects/experimental/directives/skeleton/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './skeleton.component';
export * from './skeleton.directive';
export * from './skeleton.module';
5 changes: 5 additions & 0 deletions projects/experimental/directives/skeleton/ng-package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"lib": {
"entryFile": "index.ts"
}
}
12 changes: 12 additions & 0 deletions projects/experimental/directives/skeleton/skeleton.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {ChangeDetectionStrategy, Component, ViewEncapsulation} from '@angular/core';

@Component({
template: '',
styleUrls: ['./skeleton.style.less'],
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'tui-skeleton-styles',
},
})
export class TuiSkeletonComponent {}
57 changes: 57 additions & 0 deletions projects/experimental/directives/skeleton/skeleton.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type {OnChanges, SimpleChanges} from '@angular/core';
import {Directive, ElementRef, Inject, Input} from '@angular/core';
import {CHAR_NO_BREAK_SPACE, TuiDirectiveStylesService, tuiPure} from '@taiga-ui/cdk';
import {TUI_ANIMATIONS_DURATION} from '@taiga-ui/core';

import {TuiSkeletonComponent} from './skeleton.component';

const FADE = [{opacity: 0.06}, {opacity: 1}];

@Directive({
selector: '[tuiSkeleton]',
host: {
tuiSkeleton: '',
'[class._skeleton]': 'tuiSkeleton',
'[attr.data-tui-skeleton]': 'getPlaceholder(tuiSkeleton)',
},
})
export class TuiSkeletonDirective implements OnChanges {
private animation?: Animation;

@Input()
tuiSkeleton: boolean | number | string = false;

constructor(
@Inject(ElementRef) private readonly el: ElementRef<HTMLElement>,
@Inject(TUI_ANIMATIONS_DURATION) private readonly duration: number,
@Inject(TuiDirectiveStylesService) directiveStyles: TuiDirectiveStylesService,
) {
directiveStyles.addComponent(TuiSkeletonComponent);
}

@tuiPure
getPlaceholder(value: boolean | number | string): string | null {
switch (typeof value) {
case 'number':
return Array.from({length: value})
.map(() => CHAR_NO_BREAK_SPACE.repeat(getLength()))
.join(' ');
case 'string':
return value;
default:
return null;
}
}

ngOnChanges({tuiSkeleton}: SimpleChanges): void {
this.animation?.cancel();

if (!tuiSkeleton.currentValue && !tuiSkeleton.firstChange) {
this.animation = this.el.nativeElement.animate(FADE, this.duration * 2);
}
}
}

function getLength(): number {
return Math.floor(Math.random() * (15 - 5 + 1)) + 5;
}
10 changes: 10 additions & 0 deletions projects/experimental/directives/skeleton/skeleton.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {NgModule} from '@angular/core';

import {TuiSkeletonComponent} from './skeleton.component';
import {TuiSkeletonDirective} from './skeleton.directive';

@NgModule({
declarations: [TuiSkeletonComponent, TuiSkeletonDirective],
exports: [TuiSkeletonDirective],
})
export class TuiSkeletonModule {}
Loading

0 comments on commit 3785a77

Please sign in to comment.