Refactored project structure

This commit is contained in:
squidfunk
2021-11-14 16:09:09 +01:00
parent ad1b964aaa
commit 88ba609ee1
52 changed files with 721 additions and 459 deletions

View File

@@ -20,7 +20,7 @@
* IN THE SOFTWARE.
*/
import { getElementOrThrow, getElements } from "~/browser"
import { getElement, getElements } from "~/browser"
/* ----------------------------------------------------------------------------
* Types
@@ -114,7 +114,7 @@ interface ComponentTypeMap {
export function getComponentElement<T extends ComponentType>(
type: T, node: ParentNode = document
): ComponentTypeMap[T] {
return getElementOrThrow(`[data-md-component=${type}]`, node)
return getElement(`[data-md-component=${type}]`, node)
}
/**

View File

@@ -53,7 +53,8 @@ export type Content =
interface MountOptions {
target$: Observable<HTMLElement> /* Location target observable */
viewport$: Observable<Viewport> /* Viewport observable */
print$: Observable<boolean> /* Print observable */
hover$: Observable<boolean> /* Media hover observable */
print$: Observable<boolean> /* Media print observable */
}
/* ----------------------------------------------------------------------------
@@ -72,13 +73,13 @@ interface MountOptions {
* @returns Content component observable
*/
export function mountContent(
el: HTMLElement, { target$, viewport$, print$ }: MountOptions
el: HTMLElement, { target$, viewport$, hover$, print$ }: MountOptions
): Observable<Component<Content>> {
return merge(
/* Code blocks */
...getElements("pre > code", el)
.map(child => mountCodeBlock(child, { viewport$, print$ })),
.map(child => mountCodeBlock(child, { viewport$, hover$, print$ })),
/* Data tables */
...getElements("table:not([class])", el)

View File

@@ -41,14 +41,17 @@ import {
} from "rxjs"
import { feature } from "~/_"
import { resetFocusable, setFocusable } from "~/actions"
import {
resetFocusable,
setFocusable
} from "~/actions"
import {
Viewport,
getElement,
getElementContentSize,
getElementOrThrow,
getElementSize,
getElements,
getOptionalElement,
watchMedia
} from "~/browser"
import {
@@ -174,7 +177,7 @@ export function watchCodeBlock(
container.insertAdjacentElement("afterend", list)
for (const annotation of annotations) {
const id = parseInt(annotation.getAttribute("data-index")!, 10)
const typeset = getElement(":scope .md-typeset", annotation)!
const typeset = getOptionalElement(":scope .md-typeset", annotation)!
items[id - 1].append(...Array.from(typeset.childNodes))
}
} else {
@@ -182,7 +185,7 @@ export function watchCodeBlock(
for (const annotation of annotations) {
const id = parseInt(annotation.getAttribute("data-index")!, 10)
const nodes = items[id - 1].childNodes
getElementOrThrow(":scope .md-typeset", annotation)
getElement(":scope .md-typeset", annotation)
.append(...Array.from(nodes))
}
}
@@ -239,7 +242,7 @@ export function mountCodeBlock(
take(1),
takeWhile(({ annotations }) => !!annotations?.length),
map(({ annotations }) => annotations!
.map(annotation => getElementOrThrow(".md-tooltip", annotation))
.map(annotation => getElement(".md-tooltip", annotation))
),
combineLatestWith(viewport$
.pipe(

View File

@@ -54,7 +54,7 @@ export interface Details {
*/
interface WatchOptions {
target$: Observable<HTMLElement> /* Location target observable */
print$: Observable<boolean> /* Print observable */
print$: Observable<boolean> /* Media print observable */
}
/**
@@ -62,7 +62,7 @@ interface WatchOptions {
*/
interface MountOptions {
target$: Observable<HTMLElement> /* Location target observable */
print$: Observable<boolean> /* Print observable */
print$: Observable<boolean> /* Media print observable */
}
/* ----------------------------------------------------------------------------

View File

@@ -22,7 +22,6 @@
import { Observable, of } from "rxjs"
import { replaceElement } from "~/browser"
import { renderTable } from "~/templates"
import { h } from "~/utilities"
@@ -63,8 +62,8 @@ const sentinel = h("table")
export function mountDataTable(
el: HTMLElement
): Observable<Component<DataTable>> {
replaceElement(el, sentinel)
replaceElement(sentinel, renderTable(el))
el.replaceWith(sentinel)
sentinel.replaceWith(renderTable(el))
/* Create and return component */
return of({ ref: el })

View File

@@ -21,7 +21,6 @@
*/
import {
NEVER,
Observable,
Subject,
finalize,
@@ -33,7 +32,7 @@ import {
} from "rxjs"
import {
getElementOrThrow,
getElement,
getElements
} from "~/browser"
@@ -64,17 +63,14 @@ export interface ContentTabs {
export function watchContentTabs(
el: HTMLElement
): Observable<ContentTabs> {
if (!el.classList.contains("tabbed-alternate"))
return NEVER
else
return merge(...getElements(":scope > input", el)
.map(input => fromEvent(input, "change").pipe(mapTo(input.id)))
return merge(...getElements(":scope > input", el)
.map(input => fromEvent(input, "change").pipe(mapTo(input.id)))
)
.pipe(
map(id => ({
active: getElement<HTMLLabelElement>(`label[for=${id}]`)
}))
)
.pipe(
map(id => ({
active: getElementOrThrow<HTMLLabelElement>(`label[for=${id}]`)
}))
)
}
/**

View File

@@ -40,7 +40,10 @@ import {
} from "rxjs"
import { feature } from "~/_"
import { resetHeaderState, setHeaderState } from "~/actions"
import {
resetHeaderState,
setHeaderState
} from "~/actions"
import {
Viewport,
watchElementSize,

View File

@@ -38,8 +38,8 @@ import {
} from "~/actions"
import {
Viewport,
getElement,
getElementSize,
getOptionalElement,
watchViewportAt
} from "~/browser"
@@ -131,7 +131,7 @@ export function mountHeaderTitle(
})
/* Obtain headline, if any */
const headline = getElement<HTMLHeadingElement>("article h1")
const headline = getOptionalElement<HTMLHeadingElement>("article h1")
if (typeof headline === "undefined")
return NEVER

View File

@@ -29,7 +29,10 @@ import {
switchMap
} from "rxjs"
import { Viewport, watchElementSize } from "~/browser"
import {
Viewport,
watchElementSize
} from "~/browser"
import { Header } from "../header"

View File

@@ -53,10 +53,19 @@ import {
getComponentElement,
getComponentElements
} from "../../_"
import { SearchQuery, mountSearchQuery } from "../query"
import {
SearchQuery,
mountSearchQuery
} from "../query"
import { mountSearchResult } from "../result"
import { SearchShare, mountSearchShare } from "../share"
import { SearchSuggest, mountSearchSuggest } from "../suggest"
import {
SearchShare,
mountSearchShare
} from "../share"
import {
SearchSuggest,
mountSearchSuggest
} from "../suggest"
/* ----------------------------------------------------------------------------
* Types

View File

@@ -46,8 +46,8 @@ import {
setSearchResultMeta
} from "~/actions"
import {
getElementOrThrow,
watchElementThreshold
getElement,
watchElementBoundary
} from "~/browser"
import {
SearchResult,
@@ -91,14 +91,14 @@ export function mountSearchResult(
el: HTMLElement, { rx$ }: SearchWorker, { query$ }: MountOptions
): Observable<Component<SearchResult>> {
const internal$ = new Subject<SearchResult>()
const boundary$ = watchElementThreshold(el.parentElement!)
const boundary$ = watchElementBoundary(el.parentElement!)
.pipe(
filter(Boolean)
)
/* Retrieve nested components */
const meta = getElementOrThrow(":scope > :first-child", el)
const list = getElementOrThrow(":scope > :last-child", el)
const meta = getElement(":scope > :first-child", el)
const list = getElement(":scope > :last-child", el)
/* Wait until search is ready */
const ready$ = rx$

View File

@@ -98,9 +98,10 @@ interface MountOptions {
export function watchSidebar(
el: HTMLElement, { viewport$, main$ }: WatchOptions
): Observable<Sidebar> {
const parent = el.parentElement!
const adjust =
el.parentElement!.offsetTop -
el.parentElement!.parentElement!.offsetTop
parent.offsetTop -
parent.parentElement!.offsetTop
/* Compute the sidebar's available height and if it should be locked */
return combineLatest([main$, viewport$])

View File

@@ -34,11 +34,17 @@ import {
tap
} from "rxjs"
import { setSourceFacts, setSourceState } from "~/actions"
import {
setSourceFacts,
setSourceState
} from "~/actions"
import { renderSourceFacts } from "~/templates"
import { Component } from "../../_"
import { SourceFacts, fetchSourceFacts } from "../facts"
import {
SourceFacts,
fetchSourceFacts
} from "../facts"
/* ----------------------------------------------------------------------------
* Types

View File

@@ -34,7 +34,10 @@ import {
} from "rxjs"
import { feature } from "~/_"
import { resetTabsState, setTabsState } from "~/actions"
import {
resetTabsState,
setTabsState
} from "~/actions"
import {
Viewport,
watchElementSize,

View File

@@ -48,9 +48,9 @@ import {
} from "~/actions"
import {
Viewport,
getElement,
getElements,
getLocation,
getOptionalElement,
watchElementSize
} from "~/browser"
@@ -122,7 +122,7 @@ export function watchTableOfContents(
const anchors = getElements<HTMLAnchorElement>("[href^=\\#]", el)
for (const anchor of anchors) {
const id = decodeURIComponent(anchor.hash.substring(1))
const target = getElement(`[id="${id}"]`)
const target = getOptionalElement(`[id="${id}"]`)
if (typeof target !== "undefined")
table.set(anchor, target)
}

View File

@@ -43,7 +43,10 @@ import {
setBackToTopState,
setFocusable
} from "~/actions"
import { Viewport, setElementFocus } from "~/browser"
import {
Viewport,
setElementFocus
} from "~/browser"
import { Component } from "../_"
import { Header } from "../header"