From 3d9222f6b878a62f10344c0125050a40252f50db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gary=20Gro=C3=9Fgarten?= Date: Sat, 12 Dec 2020 02:24:48 +0100 Subject: [PATCH 1/2] add shortcodes and scrolltop blog post --- content/blog/rxjs-scroll-position.md | 25 +++++++++++++++++++ ...=> simple-rxjs-keyboard-shortcuts copy.md} | 0 package-lock.json | 17 +++++++++++++ package.json | 2 ++ src/app/app.module.ts | 12 +++++++-- src/app/demos/scroll/scroll.module.ts | 25 +++++++++++++++++++ src/app/demos/scroll/scroll.pipe.ts | 13 ++++++++++ src/app/demos/scroll/scroll.ts | 19 ++++++++++++++ .../demos/scroll/scrollcontainer.component.ts | 21 ++++++++++++++++ .../demos/scroll/scrollpercent.component.ts | 14 +++++++++++ src/app/demos/scroll/scrolltop.component.ts | 16 ++++++++++++ .../pages/blog-post/blog-post.component.html | 2 +- src/app/pages/blog-post/blog-post.module.ts | 2 ++ 13 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 content/blog/rxjs-scroll-position.md rename content/blog/{simple-rxjs-keyboard-shortcuts.md => simple-rxjs-keyboard-shortcuts copy.md} (100%) create mode 100644 src/app/demos/scroll/scroll.module.ts create mode 100644 src/app/demos/scroll/scroll.pipe.ts create mode 100644 src/app/demos/scroll/scroll.ts create mode 100644 src/app/demos/scroll/scrollcontainer.component.ts create mode 100644 src/app/demos/scroll/scrollpercent.component.ts create mode 100644 src/app/demos/scroll/scrolltop.component.ts diff --git a/content/blog/rxjs-scroll-position.md b/content/blog/rxjs-scroll-position.md new file mode 100644 index 00000000..c3146de5 --- /dev/null +++ b/content/blog/rxjs-scroll-position.md @@ -0,0 +1,25 @@ +--- +title: 'Tracking the scroll position in Angular | A practical guide to RxJS' +description: '' +published: true +publishedAt: 2020-12-14T19:20:51.808Z +updatedAt: 2020-12-14T19:20:51.808Z +tags: + - RxJS + - Angular +keywords: + - Scroll Position + - RxJS + - Angular +authors: + - 'Gary Großgarten' +github: https://github.com/garygrossgarten/observables +--- + +## Demo + +Here's a demo tracking the scrolltop of the container element. + +
+
+
\ No newline at end of file diff --git a/content/blog/simple-rxjs-keyboard-shortcuts.md b/content/blog/simple-rxjs-keyboard-shortcuts copy.md similarity index 100% rename from content/blog/simple-rxjs-keyboard-shortcuts.md rename to content/blog/simple-rxjs-keyboard-shortcuts copy.md diff --git a/package-lock.json b/package-lock.json index a8430f86..ab455d1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -716,6 +716,15 @@ "tslib": "^2.0.0" } }, + "@angular/cdk": { + "version": "11.0.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-11.0.2.tgz", + "integrity": "sha512-hdZ9UJVGgCFhdOuB4RPS1Ku45VSG/WfRjbyxu/7teYyFKqAvcd3vawkeQfZf+lExmFaeW43+5hnpu/JIlGTrSA==", + "requires": { + "parse5": "^5.0.0", + "tslib": "^2.0.0" + } + }, "@angular/cli": { "version": "11.0.1", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-11.0.1.tgz", @@ -3804,6 +3813,14 @@ "tslib": "^2.0.0" } }, + "@garygrossgarten/shortcodes": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@garygrossgarten/shortcodes/-/shortcodes-0.0.1.tgz", + "integrity": "sha512-eKERVbWO7c3PlK+w0MzJGieqbduuT+LF9GmNu4UGNtZDyWT5m4wKmNZ4pKu3zI/K31UQN51xzIcJn3CgrOccmQ==", + "requires": { + "tslib": "^2.0.0" + } + }, "@istanbuljs/schema": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", diff --git a/package.json b/package.json index 158661f0..08811f96 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "private": true, "dependencies": { "@angular/animations": "11.0.0", + "@angular/cdk": "^11.0.2", "@angular/common": "11.0.0", "@angular/compiler": "11.0.0", "@angular/core": "11.0.0", @@ -44,6 +45,7 @@ "@angular/platform-browser-dynamic": "11.0.0", "@angular/router": "11.0.0", "@angular/service-worker": "11.0.0", + "@garygrossgarten/shortcodes": "0.0.1", "@scullyio/init": "1.0.1", "@scullyio/ng-lib": "1.0.0", "@scullyio/scully": "1.0.5", diff --git a/src/app/app.module.ts b/src/app/app.module.ts index b6320730..28892b6f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -21,6 +21,7 @@ import { NewsletterSignupModule } from '@components/newsletter-signup/newsletter import { NizSearchComponentModule } from '@components/search/search.module'; import { PipesModule } from '@pipes/pipes.module'; import { NizFooterModule } from '@components/footer/footer.module'; +import { ShortcodeModule } from '@garygrossgarten/shortcodes'; @NgModule({ declarations: [AppComponent], @@ -35,7 +36,7 @@ import { NizFooterModule } from '@components/footer/footer.module'; MarkdownModule.forRoot({ loader: HttpClient }), NizTabsModule, NizTabModule, - NizFooterModule, + NizFooterModule, NizNavbarModule, NizToolbarModule, NizInlineSvgModule, @@ -43,7 +44,14 @@ import { NizFooterModule } from '@components/footer/footer.module'; NizSearchComponentModule, PipesModule, NizToastModule, - NizMenuModule + NizMenuModule, + ShortcodeModule.forRoot([ + { + path: 'scroll', + loadChildren: () => + import('./demos/scroll/scroll.module').then((d) => d.ScrollModule), + }, + ]), ], providers: [], bootstrap: [AppComponent], diff --git a/src/app/demos/scroll/scroll.module.ts b/src/app/demos/scroll/scroll.module.ts new file mode 100644 index 00000000..e6c0ccdb --- /dev/null +++ b/src/app/demos/scroll/scroll.module.ts @@ -0,0 +1,25 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { ScrollComponent } from './scrolltop.component'; +import { ScrollPercentComponent } from './scrollpercent.component'; +import { ScrollContainerComponent } from './scrollcontainer.component'; +import { ShortcodeModule } from '@garygrossgarten/shortcodes'; +import { ScrollPipe } from './scroll.pipe'; + +@NgModule({ + declarations: [ + ScrollComponent, + ScrollPipe, + ScrollPercentComponent, + ScrollContainerComponent, + ], + imports: [ + CommonModule, + ShortcodeModule.forChild([ + { path: '', component: ScrollComponent }, + { path: 'percent', component: ScrollPercentComponent }, + { path: 'container', component: ScrollContainerComponent }, + ]), + ], +}) +export class ScrollModule {} diff --git a/src/app/demos/scroll/scroll.pipe.ts b/src/app/demos/scroll/scroll.pipe.ts new file mode 100644 index 00000000..bd1be20e --- /dev/null +++ b/src/app/demos/scroll/scroll.pipe.ts @@ -0,0 +1,13 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { Observable } from "rxjs"; +import { scroll$ } from "./scroll"; + +@Pipe({ + name: "scroll", + pure: true, +}) +export class ScrollPipe implements PipeTransform { + transform(el: HTMLElement): Observable { + return scroll$(el); + } +} diff --git a/src/app/demos/scroll/scroll.ts b/src/app/demos/scroll/scroll.ts new file mode 100644 index 00000000..42a49fcb --- /dev/null +++ b/src/app/demos/scroll/scroll.ts @@ -0,0 +1,19 @@ +import { fromEvent, merge, zip } from 'rxjs'; +import { map, startWith } from 'rxjs/operators'; + +export const scrolltop$ = (el: Element) => + merge(fromEvent(el, 'scroll'), fromEvent(window, 'scroll')).pipe( + startWith(el.scrollTop), + map(() => el.scrollTop) + ); + +export const scrollHeight$ = (el: Element) => + merge(fromEvent(el, 'scroll'), fromEvent(window, 'scroll')).pipe( + startWith(el.scrollHeight), + map(() => el.scrollHeight) + ); + +export const scroll$ = (el: Element) => + zip(scrolltop$(el), scrollHeight$(el)).pipe( + map(([top, height]) => (100 * top) / (height - el.clientHeight)) + ); diff --git a/src/app/demos/scroll/scrollcontainer.component.ts b/src/app/demos/scroll/scrollcontainer.component.ts new file mode 100644 index 00000000..a98be244 --- /dev/null +++ b/src/app/demos/scroll/scrollcontainer.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'niz-scroll', + template: ` {{ (el | scroll | async)?.toFixed() }}% +
+
+
`, +}) +export class ScrollContainerComponent implements OnInit { + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/demos/scroll/scrollpercent.component.ts b/src/app/demos/scroll/scrollpercent.component.ts new file mode 100644 index 00000000..6c70cb16 --- /dev/null +++ b/src/app/demos/scroll/scrollpercent.component.ts @@ -0,0 +1,14 @@ +import { Component, OnInit } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { scroll$ } from './scroll'; + +@Component({ + selector: 'niz-scroll', + template: ` Page Scrolltop: {{ scroll$ | async }} % `, +}) +export class ScrollPercentComponent implements OnInit { + scroll$ = scroll$(document.documentElement).pipe(map((v) => v.toFixed())); + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/demos/scroll/scrolltop.component.ts b/src/app/demos/scroll/scrolltop.component.ts new file mode 100644 index 00000000..4b60b51d --- /dev/null +++ b/src/app/demos/scroll/scrolltop.component.ts @@ -0,0 +1,16 @@ +import { Component, OnInit } from '@angular/core'; +import { map } from 'rxjs/operators'; +import { scroll$, scrolltop$ } from './scroll'; + +@Component({ + selector: 'niz-scroll', + template: ` + Page Scrolltop: {{scroll$ | async}} + `, +}) +export class ScrollComponent implements OnInit { + scroll$ = scrolltop$(document.documentElement).pipe(map((v) => v.toFixed())); + constructor() {} + + ngOnInit(): void {} +} diff --git a/src/app/pages/blog-post/blog-post.component.html b/src/app/pages/blog-post/blog-post.component.html index f1131292..a17f973a 100644 --- a/src/app/pages/blog-post/blog-post.component.html +++ b/src/app/pages/blog-post/blog-post.component.html @@ -41,7 +41,7 @@

-
+
diff --git a/src/app/pages/blog-post/blog-post.module.ts b/src/app/pages/blog-post/blog-post.module.ts index f7c3d034..d7d2aadb 100644 --- a/src/app/pages/blog-post/blog-post.module.ts +++ b/src/app/pages/blog-post/blog-post.module.ts @@ -18,6 +18,7 @@ import { RouterModule } from '@angular/router'; import { PipesModule } from '@pipes/pipes.module'; import { SeoModule } from '@components/seo/seo.module'; +import { ShortcodeModule } from '@garygrossgarten/shortcodes'; @NgModule({ declarations: [BlogPostComponent], @@ -37,6 +38,7 @@ import { SeoModule } from '@components/seo/seo.module'; NizChipModule, PipesModule, SeoModule, + ShortcodeModule ], }) export class BlogPostModule {} From f2eb6d26c9f43c8d646f5705193ab3cc96cd7149 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gary=20Gro=C3=9Fgarten?= Date: Sat, 12 Dec 2020 23:32:10 +0100 Subject: [PATCH 2/2] update demo --- content/blog/rxjs-scroll-position.md | 1 - src/app/demos/scroll/scroll.module.ts | 7 +++-- src/app/demos/scroll/scroll.pipe.ts | 10 +++---- src/app/demos/scroll/scroll.ts | 30 +++++++++++++++---- .../demos/scroll/scrollcontainer.component.ts | 9 +++++- src/app/demos/scroll/scrolldirection.pipe.ts | 13 ++++++++ .../demos/scroll/scrollpercent.component.ts | 14 --------- src/app/demos/scroll/scrolltop.component.ts | 4 +-- src/assets/img/arrow_downward-black-18dp.svg | 1 + 9 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 src/app/demos/scroll/scrolldirection.pipe.ts delete mode 100644 src/app/demos/scroll/scrollpercent.component.ts create mode 100644 src/assets/img/arrow_downward-black-18dp.svg diff --git a/content/blog/rxjs-scroll-position.md b/content/blog/rxjs-scroll-position.md index c3146de5..4f9be6a5 100644 --- a/content/blog/rxjs-scroll-position.md +++ b/content/blog/rxjs-scroll-position.md @@ -21,5 +21,4 @@ github: https://github.com/garygrossgarten/observables Here's a demo tracking the scrolltop of the container element.
-
\ No newline at end of file diff --git a/src/app/demos/scroll/scroll.module.ts b/src/app/demos/scroll/scroll.module.ts index e6c0ccdb..805548a2 100644 --- a/src/app/demos/scroll/scroll.module.ts +++ b/src/app/demos/scroll/scroll.module.ts @@ -1,23 +1,24 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ScrollComponent } from './scrolltop.component'; -import { ScrollPercentComponent } from './scrollpercent.component'; import { ScrollContainerComponent } from './scrollcontainer.component'; import { ShortcodeModule } from '@garygrossgarten/shortcodes'; import { ScrollPipe } from './scroll.pipe'; +import { ScrollDirectionPipe } from './scrolldirection.pipe'; +import { NizInlineSvgModule } from '@notiz/ngx-design'; @NgModule({ declarations: [ ScrollComponent, ScrollPipe, - ScrollPercentComponent, ScrollContainerComponent, + ScrollDirectionPipe ], imports: [ CommonModule, + NizInlineSvgModule, ShortcodeModule.forChild([ { path: '', component: ScrollComponent }, - { path: 'percent', component: ScrollPercentComponent }, { path: 'container', component: ScrollContainerComponent }, ]), ], diff --git a/src/app/demos/scroll/scroll.pipe.ts b/src/app/demos/scroll/scroll.pipe.ts index bd1be20e..5687b7cb 100644 --- a/src/app/demos/scroll/scroll.pipe.ts +++ b/src/app/demos/scroll/scroll.pipe.ts @@ -1,13 +1,13 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { Observable } from "rxjs"; -import { scroll$ } from "./scroll"; +import { Pipe, PipeTransform } from '@angular/core'; +import { Observable } from 'rxjs'; +import { scrollPercent$ } from './scroll'; @Pipe({ - name: "scroll", + name: 'scroll', pure: true, }) export class ScrollPipe implements PipeTransform { transform(el: HTMLElement): Observable { - return scroll$(el); + return scrollPercent$(el); } } diff --git a/src/app/demos/scroll/scroll.ts b/src/app/demos/scroll/scroll.ts index 42a49fcb..f680f59e 100644 --- a/src/app/demos/scroll/scroll.ts +++ b/src/app/demos/scroll/scroll.ts @@ -1,19 +1,39 @@ import { fromEvent, merge, zip } from 'rxjs'; -import { map, startWith } from 'rxjs/operators'; +import { + distinctUntilChanged, + filter, + map, + pairwise, + startWith, +} from 'rxjs/operators'; + +export const pageScroll$ = () => + fromEvent(window, 'scroll').pipe( + map(() => document.documentElement.scrollTop) + ); export const scrolltop$ = (el: Element) => - merge(fromEvent(el, 'scroll'), fromEvent(window, 'scroll')).pipe( + merge(fromEvent(el, 'scroll')).pipe( startWith(el.scrollTop), map(() => el.scrollTop) ); export const scrollHeight$ = (el: Element) => - merge(fromEvent(el, 'scroll'), fromEvent(window, 'scroll')).pipe( + merge(fromEvent(el, 'scroll')).pipe( startWith(el.scrollHeight), map(() => el.scrollHeight) ); -export const scroll$ = (el: Element) => +export const scrollPercent$ = (el: Element) => zip(scrolltop$(el), scrollHeight$(el)).pipe( - map(([top, height]) => (100 * top) / (height - el.clientHeight)) + filter(([top, height]) => height - el.clientHeight !== 0), + map(([top, height]) => (100 * top) / (height - el.clientHeight)), + startWith(0) + ); + +export const scrolldir$ = (el: Element) => + scrolltop$(el).pipe( + pairwise(), + map(([v1, v2]) => (v1 > v2 ? 'UP' : 'DOWN')), + distinctUntilChanged() ); diff --git a/src/app/demos/scroll/scrollcontainer.component.ts b/src/app/demos/scroll/scrollcontainer.component.ts index a98be244..90c00d0e 100644 --- a/src/app/demos/scroll/scrollcontainer.component.ts +++ b/src/app/demos/scroll/scrollcontainer.component.ts @@ -2,7 +2,14 @@ import { Component, OnInit } from '@angular/core'; @Component({ selector: 'niz-scroll', - template: ` {{ (el | scroll | async)?.toFixed() }}% + template: `
+ {{ (el | scroll | async)?.toFixed() }}% + +
{ + return scrolldir$(el); + } +} diff --git a/src/app/demos/scroll/scrollpercent.component.ts b/src/app/demos/scroll/scrollpercent.component.ts deleted file mode 100644 index 6c70cb16..00000000 --- a/src/app/demos/scroll/scrollpercent.component.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { map } from 'rxjs/operators'; -import { scroll$ } from './scroll'; - -@Component({ - selector: 'niz-scroll', - template: ` Page Scrolltop: {{ scroll$ | async }} % `, -}) -export class ScrollPercentComponent implements OnInit { - scroll$ = scroll$(document.documentElement).pipe(map((v) => v.toFixed())); - constructor() {} - - ngOnInit(): void {} -} diff --git a/src/app/demos/scroll/scrolltop.component.ts b/src/app/demos/scroll/scrolltop.component.ts index 4b60b51d..538c4a05 100644 --- a/src/app/demos/scroll/scrolltop.component.ts +++ b/src/app/demos/scroll/scrolltop.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { map } from 'rxjs/operators'; -import { scroll$, scrolltop$ } from './scroll'; +import { pageScroll$ } from './scroll'; @Component({ selector: 'niz-scroll', @@ -9,7 +9,7 @@ import { scroll$, scrolltop$ } from './scroll'; `, }) export class ScrollComponent implements OnInit { - scroll$ = scrolltop$(document.documentElement).pipe(map((v) => v.toFixed())); + scroll$ = pageScroll$().pipe(map((v) => v.toFixed())); constructor() {} ngOnInit(): void {} diff --git a/src/assets/img/arrow_downward-black-18dp.svg b/src/assets/img/arrow_downward-black-18dp.svg new file mode 100644 index 00000000..9b934b4b --- /dev/null +++ b/src/assets/img/arrow_downward-black-18dp.svg @@ -0,0 +1 @@ + \ No newline at end of file