Merge of Insiders features tied to 'Caribbean Red' funding goal

This commit is contained in:
squidfunk
2021-09-23 08:53:51 +02:00
parent 62742b4f0d
commit 377b4d648f
32 changed files with 228 additions and 198 deletions

View File

@@ -33,8 +33,10 @@ export type Flag =
| "header.autohide" /* Hide header */
| "navigation.expand" /* Automatic expansion */
| "navigation.instant" /* Instant loading */
| "navigation.sections" /* Sections navigation */
| "navigation.indexes" /* Section pages */
| "navigation.sections" /* Section navigation */
| "navigation.tabs" /* Tabs navigation */
| "navigation.tabs.sticky" /* Tabs navigation (sticky) */
| "navigation.top" /* Back-to-top button */
| "search.highlight" /* Search highlighting */
| "search.share" /* Search sharing */

View File

@@ -36,7 +36,7 @@
*/
export function getElement<T extends keyof HTMLElementTagNameMap>(
selector: T, node?: ParentNode
): HTMLElementTagNameMap[T]
): HTMLElementTagNameMap[T] | undefined
export function getElement<T extends HTMLElement>(
selector: string, node?: ParentNode
@@ -74,6 +74,8 @@ export function getElementOrThrow<T extends HTMLElement>(
throw new ReferenceError(
`Missing element: expected "${selector}" to be present`
)
/* Return element */
return el
}
@@ -114,21 +116,6 @@ export function getElements<T extends HTMLElement>(
/* ------------------------------------------------------------------------- */
/**
* Create an element
*
* @template T - Tag name type
*
* @param tagName - Tag name
*
* @returns Element
*/
export function createElement<T extends keyof HTMLElementTagNameMap>(
tagName: T
): HTMLElementTagNameMap[T] {
return document.createElement(tagName)
}
/**
* Replace an element with the given list of nodes
*

View File

@@ -28,7 +28,8 @@ import {
startWith
} from "rxjs/operators"
import { createElement, getElement } from "~/browser"
import { getElement } from "~/browser"
import { h } from "~/utilities"
/* ----------------------------------------------------------------------------
* Functions
@@ -54,8 +55,7 @@ export function getLocationHash(): string {
* @param hash - Location hash
*/
export function setLocationHash(hash: string): void {
const el = createElement("a")
el.href = hash
const el = h("a", { href: hash })
el.addEventListener("click", ev => ev.stopPropagation())
el.click()
}

View File

@@ -27,7 +27,7 @@ import { getElementOrThrow, getElements } from "~/browser"
* ------------------------------------------------------------------------- */
/**
* Component
* Component type
*/
export type ComponentType =
| "announce" /* Announcement bar */
@@ -52,7 +52,7 @@ export type ComponentType =
| "top" /* Back-to-top button */
/**
* A component
* Component
*
* @template T - Component type
* @template U - Reference type

View File

@@ -22,8 +22,9 @@
import { Observable, of } from "rxjs"
import { createElement, replaceElement } from "~/browser"
import { replaceElement } from "~/browser"
import { renderTable } from "~/templates"
import { h } from "~/utilities"
import { Component } from "../../_"
@@ -43,7 +44,7 @@ export interface DataTable {}
/**
* Sentinel for replacement
*/
const sentinel = createElement("table")
const sentinel = h("table")
/* ----------------------------------------------------------------------------
* Functions

View File

@@ -213,7 +213,7 @@ export function mountSearch(
/* Search sharing */
...getComponentElements("search-share", el)
.map(child => mountSearchShare(child, { query$ })),
.map(child => mountSearchShare(child, { query$ })),
/* Search suggestions */
...getComponentElements("search-suggest", el)

View File

@@ -20,7 +20,12 @@
* IN THE SOFTWARE.
*/
import { Observable, Subject, animationFrameScheduler } from "rxjs"
import {
Observable,
Subject,
animationFrameScheduler,
of
} from "rxjs"
import {
distinctUntilKeyChanged,
finalize,
@@ -30,6 +35,7 @@ import {
tap
} from "rxjs/operators"
import { feature } from "~/_"
import { resetTabsState, setTabsState } from "~/actions"
import {
Viewport,
@@ -134,7 +140,11 @@ export function mountTabs(
})
/* Create and return component */
return watchTabs(el, options)
return (
feature("navigation.tabs.sticky")
? of({ hidden: false })
: watchTabs(el, options)
)
.pipe(
tap(state => internal$.next(state)),
finalize(() => internal$.complete()),

View File

@@ -45,11 +45,10 @@ import {
switchMap
} from "rxjs/operators"
import { configuration } from "~/_"
import { configuration, feature } from "~/_"
import {
Viewport,
ViewportOffset,
createElement,
getElement,
getElements,
replaceElement,
@@ -60,6 +59,7 @@ import {
setViewportOffset
} from "~/browser"
import { getComponentElement } from "~/components"
import { h } from "~/utilities"
/* ----------------------------------------------------------------------------
* Types
@@ -283,7 +283,10 @@ export function setupInstantLoading(
"[data-md-component=container]",
"[data-md-component=header-topic]",
"[data-md-component=logo], .md-logo", // compat
"[data-md-component=skip]"
"[data-md-component=skip]",
...feature("navigation.tabs.sticky")
? ["[data-md-component=tabs]"]
: []
]) {
const source = getElement(selector)
const target = getElement(selector, replacement)
@@ -303,7 +306,7 @@ export function setupInstantLoading(
map(() => getComponentElement("container")),
switchMap(el => of(...getElements("script", el))),
concatMap(el => {
const script = createElement("script")
const script = h("script")
if (el.src) {
for (const name of el.getAttributeNames())
script.setAttribute(name, el.getAttribute(name)!)

View File

@@ -39,7 +39,7 @@ export const enum SearchMessageType {
/* ------------------------------------------------------------------------- */
/**
* A message containing the data necessary to setup the search index
* Message containing the data necessary to setup the search index
*/
export interface SearchSetupMessage {
type: SearchMessageType.SETUP /* Message type */
@@ -47,14 +47,14 @@ export interface SearchSetupMessage {
}
/**
* A message indicating the search index is ready
* Message indicating the search index is ready
*/
export interface SearchReadyMessage {
type: SearchMessageType.READY /* Message type */
}
/**
* A message containing a search query
* Message containing a search query
*/
export interface SearchQueryMessage {
type: SearchMessageType.QUERY /* Message type */
@@ -62,7 +62,7 @@ export interface SearchQueryMessage {
}
/**
* A message containing results for a search query
* Message containing results for a search query
*/
export interface SearchResultMessage {
type: SearchMessageType.RESULT /* Message type */
@@ -72,7 +72,7 @@ export interface SearchResultMessage {
/* ------------------------------------------------------------------------- */
/**
* A message exchanged with the search worker
* Message exchanged with the search worker
*/
export type SearchMessage =
| SearchSetupMessage

View File

@@ -1,6 +1,7 @@
{
"rules": {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-namespace": "off"
"@typescript-eslint/no-namespace": "off",
"jsdoc/require-jsdoc": "off"
}
}

View File

@@ -77,15 +77,25 @@ function appendChild(el: HTMLElement, child: Child | Child[]): void {
/**
* JSX factory
*
* @template T - Element type
*
* @param tag - HTML tag
* @param attributes - HTML attributes
* @param children - Child elements
*
* @returns Element
*/
export function h(
tag: string, attributes: Attributes | null, ...children: Child[]
): HTMLElement {
export function h<T extends keyof HTMLElementTagNameMap>(
tag: T, attributes?: Attributes | null, ...children: Child[]
): HTMLElementTagNameMap[T]
export function h<T extends h.JSX.Element>(
tag: string, attributes?: Attributes | null, ...children: Child[]
): T
export function h<T extends h.JSX.Element>(
tag: string, attributes?: Attributes | null, ...children: Child[]
): T {
const el = document.createElement(tag)
/* Set attributes, if any */
@@ -101,7 +111,7 @@ export function h(
appendChild(el, child)
/* Return element */
return el
return el as T
}
/* ----------------------------------------------------------------------------