run prettier

This commit is contained in:
Jacky Zhao 2023-07-22 17:27:41 -07:00
parent 2034b970b6
commit 7db2eda76c
101 changed files with 1810 additions and 1405 deletions

View file

@ -7,7 +7,9 @@ function toggleCallout(this: HTMLElement) {
}
function setupCallout() {
const collapsible = document.getElementsByClassName(`callout is-collapsible`) as HTMLCollectionOf<HTMLElement>
const collapsible = document.getElementsByClassName(
`callout is-collapsible`,
) as HTMLCollectionOf<HTMLElement>
for (const div of collapsible) {
const title = div.firstElementChild

View file

@ -1,24 +1,23 @@
const userPref = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'
const currentTheme = localStorage.getItem('theme') ?? userPref
document.documentElement.setAttribute('saved-theme', currentTheme)
const userPref = window.matchMedia("(prefers-color-scheme: light)").matches ? "light" : "dark"
const currentTheme = localStorage.getItem("theme") ?? userPref
document.documentElement.setAttribute("saved-theme", currentTheme)
document.addEventListener("nav", () => {
const switchTheme = (e: any) => {
if (e.target.checked) {
document.documentElement.setAttribute('saved-theme', 'dark')
localStorage.setItem('theme', 'dark')
}
else {
document.documentElement.setAttribute('saved-theme', 'light')
localStorage.setItem('theme', 'light')
document.documentElement.setAttribute("saved-theme", "dark")
localStorage.setItem("theme", "dark")
} else {
document.documentElement.setAttribute("saved-theme", "light")
localStorage.setItem("theme", "light")
}
}
// Darkmode toggle
const toggleSwitch = document.querySelector('#darkmode-toggle') as HTMLInputElement
toggleSwitch.removeEventListener('change', switchTheme)
toggleSwitch.addEventListener('change', switchTheme)
if (currentTheme === 'dark') {
const toggleSwitch = document.querySelector("#darkmode-toggle") as HTMLInputElement
toggleSwitch.removeEventListener("change", switchTheme)
toggleSwitch.addEventListener("change", switchTheme)
if (currentTheme === "dark") {
toggleSwitch.checked = true
}
})

View file

@ -1,16 +1,16 @@
import { ContentDetails } from "../../plugins/emitters/contentIndex"
import * as d3 from 'd3'
import * as d3 from "d3"
import { registerEscapeHandler, removeAllChildren } from "./util"
import { CanonicalSlug, getCanonicalSlug, getClientSlug, resolveRelative } from "../../path"
type NodeData = {
id: CanonicalSlug,
text: string,
id: CanonicalSlug
text: string
tags: string[]
} & d3.SimulationNodeDatum
type LinkData = {
source: CanonicalSlug,
source: CanonicalSlug
target: CanonicalSlug
}
@ -40,7 +40,7 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
centerForce,
linkDistance,
fontSize,
opacityScale
opacityScale,
} = JSON.parse(graph.dataset["cfg"]!)
const data = await fetchData
@ -66,18 +66,22 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
wl.push("__SENTINEL")
} else {
neighbourhood.add(cur)
const outgoing = links.filter(l => l.source === cur)
const incoming = links.filter(l => l.target === cur)
const outgoing = links.filter((l) => l.source === cur)
const incoming = links.filter((l) => l.target === cur)
wl.push(...outgoing.map((l) => l.target), ...incoming.map((l) => l.source))
}
}
} else {
Object.keys(data).forEach(id => neighbourhood.add(id as CanonicalSlug))
Object.keys(data).forEach((id) => neighbourhood.add(id as CanonicalSlug))
}
const graphData: { nodes: NodeData[], links: LinkData[] } = {
nodes: [...neighbourhood].map(url => ({ id: url, text: data[url]?.title ?? url, tags: data[url]?.tags ?? [] })),
links: links.filter((l) => neighbourhood.has(l.source) && neighbourhood.has(l.target))
const graphData: { nodes: NodeData[]; links: LinkData[] } = {
nodes: [...neighbourhood].map((url) => ({
id: url,
text: data[url]?.title ?? url,
tags: data[url]?.tags ?? [],
})),
links: links.filter((l) => neighbourhood.has(l.source) && neighbourhood.has(l.target)),
}
const simulation: d3.Simulation<NodeData, LinkData> = d3
@ -96,11 +100,11 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
const width = graph.offsetWidth
const svg = d3
.select<HTMLElement, NodeData>('#' + container)
.select<HTMLElement, NodeData>("#" + container)
.append("svg")
.attr("width", width)
.attr("height", height)
.attr('viewBox', [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale])
.attr("viewBox", [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale])
// draw links between nodes
const link = svg
@ -145,7 +149,7 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
d.fy = null
}
const noop = () => { }
const noop = () => {}
return d3
.drag<Element, NodeData>()
.on("start", enableDrag ? dragstarted : noop)
@ -170,9 +174,11 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
const targ = resolveRelative(slug, d.id)
window.spaNavigate(new URL(targ, getClientSlug(window)))
})
.on("mouseover", function(_, d) {
.on("mouseover", function (_, d) {
const neighbours: CanonicalSlug[] = data[slug].links ?? []
const neighbourNodes = d3.selectAll<HTMLElement, NodeData>(".node").filter((d) => neighbours.includes(d.id))
const neighbourNodes = d3
.selectAll<HTMLElement, NodeData>(".node")
.filter((d) => neighbours.includes(d.id))
console.log(neighbourNodes)
const currentId = d.id
const linkNodes = d3
@ -183,12 +189,7 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
neighbourNodes.transition().duration(200).attr("fill", color)
// highlight links
linkNodes
.transition()
.duration(200)
.attr("stroke", "var(--gray)")
.attr("stroke-width", 1)
linkNodes.transition().duration(200).attr("stroke", "var(--gray)").attr("stroke-width", 1)
const bigFont = fontSize * 1.5
@ -199,11 +200,11 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
.select("text")
.transition()
.duration(200)
.attr('opacityOld', d3.select(parent).select('text').style("opacity"))
.style('opacity', 1)
.style('font-size', bigFont + 'em')
.attr("opacityOld", d3.select(parent).select("text").style("opacity"))
.style("opacity", 1)
.style("font-size", bigFont + "em")
})
.on("mouseleave", function(_, d) {
.on("mouseleave", function (_, d) {
const currentId = d.id
const linkNodes = d3
.selectAll(".link")
@ -216,8 +217,8 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
.select("text")
.transition()
.duration(200)
.style('opacity', d3.select(parent).select('text').attr("opacityOld"))
.style('font-size', fontSize + 'em')
.style("opacity", d3.select(parent).select("text").attr("opacityOld"))
.style("font-size", fontSize + "em")
})
// @ts-ignore
.call(drag(simulation))
@ -228,10 +229,12 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
.attr("dx", 0)
.attr("dy", (d) => -nodeRadius(d) + "px")
.attr("text-anchor", "middle")
.text((d) => data[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " "))
.style('opacity', (opacityScale - 1) / 3.75)
.text(
(d) => data[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " "),
)
.style("opacity", (opacityScale - 1) / 3.75)
.style("pointer-events", "none")
.style('font-size', fontSize + 'em')
.style("font-size", fontSize + "em")
.raise()
// @ts-ignore
.call(drag(simulation))
@ -249,7 +252,7 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
.on("zoom", ({ transform }) => {
link.attr("transform", transform)
node.attr("transform", transform)
const scale = transform.k * opacityScale;
const scale = transform.k * opacityScale
const scaledOpacity = Math.max((scale - 1) / 3.75, 0)
labels.attr("transform", transform).style("opacity", scaledOpacity)
}),
@ -263,17 +266,13 @@ async function renderGraph(container: string, slug: CanonicalSlug) {
.attr("y1", (d: any) => d.source.y)
.attr("x2", (d: any) => d.target.x)
.attr("y2", (d: any) => d.target.y)
node
.attr("cx", (d: any) => d.x)
.attr("cy", (d: any) => d.y)
labels
.attr("x", (d: any) => d.x)
.attr("y", (d: any) => d.y)
node.attr("cx", (d: any) => d.x).attr("cy", (d: any) => d.y)
labels.attr("x", (d: any) => d.x).attr("y", (d: any) => d.y)
})
}
function renderGlobalGraph() {
const slug = getCanonicalSlug(window)
const slug = getCanonicalSlug(window)
const container = document.getElementById("global-graph-outer")
const sidebar = container?.closest(".sidebar") as HTMLElement
container?.classList.add("active")
@ -305,4 +304,3 @@ document.addEventListener("nav", async (e: unknown) => {
containerIcon?.removeEventListener("click", renderGlobalGraph)
containerIcon?.addEventListener("click", renderGlobalGraph)
})

View file

@ -1,3 +1,3 @@
import Plausible from 'plausible-tracker'
import Plausible from "plausible-tracker"
const { trackPageview } = Plausible()
document.addEventListener("nav", () => trackPageview())

View file

@ -2,33 +2,25 @@ import { computePosition, flip, inline, shift } from "@floating-ui/dom"
// from micromorph/src/utils.ts
// https://github.com/natemoo-re/micromorph/blob/main/src/utils.ts#L5
export function normalizeRelativeURLs(
el: Element | Document,
base: string | URL
) {
export function normalizeRelativeURLs(el: Element | Document, base: string | URL) {
const update = (el: Element, attr: string, base: string | URL) => {
el.setAttribute(attr, new URL(el.getAttribute(attr)!, base).pathname)
}
el.querySelectorAll('[href^="./"], [href^="../"]').forEach((item) =>
update(item, 'href', base)
)
el.querySelectorAll('[href^="./"], [href^="../"]').forEach((item) => update(item, "href", base))
el.querySelectorAll('[src^="./"], [src^="../"]').forEach((item) =>
update(item, 'src', base)
)
el.querySelectorAll('[src^="./"], [src^="../"]').forEach((item) => update(item, "src", base))
}
const p = new DOMParser()
async function mouseEnterHandler(this: HTMLLinkElement, { clientX, clientY }: { clientX: number, clientY: number }) {
async function mouseEnterHandler(
this: HTMLLinkElement,
{ clientX, clientY }: { clientX: number; clientY: number },
) {
const link = this
async function setPosition(popoverElement: HTMLElement) {
const { x, y } = await computePosition(link, popoverElement, {
middleware: [
inline({ x: clientX, y: clientY }),
shift(),
flip()
]
middleware: [inline({ x: clientX, y: clientY }), shift(), flip()],
})
Object.assign(popoverElement.style, {
left: `${x}px`,
@ -37,7 +29,7 @@ async function mouseEnterHandler(this: HTMLLinkElement, { clientX, clientY }: {
}
// dont refetch if there's already a popover
if ([...link.children].some(child => child.classList.contains("popover"))) {
if ([...link.children].some((child) => child.classList.contains("popover"))) {
return setPosition(link.lastChild as HTMLElement)
}
@ -68,7 +60,7 @@ async function mouseEnterHandler(this: HTMLLinkElement, { clientX, clientY }: {
const popoverInner = document.createElement("div")
popoverInner.classList.add("popover-inner")
popoverElement.appendChild(popoverInner)
elts.forEach(elt => popoverInner.appendChild(elt))
elts.forEach((elt) => popoverInner.appendChild(elt))
setPosition(popoverElement)
link.appendChild(popoverElement)
@ -77,7 +69,7 @@ async function mouseEnterHandler(this: HTMLLinkElement, { clientX, clientY }: {
const heading = popoverInner.querySelector(hash) as HTMLElement | null
if (heading) {
// leave ~12px of buffer when scrolling to a heading
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: 'instant' })
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: "instant" })
}
}
}

View file

@ -4,9 +4,9 @@ import { registerEscapeHandler, removeAllChildren } from "./util"
import { CanonicalSlug, getClientSlug, resolveRelative } from "../../path"
interface Item {
slug: CanonicalSlug,
title: string,
content: string,
slug: CanonicalSlug
title: string
content: string
}
let index: Document<Item> | undefined = undefined
@ -15,15 +15,17 @@ const contextWindowWords = 30
const numSearchResults = 5
function highlight(searchTerm: string, text: string, trim?: boolean) {
// try to highlight longest tokens first
const tokenizedTerms = searchTerm.split(/\s+/).filter(t => t !== "").sort((a, b) => b.length - a.length)
let tokenizedText = text
const tokenizedTerms = searchTerm
.split(/\s+/)
.filter(t => t !== "")
.filter((t) => t !== "")
.sort((a, b) => b.length - a.length)
let tokenizedText = text.split(/\s+/).filter((t) => t !== "")
let startIndex = 0
let endIndex = tokenizedText.length - 1
if (trim) {
const includesCheck = (tok: string) => tokenizedTerms.some((term) => tok.toLowerCase().startsWith(term.toLowerCase()))
const includesCheck = (tok: string) =>
tokenizedTerms.some((term) => tok.toLowerCase().startsWith(term.toLowerCase()))
const occurencesIndices = tokenizedText.map(includesCheck)
let bestSum = 0
@ -42,19 +44,22 @@ function highlight(searchTerm: string, text: string, trim?: boolean) {
tokenizedText = tokenizedText.slice(startIndex, endIndex)
}
const slice = tokenizedText.map(tok => {
// see if this tok is prefixed by any search terms
for (const searchTok of tokenizedTerms) {
if (tok.toLowerCase().includes(searchTok.toLowerCase())) {
const regex = new RegExp(searchTok.toLowerCase(), "gi")
return tok.replace(regex, `<span class="highlight">$&</span>`)
const slice = tokenizedText
.map((tok) => {
// see if this tok is prefixed by any search terms
for (const searchTok of tokenizedTerms) {
if (tok.toLowerCase().includes(searchTok.toLowerCase())) {
const regex = new RegExp(searchTok.toLowerCase(), "gi")
return tok.replace(regex, `<span class="highlight">$&</span>`)
}
}
}
return tok
})
return tok
})
.join(" ")
return `${startIndex === 0 ? "" : "..."}${slice}${endIndex === tokenizedText.length - 1 ? "" : "..."}`
return `${startIndex === 0 ? "" : "..."}${slice}${
endIndex === tokenizedText.length - 1 ? "" : "..."
}`
}
const encoder = (str: string) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])/)
@ -113,7 +118,7 @@ document.addEventListener("nav", async (e: unknown) => {
button.classList.add("result-card")
button.id = slug
button.innerHTML = `<h3>${title}</h3><p>${content}</p>`
button.addEventListener('click', () => {
button.addEventListener("click", () => {
const targ = resolveRelative(currentSlug, slug)
window.spaNavigate(new URL(targ, getClientSlug(window)))
})
@ -132,7 +137,6 @@ document.addEventListener("nav", async (e: unknown) => {
} else {
results.append(...finalResults.map(resultToHTML))
}
}
function onType(e: HTMLElementEventMap["input"]) {
@ -140,12 +144,12 @@ document.addEventListener("nav", async (e: unknown) => {
const searchResults = index?.search(term, numSearchResults) ?? []
const getByField = (field: string): CanonicalSlug[] => {
const results = searchResults.filter((x) => x.field === field)
return results.length === 0 ? [] : [...results[0].result] as CanonicalSlug[]
return results.length === 0 ? [] : ([...results[0].result] as CanonicalSlug[])
}
// order titles ahead of content
const allIds: Set<CanonicalSlug> = new Set([...getByField("title"), ...getByField("content")])
const finalResults = [...allIds].map(id => formatForDisplay(term, id))
const finalResults = [...allIds].map((id) => formatForDisplay(term, id))
displayResults(finalResults)
}
@ -160,7 +164,7 @@ document.addEventListener("nav", async (e: unknown) => {
if (!index) {
index = new Document({
cache: true,
charset: 'latin:extra',
charset: "latin:extra",
optimize: true,
encode: encoder,
document: {
@ -174,7 +178,7 @@ document.addEventListener("nav", async (e: unknown) => {
field: "content",
tokenize: "reverse",
},
]
],
},
})
@ -182,7 +186,7 @@ document.addEventListener("nav", async (e: unknown) => {
await index.addAsync(slug, {
slug: slug as CanonicalSlug,
title: fileData.title,
content: fileData.content
content: fileData.content,
})
}
}

View file

@ -5,8 +5,9 @@ import { CanonicalSlug, RelativeURL, getCanonicalSlug } from "../../path"
// https://github.com/natemoo-re/micromorph
const NODE_TYPE_ELEMENT = 1
let announcer = document.createElement('route-announcer')
const isElement = (target: EventTarget | null): target is Element => (target as Node)?.nodeType === NODE_TYPE_ELEMENT
let announcer = document.createElement("route-announcer")
const isElement = (target: EventTarget | null): target is Element =>
(target as Node)?.nodeType === NODE_TYPE_ELEMENT
const isLocalUrl = (href: string) => {
try {
const url = new URL(href)
@ -16,18 +17,18 @@ const isLocalUrl = (href: string) => {
}
return true
}
} catch (e) { }
} catch (e) {}
return false
}
const getOpts = ({ target }: Event): { url: URL, scroll?: boolean } | undefined => {
const getOpts = ({ target }: Event): { url: URL; scroll?: boolean } | undefined => {
if (!isElement(target)) return
const a = target.closest("a")
if (!a) return
if ('routerIgnore' in a.dataset) return
if ("routerIgnore" in a.dataset) return
const { href } = a
if (!isLocalUrl(href)) return
return { url: new URL(href), scroll: 'routerNoscroll' in a.dataset ? false : undefined }
return { url: new URL(href), scroll: "routerNoscroll" in a.dataset ? false : undefined }
}
function notifyNav(url: CanonicalSlug) {
@ -44,7 +45,7 @@ async function navigate(url: URL, isBack: boolean = false) {
window.location.assign(url)
})
if (!contents) return;
if (!contents) return
if (!isBack) {
history.pushState({}, "", url)
window.scrollTo({ top: 0 })
@ -54,22 +55,22 @@ async function navigate(url: URL, isBack: boolean = false) {
if (title) {
document.title = title
} else {
const h1 = document.querySelector('h1')
const h1 = document.querySelector("h1")
title = h1?.innerText ?? h1?.textContent ?? url.pathname
}
if (announcer.textContent !== title) {
announcer.textContent = title
}
announcer.dataset.persist = ''
announcer.dataset.persist = ""
html.body.appendChild(announcer)
micromorph(document.body, html.body)
// now, patch head
const elementsToRemove = document.head.querySelectorAll(':not([spa-preserve])')
elementsToRemove.forEach(el => el.remove())
const elementsToAdd = html.head.querySelectorAll(':not([spa-preserve])')
elementsToAdd.forEach(el => document.head.appendChild(el))
// now, patch head
const elementsToRemove = document.head.querySelectorAll(":not([spa-preserve])")
elementsToRemove.forEach((el) => el.remove())
const elementsToAdd = html.head.querySelectorAll(":not([spa-preserve])")
elementsToAdd.forEach((el) => document.head.appendChild(el))
notifyNav(getCanonicalSlug(window))
delete announcer.dataset.persist
@ -101,7 +102,7 @@ function createRouter() {
})
}
return new class Router {
return new (class Router {
go(pathname: RelativeURL) {
const url = new URL(pathname, window.location.toString())
return navigate(url, false)
@ -114,26 +115,30 @@ function createRouter() {
forward() {
return window.history.forward()
}
}
})()
}
createRouter()
notifyNav(getCanonicalSlug(window))
if (!customElements.get('route-announcer')) {
if (!customElements.get("route-announcer")) {
const attrs = {
'aria-live': 'assertive',
'aria-atomic': 'true',
'style': 'position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px'
"aria-live": "assertive",
"aria-atomic": "true",
style:
"position: absolute; left: 0; top: 0; clip: rect(0 0 0 0); clip-path: inset(50%); overflow: hidden; white-space: nowrap; width: 1px; height: 1px",
}
customElements.define('route-announcer', class RouteAnnouncer extends HTMLElement {
constructor() {
super()
}
connectedCallback() {
for (const [key, value] of Object.entries(attrs)) {
this.setAttribute(key, value)
customElements.define(
"route-announcer",
class RouteAnnouncer extends HTMLElement {
constructor() {
super()
}
}
})
connectedCallback() {
for (const [key, value] of Object.entries(attrs)) {
this.setAttribute(key, value)
}
}
},
)
}

View file

@ -1,5 +1,5 @@
const bufferPx = 150
const observer = new IntersectionObserver(entries => {
const observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
const slug = entry.target.id
const tocEntryElement = document.querySelector(`a[data-for="${slug}"]`)
@ -38,5 +38,5 @@ document.addEventListener("nav", () => {
// update toc entry highlighting
observer.disconnect()
const headers = document.querySelectorAll("h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]")
headers.forEach(header => observer.observe(header))
headers.forEach((header) => observer.observe(header))
})

View file

@ -15,7 +15,7 @@ export function registerEscapeHandler(outsideContainer: HTMLElement | null, cb:
outsideContainer?.removeEventListener("click", click)
outsideContainer?.addEventListener("click", click)
document.removeEventListener("keydown", esc)
document.addEventListener('keydown', esc)
document.addEventListener("keydown", esc)
}
export function removeAllChildren(node: HTMLElement) {