From 3518ca9e2a04f326eda25ada2393a4bbfde10738 Mon Sep 17 00:00:00 2001 From: Alq Date: Sun, 11 Feb 2024 21:43:08 +0300 Subject: [PATCH 1/9] feat(i18n): localize the min read string (#838) * feat(i18n): localize the min read string fixes #825 * chore: format --- quartz/components/ContentMeta.tsx | 8 ++++++-- quartz/i18n/locales/ar-SA.ts | 8 ++++++++ quartz/i18n/locales/de-DE.ts | 3 +++ quartz/i18n/locales/definition.ts | 3 +++ quartz/i18n/locales/en-US.ts | 3 +++ quartz/i18n/locales/es-ES.ts | 3 +++ quartz/i18n/locales/fr-FR.ts | 3 +++ quartz/i18n/locales/ja-JP.ts | 3 +++ quartz/i18n/locales/nl-NL.ts | 3 +++ quartz/i18n/locales/ro-RO.ts | 3 +++ quartz/i18n/locales/uk-UA.ts | 3 +++ 11 files changed, 41 insertions(+), 2 deletions(-) diff --git a/quartz/components/ContentMeta.tsx b/quartz/components/ContentMeta.tsx index 6cd083e69..bcbe4285d 100644 --- a/quartz/components/ContentMeta.tsx +++ b/quartz/components/ContentMeta.tsx @@ -2,6 +2,7 @@ import { formatDate, getDate } from "./Date" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import readingTime from "reading-time" import { classNames } from "../util/lang" +import { i18n } from "../i18n" interface ContentMetaOptions { /** @@ -30,8 +31,11 @@ export default ((opts?: Partial) => { // Display reading time if enabled if (options.showReadingTime) { - const { text: timeTaken, words: _words } = readingTime(text) - segments.push(timeTaken) + const { minutes, words: _words } = readingTime(text) + const displayedTime = i18n(cfg.locale).components.contentMeta.readingTime({ + minutes: Math.ceil(minutes), + }) + segments.push(displayedTime) } return

{segments.join(", ")}

diff --git a/quartz/i18n/locales/ar-SA.ts b/quartz/i18n/locales/ar-SA.ts index d8efeffef..f7048103f 100644 --- a/quartz/i18n/locales/ar-SA.ts +++ b/quartz/i18n/locales/ar-SA.ts @@ -53,6 +53,14 @@ export default { tableOfContents: { title: "فهرس المحتويات", }, + contentMeta: { + readingTime: ({ minutes }) => + minutes == 1 + ? `دقيقة أو أقل للقراءة` + : minutes == 2 + ? `دقيقتان للقراءة` + : `${minutes} دقائق للقراءة`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/de-DE.ts b/quartz/i18n/locales/de-DE.ts index f2125bf60..e3821944b 100644 --- a/quartz/i18n/locales/de-DE.ts +++ b/quartz/i18n/locales/de-DE.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Inhaltsverzeichnis", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/definition.ts b/quartz/i18n/locales/definition.ts index baf2a5875..1d5d3dda6 100644 --- a/quartz/i18n/locales/definition.ts +++ b/quartz/i18n/locales/definition.ts @@ -55,6 +55,9 @@ export interface Translation { tableOfContents: { title: string } + contentMeta: { + readingTime: (variables: { minutes: number }) => string + } } pages: { rss: { diff --git a/quartz/i18n/locales/en-US.ts b/quartz/i18n/locales/en-US.ts index 3ba28a0d5..4a308d79a 100644 --- a/quartz/i18n/locales/en-US.ts +++ b/quartz/i18n/locales/en-US.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Table of Contents", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/es-ES.ts b/quartz/i18n/locales/es-ES.ts index 92a74a03c..f59d201a3 100644 --- a/quartz/i18n/locales/es-ES.ts +++ b/quartz/i18n/locales/es-ES.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Tabla de Contenidos", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/fr-FR.ts b/quartz/i18n/locales/fr-FR.ts index fee1ad921..8b7229201 100644 --- a/quartz/i18n/locales/fr-FR.ts +++ b/quartz/i18n/locales/fr-FR.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Table des Matières", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/ja-JP.ts b/quartz/i18n/locales/ja-JP.ts index f684c36b3..d429db411 100644 --- a/quartz/i18n/locales/ja-JP.ts +++ b/quartz/i18n/locales/ja-JP.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "目次", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/nl-NL.ts b/quartz/i18n/locales/nl-NL.ts index b40362355..3ff3e8cd9 100644 --- a/quartz/i18n/locales/nl-NL.ts +++ b/quartz/i18n/locales/nl-NL.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Inhoudsopgave", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/ro-RO.ts b/quartz/i18n/locales/ro-RO.ts index 39f1344be..a1c216ded 100644 --- a/quartz/i18n/locales/ro-RO.ts +++ b/quartz/i18n/locales/ro-RO.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Cuprins", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { diff --git a/quartz/i18n/locales/uk-UA.ts b/quartz/i18n/locales/uk-UA.ts index d60b1f8cf..c997a6972 100644 --- a/quartz/i18n/locales/uk-UA.ts +++ b/quartz/i18n/locales/uk-UA.ts @@ -53,6 +53,9 @@ export default { tableOfContents: { title: "Зміст", }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, }, pages: { rss: { From af5f5abad4c3b01315a8ccda1c2c9aef9d26d695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Silviu=20Loren=C8=9B?= <124451350+smilorent@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:51:10 +0200 Subject: [PATCH 2/9] docs: add documentation for Umami analytics integration (#846) --- docs/configuration.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/configuration.md b/docs/configuration.md index b0c850623..366430cc2 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -25,8 +25,9 @@ This part of the configuration concerns anything that can affect the whole site. - `enablePopovers`: whether to enable [[popover previews]] on your site. - `analytics`: what to use for analytics on your site. Values can be - `null`: don't use analytics; - - `{ provider: 'plausible' }`: use [Plausible](https://plausible.io/), a privacy-friendly alternative to Google Analytics; or - - `{ provider: 'google', tagId: }`: use Google Analytics + - `{ provider: 'google', tagId: '' }`: use Google Analytics; + - `{ provider: 'plausible' }` (managed) or `{ provider: 'plausible', host: '' }` (self-hosted): use [Plausible](https://plausible.io/); + - `{ provider: 'umami', host: '', websiteId: '' }`: use [Umami](https://umami.is/); - `locale`: used for [[i18n]] and date formatting - `baseUrl`: this is used for sitemaps and RSS feeds that require an absolute URL to know where the canonical 'home' of your site lives. This is normally the deployed URL of your site (e.g. `quartz.jzhao.xyz` for this site). Do not include the protocol (i.e. `https://`) or any leading or trailing slashes. - This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz` From ab0e20b4d0ad1e650126ffd0afa7d0ed6bd46da2 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sun, 11 Feb 2024 10:57:24 -0800 Subject: [PATCH 3/9] chore: refactor out and export endsWith --- quartz/components/Head.tsx | 2 +- quartz/components/pages/FolderContent.tsx | 6 +-- quartz/plugins/emitters/folderPage.tsx | 6 +-- quartz/plugins/transformers/links.ts | 4 +- quartz/util/path.ts | 49 ++++++++++++----------- 5 files changed, 34 insertions(+), 33 deletions(-) diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index dae81c731..8292acc05 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -1,5 +1,5 @@ import { i18n } from "../i18n" -import { FullSlug, _stripSlashes, joinSegments, pathToRoot } from "../util/path" +import { FullSlug, joinSegments, pathToRoot } from "../util/path" import { JSResourceToScriptElement } from "../util/resources" import { QuartzComponentConstructor, QuartzComponentProps } from "./types" diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index b954ea21c..d3f28ddf1 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -3,7 +3,7 @@ import path from "path" import style from "../styles/listPage.scss" import { PageList } from "../PageList" -import { _stripSlashes, simplifySlug } from "../../util/path" +import { stripSlashes, simplifySlug } from "../../util/path" import { Root } from "hast" import { htmlToJsx } from "../../util/jsx" import { i18n } from "../../i18n" @@ -24,9 +24,9 @@ export default ((opts?: Partial) => { function FolderContent(props: QuartzComponentProps) { const { tree, fileData, allFiles, cfg } = props - const folderSlug = _stripSlashes(simplifySlug(fileData.slug!)) + const folderSlug = stripSlashes(simplifySlug(fileData.slug!)) const allPagesInFolder = allFiles.filter((file) => { - const fileSlug = _stripSlashes(simplifySlug(file.slug!)) + const fileSlug = stripSlashes(simplifySlug(file.slug!)) const prefixed = fileSlug.startsWith(folderSlug) && fileSlug !== folderSlug const folderParts = folderSlug.split(path.posix.sep) const fileParts = fileSlug.split(path.posix.sep) diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index 7a62cda56..690fa56f7 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -10,7 +10,7 @@ import { FilePath, FullSlug, SimpleSlug, - _stripSlashes, + stripSlashes, joinSegments, pathToRoot, simplifySlug, @@ -38,7 +38,7 @@ export const FolderPage: QuartzEmitterPlugin> = (userOpt getQuartzComponents() { return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, - async getDependencyGraph(ctx, content, _resources) { + async getDependencyGraph(_ctx, _content, _resources) { // Example graph: // nested/file.md --> nested/file.html // \-------> nested/index.html @@ -75,7 +75,7 @@ export const FolderPage: QuartzEmitterPlugin> = (userOpt ) for (const [tree, file] of content) { - const slug = _stripSlashes(simplifySlug(file.data.slug!)) as SimpleSlug + const slug = stripSlashes(simplifySlug(file.data.slug!)) as SimpleSlug if (folders.has(slug)) { folderDescriptions[slug] = [tree, file] } diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index 1ba0c8e58..2d43be1b2 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -4,7 +4,7 @@ import { RelativeURL, SimpleSlug, TransformOptions, - _stripSlashes, + stripSlashes, simplifySlug, splitAnchor, transformLink, @@ -115,7 +115,7 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = } // need to decodeURIComponent here as WHATWG URL percent-encodes everything - const full = decodeURIComponent(_stripSlashes(destCanonical, true)) as FullSlug + const full = decodeURIComponent(stripSlashes(destCanonical, true)) as FullSlug const simple = simplifySlug(full) outgoing.add(simple) node.properties["data-slug"] = full diff --git a/quartz/util/path.ts b/quartz/util/path.ts index 5cd79ba5f..dceb89bfa 100644 --- a/quartz/util/path.ts +++ b/quartz/util/path.ts @@ -23,22 +23,22 @@ export type FullSlug = SlugLike<"full"> export function isFullSlug(s: string): s is FullSlug { const validStart = !(s.startsWith(".") || s.startsWith("/")) const validEnding = !s.endsWith("/") - return validStart && validEnding && !_containsForbiddenCharacters(s) + return validStart && validEnding && !containsForbiddenCharacters(s) } /** Shouldn't be a relative path and shouldn't have `/index` as an ending or a file extension. It _can_ however have a trailing slash to indicate a folder path. */ export type SimpleSlug = SlugLike<"simple"> export function isSimpleSlug(s: string): s is SimpleSlug { const validStart = !(s.startsWith(".") || (s.length > 1 && s.startsWith("/"))) - const validEnding = !(s.endsWith("/index") || s === "index") - return validStart && !_containsForbiddenCharacters(s) && validEnding && !_hasFileExtension(s) + const validEnding = !endsWith(s, "index") + return validStart && !containsForbiddenCharacters(s) && validEnding && !_hasFileExtension(s) } /** Can be found on `href`s but can also be constructed for client-side navigation (e.g. search and graph) */ export type RelativeURL = SlugLike<"relative"> export function isRelativeURL(s: string): s is RelativeURL { const validStart = /^\.{1,2}/.test(s) - const validEnding = !(s.endsWith("/index") || s === "index") + const validEnding = !endsWith(s, "index") return validStart && validEnding && ![".md", ".html"].includes(_getFileExtension(s) ?? "") } @@ -63,7 +63,7 @@ function sluggify(s: string): string { } export function slugifyFilePath(fp: FilePath, excludeExt?: boolean): FullSlug { - fp = _stripSlashes(fp) as FilePath + fp = stripSlashes(fp) as FilePath let ext = _getFileExtension(fp) const withoutFileExt = fp.replace(new RegExp(ext + "$"), "") if (excludeExt || [".md", ".html", undefined].includes(ext)) { @@ -73,7 +73,7 @@ export function slugifyFilePath(fp: FilePath, excludeExt?: boolean): FullSlug { let slug = sluggify(withoutFileExt) // treat _index as index - if (_endsWith(slug, "_index")) { + if (endsWith(slug, "_index")) { slug = slug.replace(/_index$/, "index") } @@ -81,21 +81,21 @@ export function slugifyFilePath(fp: FilePath, excludeExt?: boolean): FullSlug { } export function simplifySlug(fp: FullSlug): SimpleSlug { - const res = _stripSlashes(_trimSuffix(fp, "index"), true) + const res = stripSlashes(trimSuffix(fp, "index"), true) return (res.length === 0 ? "/" : res) as SimpleSlug } export function transformInternalLink(link: string): RelativeURL { let [fplike, anchor] = splitAnchor(decodeURI(link)) - const folderPath = _isFolderPath(fplike) + const folderPath = isFolderPath(fplike) let segments = fplike.split("/").filter((x) => x.length > 0) - let prefix = segments.filter(_isRelativeSegment).join("/") - let fp = segments.filter((seg) => !_isRelativeSegment(seg) && seg !== "").join("/") + let prefix = segments.filter(isRelativeSegment).join("/") + let fp = segments.filter((seg) => !isRelativeSegment(seg) && seg !== "").join("/") // manually add ext here as we want to not strip 'index' if it has an extension const simpleSlug = simplifySlug(slugifyFilePath(fp as FilePath)) - const joined = joinSegments(_stripSlashes(prefix), _stripSlashes(simpleSlug)) + const joined = joinSegments(stripSlashes(prefix), stripSlashes(simpleSlug)) const trail = folderPath ? "/" : "" const res = (_addRelativeToStart(joined) + trail + anchor) as RelativeURL return res @@ -206,8 +206,8 @@ export function transformLink(src: FullSlug, target: string, opts: TransformOpti if (opts.strategy === "relative") { return targetSlug as RelativeURL } else { - const folderTail = _isFolderPath(targetSlug) ? "/" : "" - const canonicalSlug = _stripSlashes(targetSlug.slice(".".length)) + const folderTail = isFolderPath(targetSlug) ? "/" : "" + const canonicalSlug = stripSlashes(targetSlug.slice(".".length)) let [targetCanonical, targetAnchor] = splitAnchor(canonicalSlug) if (opts.strategy === "shortest") { @@ -230,28 +230,29 @@ export function transformLink(src: FullSlug, target: string, opts: TransformOpti } } -function _isFolderPath(fplike: string): boolean { +// path helpers +function isFolderPath(fplike: string): boolean { return ( fplike.endsWith("/") || - _endsWith(fplike, "index") || - _endsWith(fplike, "index.md") || - _endsWith(fplike, "index.html") + endsWith(fplike, "index") || + endsWith(fplike, "index.md") || + endsWith(fplike, "index.html") ) } -function _endsWith(s: string, suffix: string): boolean { +export function endsWith(s: string, suffix: string): boolean { return s === suffix || s.endsWith("/" + suffix) } -function _trimSuffix(s: string, suffix: string): string { - if (_endsWith(s, suffix)) { +function trimSuffix(s: string, suffix: string): string { + if (endsWith(s, suffix)) { s = s.slice(0, -suffix.length) } return s } -function _containsForbiddenCharacters(s: string): boolean { - return s.includes(" ") || s.includes("#") || s.includes("?") +function containsForbiddenCharacters(s: string): boolean { + return s.includes(" ") || s.includes("#") || s.includes("?") || s.includes("&") } function _hasFileExtension(s: string): boolean { @@ -262,11 +263,11 @@ function _getFileExtension(s: string): string | undefined { return s.match(/\.[A-Za-z0-9]+$/)?.[0] } -function _isRelativeSegment(s: string): boolean { +function isRelativeSegment(s: string): boolean { return /^\.{0,2}$/.test(s) } -export function _stripSlashes(s: string, onlyStripPrefix?: boolean): string { +export function stripSlashes(s: string, onlyStripPrefix?: boolean): string { if (s.startsWith("/")) { s = s.substring(1) } From b5295e0f261dd6dc7903bae2102115340ccd46dd Mon Sep 17 00:00:00 2001 From: Neel Shah Date: Mon, 12 Feb 2024 00:38:12 +0530 Subject: [PATCH 4/9] fix: breadcrumbs displayName issue for file names ending with index (#839) --- quartz/components/Breadcrumbs.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx index 3875f5e55..116f9523a 100644 --- a/quartz/components/Breadcrumbs.tsx +++ b/quartz/components/Breadcrumbs.tsx @@ -68,8 +68,8 @@ export default ((opts?: Partial) => { folderIndex = new Map() // construct the index for the first time for (const file of allFiles) { - if (file.slug?.endsWith("index")) { - const folderParts = file.slug?.split("/") + const folderParts = file.slug?.split("/") + if (folderParts?.at(-1) === "index") { // 2nd last to exclude the /index const folderName = folderParts?.at(-2) if (folderName) { From 2b39bd93f38414d7fb03458bbb51252ada194df0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Silviu=20Loren=C8=9B?= <124451350+smilorent@users.noreply.github.com> Date: Sun, 11 Feb 2024 21:23:58 +0200 Subject: [PATCH 5/9] feat(i18n): localize the `min read` string for the `ro-RO` locale (#847) * feat(i18n): localize `min read` string for `ro-RO` locale * chore: run Prettier on `quartz/i18n/locales/ro-RO.ts` --- quartz/i18n/locales/ro-RO.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quartz/i18n/locales/ro-RO.ts b/quartz/i18n/locales/ro-RO.ts index a1c216ded..556b18995 100644 --- a/quartz/i18n/locales/ro-RO.ts +++ b/quartz/i18n/locales/ro-RO.ts @@ -54,7 +54,8 @@ export default { title: "Cuprins", }, contentMeta: { - readingTime: ({ minutes }) => `${minutes} min read`, + readingTime: ({ minutes }) => + minutes == 1 ? `lectură de 1 minut` : `lectură de ${minutes} minute`, }, }, pages: { From 4a6a44950fbfb8cf0e60b62254fc38404c35a1b8 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sun, 11 Feb 2024 11:26:14 -0800 Subject: [PATCH 6/9] fix(breadcrumbs): folder index by full path rather than folder name (closes #676) --- quartz/components/Breadcrumbs.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx index 116f9523a..eab8a34e2 100644 --- a/quartz/components/Breadcrumbs.tsx +++ b/quartz/components/Breadcrumbs.tsx @@ -70,11 +70,7 @@ export default ((opts?: Partial) => { for (const file of allFiles) { const folderParts = file.slug?.split("/") if (folderParts?.at(-1) === "index") { - // 2nd last to exclude the /index - const folderName = folderParts?.at(-2) - if (folderName) { - folderIndex.set(folderName, file) - } + folderIndex.set(folderParts.slice(0, -1).join("/"), file) } } } @@ -88,7 +84,7 @@ export default ((opts?: Partial) => { let curPathSegment = slugParts[i] // Try to resolve frontmatter folder title - const currentFile = folderIndex?.get(curPathSegment) + const currentFile = folderIndex?.get(slugParts.slice(0, i + 1).join("/")) if (currentFile) { const title = currentFile.frontmatter!.title if (title !== "index") { From 998198cffb9bbcc8a75cd07310c06fabff6750bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 11 Feb 2024 11:27:16 -0800 Subject: [PATCH 7/9] chore(deps): bump esbuild-sass-plugin from 2.16.0 to 2.16.1 (#778) Bumps [esbuild-sass-plugin](https://github.com/glromeo/esbuild-sass-plugin) from 2.16.0 to 2.16.1. - [Release notes](https://github.com/glromeo/esbuild-sass-plugin/releases) - [Commits](https://github.com/glromeo/esbuild-sass-plugin/compare/v2.16.0...v2.16.1) --- updated-dependencies: - dependency-name: esbuild-sass-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1b6a4e033..e48812495 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "chokidar": "^3.5.3", "cli-spinner": "^0.2.10", "d3": "^7.8.5", - "esbuild-sass-plugin": "^2.16.0", + "esbuild-sass-plugin": "^2.16.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", "globby": "^14.0.0", @@ -2052,9 +2052,9 @@ } }, "node_modules/esbuild-sass-plugin": { - "version": "2.16.0", - "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.16.0.tgz", - "integrity": "sha512-mGCe9MxNYvZ+j77Q/QFO+rwUGA36mojDXkOhtVmoyz1zwYbMaNrtVrmXwwYDleS/UMKTNU3kXuiTtPiAD3K+Pw==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/esbuild-sass-plugin/-/esbuild-sass-plugin-2.16.1.tgz", + "integrity": "sha512-mBB2aEF0xk7yo+Q9pSUh8xYED/1O2wbAM6IauGkDrqy6pl9SbJNakLeLGXiNpNujWIudu8TJTZCv2L5AQYRXtA==", "dependencies": { "resolve": "^1.22.6", "sass": "^1.7.3" diff --git a/package.json b/package.json index 5c7570125..3235b5fa5 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "chokidar": "^3.5.3", "cli-spinner": "^0.2.10", "d3": "^7.8.5", - "esbuild-sass-plugin": "^2.16.0", + "esbuild-sass-plugin": "^2.16.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", "globby": "^14.0.0", From 389f2e8beee35c60da9b343883d0e09ca92f821b Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sun, 11 Feb 2024 12:11:52 -0800 Subject: [PATCH 8/9] fix(ofm): allow diacretic marks in tag regex (closes #830) --- quartz/plugins/transformers/ofm.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index 89b297b2e..e110e403f 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -118,7 +118,10 @@ const calloutLineRegex = new RegExp(/^> *\[\!\w+\][+-]?.*$/, "gm") // #(...) -> capturing group, tag itself must start with # // (?:[-_\p{L}\d\p{Z}])+ -> non-capturing group, non-empty string of (Unicode-aware) alpha-numeric characters and symbols, hyphens and/or underscores // (?:\/[-_\p{L}\d\p{Z}]+)*) -> non-capturing group, matches an arbitrary number of tag strings separated by "/" -const tagRegex = new RegExp(/(?:^| )#((?:[-_\p{L}\p{Emoji}\d])+(?:\/[-_\p{L}\p{Emoji}\d]+)*)/, "gu") +const tagRegex = new RegExp( + /(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/, + "gu", +) const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9]+)$/, "g") const ytLinkRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ const videoExtensionRegex = new RegExp(/\.(mp4|webm|ogg|avi|mov|flv|wmv|mkv|mpg|mpeg|3gp|m4v)$/) From 226891b9b1630c90835d1bc1a239c2ebbb5c9ff1 Mon Sep 17 00:00:00 2001 From: kabirgh <15871468+kabirgh@users.noreply.github.com> Date: Sun, 11 Feb 2024 20:20:44 +0000 Subject: [PATCH 9/9] fix(fast rebuild): call only required emitters, don't always copy assets (#845) * fix(fast rebuild): call only required emitters, don't always copy assets * Type function --- quartz/build.ts | 5 +++-- quartz/plugins/emitters/assets.ts | 12 +++++++++--- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/quartz/build.ts b/quartz/build.ts index ed166bb6c..452a2f1ae 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -203,8 +203,9 @@ async function partialRebuildFromEntrypoint( const emitterGraph = (await emitter.getDependencyGraph?.(ctx, processedFiles, staticResources)) ?? null - // emmiter may not define a dependency graph. nothing to update if so - if (emitterGraph) { + // only update the graph if the emitter plugin uses the changed file + // eg. Assets plugin ignores md files, so we skip updating the graph + if (emitterGraph?.hasNode(fp)) { // merge the new dependencies into the dep graph dependencies[emitter.name]?.updateIncomingEdgesForNode(emitterGraph, fp) } diff --git a/quartz/plugins/emitters/assets.ts b/quartz/plugins/emitters/assets.ts index 379cd5b2d..036b27da4 100644 --- a/quartz/plugins/emitters/assets.ts +++ b/quartz/plugins/emitters/assets.ts @@ -4,6 +4,13 @@ import path from "path" import fs from "fs" import { glob } from "../../util/glob" import DepGraph from "../../depgraph" +import { Argv } from "../../util/ctx" +import { QuartzConfig } from "../../cfg" + +const filesToCopy = async (argv: Argv, cfg: QuartzConfig) => { + // glob all non MD files in content folder and copy it over + return await glob("**", argv.directory, ["**/*.md", ...cfg.configuration.ignorePatterns]) +} export const Assets: QuartzEmitterPlugin = () => { return { @@ -15,7 +22,7 @@ export const Assets: QuartzEmitterPlugin = () => { const { argv, cfg } = ctx const graph = new DepGraph() - const fps = await glob("**", argv.directory, ["**/*.md", ...cfg.configuration.ignorePatterns]) + const fps = await filesToCopy(argv, cfg) for (const fp of fps) { const ext = path.extname(fp) @@ -30,9 +37,8 @@ export const Assets: QuartzEmitterPlugin = () => { return graph }, async emit({ argv, cfg }, _content, _resources): Promise { - // glob all non MD/MDX/HTML files in content folder and copy it over const assetsPath = argv.output - const fps = await glob("**", argv.directory, ["**/*.md", ...cfg.configuration.ignorePatterns]) + const fps = await filesToCopy(argv, cfg) const res: FilePath[] = [] for (const fp of fps) { const ext = path.extname(fp)