diff --git a/src/assets/javascripts/component/_/index.ts b/src/assets/javascripts/component/_/index.ts index b595994fb..e3d04f2e7 100644 --- a/src/assets/javascripts/component/_/index.ts +++ b/src/assets/javascripts/component/_/index.ts @@ -20,8 +20,9 @@ * IN THE SOFTWARE. */ +import { keys } from "ramda" import { MonoTypeOperatorFunction, Observable, of, pipe } from "rxjs" -import { scan, shareReplay, tap } from "rxjs/operators" +import { scan, shareReplay } from "rxjs/operators" import { getElement } from "../../ui" @@ -40,10 +41,11 @@ export type Component = | "reset" /* Search reset */ | "result" /* Search results */ | "container" /* Container */ + | "main" /* Main area */ + | "hero" /* Hero */ | "tabs" /* Tabs */ | "navigation" /* Navigation */ | "toc" /* Table of contents */ - | "footer" /* Footer */ /** * Component map @@ -79,10 +81,11 @@ export function watchComponentMap( "reset", /* Search reset */ "result", /* Search results */ "container", /* Container */ + "main", /* Main area */ + "hero", /* Hero */ "tabs", /* Tabs */ "navigation", /* Navigation */ - "toc", /* Table of contents */ - "footer" /* Footer */ + "toc" /* Table of contents */ ].reduce((map, name) => { const el = getElement(`[data-md-component=${name}]`, document) return { @@ -104,21 +107,30 @@ export function watchComponentMap( * Paint component map from source observable * * This operator function will swap the components in the previous component - * map with the new components identified by the given names. + * map with the new components identified by the given names and rebind all + * remaining components, as they may be children of swapped components. * * @param names - Components to paint * * @return Operator function */ export function paintComponentMap( - names: Component[] = ["title", "tabs", "container", "footer"] + names: Component[] = ["title", "container"] ): MonoTypeOperatorFunction { return pipe( scan((prev, next) => { - for (const name of names) { - if (name in prev && typeof prev[name] !== "undefined") { - prev[name]!.replaceWith(next[name]!) - prev[name] = next[name] + for (const name of keys(prev)) { + + /* Swap component */ + if (names.includes(name)) { + if (name in prev && typeof prev[name] !== "undefined") { + prev[name]!.replaceWith(next[name]!) + prev[name] = next[name] + } + + /* Bind component */ + } else { + prev[name] = getElement(`[data-md-component=${name}]`) } } return prev diff --git a/src/assets/javascripts/component/header/_/index.ts b/src/assets/javascripts/component/header/_/index.ts index 7d04e886a..bf0bbc243 100644 --- a/src/assets/javascripts/component/header/_/index.ts +++ b/src/assets/javascripts/component/header/_/index.ts @@ -28,7 +28,7 @@ import { tap } from "rxjs/operators" -import { Container } from "../../container" +import { Main } from "../../main" import { resetHeaderShadow, setHeaderShadow @@ -87,7 +87,7 @@ export function watchHeader( */ export function paintHeaderShadow( el: HTMLElement -): MonoTypeOperatorFunction { +): MonoTypeOperatorFunction
{ return pipe( distinctUntilKeyChanged("active"), tap(({ active }) => { diff --git a/src/assets/javascripts/component/index.ts b/src/assets/javascripts/component/index.ts index c7225272c..8ab75bae6 100644 --- a/src/assets/javascripts/component/index.ts +++ b/src/assets/javascripts/component/index.ts @@ -22,7 +22,7 @@ export * from "./_" export * from "./anchor" -export * from "./container" export * from "./header" +export * from "./main" export * from "./navigation" export * from "./sidebar" diff --git a/src/assets/javascripts/component/container/index.ts b/src/assets/javascripts/component/main/index.ts similarity index 84% rename from src/assets/javascripts/component/container/index.ts rename to src/assets/javascripts/component/main/index.ts index 4ae167ee5..6d3407427 100644 --- a/src/assets/javascripts/component/container/index.ts +++ b/src/assets/javascripts/component/main/index.ts @@ -36,11 +36,11 @@ import { Header } from "../header" * ------------------------------------------------------------------------- */ /** - * Container + * Main area */ -export interface Container { - offset: number /* Container top offset */ - height: number /* Container visible height */ +export interface Main { + offset: number /* Main area top offset */ + height: number /* Main area visible height */ active: boolean /* Scrolled past top offset */ } @@ -62,19 +62,16 @@ interface WatchOptions { * ------------------------------------------------------------------------- */ /** - * Create an observable to watch the container + * Create an observable to watch the main area * - * The container represents the main content area including the sidebars (table - * of contents and navigation), as well as the actual page content. - * - * @param el - Container element + * @param el - Main area element * @param options - Options * - * @return Container observable + * @return Main area observable */ -export function watchContainer( +export function watchMain( el: HTMLElement, { size$, offset$, header$ }: WatchOptions -): Observable { +): Observable
{ /* Compute necessary adjustment for header */ const adjust$ = header$ @@ -82,7 +79,7 @@ export function watchContainer( pluck("height") ) - /* Compute the container's visible height */ + /* Compute the main area's visible height */ const height$ = combineLatest(offset$, size$, adjust$) .pipe( map(([{ y }, { height }, adjust]) => { @@ -95,7 +92,7 @@ export function watchContainer( distinctUntilChanged() ) - /* Compute whether the viewport offset is past the container's top */ + /* Compute whether the viewport offset is past the main area's top */ const active$ = combineLatest(offset$, adjust$) .pipe( map(([{ y }, adjust]) => y >= el.offsetTop - adjust), diff --git a/src/assets/javascripts/component/sidebar/_/index.ts b/src/assets/javascripts/component/sidebar/_/index.ts index d8df809de..f02e712d1 100644 --- a/src/assets/javascripts/component/sidebar/_/index.ts +++ b/src/assets/javascripts/component/sidebar/_/index.ts @@ -38,7 +38,7 @@ import { } from "rxjs/operators" import { ViewportOffset } from "../../../ui" -import { Container } from "../../container" +import { Main } from "../../main" import { resetSidebarHeight, resetSidebarLock, @@ -67,7 +67,7 @@ export interface Sidebar { */ interface WatchOptions { offset$: Observable /* Viewport offset observable */ - container$: Observable /* Container observable */ + main$: Observable
/* Main area observable */ } /* ---------------------------------------------------------------------------- @@ -83,17 +83,17 @@ interface WatchOptions { * @return Sidebar observable */ export function watchSidebar( - el: HTMLElement, { offset$, container$ }: WatchOptions + el: HTMLElement, { offset$, main$ }: WatchOptions ): Observable { - /* Adjust for internal container offset */ + /* Adjust for internal main area offset */ const adjust = parseFloat( getComputedStyle(el.parentElement!) .getPropertyValue("padding-top") ) /* Compute the sidebar's available height */ - const height$ = combineLatest(offset$, container$) + const height$ = combineLatest(offset$, main$) .pipe( map(([{ y }, { offset, height }]) => { return height - adjust + Math.min(adjust, Math.max(0, y - offset)) @@ -101,7 +101,7 @@ export function watchSidebar( ) /* Compute whether the sidebar should be locked */ - const lock$ = combineLatest(offset$, container$) + const lock$ = combineLatest(offset$, main$) .pipe( map(([{ y }, { offset }]) => y >= offset + adjust) )