From e457d901b23acc98c73b2afd58d903ac423df585 Mon Sep 17 00:00:00 2001 From: squidfunk Date: Wed, 20 Nov 2019 10:09:23 +0100 Subject: [PATCH] Added navigation component --- .../javascripts/component/anchor/index.ts | 7 +- src/assets/javascripts/component/index.ts | 1 + .../javascripts/component/navigation/index.ts | 82 +++++++++++++++++++ .../javascripts/component/sidebar/index.ts | 7 +- 4 files changed, 92 insertions(+), 5 deletions(-) create mode 100644 src/assets/javascripts/component/navigation/index.ts diff --git a/src/assets/javascripts/component/anchor/index.ts b/src/assets/javascripts/component/anchor/index.ts index cd599fe8d..f19580035 100644 --- a/src/assets/javascripts/component/anchor/index.ts +++ b/src/assets/javascripts/component/anchor/index.ts @@ -34,7 +34,7 @@ import { ViewportOffset, getElement } from "../../ui" * Anchors */ export interface Anchors { - done: HTMLAnchorElement[][] /* Read anchors */ + done: HTMLAnchorElement[][] /* Done anchors */ next: HTMLAnchorElement[][] /* Next anchors */ } @@ -158,7 +158,10 @@ export function watchAnchors( /* Return partition */ return [done, next] }, [[], [...table]]), - distinctUntilChanged((a, b) => a[0] === b[0] && a[1] === b[1]) + distinctUntilChanged((a, b) => { + return a[0] === b[0] + && a[1] === b[1] + }) ) /* Extract anchors and return hot observable */ diff --git a/src/assets/javascripts/component/index.ts b/src/assets/javascripts/component/index.ts index b413f801f..b5453cf95 100644 --- a/src/assets/javascripts/component/index.ts +++ b/src/assets/javascripts/component/index.ts @@ -23,4 +23,5 @@ export * from "./anchor" export * from "./container" export * from "./header" +export * from "./navigation" export * from "./sidebar" diff --git a/src/assets/javascripts/component/navigation/index.ts b/src/assets/javascripts/component/navigation/index.ts new file mode 100644 index 000000000..7366fff39 --- /dev/null +++ b/src/assets/javascripts/component/navigation/index.ts @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2016-2019 Martin Donath + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +import { Observable, of } from "rxjs" +import { shareReplay } from "rxjs/operators" + +import { getElement, getElements } from "../../ui" + +/* ---------------------------------------------------------------------------- + * Types + * ------------------------------------------------------------------------- */ + +/** + * Navigation index + */ +export type NavigationIndex = Map + +/* ---------------------------------------------------------------------------- + * Functions + * ------------------------------------------------------------------------- */ + +/** + * Set navigation overflow scrolling + * + * @param nav - Navigation element + * @param active - Whether overflow scrolling is active + */ +export function setNavigationOverflowScrolling( + nav: HTMLElement, active: boolean +): void { + nav.style.webkitOverflowScrolling = active ? "touch" : "" +} + +/* ------------------------------------------------------------------------- */ + +/** + * Create an observable to index all navigation elements + * + * @param nav - Top-level navigation element + * + * @return Navigation index observable + */ +export function watchNavigationIndex( + nav: HTMLElement +): Observable { + const list = getElements("nav", nav) + + /* Build index to map inputs to navigation lists */ + const index = new Map() + for (const item of list) { + const label = getElement("label", item)! + if (typeof label !== "undefined") { + const input = getElement(`#${label.htmlFor}`)! + index.set(input, item) + } + } + + /* Return navigation index */ + return of(index) + .pipe( + shareReplay({ bufferSize: 1, refCount: true }) + ) +} diff --git a/src/assets/javascripts/component/sidebar/index.ts b/src/assets/javascripts/component/sidebar/index.ts index 48516cb66..7ea409833 100644 --- a/src/assets/javascripts/component/sidebar/index.ts +++ b/src/assets/javascripts/component/sidebar/index.ts @@ -20,8 +20,9 @@ * IN THE SOFTWARE. */ +import { equals } from "ramda" import { Observable, combineLatest } from "rxjs" -import { map, shareReplay } from "rxjs/operators" +import { distinctUntilChanged, map, shareReplay } from "rxjs/operators" import { ViewportOffset } from "../../ui" import { Container } from "../container" @@ -112,8 +113,7 @@ export function watchSidebar( const height$ = combineLatest(offset$, container$) .pipe( map(([{ y }, { offset, height }]) => { - return height - adjust - + Math.min(adjust, Math.max(0, y - offset)) + return height - adjust + Math.min(adjust, Math.max(0, y - offset)) }) ) @@ -127,6 +127,7 @@ export function watchSidebar( return combineLatest(height$, lock$) .pipe( map(([height, lock]) => ({ height, lock })), + distinctUntilChanged(equals), shareReplay({ bufferSize: 1, refCount: true }) ) }