Merge commit '4923affa7722dfc751f1074348e6dad214fe0c08' into v4
This commit is contained in:
@@ -17,6 +17,7 @@ type Options = {
|
||||
strict?: boolean
|
||||
reactionsEnabled?: boolean
|
||||
inputPosition?: "top" | "bottom"
|
||||
lang?: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +51,7 @@ export default ((opts: Options) => {
|
||||
data-theme-url={
|
||||
opts.options.themeUrl ?? `https://${cfg.baseUrl ?? "example.com"}/static/giscus`
|
||||
}
|
||||
data-lang={opts.options.lang ?? "en"}
|
||||
></div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -55,11 +55,14 @@ export type FolderState = {
|
||||
collapsed: boolean
|
||||
}
|
||||
|
||||
let numExplorers = 0
|
||||
export default ((userOpts?: Partial<Options>) => {
|
||||
const opts: Options = { ...defaultOptions, ...userOpts }
|
||||
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
||||
|
||||
const Explorer: QuartzComponent = ({ cfg, displayClass }: QuartzComponentProps) => {
|
||||
const id = `explorer-${numExplorers++}`
|
||||
|
||||
return (
|
||||
<div
|
||||
class={classNames(displayClass, "explorer")}
|
||||
@@ -77,7 +80,7 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
type="button"
|
||||
class="explorer-toggle mobile-explorer hide-until-loaded"
|
||||
data-mobile={true}
|
||||
aria-controls="explorer-content"
|
||||
aria-controls={id}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -116,7 +119,7 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="explorer-content" aria-expanded={false}>
|
||||
<div id={id} class="explorer-content" aria-expanded={false} role="group">
|
||||
<OverflowList class="explorer-ul" />
|
||||
</div>
|
||||
<template id="template-file">
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { concatenateResources } from "../util/resources"
|
||||
import { classNames } from "../util/lang"
|
||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||
|
||||
type FlexConfig = {
|
||||
@@ -23,7 +24,10 @@ export default ((config: FlexConfig) => {
|
||||
const gap = config.gap ?? "1rem"
|
||||
|
||||
return (
|
||||
<div style={`display: flex; flex-direction: ${direction}; flex-wrap: ${wrap}; gap: ${gap};`}>
|
||||
<div
|
||||
class={classNames(props.displayClass, "flex-component")}
|
||||
style={`flex-direction: ${direction}; flex-wrap: ${wrap}; gap: ${gap};`}
|
||||
>
|
||||
{config.components.map((c) => {
|
||||
const grow = c.grow ? 1 : 0
|
||||
const shrink = (c.shrink ?? true) ? 1 : 0
|
||||
|
||||
@@ -12,9 +12,9 @@ const OverflowList = ({
|
||||
)
|
||||
}
|
||||
|
||||
let numExplorers = 0
|
||||
let numLists = 0
|
||||
export default () => {
|
||||
const id = `list-${numExplorers++}`
|
||||
const id = `list-${numLists++}`
|
||||
|
||||
return {
|
||||
OverflowList: (props: JSX.HTMLAttributes<HTMLUListElement>) => (
|
||||
|
||||
@@ -20,7 +20,6 @@ export default ((userOpts?: Partial<SearchOptions>) => {
|
||||
return (
|
||||
<div class={classNames(displayClass, "search")}>
|
||||
<button class="search-button">
|
||||
<p>{i18n(cfg.locale).components.search.title}</p>
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.9 19.7">
|
||||
<title>Search</title>
|
||||
<g class="search-path" fill="none">
|
||||
@@ -28,6 +27,7 @@ export default ((userOpts?: Partial<SearchOptions>) => {
|
||||
<circle cx="8" cy="8" r="7" />
|
||||
</g>
|
||||
</svg>
|
||||
<p>{i18n(cfg.locale).components.search.title}</p>
|
||||
</button>
|
||||
<div class="search-container">
|
||||
<div class="search-space">
|
||||
|
||||
@@ -17,6 +17,7 @@ const defaultOptions: Options = {
|
||||
layout: "modern",
|
||||
}
|
||||
|
||||
let numTocs = 0
|
||||
export default ((opts?: Partial<Options>) => {
|
||||
const layout = opts?.layout ?? defaultOptions.layout
|
||||
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
||||
@@ -29,12 +30,13 @@ export default ((opts?: Partial<Options>) => {
|
||||
return null
|
||||
}
|
||||
|
||||
const id = `toc-${numTocs++}`
|
||||
return (
|
||||
<div class={classNames(displayClass, "toc")}>
|
||||
<button
|
||||
type="button"
|
||||
class={fileData.collapseToc ? "collapsed toc-header" : "toc-header"}
|
||||
aria-controls="toc-content"
|
||||
aria-controls={id}
|
||||
aria-expanded={!fileData.collapseToc}
|
||||
>
|
||||
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
|
||||
@@ -53,7 +55,10 @@ export default ((opts?: Partial<Options>) => {
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<OverflowList class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}>
|
||||
<OverflowList
|
||||
id={id}
|
||||
class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}
|
||||
>
|
||||
{fileData.toc.map((tocEntry) => (
|
||||
<li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
|
||||
<a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>
|
||||
|
||||
@@ -231,8 +231,9 @@ export function renderPage(
|
||||
)
|
||||
|
||||
const lang = componentData.fileData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
|
||||
const direction = i18n(cfg.locale).direction ?? "ltr"
|
||||
const doc = (
|
||||
<html lang={lang}>
|
||||
<html lang={lang} dir={direction}>
|
||||
<Head {...componentData} />
|
||||
<body data-slug={slug}>
|
||||
<div id="quartz-root" class="page">
|
||||
|
||||
@@ -55,6 +55,7 @@ type GiscusElement = Omit<HTMLElement, "dataset"> & {
|
||||
strict: string
|
||||
reactionsEnabled: string
|
||||
inputPosition: "top" | "bottom"
|
||||
lang: string
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +79,7 @@ document.addEventListener("nav", () => {
|
||||
giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict)
|
||||
giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled)
|
||||
giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition)
|
||||
|
||||
giscusScript.setAttribute("data-lang", giscusContainer.dataset.lang)
|
||||
const theme = document.documentElement.getAttribute("saved-theme")
|
||||
if (theme) {
|
||||
giscusScript.setAttribute("data-theme", getThemeUrl(getThemeName(theme)))
|
||||
|
||||
@@ -68,30 +68,6 @@ type TweenNode = {
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
// workaround for pixijs webgpu issue: https://github.com/pixijs/pixijs/issues/11389
|
||||
async function determineGraphicsAPI(): Promise<"webgpu" | "webgl"> {
|
||||
const adapter = await navigator.gpu?.requestAdapter().catch(() => null)
|
||||
const device = adapter && (await adapter.requestDevice().catch(() => null))
|
||||
if (!device) {
|
||||
return "webgl"
|
||||
}
|
||||
|
||||
const canvas = document.createElement("canvas")
|
||||
const gl =
|
||||
(canvas.getContext("webgl2") as WebGL2RenderingContext | null) ??
|
||||
(canvas.getContext("webgl") as WebGLRenderingContext | null)
|
||||
|
||||
// we have to return webgl so pixijs automatically falls back to canvas
|
||||
if (!gl) {
|
||||
return "webgl"
|
||||
}
|
||||
|
||||
const webglMaxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
|
||||
const webgpuMaxTextures = device.limits.maxSampledTexturesPerShaderStage
|
||||
|
||||
return webglMaxTextures === webgpuMaxTextures ? "webgpu" : "webgl"
|
||||
}
|
||||
|
||||
async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
const slug = simplifySlug(fullSlug)
|
||||
const visited = getVisited()
|
||||
@@ -373,7 +349,6 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
tweens.forEach((tween) => tween.stop())
|
||||
tweens.clear()
|
||||
|
||||
const pixiPreference = await determineGraphicsAPI()
|
||||
const app = new Application()
|
||||
await app.init({
|
||||
width,
|
||||
@@ -382,7 +357,7 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
autoStart: false,
|
||||
autoDensity: true,
|
||||
backgroundAlpha: 0,
|
||||
preference: pixiPreference,
|
||||
preference: "webgpu",
|
||||
resolution: window.devicePixelRatio,
|
||||
eventMode: "static",
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import FlexSearch from "flexsearch"
|
||||
import FlexSearch, { DefaultDocumentSearchResults } from "flexsearch"
|
||||
import { ContentDetails } from "../../plugins/emitters/contentIndex"
|
||||
import { registerEscapeHandler, removeAllChildren } from "./util"
|
||||
import { FullSlug, normalizeRelativeURLs, resolveRelative } from "../../util/path"
|
||||
@@ -9,15 +9,21 @@ interface Item {
|
||||
title: string
|
||||
content: string
|
||||
tags: string[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
// Can be expanded with things like "term" in the future
|
||||
type SearchType = "basic" | "tags"
|
||||
let searchType: SearchType = "basic"
|
||||
let currentSearchTerm: string = ""
|
||||
const encoder = (str: string) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])/)
|
||||
const encoder = (str: string) => {
|
||||
return str
|
||||
.toLowerCase()
|
||||
.split(/\s+/)
|
||||
.filter((token) => token.length > 0)
|
||||
}
|
||||
|
||||
let index = new FlexSearch.Document<Item>({
|
||||
charset: "latin:extra",
|
||||
encode: encoder,
|
||||
document: {
|
||||
id: "id",
|
||||
@@ -220,7 +226,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
|
||||
// If search is active, then we will render the first result and display accordingly
|
||||
if (!container.classList.contains("active")) return
|
||||
if (e.key === "Enter") {
|
||||
if (e.key === "Enter" && !e.isComposing) {
|
||||
// If result has focus, navigate to that one, otherwise pick first result
|
||||
if (results.contains(document.activeElement)) {
|
||||
const active = document.activeElement as HTMLInputElement
|
||||
@@ -397,7 +403,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
searchLayout.classList.toggle("display-results", currentSearchTerm !== "")
|
||||
searchType = currentSearchTerm.startsWith("#") ? "tags" : "basic"
|
||||
|
||||
let searchResults: FlexSearch.SimpleDocumentSearchResultSetUnit[]
|
||||
let searchResults: DefaultDocumentSearchResults<Item>
|
||||
if (searchType === "tags") {
|
||||
currentSearchTerm = currentSearchTerm.substring(1).trim()
|
||||
const separatorIndex = currentSearchTerm.indexOf(" ")
|
||||
@@ -410,7 +416,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
// return at least 10000 documents, so it is enough to filter them by tag (implemented in flexsearch)
|
||||
limit: Math.max(numSearchResults, 10000),
|
||||
index: ["title", "content"],
|
||||
tag: tag,
|
||||
tag: { tags: tag },
|
||||
})
|
||||
for (let searchResult of searchResults) {
|
||||
searchResult.result = searchResult.result.slice(0, numSearchResults)
|
||||
|
||||
@@ -239,7 +239,7 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
margin-top: 0;
|
||||
background-color: var(--light);
|
||||
max-width: 100vw;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
transform: translateX(-100vw);
|
||||
transition:
|
||||
transform 200ms ease,
|
||||
@@ -265,6 +265,6 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
|
||||
.mobile-no-scroll {
|
||||
@media all and ($mobile) {
|
||||
overflow: hidden;
|
||||
overscroll-behavior: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,24 +8,23 @@
|
||||
}
|
||||
|
||||
& > .search-button {
|
||||
background-color: color-mix(in srgb, var(--lightgray) 60%, var(--light));
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
border: 1px var(--lightgray) solid;
|
||||
border-radius: 4px;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
height: 2rem;
|
||||
padding: 0;
|
||||
padding: 0 1rem 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: inherit;
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
justify-content: space-between;
|
||||
|
||||
& > p {
|
||||
display: inline;
|
||||
padding: 0 1rem;
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
& svg {
|
||||
@@ -36,7 +35,7 @@
|
||||
|
||||
.search-path {
|
||||
stroke: var(--darkgray);
|
||||
stroke-width: 2px;
|
||||
stroke-width: 1.5px;
|
||||
transition: stroke 0.5s ease;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user