mirror of
https://github.com/squidfunk/mkdocs-material.git
synced 2024-06-14 11:52:32 +03:00
Improved overall structure
This commit is contained in:
parent
9b0410962d
commit
3aa251fb03
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
24
material/assets/javascripts/bundle.4cda9c77.min.js
vendored
Normal file
24
material/assets/javascripts/bundle.4cda9c77.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
material/assets/javascripts/bundle.4cda9c77.min.js.map
Normal file
1
material/assets/javascripts/bundle.4cda9c77.min.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,6 @@
|
||||
{
|
||||
"assets/javascripts/bundle.js": "assets/javascripts/bundle.02fd1bf7.min.js",
|
||||
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.02fd1bf7.min.js.map",
|
||||
"assets/javascripts/bundle.js": "assets/javascripts/bundle.4cda9c77.min.js",
|
||||
"assets/javascripts/bundle.js.map": "assets/javascripts/bundle.4cda9c77.min.js.map",
|
||||
"assets/javascripts/worker/search.js": "assets/javascripts/worker/search.926ffd9e.min.js",
|
||||
"assets/javascripts/worker/search.js.map": "assets/javascripts/worker/search.926ffd9e.min.js.map",
|
||||
"assets/stylesheets/app-palette.scss": "assets/stylesheets/app-palette.3f90c815.min.css",
|
||||
|
@ -190,7 +190,7 @@
|
||||
{% endblock %}
|
||||
</div>
|
||||
{% block scripts %}
|
||||
<script src="{{ 'assets/javascripts/bundle.02fd1bf7.min.js' | url }}"></script>
|
||||
<script src="{{ 'assets/javascripts/bundle.4cda9c77.min.js' | url }}"></script>
|
||||
<script id="__lang" type="application/json">
|
||||
{%- set translations = {} -%}
|
||||
{%- for key in [
|
||||
|
@ -20,9 +20,9 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { NEVER, Observable, OperatorFunction, pipe } from "rxjs"
|
||||
import { Observable, OperatorFunction, pipe } from "rxjs"
|
||||
import {
|
||||
catchError,
|
||||
filter,
|
||||
map,
|
||||
shareReplay,
|
||||
switchMap
|
||||
@ -31,7 +31,7 @@ import {
|
||||
import {
|
||||
Header,
|
||||
Viewport,
|
||||
getElementOrThrow,
|
||||
getElement,
|
||||
paintHeaderTitle,
|
||||
watchViewportAt
|
||||
} from "observables"
|
||||
@ -67,15 +67,15 @@ export function mountHeaderTitle(
|
||||
return pipe(
|
||||
switchMap(el => useComponent("main")
|
||||
.pipe(
|
||||
map(main => getElementOrThrow("h1, h2, h3, h4, h5, h6", main)),
|
||||
switchMap(headline => watchViewportAt(headline, { header$, viewport$ })
|
||||
map(main => getElement("h1, h2, h3, h4, h5, h6", main)!),
|
||||
filter(hx => typeof hx !== "undefined"),
|
||||
switchMap(hx => watchViewportAt(hx, { header$, viewport$ })
|
||||
.pipe(
|
||||
map(({ offset: { y } }) => y >= headline.offsetHeight),
|
||||
map(({ offset: { y } }) => y >= hx.offsetHeight),
|
||||
paintHeaderTitle(el)
|
||||
)
|
||||
),
|
||||
shareReplay(1),
|
||||
catchError(() => NEVER)
|
||||
shareReplay(1)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
@ -20,17 +20,11 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { OperatorFunction, combineLatest, pipe } from "rxjs"
|
||||
import { Observable, OperatorFunction, combineLatest, pipe } from "rxjs"
|
||||
import { map, shareReplay, switchMap } from "rxjs/operators"
|
||||
|
||||
import { SearchResult } from "integrations/search"
|
||||
import { SearchQuery, WorkerHandler } from "observables"
|
||||
import { SearchMessage } from "workers"
|
||||
|
||||
import { useComponent } from "../../_"
|
||||
import { mountSearchQuery } from "../query"
|
||||
import { mountSearchReset } from "../reset"
|
||||
import { mountSearchResult } from "../result"
|
||||
import { SearchQuery } from "observables"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
@ -44,6 +38,19 @@ export interface Search {
|
||||
result: SearchResult[] /* Search result list */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Helper types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Mount options
|
||||
*/
|
||||
interface MountOptions {
|
||||
query$: Observable<SearchQuery> /* Search query observable */
|
||||
reset$: Observable<void> /* Search reset observable */
|
||||
result$: Observable<SearchResult[]> /* Search result observable */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
@ -51,42 +58,18 @@ export interface Search {
|
||||
/**
|
||||
* Mount search from source observable
|
||||
*
|
||||
* @param handler - Worker handler
|
||||
* @param options - Options
|
||||
*
|
||||
* @return Search observable
|
||||
*/
|
||||
export function mountSearch(
|
||||
handler: WorkerHandler<SearchMessage>
|
||||
{ query$, reset$, result$ }: MountOptions
|
||||
): OperatorFunction<HTMLElement, Search> {
|
||||
return pipe(
|
||||
switchMap(() => {
|
||||
|
||||
/* Mount search query */
|
||||
const query$ = useComponent<HTMLInputElement>("search-query")
|
||||
.pipe(
|
||||
mountSearchQuery(handler),
|
||||
shareReplay(1)
|
||||
)
|
||||
|
||||
/* Mount search reset */
|
||||
const reset$ = useComponent("search-reset")
|
||||
.pipe(
|
||||
mountSearchReset()
|
||||
)
|
||||
|
||||
/* Mount search result */
|
||||
const result$ = useComponent("search-result")
|
||||
.pipe(
|
||||
mountSearchResult(handler, { query$ })
|
||||
)
|
||||
|
||||
/* Combine into a single hot observable */
|
||||
return combineLatest([query$, result$, reset$])
|
||||
switchMap(() => combineLatest([query$, result$, reset$])
|
||||
.pipe(
|
||||
map(([query, result]) => ({ query, result })),
|
||||
shareReplay(1)
|
||||
)
|
||||
})
|
||||
))
|
||||
)
|
||||
}
|
||||
|
@ -41,6 +41,17 @@ import {
|
||||
SearchQueryMessage
|
||||
} from "workers"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Helper types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Mount options
|
||||
*/
|
||||
interface MountOptions {
|
||||
transform?(value: string): string /* Transformation function */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
* ------------------------------------------------------------------------- */
|
||||
@ -49,16 +60,17 @@ import {
|
||||
* Mount search query from source observable
|
||||
*
|
||||
* @param handler - Worker handler
|
||||
* @param options - Options
|
||||
*
|
||||
* @return Operator function
|
||||
*/
|
||||
export function mountSearchQuery(
|
||||
{ tx$ }: WorkerHandler<SearchMessage>
|
||||
{ tx$ }: WorkerHandler<SearchMessage>, options: MountOptions = {}
|
||||
): OperatorFunction<HTMLInputElement, SearchQuery> {
|
||||
const toggle$ = useToggle("search")
|
||||
return pipe(
|
||||
switchMap(el => {
|
||||
const query$ = watchSearchQuery(el)
|
||||
const query$ = watchSearchQuery(el, options)
|
||||
|
||||
/* Subscribe worker to search query */
|
||||
query$
|
||||
|
@ -29,7 +29,6 @@ import "../stylesheets/app-palette.scss"
|
||||
import { values } from "ramda"
|
||||
import {
|
||||
merge,
|
||||
of,
|
||||
combineLatest,
|
||||
animationFrameScheduler
|
||||
} from "rxjs"
|
||||
@ -40,7 +39,9 @@ import {
|
||||
filter,
|
||||
withLatestFrom,
|
||||
observeOn,
|
||||
take
|
||||
take,
|
||||
mapTo,
|
||||
shareReplay
|
||||
} from "rxjs/operators"
|
||||
|
||||
import {
|
||||
@ -52,9 +53,9 @@ import {
|
||||
watchLocation,
|
||||
watchLocationHash,
|
||||
watchViewport,
|
||||
watchKeyboard,
|
||||
watchToggleMap,
|
||||
useToggle
|
||||
useToggle,
|
||||
getElement
|
||||
} from "./observables"
|
||||
import { setupSearchWorker } from "./workers"
|
||||
|
||||
@ -69,7 +70,10 @@ import {
|
||||
mountTabs,
|
||||
useComponent,
|
||||
watchComponentMap,
|
||||
mountHeaderTitle
|
||||
mountHeaderTitle,
|
||||
mountSearchQuery,
|
||||
mountSearchReset,
|
||||
mountSearchResult
|
||||
} from "components"
|
||||
import { setupClipboard } from "./integrations/clipboard"
|
||||
import { setupKeyboard } from "./integrations/keyboard"
|
||||
@ -80,7 +84,7 @@ import {
|
||||
patchSource
|
||||
} from "patches"
|
||||
import { isConfig } from "utilities"
|
||||
import { renderDialog } from "templates/dialog"
|
||||
import { setupDialog } from "integrations/dialog"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@ -153,11 +157,34 @@ export function initialize(config: unknown) {
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
/* Mount search query */
|
||||
const query$ = useComponent<HTMLInputElement>("search-query")
|
||||
.pipe(
|
||||
mountSearchQuery(worker),
|
||||
shareReplay(1) // TODO: this must be put onto EVERY component!
|
||||
)
|
||||
|
||||
/* Mount search reset */
|
||||
const reset$ = useComponent("search-reset")
|
||||
.pipe(
|
||||
mountSearchReset()
|
||||
)
|
||||
|
||||
/* Mount search result */
|
||||
const result$ = useComponent("search-result")
|
||||
.pipe(
|
||||
mountSearchResult(worker, { query$ })
|
||||
)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
const search$ = useComponent("search")
|
||||
.pipe(
|
||||
mountSearch(worker)
|
||||
mountSearch({ query$, reset$, result$ })
|
||||
)
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
const navigation$ = useComponent("navigation")
|
||||
.pipe(
|
||||
mountNavigation({ header$, main$, viewport$, screen$ })
|
||||
@ -178,7 +205,6 @@ export function initialize(config: unknown) {
|
||||
mountHero({ header$, viewport$ })
|
||||
)
|
||||
|
||||
// TODO: make this part of mountHeader!?
|
||||
const title$ = useComponent("header-title")
|
||||
.pipe(
|
||||
mountHeaderTitle({ header$, viewport$ })
|
||||
@ -196,57 +222,38 @@ export function initialize(config: unknown) {
|
||||
if (navigator.userAgent.match(/(iPad|iPhone|iPod)/g))
|
||||
patchScrollfix({ document$ })
|
||||
|
||||
// snackbar for copy to clipboard
|
||||
const dialog = renderDialog("Copied to Clipboard")
|
||||
setupClipboard({ document$ })
|
||||
.pipe(
|
||||
switchMap(ev => {
|
||||
ev.clearSelection()
|
||||
return useComponent("container")
|
||||
.pipe(
|
||||
tap(el => el.appendChild(dialog)), // only set text on dialog... render once...
|
||||
observeOn(animationFrameScheduler),
|
||||
tap(() => dialog.dataset.mdState = "open"),
|
||||
delay(2000),
|
||||
tap(() => dialog.dataset.mdState = ""),
|
||||
delay(400),
|
||||
tap(() => dialog.remove())
|
||||
)
|
||||
})
|
||||
)
|
||||
.subscribe()
|
||||
/* Setup clipboard and dialog */
|
||||
const dialog$ = setupDialog()
|
||||
const clipboard$ = setupClipboard({ document$, dialog$ })
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
// Close drawer and search on hash change
|
||||
// put into navigation...
|
||||
hash$.subscribe(x => {
|
||||
|
||||
useToggle("drawer").subscribe(el => {
|
||||
setToggle(el, false)
|
||||
})
|
||||
})
|
||||
|
||||
// TODO:
|
||||
// put into search...
|
||||
hash$
|
||||
.pipe(
|
||||
switchMap(hash => {
|
||||
|
||||
return useToggle("search")
|
||||
switchMap(hash => useToggle("search")
|
||||
.pipe(
|
||||
filter(x => x.checked), // only active
|
||||
tap(toggle => setToggle(toggle, false)),
|
||||
delay(125), // ensure that it runs after the body scroll reset...
|
||||
tap(() => {
|
||||
location.hash = " "
|
||||
location.hash = hash
|
||||
}) // encapsulate this...
|
||||
mapTo(hash)
|
||||
)
|
||||
|
||||
)
|
||||
)
|
||||
.subscribe(hash => {
|
||||
getElement(hash)!.scrollIntoView()
|
||||
})
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
// Scroll lock
|
||||
// Scroll lock // document -> document$ => { body } !?
|
||||
// put into search...
|
||||
const toggle$ = useToggle("search")
|
||||
combineLatest([
|
||||
toggle$.pipe(switchMap(watchToggle)),
|
||||
@ -256,13 +263,13 @@ export function initialize(config: unknown) {
|
||||
withLatestFrom(viewport$),
|
||||
switchMap(([[toggle, tablet], { offset: { y }}]) => {
|
||||
const active = toggle && !tablet
|
||||
return of(document.body)
|
||||
return document$
|
||||
.pipe(
|
||||
delay(active ? 400 : 100),
|
||||
delay(active ? 400 : 100), // TOOD: directly combine this with the hash!
|
||||
observeOn(animationFrameScheduler),
|
||||
tap(el => active
|
||||
? setScrollLock(el, y)
|
||||
: resetScrollLock(el)
|
||||
tap(({ body }) => active
|
||||
? setScrollLock(body, y)
|
||||
: resetScrollLock(body)
|
||||
)
|
||||
)
|
||||
})
|
||||
@ -283,18 +290,21 @@ export function initialize(config: unknown) {
|
||||
link.style.visibility = "visible"
|
||||
})
|
||||
|
||||
// build a notification component! feed txt into it...
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
const state = {
|
||||
search$,
|
||||
clipboard$,
|
||||
location$,
|
||||
hash$,
|
||||
keyboard$,
|
||||
dialog$,
|
||||
main$,
|
||||
navigation$,
|
||||
toc$,
|
||||
tabs$,
|
||||
hero$,
|
||||
title$
|
||||
title$ // TODO: header title
|
||||
}
|
||||
|
||||
const { ...rest } = state
|
||||
|
@ -21,11 +21,12 @@
|
||||
*/
|
||||
|
||||
import * as ClipboardJS from "clipboard"
|
||||
import { NEVER, Observable, fromEventPattern } from "rxjs"
|
||||
import { shareReplay } from "rxjs/operators"
|
||||
import { NEVER, Observable, Subject, fromEventPattern } from "rxjs"
|
||||
import { mapTo, shareReplay, tap } from "rxjs/operators"
|
||||
|
||||
import { getElements } from "observables"
|
||||
import { renderClipboard } from "templates"
|
||||
import { translate } from "utilities"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Helper types
|
||||
@ -36,6 +37,7 @@ import { renderClipboard } from "templates"
|
||||
*/
|
||||
interface SetupOptions {
|
||||
document$: Observable<Document> /* Document observable */
|
||||
dialog$: Subject<string> /* Dialog subject */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
@ -53,7 +55,7 @@ interface SetupOptions {
|
||||
* @return Clipboard observable
|
||||
*/
|
||||
export function setupClipboard(
|
||||
{ document$ }: SetupOptions
|
||||
{ document$, dialog$ }: SetupOptions
|
||||
): Observable<ClipboardJS.Event> {
|
||||
if (!ClipboardJS.isSupported())
|
||||
return NEVER
|
||||
@ -74,9 +76,15 @@ export function setupClipboard(
|
||||
new ClipboardJS(".md-clipboard").on("success", next)
|
||||
})
|
||||
|
||||
// TODO: integrate rendering of dialog
|
||||
/* Display notification upon clipboard copy */
|
||||
clipboard$
|
||||
.pipe(
|
||||
tap(ev => ev.clearSelection()),
|
||||
mapTo(translate("clipboard.copied"))
|
||||
)
|
||||
.subscribe(dialog$)
|
||||
|
||||
/* */
|
||||
/* Return clipboard as hot observable */
|
||||
return clipboard$
|
||||
.pipe(
|
||||
shareReplay(1)
|
||||
|
@ -20,17 +20,26 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { h } from "utilities"
|
||||
import { Subject, animationFrameScheduler } from "rxjs"
|
||||
import {
|
||||
delay,
|
||||
map,
|
||||
observeOn,
|
||||
switchMap,
|
||||
tap
|
||||
} from "rxjs/operators"
|
||||
|
||||
import { useComponent } from "components"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Data
|
||||
* Types
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* CSS classes
|
||||
* Setup options
|
||||
*/
|
||||
const css = {
|
||||
container: "md-dialog md-typeset"
|
||||
interface SetupOptions {
|
||||
duration?: number /* Display duration (default: 2s) */
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
@ -38,18 +47,44 @@ const css = {
|
||||
* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Render a dismissable dialog
|
||||
* Setup dialog
|
||||
*
|
||||
* @param text - Dialog text
|
||||
* @param options - Options
|
||||
*
|
||||
* @return Element
|
||||
* @return Dialog observable
|
||||
*/
|
||||
export function renderDialog(
|
||||
text: string
|
||||
): HTMLElement {
|
||||
return (
|
||||
<div class={css.container}>
|
||||
{text}
|
||||
</div>
|
||||
export function setupDialog(
|
||||
{ duration }: SetupOptions = {}
|
||||
): Subject<string> {
|
||||
const dialog$ = new Subject<string>()
|
||||
|
||||
/* Create dialog */
|
||||
const dialog = document.createElement("div") // TODO: improve scoping
|
||||
dialog.classList.add("md-dialog", "md-typeset")
|
||||
|
||||
/* Display dialog */
|
||||
dialog$
|
||||
.pipe(
|
||||
switchMap(text => useComponent("container")
|
||||
.pipe(
|
||||
map(container => container.appendChild(dialog)),
|
||||
delay(1), // Strangley it doesnt work when we push things to the new animation frame...
|
||||
tap(el => {
|
||||
el.innerHTML = text
|
||||
el.setAttribute("data-md-state", "open")
|
||||
}),
|
||||
delay(duration || 2000),
|
||||
tap(el => el.removeAttribute("data-md-state")),
|
||||
delay(400),
|
||||
tap(el => {
|
||||
el.innerHTML = ""
|
||||
el.remove()
|
||||
})
|
||||
)
|
||||
)
|
||||
)
|
||||
.subscribe()
|
||||
|
||||
/* Return dialog subject */
|
||||
return dialog$
|
||||
}
|
@ -198,6 +198,6 @@ export function setupKeyboard(): Observable<Keyboard> {
|
||||
}
|
||||
})
|
||||
|
||||
/* Return keyboard observable */
|
||||
/* Return keyboard */
|
||||
return keyboard$
|
||||
}
|
||||
|
@ -51,6 +51,6 @@ export function watchLocation(): Subject<string> {
|
||||
)
|
||||
.subscribe(location$)
|
||||
|
||||
/* Return subject */
|
||||
/* Return location subject */
|
||||
return location$
|
||||
}
|
||||
|
@ -21,7 +21,7 @@
|
||||
*/
|
||||
|
||||
import { Observable, fromEvent } from "rxjs"
|
||||
import { filter, map, share } from "rxjs/operators"
|
||||
import { filter, map, share, startWith } from "rxjs/operators"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Functions
|
||||
@ -36,22 +36,6 @@ export function getLocationHash(): string {
|
||||
return location.hash
|
||||
}
|
||||
|
||||
/**
|
||||
* Set location hash
|
||||
*
|
||||
* This will force a reset of the location hash, inducing an anchor jump if
|
||||
* the hash matches the `id` of an element. It is implemented outside of the
|
||||
* whole RxJS architecture using `setTimeout` to keep it plain and simple.
|
||||
*
|
||||
* @param value - Location hash
|
||||
*/
|
||||
export function setLocationHash(value: string): void {
|
||||
location.hash = ""
|
||||
setTimeout(() => {
|
||||
location.hash = value
|
||||
}, 1)
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
@ -63,6 +47,7 @@ export function watchLocationHash(): Observable<string> {
|
||||
return fromEvent<HashChangeEvent>(window, "hashchange")
|
||||
.pipe(
|
||||
map(getLocationHash),
|
||||
startWith(getLocationHash()),
|
||||
filter(hash => hash.length > 0),
|
||||
share()
|
||||
)
|
||||
|
@ -20,8 +20,8 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { Observable, combineLatest, fromEvent, merge } from "rxjs"
|
||||
import { map, shareReplay, startWith } from "rxjs/operators"
|
||||
import { Observable, fromEvent } from "rxjs"
|
||||
import { map, startWith } from "rxjs/operators"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Types
|
||||
|
@ -99,7 +99,7 @@ export function watchNavigationLayer(
|
||||
)))
|
||||
)
|
||||
|
||||
/* Return previous and next layer */
|
||||
/* Return previous and next layer as hot observable */
|
||||
return layer$
|
||||
.pipe(
|
||||
map(next => ({ next })),
|
||||
|
@ -21,20 +21,17 @@
|
||||
*/
|
||||
|
||||
import { identity } from "ramda"
|
||||
import { NEVER, Observable, fromEvent, merge, of } from "rxjs"
|
||||
import { Observable, fromEvent, merge } from "rxjs"
|
||||
import {
|
||||
catchError,
|
||||
filter,
|
||||
map,
|
||||
switchMap,
|
||||
switchMapTo,
|
||||
tap
|
||||
} from "rxjs/operators"
|
||||
|
||||
import {
|
||||
getElementOrThrow,
|
||||
getElement,
|
||||
getElements,
|
||||
getLocationHash,
|
||||
setLocationHash,
|
||||
watchMedia
|
||||
} from "observables"
|
||||
|
||||
@ -72,8 +69,8 @@ export function patchDetails(
|
||||
|
||||
/* Open all details before printing */
|
||||
merge(
|
||||
watchMedia("print").pipe(filter(identity)), // Webkit
|
||||
fromEvent(window, "beforeprint") // IE, FF
|
||||
watchMedia("print").pipe(filter(identity)), /* Webkit */
|
||||
fromEvent(window, "beforeprint") /* IE, FF */
|
||||
)
|
||||
.pipe(
|
||||
switchMapTo(els$)
|
||||
@ -83,20 +80,16 @@ export function patchDetails(
|
||||
el.setAttribute("open", "")
|
||||
})
|
||||
|
||||
/* Open parent details before anchor jump */
|
||||
merge(hash$, of(getLocationHash()))
|
||||
/* Open parent details and fix anchor jump */
|
||||
hash$
|
||||
.pipe(
|
||||
filter(hash => !!hash.length),
|
||||
switchMap(hash => of(getElementOrThrow<HTMLElement>(hash))
|
||||
.pipe(
|
||||
map(el => [el.closest("details")!, hash] as const),
|
||||
filter(([el]) => el && !el.open)
|
||||
)
|
||||
),
|
||||
catchError(() => NEVER)
|
||||
)
|
||||
.subscribe(([el, hash]) => {
|
||||
el.setAttribute("open", "")
|
||||
setLocationHash(hash)
|
||||
map(hash => getElement(hash)!),
|
||||
filter(el => typeof el !== "undefined"),
|
||||
tap(el => {
|
||||
const details = el.closest("details")
|
||||
if (details && !details.open)
|
||||
details.setAttribute("open", "")
|
||||
})
|
||||
)
|
||||
.subscribe(el => el.scrollIntoView())
|
||||
}
|
||||
|
@ -58,7 +58,10 @@ export function patchScrollfix(
|
||||
.pipe(
|
||||
map(() => getElements("[data-md-scrollfix]")),
|
||||
switchMap(els => merge(...els.map(el => (
|
||||
fromEvent(el, "touchstart").pipe(mapTo(el))
|
||||
fromEvent(el, "touchstart")
|
||||
.pipe(
|
||||
mapTo(el)
|
||||
)
|
||||
))))
|
||||
)
|
||||
.subscribe(el => {
|
||||
|
@ -23,12 +23,7 @@
|
||||
import { Repo, User } from "github-types"
|
||||
import { Observable, of } from "rxjs"
|
||||
import { ajax } from "rxjs/ajax"
|
||||
import {
|
||||
filter,
|
||||
pluck,
|
||||
shareReplay,
|
||||
switchMap
|
||||
} from "rxjs/operators"
|
||||
import { filter, pluck, switchMap } from "rxjs/operators"
|
||||
|
||||
import { round } from "utilities"
|
||||
|
||||
@ -75,7 +70,6 @@ export function fetchSourceFactsFromGitHub(
|
||||
`${round(public_repos || 0)} Repositories`
|
||||
])
|
||||
}
|
||||
}),
|
||||
shareReplay(1)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
@ -23,12 +23,7 @@
|
||||
import { ProjectSchema } from "gitlab"
|
||||
import { Observable } from "rxjs"
|
||||
import { ajax } from "rxjs/ajax"
|
||||
import {
|
||||
filter,
|
||||
map,
|
||||
pluck,
|
||||
shareReplay
|
||||
} from "rxjs/operators"
|
||||
import { filter, map, pluck } from "rxjs/operators"
|
||||
|
||||
import { round } from "utilities"
|
||||
|
||||
@ -59,7 +54,6 @@ export function fetchSourceFactsFromGitLab(
|
||||
map(({ star_count, forks_count }: ProjectSchema) => ([
|
||||
`${round(star_count)} Stars`,
|
||||
`${round(forks_count)} Forks`
|
||||
])),
|
||||
shareReplay(1)
|
||||
]))
|
||||
)
|
||||
}
|
||||
|
@ -52,15 +52,15 @@ interface MountOptions {
|
||||
export function patchTables(
|
||||
{ document$ }: MountOptions
|
||||
): void {
|
||||
const placeholder = document.createElement("table")
|
||||
const sentinel = document.createElement("table")
|
||||
document$
|
||||
.pipe(
|
||||
map(() => getElements<HTMLTableElement>("table:not([class])"))
|
||||
)
|
||||
.subscribe(els => {
|
||||
for (const el of els) {
|
||||
el.replaceWith(placeholder)
|
||||
placeholder.replaceWith(renderTable(el))
|
||||
el.replaceWith(sentinel)
|
||||
sentinel.replaceWith(renderTable(el))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
*/
|
||||
|
||||
export * from "./clipboard"
|
||||
export * from "./dialog"
|
||||
export * from "./search"
|
||||
export * from "./source"
|
||||
export * from "./table"
|
||||
|
@ -20,7 +20,7 @@
|
||||
* IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import { SourceFacts } from "integrations/source"
|
||||
import { SourceFacts } from "patches/source"
|
||||
import { h } from "utilities"
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
@ -49,7 +49,9 @@ const css = {
|
||||
export function renderSource(
|
||||
facts: SourceFacts
|
||||
): HTMLElement {
|
||||
const children = facts.map(fact => <li class={css.fact}>{fact}</li>)
|
||||
const children = facts.map(fact => (
|
||||
<li class={css.fact}>{fact}</li>
|
||||
))
|
||||
return (
|
||||
<ul class={css.facts}>
|
||||
{children}
|
||||
|
@ -61,7 +61,7 @@ export function cache<T>(
|
||||
}
|
||||
})
|
||||
|
||||
/* Return value observable */
|
||||
/* Return value */
|
||||
return value$
|
||||
}
|
||||
})
|
||||
|
@ -81,14 +81,13 @@ export function truncate(value: string, n: number): string {
|
||||
/**
|
||||
* Round a number for display with source facts
|
||||
*
|
||||
* This is a reverse engineered implementation of GitHub's weird rounding
|
||||
* algorithm for stars, forks and all other numbers. While all numbers below
|
||||
* `1,000` are returned as-is, bigger numbers are converted to fixed numbers
|
||||
* in the following way:
|
||||
* This is a reverse engineered version of GitHub's weird rounding algorithm
|
||||
* for stars, forks and all other numbers. While all numbers below `1,000` are
|
||||
* returned as-is, bigger numbers are converted to fixed numbers:
|
||||
*
|
||||
* - `1,049` => `1k`
|
||||
* - `1,050` => `1,1k`
|
||||
* - `1,949` => `1,9k`
|
||||
* - `1,050` => `1.1k`
|
||||
* - `1,949` => `1.9k`
|
||||
* - `1,950` => `2k`
|
||||
*
|
||||
* @param value - Original value
|
||||
|
Loading…
Reference in New Issue
Block a user