Improved back-to-top button behavior on anchor jump

This commit is contained in:
squidfunk 2022-01-16 16:09:51 +01:00
parent 0a08e6795c
commit 014ab602cb
7 changed files with 57 additions and 54 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -213,7 +213,7 @@
</script>
{% endblock %}
{% block scripts %}
<script src="{{ 'assets/javascripts/bundle.1514a9a0.min.js' | url }}"></script>
<script src="{{ 'assets/javascripts/bundle.01de222e.min.js' | url }}"></script>
{% for path in config["extra_javascript"] %}
<script src="{{ path | url }}"></script>
{% endfor %}

View File

@ -233,7 +233,7 @@ const content$ = defer(() => merge(
/* Back-to-top button */
...getComponentElements("top")
.map(el => mountBackToTop(el, { viewport$, header$, main$ }))
.map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))
))
/* Set up component observables */

View File

@ -30,6 +30,8 @@ import {
endWith,
finalize,
map,
repeat,
skip,
takeLast,
takeUntil,
tap
@ -61,8 +63,8 @@ export interface BackToTop {
*/
interface WatchOptions {
viewport$: Observable<Viewport> /* Viewport observable */
header$: Observable<Header> /* Header observable */
main$: Observable<Main> /* Main area observable */
target$: Observable<HTMLElement> /* Location target observable */
}
/**
@ -72,6 +74,7 @@ interface MountOptions {
viewport$: Observable<Viewport> /* Viewport observable */
header$: Observable<Header> /* Header observable */
main$: Observable<Main> /* Main area observable */
target$: Observable<HTMLElement> /* Location target observable */
}
/* ----------------------------------------------------------------------------
@ -87,7 +90,7 @@ interface MountOptions {
* @returns Back-to-top observable
*/
export function watchBackToTop(
_el: HTMLElement, { viewport$, main$ }: WatchOptions
_el: HTMLElement, { viewport$, main$, target$ }: WatchOptions
): Observable<BackToTop> {
/* Compute direction */
@ -95,25 +98,25 @@ export function watchBackToTop(
.pipe(
map(({ offset: { y } }) => y),
bufferCount(2, 1),
map(([a, b]) => a > b && b),
map(([a, b]) => a > b),
distinctUntilChanged()
)
/* Compute whether button should be hidden */
const hidden$ = main$
/* Compute whether main area is active */
const active$ = main$
.pipe(
distinctUntilKeyChanged("active")
map(({ active }) => active)
)
/* Compute threshold for hiding */
return combineLatest([hidden$, direction$])
return combineLatest([active$, direction$])
.pipe(
map(([{ active }, direction]) => ({
hidden: !(active && direction)
})),
distinctUntilChanged((a, b) => (
a.hidden === b.hidden
))
map(([active, direction]) => !(active && direction)),
distinctUntilChanged(),
takeUntil(target$.pipe(skip(1))),
endWith(true),
repeat({ delay: 250 }),
map(hidden => ({ hidden }))
)
}
@ -128,7 +131,7 @@ export function watchBackToTop(
* @returns Back-to-top component observable
*/
export function mountBackToTop(
el: HTMLElement, { viewport$, header$, main$ }: MountOptions
el: HTMLElement, { viewport$, header$, main$, target$ }: MountOptions
): Observable<Component<BackToTop>> {
const push$ = new Subject<BackToTop>()
push$.subscribe({
@ -164,7 +167,7 @@ export function mountBackToTop(
})
/* Create and return component */
return watchBackToTop(el, { viewport$, header$, main$ })
return watchBackToTop(el, { viewport$, main$, target$ })
.pipe(
tap(state => push$.next(state)),
finalize(() => push$.complete()),