mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2024-06-14 11:52:32 +03:00
Refactored main and header observables
This commit is contained in:
parent
f4de690712
commit
ca27f23674
@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* 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 { keys } from "ramda"
|
||||
import { NEVER, Observable, OperatorFunction, of, pipe } from "rxjs"
|
||||
import { map, scan, shareReplay, switchMap } from "rxjs/operators"
|
||||
|
||||
import { getElement } from "observables"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Component names
|
||||
*/
|
||||
export type Component =
|
||||
| "container" /* Container */
|
||||
| "header" /* Header */
|
||||
| "header-title" /* Header title */
|
||||
| "hero" /* Hero */
|
||||
| "main" /* Main area */
|
||||
| "navigation" /* Navigation */
|
||||
| "search" /* Search */
|
||||
| "search-query" /* Search input */
|
||||
| "search-reset" /* Search reset */
|
||||
| "search-result" /* Search results */
|
||||
| "tabs" /* Tabs */
|
||||
| "toc" /* Table of contents */
|
||||
|
||||
/**
|
||||
* Component map
|
||||
*/
|
||||
export type ComponentMap = {
|
||||
[P in Component]?: HTMLElement
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Helper types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Options
|
||||
*/
|
||||
interface Options {
|
||||
document$: Observable<Document> /* Document observable */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Watch component mapping
|
||||
*
|
||||
* This function returns an observable that will maintain bindings to the given
|
||||
* components in-between document switches and update the document in-place.
|
||||
*
|
||||
* @param names - Component names
|
||||
* @param options - Options
|
||||
*
|
||||
* @return Component mapping observable
|
||||
*/
|
||||
export function watchComponentMap(
|
||||
names: Component[], { document$ }: Options
|
||||
): Observable<ComponentMap> {
|
||||
const components$ = document$
|
||||
.pipe(
|
||||
|
||||
/* Build component map */
|
||||
map(document => names.reduce<ComponentMap>((components, name) => {
|
||||
const el = getElement(`[data-md-component=${name}]`, document)
|
||||
return {
|
||||
...components,
|
||||
...typeof el !== "undefined" ? { [name]: el } : {}
|
||||
}
|
||||
}, {})),
|
||||
|
||||
/* Re-compute component map on document switch */
|
||||
scan((prev, next) => {
|
||||
for (const name of keys(prev)) {
|
||||
switch (name) {
|
||||
|
||||
/* Top-level components: update */
|
||||
case "header-title":
|
||||
case "container":
|
||||
if (name in prev && typeof prev[name] !== "undefined") {
|
||||
prev[name]!.replaceWith(next[name]!)
|
||||
prev[name] = next[name]
|
||||
}
|
||||
break
|
||||
|
||||
/* All other components: rebind */
|
||||
default:
|
||||
prev[name] = getElement(`[data-md-component=${name}]`)
|
||||
}
|
||||
}
|
||||
return prev
|
||||
})
|
||||
)
|
||||
|
||||
/* Return component map as hot observable */
|
||||
return components$
|
||||
.pipe(
|
||||
shareReplay(1)
|
||||
)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Switch to component
|
||||
*
|
||||
* @template T - Element type
|
||||
*
|
||||
* @param name - Component name
|
||||
*
|
||||
* @return Operator function
|
||||
*/
|
||||
export function switchComponent<T extends HTMLElement>(
|
||||
name: Component
|
||||
): OperatorFunction<ComponentMap, T> {
|
||||
return pipe(
|
||||
switchMap(components => {
|
||||
return typeof components[name] !== "undefined"
|
||||
? of(components[name] as T)
|
||||
: NEVER
|
||||
})
|
||||
)
|
||||
}
|
@ -21,4 +21,5 @@
|
||||
*/
|
||||
|
||||
export * from "./_"
|
||||
export * from "./main"
|
||||
export * from "./search"
|
||||
|
74
src/assets/javascripts/components2/main/index.ts
Normal file
74
src/assets/javascripts/components2/main/index.ts
Normal file
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2016-2020 Martin Donath <martin.donath@squidfunk.com>
|
||||
*
|
||||
* 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, OperatorFunction, pipe } from "rxjs"
|
||||
import { shareReplay, switchMap } from "rxjs/operators"
|
||||
|
||||
import {
|
||||
Header,
|
||||
Main,
|
||||
Viewport,
|
||||
paintHeaderShadow,
|
||||
watchMain
|
||||
} from "observables"
|
||||
|
||||
import { useComponent } from "../_"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Helper types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Mount options
|
||||
*/
|
||||
interface MountOptions {
|
||||
header$: Observable<Header> /* Header observable */
|
||||
viewport$: Observable<Viewport> /* Viewport observable */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Mount main area from source observable
|
||||
*
|
||||
* @param options - Options
|
||||
*
|
||||
* @return Main area observable
|
||||
*/
|
||||
export function mountMain(
|
||||
{ header$, viewport$ }: MountOptions
|
||||
): OperatorFunction<HTMLElement, Main> {
|
||||
return pipe(
|
||||
switchMap(el => useComponent("header")
|
||||
.pipe(
|
||||
switchMap(header => watchMain(el, { header$, viewport$ })
|
||||
.pipe(
|
||||
paintHeaderShadow(header)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
shareReplay(1)
|
||||
)
|
||||
}
|
@ -1,128 +0,0 @@
|
||||
// /*
|
||||
// * Copyright (c) 2016-2020 Martin Donath <martin.donath@squidfunk.com>
|
||||
// *
|
||||
// * 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, OperatorFunction, combineLatest, pipe } from "rxjs"
|
||||
// import { map, shareReplay, switchMap } from "rxjs/operators"
|
||||
|
||||
// import { switchMapIf } from "extensions"
|
||||
// import { Agent, getElements } from "utilities"
|
||||
|
||||
// import { HeaderState } from "../../header"
|
||||
// import {
|
||||
// MainState,
|
||||
// SidebarState,
|
||||
// paintSidebar,
|
||||
// watchSidebar
|
||||
// } from "../../main"
|
||||
// import {
|
||||
// AnchorList,
|
||||
// paintAnchorList,
|
||||
// watchAnchorList
|
||||
// } from "../anchor"
|
||||
|
||||
// /* ----------------------------------------------------------------------------
|
||||
// * Types
|
||||
// * ------------------------------------------------------------------------- */
|
||||
|
||||
// /**
|
||||
// * Table of contents
|
||||
// */
|
||||
// export interface TableOfContents {
|
||||
// sidebar: SidebarState /* Sidebar state */
|
||||
// anchors: AnchorList /* Anchor list */
|
||||
// }
|
||||
|
||||
// /* ----------------------------------------------------------------------------
|
||||
// * Helper types
|
||||
// * ------------------------------------------------------------------------- */
|
||||
|
||||
// /**
|
||||
// * Options
|
||||
// */
|
||||
// interface Options {
|
||||
// header$: Observable<Header> /* Header observable */
|
||||
// main$: Observable<Main> /* Main area observable */
|
||||
// }
|
||||
|
||||
// /* ----------------------------------------------------------------------------
|
||||
// * Functions
|
||||
// * ------------------------------------------------------------------------- */
|
||||
|
||||
// /**
|
||||
// * Watch table of contents
|
||||
// *
|
||||
// * @param el - Table of contents element
|
||||
// * @param agent - Agent
|
||||
// * @param options - Options
|
||||
// *
|
||||
// * @return Table of contents observable
|
||||
// */
|
||||
// export function watchTableOfContents(
|
||||
// el: HTMLElement, agent: Agent, { header$, main$ }: Options
|
||||
// ): Observable<TableOfContents> {
|
||||
|
||||
// /* Watch and paint sidebar */
|
||||
// const sidebar$ = watchSidebar(el, agent, { main$ })
|
||||
// .pipe(
|
||||
// paintSidebar(el)
|
||||
// )
|
||||
|
||||
// /* Watch and paint anchor list (scroll spy) */
|
||||
// const els = getElements<HTMLAnchorElement>(".md-nav__link", el)
|
||||
// const anchors$ = watchAnchorList(els, agent, { header$ })
|
||||
// .pipe(
|
||||
// paintAnchorList(els)
|
||||
// )
|
||||
|
||||
// /* Combine into a single hot observable */
|
||||
// return combineLatest([sidebar$, anchors$])
|
||||
// .pipe(
|
||||
// map(([sidebar, anchors]) => ({ sidebar, anchors }))
|
||||
// )
|
||||
// }
|
||||
|
||||
// /* ------------------------------------------------------------------------- */
|
||||
|
||||
// /**
|
||||
// * Mount table of contents from source observable
|
||||
// *
|
||||
// * @param agent - Agent
|
||||
// * @param options - Options
|
||||
// *
|
||||
// * @return Operator function
|
||||
// */
|
||||
// export function mountTableOfContents(
|
||||
// agent: Agent, options: Options
|
||||
// ): OperatorFunction<HTMLElement, TableOfContents> {
|
||||
// const { media } = agent
|
||||
// return pipe(
|
||||
// switchMap(el => media.tablet$
|
||||
// .pipe(
|
||||
// switchMap(tablet => {
|
||||
// return watchTableOfContents(el, agent, options)
|
||||
// })
|
||||
// )
|
||||
// ),
|
||||
// switchMapIf(media.tablet$, el => watchTableOfContents(el, agent, options)),
|
||||
// shareReplay(1)
|
||||
// )
|
||||
// }
|
@ -46,44 +46,42 @@ import {
|
||||
switchMapTo,
|
||||
tap,
|
||||
distinctUntilKeyChanged,
|
||||
shareReplay
|
||||
shareReplay,
|
||||
withLatestFrom
|
||||
} from "rxjs/operators"
|
||||
|
||||
import {
|
||||
Component,
|
||||
paintHeaderShadow,
|
||||
mountHero,
|
||||
mountTableOfContents,
|
||||
mountTabs,
|
||||
switchComponent,
|
||||
watchComponentMap,
|
||||
} from "./components"
|
||||
import {
|
||||
watchHeader,
|
||||
watchSearchQuery,
|
||||
watchSearchReset,
|
||||
getElement,
|
||||
watchToggle,
|
||||
setToggle,
|
||||
getElements,
|
||||
watchMedia,
|
||||
watchDocument,
|
||||
watchLocationHash,
|
||||
watchMain,
|
||||
watchViewport,
|
||||
watchKeyboard
|
||||
watchKeyboard,
|
||||
watchToggleMap,
|
||||
useToggle
|
||||
} from "./observables"
|
||||
import {
|
||||
isSearchResultMessage,
|
||||
setupSearchWorker
|
||||
} from "./workers"
|
||||
import { setupSearchWorker } from "./workers"
|
||||
import { renderSource } from "templates"
|
||||
import { not, takeIf } from "utilities"
|
||||
import { renderClipboard } from "templates/clipboard"
|
||||
import { fetchGitHubStats } from "modules/source/github"
|
||||
import { mountNavigation } from "components2/navigation"
|
||||
import { mountSearchResult } from "components2/search"
|
||||
import { watchComponentMap, useComponent } from "components2/_"
|
||||
import { renderTable } from "templates/table"
|
||||
import { setToggle } from "actions"
|
||||
import {
|
||||
Component,
|
||||
mountMain,
|
||||
mountSearch
|
||||
} from "components2"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
@ -111,6 +109,7 @@ document.documentElement.classList.add("js")
|
||||
if (navigator.userAgent.match(/(iPad|iPhone|iPod)/g))
|
||||
document.documentElement.classList.add("ios")
|
||||
|
||||
// add to config? default components to mount...?
|
||||
const names: Component[] = [
|
||||
"container", /* Container */
|
||||
"header", /* Header */
|
||||
@ -163,11 +162,14 @@ function repository() {
|
||||
return of(x)
|
||||
}
|
||||
|
||||
// TODO: do correct rounding, see GitHub
|
||||
// TODO: do correct rounding, see GitHub - done
|
||||
function format(value: number) {
|
||||
return value > 999
|
||||
? `${(value / 1000).toFixed(1)}k`
|
||||
: `${(value)}`
|
||||
if (value > 999) {
|
||||
const digits = +((value - 950) % 1000 > 99)
|
||||
return `${(++value / 1000).toFixed(digits)}k`
|
||||
} else {
|
||||
return value.toString()
|
||||
}
|
||||
}
|
||||
|
||||
// github repository...
|
||||
@ -234,126 +236,63 @@ export function initialize(config: unknown) {
|
||||
const viewport$ = watchViewport()
|
||||
const screen$ = watchMedia("(min-width: 960px)")
|
||||
const tablet$ = watchMedia("(min-width: 1220px)")
|
||||
const key$ = watchKeyboard()
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* Create component map observable */
|
||||
const components$ = watchComponentMap(names, { document$ })
|
||||
const component = <T extends HTMLElement>(name: Component): Observable<T> => {
|
||||
return components$
|
||||
.pipe(
|
||||
switchComponent<T>(name)
|
||||
)
|
||||
}
|
||||
watchComponentMap(names, { document$ })
|
||||
watchToggleMap(["drawer", "search"], { document$ })
|
||||
|
||||
/* Create header observable */
|
||||
const header$ = component("header") // TODO:!
|
||||
const header$ = useComponent("header")
|
||||
.pipe(
|
||||
switchMap(watchHeader)
|
||||
switchMap(watchHeader) // TODO: should also be the mount...
|
||||
)
|
||||
|
||||
/* Create header shadow toggle */
|
||||
component("header")
|
||||
const main$ = useComponent("main")
|
||||
.pipe(
|
||||
switchMap(el => main$
|
||||
.pipe(
|
||||
paintHeaderShadow(el) // technically, this could be done in paintMain
|
||||
mountMain({ header$, viewport$ }),
|
||||
)
|
||||
)
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
// DONE
|
||||
const main$ = component("main")
|
||||
.pipe(
|
||||
switchMap(el => watchMain(el, { header$, viewport$ })),
|
||||
shareReplay(1) // TODO: mount!?
|
||||
)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
const drawer = getElement<HTMLInputElement>("[data-md-toggle=drawer]")!
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
// build a single search observable???
|
||||
|
||||
const query$ = component<HTMLInputElement>("search-query")
|
||||
.pipe(
|
||||
switchMap(el => watchSearchQuery(el))
|
||||
)
|
||||
|
||||
const sw = setupSearchWorker(config.worker.search, {
|
||||
base: config.base,
|
||||
query$
|
||||
base: config.base
|
||||
})
|
||||
|
||||
const result$ = sw.rx$ // move worker initialization into mountSearch ?
|
||||
const search$ = useComponent("search")
|
||||
.pipe(
|
||||
filter(isSearchResultMessage),
|
||||
pluck("data")
|
||||
)
|
||||
|
||||
const search = getElement<HTMLInputElement>("[data-md-toggle=search]")!
|
||||
const searchActive$ = watchToggle(search)
|
||||
.pipe(
|
||||
delay(400)
|
||||
)
|
||||
|
||||
query$
|
||||
.pipe(
|
||||
distinctUntilKeyChanged("focus"),
|
||||
tap(query => {
|
||||
if (query.focus)
|
||||
setToggle(search, query.focus) // paintSearchQuery?
|
||||
// console.log(query)
|
||||
})
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
// implement toggle function that returns the toggles as observable...
|
||||
const reset$ = component("search-reset")
|
||||
.pipe(
|
||||
switchMap(watchSearchReset)
|
||||
mountSearch(sw, { viewport$ }),
|
||||
)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
// DONE (partly)
|
||||
const navigation$ = component("navigation")
|
||||
const navigation$ = useComponent("navigation")
|
||||
.pipe(
|
||||
mountNavigation({ main$, viewport$, screen$ })
|
||||
)
|
||||
|
||||
const toc$ = component("toc")
|
||||
const toc$ = useComponent("toc")
|
||||
.pipe(
|
||||
mountTableOfContents({ header$, main$, viewport$, tablet$ })
|
||||
)
|
||||
|
||||
// TODO: naming?
|
||||
const resultComponent$ = component("search-result")
|
||||
.pipe(
|
||||
mountSearchResult({ viewport$, result$, query$: query$.pipe(
|
||||
distinctUntilKeyChanged("value"),
|
||||
) })
|
||||
) // temporary fix
|
||||
|
||||
// mount hideable...
|
||||
|
||||
const tabs$ = component("tabs")
|
||||
const tabs$ = useComponent("tabs")
|
||||
.pipe(
|
||||
mountTabs({ header$, viewport$, screen$ })
|
||||
)
|
||||
|
||||
const hero$ = component("hero")
|
||||
const hero$ = useComponent("hero")
|
||||
.pipe(
|
||||
mountHero({ header$, viewport$, screen$ })
|
||||
)
|
||||
|
||||
// function watchKeyboard
|
||||
const key$ = watchKeyboard()
|
||||
const search = getElement<HTMLInputElement>("[data-md-toggle=search]")!
|
||||
const searchActive$ = useToggle("search").pipe(
|
||||
switchMap(el => watchToggle(el)),
|
||||
delay(400)
|
||||
)
|
||||
|
||||
// shortcodes
|
||||
key$
|
||||
@ -420,16 +359,6 @@ export function initialize(config: unknown) {
|
||||
// TODO: close search on hashchange
|
||||
// anchor jump -> always close drawer + search
|
||||
|
||||
// focus search on reset, on toggle and on keypress if open
|
||||
merge(searchActive$.pipe(filter(identity)), reset$)
|
||||
.pipe(
|
||||
switchMapTo(component<HTMLInputElement>("search-query")),
|
||||
tap(el => el.focus()) // TODO: only if element isnt focused! setFocus? setToggle?
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
// focusable -> setFocus(true, false)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* Open details before printing */
|
||||
@ -446,8 +375,14 @@ export function initialize(config: unknown) {
|
||||
|
||||
// Close drawer and search on hash change
|
||||
hash$.subscribe(() => {
|
||||
setToggle(drawer, false)
|
||||
setToggle(search, false) // we probably need to delay the anchor jump for search
|
||||
|
||||
useToggle("drawer").subscribe(el => {
|
||||
setToggle(el, false)
|
||||
})
|
||||
|
||||
useToggle("search").subscribe(el => { // omit nested subscribes...
|
||||
setToggle(el, false)
|
||||
})
|
||||
})
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
@ -547,16 +482,12 @@ export function initialize(config: unknown) {
|
||||
// )
|
||||
// .subscribe()
|
||||
|
||||
// // toiggle
|
||||
// // toggle
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
const state = {
|
||||
search: {
|
||||
query$,
|
||||
result$: resultComponent$,
|
||||
reset$,
|
||||
},
|
||||
search$,
|
||||
main$,
|
||||
navigation$,
|
||||
toc$,
|
||||
@ -564,8 +495,8 @@ export function initialize(config: unknown) {
|
||||
hero$
|
||||
}
|
||||
|
||||
const { search: temp, ...rest } = state
|
||||
merge(...values(rest), ...values(temp))
|
||||
const { ...rest } = state
|
||||
merge(...values(rest))
|
||||
.subscribe() // potential memleak <-- use takeUntil
|
||||
|
||||
return {
|
||||
@ -573,11 +504,3 @@ export function initialize(config: unknown) {
|
||||
state
|
||||
}
|
||||
}
|
||||
|
||||
// function mountSearchQuery(
|
||||
|
||||
// ): OperatorFunction<HTMLInputElement, SearchQuery> {
|
||||
// return pipe(
|
||||
// switchMap(el => watchSearchQuery(el))
|
||||
// )
|
||||
// }
|
||||
|
@ -20,4 +20,41 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export * from "./shadow"
|
||||
import { Observable, of } from "rxjs"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Header
|
||||
*/
|
||||
export interface Header {
|
||||
sticky: boolean /* Header stickyness */
|
||||
height: number /* Header visible height */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Watch header
|
||||
*
|
||||
* The header is wrapped in an observable to pave the way for auto-hiding or
|
||||
* other dynamic behaviors that may be implemented later on.
|
||||
*
|
||||
* @param el - Header element
|
||||
*
|
||||
* @return Header observable
|
||||
*/
|
||||
export function watchHeader(
|
||||
el: HTMLElement
|
||||
): Observable<Header> {
|
||||
const styles = getComputedStyle(el)
|
||||
const sticky = styles.position === "sticky"
|
||||
return of({
|
||||
sticky,
|
||||
height: sticky ? el.offsetHeight : 0
|
||||
})
|
||||
}
|
@ -20,41 +20,5 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Observable, of } from "rxjs"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Header
|
||||
*/
|
||||
export interface Header {
|
||||
sticky: boolean /* Header stickyness */
|
||||
height: number /* Header visible height */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Watch header
|
||||
*
|
||||
* The header is wrapped in an observable to pave the way for auto-hiding or
|
||||
* other dynamic behaviors that may be implemented later on.
|
||||
*
|
||||
* @param el - Header element
|
||||
*
|
||||
* @return Header observable
|
||||
*/
|
||||
export function watchHeader(
|
||||
el: HTMLElement
|
||||
): Observable<Header> {
|
||||
const styles = getComputedStyle(el)
|
||||
const sticky = styles.position === "sticky"
|
||||
return of({
|
||||
sticky,
|
||||
height: sticky ? el.offsetHeight : 0
|
||||
})
|
||||
}
|
||||
export * from "./_"
|
||||
export * from "./shadow"
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
|
||||
import { resetHeaderShadow, setHeaderShadow } from "actions"
|
||||
|
||||
import { MainState } from "../../main"
|
||||
import { Main } from "../../main"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
@ -49,7 +49,7 @@ import { MainState } from "../../main"
|
||||
*/
|
||||
export function paintHeaderShadow(
|
||||
el: HTMLElement
|
||||
): MonoTypeOperatorFunction<MainState> {
|
||||
): MonoTypeOperatorFunction<Main> {
|
||||
return pipe(
|
||||
distinctUntilKeyChanged("active"),
|
||||
|
@ -94,7 +94,7 @@ export function watchSearchQuery(
|
||||
const value$ = fromEvent(el, "keyup")
|
||||
.pipe(
|
||||
map(() => transform(el.value)),
|
||||
startWith(el.value),
|
||||
startWith(transform(el.value)),
|
||||
distinctUntilChanged()
|
||||
)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user