aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/docs/src/templates/assets/javascripts/components/palette
diff options
context:
space:
mode:
author简律纯 <i@jyunko.cn>2023-12-15 09:11:47 +0800
committer简律纯 <i@jyunko.cn>2023-12-15 09:11:47 +0800
commitbe8de118db913711eb72ae5187d26e54a0055727 (patch)
tree96cd6c012dafa3f4015e54edef90df5eaaab0ddb /docs/src/templates/assets/javascripts/components/palette
parent9b2d27ba1d91a0d5531bc9c0d52c3887a2dfb2aa (diff)
downloadinfini-be8de118db913711eb72ae5187d26e54a0055727.tar.gz
infini-be8de118db913711eb72ae5187d26e54a0055727.zip
refactor(docs): optmst `docs` dir & `deps`
Diffstat (limited to 'docs/src/templates/assets/javascripts/components/palette')
-rw-r--r--docs/src/templates/assets/javascripts/components/palette/index.ts180
1 files changed, 180 insertions, 0 deletions
diff --git a/docs/src/templates/assets/javascripts/components/palette/index.ts b/docs/src/templates/assets/javascripts/components/palette/index.ts
new file mode 100644
index 00000000..cf578f60
--- /dev/null
+++ b/docs/src/templates/assets/javascripts/components/palette/index.ts
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2016-2023 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,
+ Subject,
+ asyncScheduler,
+ defer,
+ finalize,
+ fromEvent,
+ map,
+ mergeMap,
+ observeOn,
+ of,
+ shareReplay,
+ startWith,
+ tap
+} from "rxjs"
+
+import { getElements } from "~/browser"
+import { h } from "~/utilities"
+
+import {
+ Component,
+ getComponentElement
+} from "../_"
+
+/* ----------------------------------------------------------------------------
+ * Types
+ * ------------------------------------------------------------------------- */
+
+/**
+ * Palette colors
+ */
+export interface PaletteColor {
+ scheme?: string /* Color scheme */
+ primary?: string /* Primary color */
+ accent?: string /* Accent color */
+}
+
+/**
+ * Palette
+ */
+export interface Palette {
+ index: number /* Palette index */
+ color: PaletteColor /* Palette colors */
+}
+
+/* ----------------------------------------------------------------------------
+ * Functions
+ * ------------------------------------------------------------------------- */
+
+/**
+ * Watch color palette
+ *
+ * @param inputs - Color palette element
+ *
+ * @returns Color palette observable
+ */
+export function watchPalette(
+ inputs: HTMLInputElement[]
+): Observable<Palette> {
+ const current = __md_get<Palette>("__palette") || {
+ index: inputs.findIndex(input => matchMedia(
+ input.getAttribute("data-md-color-media")!
+ ).matches)
+ }
+
+ /* Emit changes in color palette */
+ return of(...inputs)
+ .pipe(
+ mergeMap(input => fromEvent(input, "change")
+ .pipe(
+ map(() => input)
+ )
+ ),
+ startWith(inputs[Math.max(0, current.index)]),
+ map(input => ({
+ index: inputs.indexOf(input),
+ color: {
+ scheme: input.getAttribute("data-md-color-scheme"),
+ primary: input.getAttribute("data-md-color-primary"),
+ accent: input.getAttribute("data-md-color-accent")
+ }
+ } as Palette)),
+ shareReplay(1)
+ )
+}
+
+/**
+ * Mount color palette
+ *
+ * @param el - Color palette element
+ *
+ * @returns Color palette component observable
+ */
+export function mountPalette(
+ el: HTMLElement
+): Observable<Component<Palette>> {
+ const meta = h("meta", { name: "theme-color" })
+ document.head.appendChild(meta)
+
+ // Add color scheme meta tag
+ const scheme = h("meta", { name: "color-scheme" })
+ document.head.appendChild(scheme)
+
+ /* Mount component on subscription */
+ return defer(() => {
+ const push$ = new Subject<Palette>()
+ push$.subscribe(palette => {
+ document.body.setAttribute("data-md-color-switching", "")
+
+ /* Set color palette */
+ for (const [key, value] of Object.entries(palette.color))
+ document.body.setAttribute(`data-md-color-${key}`, value)
+
+ /* Toggle visibility */
+ for (let index = 0; index < inputs.length; index++) {
+ const label = inputs[index].nextElementSibling
+ if (label instanceof HTMLElement)
+ label.hidden = palette.index !== index
+ }
+
+ /* Persist preference in local storage */
+ __md_set("__palette", palette)
+ })
+
+ /* Update theme-color meta tag */
+ push$
+ .pipe(
+ map(() => {
+ const header = getComponentElement("header")
+ const style = window.getComputedStyle(header)
+
+ // Set color scheme
+ scheme.content = style.colorScheme
+
+ /* Return color in hexadecimal format */
+ return style.backgroundColor.match(/\d+/g)!
+ .map(value => (+value).toString(16).padStart(2, "0"))
+ .join("")
+ })
+ )
+ .subscribe(color => meta.content = `#${color}`)
+
+ /* Revert transition durations after color switch */
+ push$.pipe(observeOn(asyncScheduler))
+ .subscribe(() => {
+ document.body.removeAttribute("data-md-color-switching")
+ })
+
+ /* Create and return component */
+ const inputs = getElements<HTMLInputElement>("input", el)
+ return watchPalette(inputs)
+ .pipe(
+ tap(state => push$.next(state)),
+ finalize(() => push$.complete()),
+ map(state => ({ ref: el, ...state }))
+ )
+ })
+}