From 12904ab7960edc3bedd77c65cf5e6a5d599d882d Mon Sep 17 00:00:00 2001 From: Xinyang Yu <47915643+xy-241@users.noreply.github.com> Date: Fri, 9 Aug 2024 09:00:20 +0800 Subject: [PATCH 1/7] docs: Adds back Xinyang's cs garden to showcase (#1323) adding back my garden which was deleted from the cleanup showcase --- docs/showcase.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/showcase.md b/docs/showcase.md index 8730c35d3..5fd71336a 100644 --- a/docs/showcase.md +++ b/docs/showcase.md @@ -25,5 +25,6 @@ Want to see what Quartz can do? Here are some cool community gardens: - [🪴Aster's notebook](https://notes.asterhu.com) - [Gatekeeper Wiki](https://www.gatekeeper.wiki) - [Ellie's Notes](https://ellie.wtf) +- [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja) If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/v4/docs/showcase.md)! From 27a41abb62cc9005ed4234bdb02f38b6cfeedec3 Mon Sep 17 00:00:00 2001 From: Andrew <80933354+ndrooo@users.noreply.github.com> Date: Thu, 8 Aug 2024 21:07:47 -0400 Subject: [PATCH 2/7] feat(toc,explorer): add accessibility for toggle (#1327) * Restore focus highlight on explorer toggle button. Remove `unset: all` declaration causing `outline` property to be unset. This allows the default browser focus highlight to be shown. * Fix semantics of expandable sections (explorer, toc). This adds the appropriate aria attributes for the [disclosure pattern](https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/examples/disclosure-image-description/#javascriptandcsssourcecode) and uses `visibility: hidden` to remove the hidden elements from the focus order without disrupting the animations. Further work is needed on the tree view nodes. * Run prettier for SCSS files. --- quartz/components/Explorer.tsx | 2 ++ quartz/components/TableOfContents.tsx | 8 +++++++- quartz/components/scripts/explorer.inline.ts | 4 ++++ quartz/components/scripts/toc.inline.ts | 4 ++++ quartz/components/styles/explorer.scss | 13 +++++++++++-- quartz/components/styles/toc.scss | 12 +++++++++++- 6 files changed, 39 insertions(+), 4 deletions(-) diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx index 24583a1f7..e4c3dfae5 100644 --- a/quartz/components/Explorer.tsx +++ b/quartz/components/Explorer.tsx @@ -91,6 +91,8 @@ export default ((userOpts?: Partial) => { data-collapsed={opts.folderDefaultState} data-savestate={opts.useSavedState} data-tree={jsonTree} + aria-controls="explorer-content" + aria-expanded={opts.folderDefaultState === "open"} >

{opts.title ?? i18n(cfg.locale).components.explorer.title}

-

{i18n(cfg.locale).components.tableOfContents.title}

{ function toggleExplorer(this: HTMLElement) { this.classList.toggle("collapsed") + this.setAttribute( + "aria-expanded", + this.getAttribute("aria-expanded") === "true" ? "false" : "true", + ) const content = this.nextElementSibling as MaybeHTMLElement if (!content) return diff --git a/quartz/components/scripts/toc.inline.ts b/quartz/components/scripts/toc.inline.ts index 546859ed3..acc81b20d 100644 --- a/quartz/components/scripts/toc.inline.ts +++ b/quartz/components/scripts/toc.inline.ts @@ -16,6 +16,10 @@ const observer = new IntersectionObserver((entries) => { function toggleToc(this: HTMLElement) { this.classList.toggle("collapsed") + this.setAttribute( + "aria-expanded", + this.getAttribute("aria-expanded") === "true" ? "false" : "true", + ) const content = this.nextElementSibling as HTMLElement | undefined if (!content) return content.classList.toggle("collapsed") diff --git a/quartz/components/styles/explorer.scss b/quartz/components/styles/explorer.scss index d4875e7c9..2f94b158c 100644 --- a/quartz/components/styles/explorer.scss +++ b/quartz/components/styles/explorer.scss @@ -1,7 +1,6 @@ @use "../../styles/variables.scss" as *; button#explorer { - all: unset; background-color: transparent; border: none; text-align: left; @@ -46,8 +45,18 @@ button#explorer { list-style: none; overflow: hidden; max-height: none; - transition: max-height 0.35s ease; + transition: + max-height 0.35s ease, + visibility 0s linear 0s; margin-top: 0.5rem; + visibility: visible; + + &.collapsed { + transition: + max-height 0.35s ease, + visibility 0s linear 0.35s; + visibility: hidden; + } &.collapsed > .overflow::after { opacity: 0; diff --git a/quartz/components/styles/toc.scss b/quartz/components/styles/toc.scss index 27ff62a40..6845812f5 100644 --- a/quartz/components/styles/toc.scss +++ b/quartz/components/styles/toc.scss @@ -29,8 +29,18 @@ button#toc { list-style: none; overflow: hidden; max-height: none; - transition: max-height 0.5s ease; + transition: + max-height 0.5s ease, + visibility 0s linear 0s; position: relative; + visibility: visible; + + &.collapsed { + transition: + max-height 0.5s ease, + visibility 0s linear 0.5s; + visibility: hidden; + } &.collapsed > .overflow::after { opacity: 0; From 9acaa1c8ac8c8afd3fa08d3b1f58a60006fcfc6f Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Thu, 8 Aug 2024 18:19:45 -0700 Subject: [PATCH 3/7] feat: custom global latex macros (closes #1325) --- docs/plugins/Latex.md | 1 + quartz/plugins/transformers/latex.ts | 10 ++++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/plugins/Latex.md b/docs/plugins/Latex.md index ac4367841..236cbeca4 100644 --- a/docs/plugins/Latex.md +++ b/docs/plugins/Latex.md @@ -12,6 +12,7 @@ This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more This plugin accepts the following configuration options: - `renderEngine`: the engine to use to render LaTeX equations. Can be `"katex"` for [KaTeX](https://katex.org/) or `"mathjax"` for [MathJax](https://www.mathjax.org/) [SVG rendering](https://docs.mathjax.org/en/latest/output/svg.html). Defaults to KaTeX. +- `customMacros`: custom macros for all LaTeX blocks. It takes the form of a key-value pair where the key is a new command name and the value is the expansion of the macro. For example: `{"\\R": "\\mathbb{R}"}` ## API diff --git a/quartz/plugins/transformers/latex.ts b/quartz/plugins/transformers/latex.ts index c9f6bff0d..757333abb 100644 --- a/quartz/plugins/transformers/latex.ts +++ b/quartz/plugins/transformers/latex.ts @@ -5,10 +5,16 @@ import { QuartzTransformerPlugin } from "../types" interface Options { renderEngine: "katex" | "mathjax" + customMacros: MacroType +} + +interface MacroType { + [key: string]: string } export const Latex: QuartzTransformerPlugin = (opts?: Options) => { const engine = opts?.renderEngine ?? "katex" + const macros = opts?.customMacros ?? {} return { name: "Latex", markdownPlugins() { @@ -16,9 +22,9 @@ export const Latex: QuartzTransformerPlugin = (opts?: Options) => { }, htmlPlugins() { if (engine === "katex") { - return [[rehypeKatex, { output: "html" }]] + return [[rehypeKatex, { output: "html", macros }]] } else { - return [rehypeMathjax] + return [[rehypeMathjax, { macros }]] } }, externalResources() { From 39eebca3cfa8adf504d08d54e6fc05912641b40f Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Thu, 8 Aug 2024 18:28:13 -0700 Subject: [PATCH 4/7] chore: ts fixes --- quartz/plugins/transformers/citations.ts | 4 ++-- quartz/plugins/transformers/description.ts | 2 +- quartz/plugins/transformers/frontmatter.ts | 2 +- quartz/plugins/transformers/gfm.ts | 4 +--- quartz/plugins/transformers/lastmod.ts | 4 +--- quartz/plugins/transformers/latex.ts | 2 +- quartz/plugins/transformers/links.ts | 3 +-- quartz/plugins/transformers/ofm.ts | 4 +--- quartz/plugins/transformers/oxhugofm.ts | 4 +--- quartz/plugins/transformers/syntax.ts | 6 ++---- quartz/plugins/transformers/toc.ts | 4 +--- 11 files changed, 13 insertions(+), 26 deletions(-) diff --git a/quartz/plugins/transformers/citations.ts b/quartz/plugins/transformers/citations.ts index bb302e437..5242f37c5 100644 --- a/quartz/plugins/transformers/citations.ts +++ b/quartz/plugins/transformers/citations.ts @@ -17,7 +17,7 @@ const defaultOptions: Options = { csl: "apa", } -export const Citations: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const Citations: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "Citations", @@ -38,7 +38,7 @@ export const Citations: QuartzTransformerPlugin | undefined> = // using https://github.com/syntax-tree/unist-util-visit as they're just anochor links plugins.push(() => { return (tree, _file) => { - visit(tree, "element", (node, index, parent) => { + visit(tree, "element", (node, _index, _parent) => { if (node.tagName === "a" && node.properties?.href?.startsWith("#bib")) { node.properties["data-no-popover"] = true } diff --git a/quartz/plugins/transformers/description.ts b/quartz/plugins/transformers/description.ts index 5900745c4..c7e592ee9 100644 --- a/quartz/plugins/transformers/description.ts +++ b/quartz/plugins/transformers/description.ts @@ -18,7 +18,7 @@ const urlRegex = new RegExp( "g", ) -export const Description: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const Description: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "Description", diff --git a/quartz/plugins/transformers/frontmatter.ts b/quartz/plugins/transformers/frontmatter.ts index 5ab239a31..70a60d8b5 100644 --- a/quartz/plugins/transformers/frontmatter.ts +++ b/quartz/plugins/transformers/frontmatter.ts @@ -40,7 +40,7 @@ function coerceToArray(input: string | string[]): string[] | undefined { .map((tag: string | number) => tag.toString()) } -export const FrontMatter: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const FrontMatter: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "FrontMatter", diff --git a/quartz/plugins/transformers/gfm.ts b/quartz/plugins/transformers/gfm.ts index 48681ff77..eec26f7b9 100644 --- a/quartz/plugins/transformers/gfm.ts +++ b/quartz/plugins/transformers/gfm.ts @@ -14,9 +14,7 @@ const defaultOptions: Options = { linkHeadings: true, } -export const GitHubFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const GitHubFlavoredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "GitHubFlavoredMarkdown", diff --git a/quartz/plugins/transformers/lastmod.ts b/quartz/plugins/transformers/lastmod.ts index 2c7b9ce47..fe8c01bcf 100644 --- a/quartz/plugins/transformers/lastmod.ts +++ b/quartz/plugins/transformers/lastmod.ts @@ -27,9 +27,7 @@ function coerceDate(fp: string, d: any): Date { } type MaybeDate = undefined | string | number -export const CreatedModifiedDate: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const CreatedModifiedDate: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "CreatedModifiedDate", diff --git a/quartz/plugins/transformers/latex.ts b/quartz/plugins/transformers/latex.ts index 757333abb..28b4d506a 100644 --- a/quartz/plugins/transformers/latex.ts +++ b/quartz/plugins/transformers/latex.ts @@ -12,7 +12,7 @@ interface MacroType { [key: string]: string } -export const Latex: QuartzTransformerPlugin = (opts?: Options) => { +export const Latex: QuartzTransformerPlugin> = (opts) => { const engine = opts?.renderEngine ?? "katex" const macros = opts?.customMacros ?? {} return { diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index 280581828..b6a2c9122 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -8,7 +8,6 @@ import { simplifySlug, splitAnchor, transformLink, - joinSegments, } from "../../util/path" import path from "path" import { visit } from "unist-util-visit" @@ -33,7 +32,7 @@ const defaultOptions: Options = { externalLinkIcon: true, } -export const CrawlLinks: QuartzTransformerPlugin | undefined> = (userOpts) => { +export const CrawlLinks: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "LinkProcessing", diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index a406c865f..0dea89384 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -136,9 +136,7 @@ const wikilinkImageEmbedRegex = new RegExp( /^(?(?!^\d*x?\d*$).*?)?(\|?\s*?(?\d+)(x(?\d+))?)?$/, ) -export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } const mdastToHtml = (ast: PhrasingContent | Paragraph) => { diff --git a/quartz/plugins/transformers/oxhugofm.ts b/quartz/plugins/transformers/oxhugofm.ts index 6e70bb190..cdbffcffd 100644 --- a/quartz/plugins/transformers/oxhugofm.ts +++ b/quartz/plugins/transformers/oxhugofm.ts @@ -47,9 +47,7 @@ const quartzLatexRegex = new RegExp(/\$\$[\s\S]*?\$\$|\$.*?\$/, "g") * markdown to make it compatible with quartz but the list of changes applied it * is not exhaustive. * */ -export const OxHugoFlavouredMarkdown: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const OxHugoFlavouredMarkdown: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "OxHugoFlavouredMarkdown", diff --git a/quartz/plugins/transformers/syntax.ts b/quartz/plugins/transformers/syntax.ts index f11734e5f..5d3aae0d8 100644 --- a/quartz/plugins/transformers/syntax.ts +++ b/quartz/plugins/transformers/syntax.ts @@ -19,10 +19,8 @@ const defaultOptions: Options = { keepBackground: false, } -export const SyntaxHighlighting: QuartzTransformerPlugin = ( - userOpts?: Partial, -) => { - const opts: Partial = { ...defaultOptions, ...userOpts } +export const SyntaxHighlighting: QuartzTransformerPlugin> = (userOpts) => { + const opts: CodeOptions = { ...defaultOptions, ...userOpts } return { name: "SyntaxHighlighting", diff --git a/quartz/plugins/transformers/toc.ts b/quartz/plugins/transformers/toc.ts index bfc2f9877..791547b6a 100644 --- a/quartz/plugins/transformers/toc.ts +++ b/quartz/plugins/transformers/toc.ts @@ -25,9 +25,7 @@ interface TocEntry { } const slugAnchor = new Slugger() -export const TableOfContents: QuartzTransformerPlugin | undefined> = ( - userOpts, -) => { +export const TableOfContents: QuartzTransformerPlugin> = (userOpts) => { const opts = { ...defaultOptions, ...userOpts } return { name: "TableOfContents", From 2db735a150e9749ba4a900deb4f82ed5d4775b70 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Thu, 8 Aug 2024 18:38:17 -0700 Subject: [PATCH 5/7] docs: recommend at least node 20 in gh --- docs/hosting.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/hosting.md b/docs/hosting.md index 4bbaeb593..013027533 100644 --- a/docs/hosting.md +++ b/docs/hosting.md @@ -61,6 +61,7 @@ jobs: with: fetch-depth: 0 # Fetch all history for git info - uses: actions/setup-node@v4 + node-version: 22 - name: Install Dependencies run: npm ci - name: Build Quartz From e89c395f7c8cabffb880ce36cc27926667b608de Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Thu, 8 Aug 2024 19:17:20 -0700 Subject: [PATCH 6/7] fix: unmemoize explorer on rebuild (closes #1077) --- quartz/build.ts | 21 +++++++++++++++------ quartz/components/Explorer.tsx | 12 +++++++----- quartz/util/ctx.ts | 1 + 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/quartz/build.ts b/quartz/build.ts index 972a7e850..342a27c92 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -38,8 +38,13 @@ type BuildData = { type FileEvent = "add" | "change" | "delete" +function newBuildId() { + return new Date().toISOString() +} + async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { const ctx: BuildCtx = { + buildId: newBuildId(), argv, cfg, allSlugs: [], @@ -167,6 +172,7 @@ async function partialRebuildFromEntrypoint( const perf = new PerfTimer() console.log(chalk.yellow("Detected change, rebuilding...")) + ctx.buildId = newBuildId() // UPDATE DEP GRAPH const fp = joinSegments(argv.directory, toPosixPath(filepath)) as FilePath @@ -363,14 +369,10 @@ async function rebuildFromEntrypoint( const perf = new PerfTimer() console.log(chalk.yellow("Detected change, rebuilding...")) + ctx.buildId = newBuildId() + try { const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp)) - - const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] - .filter((fp) => !toRemove.has(fp)) - .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) - - ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] const parsedContent = await parseMarkdown(ctx, filesToRebuild) for (const content of parsedContent) { const [_tree, vfile] = content @@ -384,6 +386,13 @@ async function rebuildFromEntrypoint( const parsedFiles = [...contentMap.values()] const filteredContent = filterContent(ctx, parsedFiles) + // re-update slugs + const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])] + .filter((fp) => !toRemove.has(fp)) + .map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath)) + + ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] + // TODO: we can probably traverse the link graph to figure out what's safe to delete here // instead of just deleting everything await rimraf(path.join(argv.output, ".*"), { glob: true }) diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx index e4c3dfae5..ec7c48ef7 100644 --- a/quartz/components/Explorer.tsx +++ b/quartz/components/Explorer.tsx @@ -44,12 +44,9 @@ export default ((userOpts?: Partial) => { // memoized let fileTree: FileNode let jsonTree: string + let lastBuildId: string = "" function constructFileTree(allFiles: QuartzPluginData[]) { - if (fileTree) { - return - } - // Construct tree from allFiles fileTree = new FileNode("") allFiles.forEach((file) => fileTree.add(file)) @@ -76,12 +73,17 @@ export default ((userOpts?: Partial) => { } const Explorer: QuartzComponent = ({ + ctx, cfg, allFiles, displayClass, fileData, }: QuartzComponentProps) => { - constructFileTree(allFiles) + if (ctx.buildId !== lastBuildId) { + lastBuildId = ctx.buildId + constructFileTree(allFiles) + } + return (