From 76f295620c5e8ffc21a78698468ab38b2916a461 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Mon, 12 Feb 2024 08:51:47 -0800 Subject: [PATCH 01/31] feat: add transclude-src to transclude 'link to original' --- quartz/components/renderPage.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx index 4643d0a3a..33671d21d 100644 --- a/quartz/components/renderPage.tsx +++ b/quartz/components/renderPage.tsx @@ -103,7 +103,7 @@ export function renderPage( { type: "element", tagName: "a", - properties: { href: inner.properties?.href, class: ["internal"] }, + properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] }, children: [ { type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal }, ], @@ -140,7 +140,7 @@ export function renderPage( { type: "element", tagName: "a", - properties: { href: inner.properties?.href, class: ["internal"] }, + properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] }, children: [ { type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal }, ], @@ -170,7 +170,7 @@ export function renderPage( { type: "element", tagName: "a", - properties: { href: inner.properties?.href, class: ["internal"] }, + properties: { href: inner.properties?.href, class: ["internal", "transclude-src"] }, children: [ { type: "text", value: i18n(cfg.locale).components.transcludes.linkToOriginal }, ], From 5dc4f21a4baf564ede85d8e702ef5b19c96657a3 Mon Sep 17 00:00:00 2001 From: Emile Bangma Date: Mon, 12 Feb 2024 17:58:00 +0100 Subject: [PATCH 02/31] feat(i18n): localize the min read string for the nl-NL locale (#850) * Update min read translation * Added nl_BE to Dutch Added Flemish (nl_BE) to point to nl. * Removed period to match other translations --- quartz/i18n/index.ts | 1 + quartz/i18n/locales/nl-NL.ts | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index a422acb79..c4fa4251c 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -15,6 +15,7 @@ export const TRANSLATIONS = { "ja-JP": ja, "de-DE": de, "nl-NL": nl, + "nl-BE": nl, "ro-RO": ro, "ro-MD": ro, "es-ES": es, diff --git a/quartz/i18n/locales/nl-NL.ts b/quartz/i18n/locales/nl-NL.ts index 3ff3e8cd9..e239be0e1 100644 --- a/quartz/i18n/locales/nl-NL.ts +++ b/quartz/i18n/locales/nl-NL.ts @@ -54,7 +54,8 @@ export default { title: "Inhoudsopgave", }, contentMeta: { - readingTime: ({ minutes }) => `${minutes} min read`, + readingTime: ({ minutes }) => + minutes === 1 ? "1 minuut leestijd" : `${minutes} minuten leestijd`, }, }, pages: { From a7325eadc1483c181928425a4c7379427f21995a Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Mon, 12 Feb 2024 09:00:58 -0800 Subject: [PATCH 03/31] fix(analytics): umami custom host should be a string (closes #852) --- quartz/plugins/emitters/componentResources.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts index 290cb6f2a..67bc69c3d 100644 --- a/quartz/plugins/emitters/componentResources.ts +++ b/quartz/plugins/emitters/componentResources.ts @@ -120,7 +120,7 @@ function addGlobalPageResources( } else if (cfg.analytics?.provider === "umami") { componentResources.afterDOMLoaded.push(` const umamiScript = document.createElement("script") - umamiScript.src = ${cfg.analytics.host} ?? "https://analytics.umami.is/script.js" + umamiScript.src = "${cfg.analytics.host}" ?? "https://analytics.umami.is/script.js" umamiScript.setAttribute("data-website-id", "${cfg.analytics.websiteId}") umamiScript.async = true From 4a28d0e5d1b8fa866d0594a89ad72a751633dc8c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:21:13 -0500 Subject: [PATCH 04/31] chore(deps-dev): bump tsx from 4.7.0 to 4.7.1 (#859) Bumps [tsx](https://github.com/privatenumber/tsx) from 4.7.0 to 4.7.1. - [Release notes](https://github.com/privatenumber/tsx/releases) - [Changelog](https://github.com/privatenumber/tsx/blob/develop/release.config.cjs) - [Commits](https://github.com/privatenumber/tsx/compare/v4.7.0...v4.7.1) --- updated-dependencies: - dependency-name: tsx dependency-type: direct:development 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 e48812495..891fcea53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -80,7 +80,7 @@ "@types/yargs": "^17.0.32", "esbuild": "^0.19.9", "prettier": "^3.2.4", - "tsx": "^4.7.0", + "tsx": "^4.7.1", "typescript": "^5.3.3" }, "engines": { @@ -5647,9 +5647,9 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" }, "node_modules/tsx": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.0.tgz", - "integrity": "sha512-I+t79RYPlEYlHn9a+KzwrvEwhJg35h/1zHsLC2JXvhC2mdynMv6Zxzvhv5EMV6VF5qJlLlkSnMVvdZV3PSIGcg==", + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.1.tgz", + "integrity": "sha512-8d6VuibXHtlN5E3zFkgY8u4DX7Y3Z27zvvPKVmLon/D4AjuKzarkUBTLDBgj9iTQ0hg5xM7c/mYiRVM+HETf0g==", "dev": true, "dependencies": { "esbuild": "~0.19.10", diff --git a/package.json b/package.json index 3235b5fa5..2d408b730 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@types/yargs": "^17.0.32", "esbuild": "^0.19.9", "prettier": "^3.2.4", - "tsx": "^4.7.0", + "tsx": "^4.7.1", "typescript": "^5.3.3" } } From 2c06e68ba6ccc5b079ca6ec96cc6e08c082d9fd8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:21:30 -0500 Subject: [PATCH 05/31] chore(deps): bump preact from 10.19.3 to 10.19.4 (#858) Bumps [preact](https://github.com/preactjs/preact) from 10.19.3 to 10.19.4. - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](https://github.com/preactjs/preact/compare/10.19.3...10.19.4) --- updated-dependencies: - dependency-name: preact 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 891fcea53..9a0d8cb4e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "mdast-util-to-hast": "^13.1.0", "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", - "preact": "^10.19.3", + "preact": "^10.19.4", "preact-render-to-string": "^6.3.1", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", @@ -4454,9 +4454,9 @@ } }, "node_modules/preact": { - "version": "10.19.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.3.tgz", - "integrity": "sha512-nHHTeFVBTHRGxJXKkKu5hT8C/YWBkPso4/Gad6xuj5dbptt9iF9NZr9pHbPhBrnT2klheu7mHTxTZ/LjwJiEiQ==", + "version": "10.19.4", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.4.tgz", + "integrity": "sha512-dwaX5jAh0Ga8uENBX1hSOujmKWgx9RtL80KaKUFLc6jb4vCEAc3EeZ0rnQO/FO4VgjfPMfoLFWnNG8bHuZ9VLw==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" diff --git a/package.json b/package.json index 2d408b730..e11e6c4da 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "mdast-util-to-hast": "^13.1.0", "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", - "preact": "^10.19.3", + "preact": "^10.19.4", "preact-render-to-string": "^6.3.1", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", From a31e3f9458431883d8ee68961132b5cdb1ef2db6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Feb 2024 00:21:45 -0500 Subject: [PATCH 06/31] chore(deps): bump @floating-ui/dom from 1.6.1 to 1.6.3 (#857) Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.6.1 to 1.6.3. - [Release notes](https://github.com/floating-ui/floating-ui/releases) - [Changelog](https://github.com/floating-ui/floating-ui/blob/master/packages/dom/CHANGELOG.md) - [Commits](https://github.com/floating-ui/floating-ui/commits/@floating-ui/dom@1.6.3/packages/dom) --- updated-dependencies: - dependency-name: "@floating-ui/dom" 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 | 12 ++++++------ package.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9a0d8cb4e..7d1d9737e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@clack/prompts": "^0.7.0", - "@floating-ui/dom": "^1.6.1", + "@floating-ui/dom": "^1.6.3", "@napi-rs/simple-git": "0.1.16", "async-mutex": "^0.4.1", "chalk": "^5.3.0", @@ -486,12 +486,12 @@ } }, "node_modules/@floating-ui/dom": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", - "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.3.tgz", + "integrity": "sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==", "dependencies": { - "@floating-ui/core": "^1.6.0", - "@floating-ui/utils": "^0.2.1" + "@floating-ui/core": "^1.0.0", + "@floating-ui/utils": "^0.2.0" } }, "node_modules/@floating-ui/utils": { diff --git a/package.json b/package.json index e11e6c4da..f89bb2a0b 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ }, "dependencies": { "@clack/prompts": "^0.7.0", - "@floating-ui/dom": "^1.6.1", + "@floating-ui/dom": "^1.6.3", "@napi-rs/simple-git": "0.1.16", "async-mutex": "^0.4.1", "chalk": "^5.3.0", From 880a9511b695f57b9b323be1f57b13d1598d42a9 Mon Sep 17 00:00:00 2001 From: Lin Date: Tue, 13 Feb 2024 09:11:16 +0100 Subject: [PATCH 07/31] fix: incorrect link resolution for transclusion in root index file (#853) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Lauréline Nevin --- quartz/plugins/transformers/links.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index 2d43be1b2..1e0387692 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -8,6 +8,7 @@ import { simplifySlug, splitAnchor, transformLink, + joinSegments, } from "../../util/path" import path from "path" import { visit } from "unist-util-visit" @@ -107,7 +108,7 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = // url.resolve is considered legacy // WHATWG equivalent https://nodejs.dev/en/api/v18/url/#urlresolvefrom-to - const url = new URL(dest, `https://base.com/${curSlug}`) + const url = new URL(dest, joinSegments(`https://base.com/`, curSlug)) const canonicalDest = url.pathname let [destCanonical, _destAnchor] = splitAnchor(canonicalDest) if (destCanonical.endsWith("/")) { From b87a701ff75946ff8150052e16916f041f065544 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Tue, 13 Feb 2024 01:27:27 -0800 Subject: [PATCH 08/31] fix: base.com not being resolved properly with joinSegments --- quartz/plugins/transformers/links.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quartz/plugins/transformers/links.ts b/quartz/plugins/transformers/links.ts index 1e0387692..f89d367d7 100644 --- a/quartz/plugins/transformers/links.ts +++ b/quartz/plugins/transformers/links.ts @@ -108,7 +108,7 @@ export const CrawlLinks: QuartzTransformerPlugin | undefined> = // url.resolve is considered legacy // WHATWG equivalent https://nodejs.dev/en/api/v18/url/#urlresolvefrom-to - const url = new URL(dest, joinSegments(`https://base.com/`, curSlug)) + const url = new URL(dest, "https://base.com/" + stripSlashes(curSlug, true)) const canonicalDest = url.pathname let [destCanonical, _destAnchor] = splitAnchor(canonicalDest) if (destCanonical.endsWith("/")) { From 21c6bbf3026cf9c06f6458bdb6614099d9a91adc Mon Sep 17 00:00:00 2001 From: Aaron Pham <29749331+aarnphm@users.noreply.github.com> Date: Tue, 13 Feb 2024 23:53:44 -0500 Subject: [PATCH 09/31] chore(types): add additional hint for LSP support (#864) Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com> --- quartz/components/ArticleTitle.tsx | 4 ++-- quartz/components/Backlinks.tsx | 9 +++++++-- quartz/components/Body.tsx | 4 ++-- quartz/components/Breadcrumbs.tsx | 9 +++++++-- quartz/components/Darkmode.tsx | 4 ++-- quartz/components/DesktopOnly.tsx | 2 +- quartz/components/Explorer.tsx | 9 +++++++-- quartz/components/Footer.tsx | 4 ++-- quartz/components/Graph.tsx | 4 ++-- quartz/components/Head.tsx | 4 ++-- quartz/components/Header.tsx | 4 ++-- quartz/components/MobileOnly.tsx | 2 +- quartz/components/PageList.tsx | 4 ++-- quartz/components/PageTitle.tsx | 4 ++-- quartz/components/RecentNotes.tsx | 9 +++++++-- quartz/components/Search.tsx | 4 ++-- quartz/components/TableOfContents.tsx | 10 +++++++--- quartz/components/TagList.tsx | 4 ++-- 18 files changed, 59 insertions(+), 35 deletions(-) diff --git a/quartz/components/ArticleTitle.tsx b/quartz/components/ArticleTitle.tsx index 7768de6cb..318aeb24e 100644 --- a/quartz/components/ArticleTitle.tsx +++ b/quartz/components/ArticleTitle.tsx @@ -1,7 +1,7 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { classNames } from "../util/lang" -function ArticleTitle({ fileData, displayClass }: QuartzComponentProps) { +const ArticleTitle: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => { const title = fileData.frontmatter?.title if (title) { return

{title}

diff --git a/quartz/components/Backlinks.tsx b/quartz/components/Backlinks.tsx index 573c1c391..aa412a2e0 100644 --- a/quartz/components/Backlinks.tsx +++ b/quartz/components/Backlinks.tsx @@ -1,10 +1,15 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import style from "./styles/backlinks.scss" import { resolveRelative, simplifySlug } from "../util/path" import { i18n } from "../i18n" import { classNames } from "../util/lang" -function Backlinks({ fileData, allFiles, displayClass, cfg }: QuartzComponentProps) { +const Backlinks: QuartzComponent = ({ + fileData, + allFiles, + displayClass, + cfg, +}: QuartzComponentProps) => { const slug = simplifySlug(fileData.slug!) const backlinkFiles = allFiles.filter((file) => file.links?.includes(slug)) return ( diff --git a/quartz/components/Body.tsx b/quartz/components/Body.tsx index fbb857293..96b627883 100644 --- a/quartz/components/Body.tsx +++ b/quartz/components/Body.tsx @@ -1,9 +1,9 @@ // @ts-ignore import clipboardScript from "./scripts/clipboard.inline" import clipboardStyle from "./styles/clipboard.scss" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -function Body({ children }: QuartzComponentProps) { +const Body: QuartzComponent = ({ children }: QuartzComponentProps) => { return
{children}
} diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx index eab8a34e2..b1a924aa8 100644 --- a/quartz/components/Breadcrumbs.tsx +++ b/quartz/components/Breadcrumbs.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import breadcrumbsStyle from "./styles/breadcrumbs.scss" import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" import { QuartzPluginData } from "../plugins/vfile" @@ -54,7 +54,11 @@ export default ((opts?: Partial) => { // computed index of folder name to its associated file data let folderIndex: Map | undefined - function Breadcrumbs({ fileData, allFiles, displayClass }: QuartzComponentProps) { + const Breadcrumbs: QuartzComponent = ({ + fileData, + allFiles, + displayClass, + }: QuartzComponentProps) => { // Hide crumbs on root if enabled if (options.hideOnRoot && fileData.slug === "index") { return <> @@ -121,5 +125,6 @@ export default ((opts?: Partial) => { ) } Breadcrumbs.css = breadcrumbsStyle + return Breadcrumbs }) satisfies QuartzComponentConstructor diff --git a/quartz/components/Darkmode.tsx b/quartz/components/Darkmode.tsx index 62d3c2382..8ed7c99b0 100644 --- a/quartz/components/Darkmode.tsx +++ b/quartz/components/Darkmode.tsx @@ -3,11 +3,11 @@ // see: https://v8.dev/features/modules#defer import darkmodeScript from "./scripts/darkmode.inline" import styles from "./styles/darkmode.scss" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { i18n } from "../i18n" import { classNames } from "../util/lang" -function Darkmode({ displayClass, cfg }: QuartzComponentProps) { +const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { return (
diff --git a/quartz/components/DesktopOnly.tsx b/quartz/components/DesktopOnly.tsx index a11f23fa8..fe2a27f14 100644 --- a/quartz/components/DesktopOnly.tsx +++ b/quartz/components/DesktopOnly.tsx @@ -3,7 +3,7 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro export default ((component?: QuartzComponent) => { if (component) { const Component = component - function DesktopOnly(props: QuartzComponentProps) { + const DesktopOnly: QuartzComponent = (props: QuartzComponentProps) => { return } diff --git a/quartz/components/Explorer.tsx b/quartz/components/Explorer.tsx index f7017342e..cffc079ef 100644 --- a/quartz/components/Explorer.tsx +++ b/quartz/components/Explorer.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import explorerStyle from "./styles/explorer.scss" // @ts-ignore @@ -75,7 +75,12 @@ export default ((userOpts?: Partial) => { jsonTree = JSON.stringify(folders) } - function Explorer({ cfg, allFiles, displayClass, fileData }: QuartzComponentProps) { + const Explorer: QuartzComponent = ({ + cfg, + allFiles, + displayClass, + fileData, + }: QuartzComponentProps) => { constructFileTree(allFiles) return (
diff --git a/quartz/components/Footer.tsx b/quartz/components/Footer.tsx index de472f729..076c37874 100644 --- a/quartz/components/Footer.tsx +++ b/quartz/components/Footer.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import style from "./styles/footer.scss" import { version } from "../../package.json" import { i18n } from "../i18n" @@ -8,7 +8,7 @@ interface Options { } export default ((opts?: Options) => { - function Footer({ displayClass, cfg }: QuartzComponentProps) { + const Footer: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { const year = new Date().getFullYear() const links = opts?.links ?? [] return ( diff --git a/quartz/components/Graph.tsx b/quartz/components/Graph.tsx index 9fce9bd8f..40ab43a2d 100644 --- a/quartz/components/Graph.tsx +++ b/quartz/components/Graph.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" // @ts-ignore import script from "./scripts/graph.inline" import style from "./styles/graph.scss" @@ -54,7 +54,7 @@ const defaultOptions: GraphOptions = { } export default ((opts?: GraphOptions) => { - function Graph({ displayClass, cfg }: QuartzComponentProps) { + const Graph: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { const localGraph = { ...defaultOptions.localGraph, ...opts?.localGraph } const globalGraph = { ...defaultOptions.globalGraph, ...opts?.globalGraph } return ( diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index 8292acc05..a3c0800ab 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -1,10 +1,10 @@ import { i18n } from "../i18n" import { FullSlug, joinSegments, pathToRoot } from "../util/path" import { JSResourceToScriptElement } from "../util/resources" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" export default (() => { - function Head({ cfg, fileData, externalResources }: QuartzComponentProps) { + const Head: QuartzComponent = ({ cfg, fileData, externalResources }: QuartzComponentProps) => { const title = fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title const description = fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description diff --git a/quartz/components/Header.tsx b/quartz/components/Header.tsx index 5281f7296..eba17ae09 100644 --- a/quartz/components/Header.tsx +++ b/quartz/components/Header.tsx @@ -1,6 +1,6 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" -function Header({ children }: QuartzComponentProps) { +const Header: QuartzComponent = ({ children }: QuartzComponentProps) => { return children.length > 0 ?
{children}
: null } diff --git a/quartz/components/MobileOnly.tsx b/quartz/components/MobileOnly.tsx index 5a190957b..7d2108de7 100644 --- a/quartz/components/MobileOnly.tsx +++ b/quartz/components/MobileOnly.tsx @@ -3,7 +3,7 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro export default ((component?: QuartzComponent) => { if (component) { const Component = component - function MobileOnly(props: QuartzComponentProps) { + const MobileOnly: QuartzComponent = (props: QuartzComponentProps) => { return } diff --git a/quartz/components/PageList.tsx b/quartz/components/PageList.tsx index 644e354c4..62b77b17b 100644 --- a/quartz/components/PageList.tsx +++ b/quartz/components/PageList.tsx @@ -1,7 +1,7 @@ import { FullSlug, resolveRelative } from "../util/path" import { QuartzPluginData } from "../plugins/vfile" import { Date, getDate } from "./Date" -import { QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentProps } from "./types" import { GlobalConfiguration } from "../cfg" export function byDateAndAlphabetical( @@ -29,7 +29,7 @@ type Props = { limit?: number } & QuartzComponentProps -export function PageList({ cfg, fileData, allFiles, limit }: Props) { +export const PageList: QuartzComponent = ({ cfg, fileData, allFiles, limit }: Props) => { let list = allFiles.sort(byDateAndAlphabetical(cfg)) if (limit) { list = list.slice(0, limit) diff --git a/quartz/components/PageTitle.tsx b/quartz/components/PageTitle.tsx index d12960264..2362f1027 100644 --- a/quartz/components/PageTitle.tsx +++ b/quartz/components/PageTitle.tsx @@ -1,9 +1,9 @@ import { pathToRoot } from "../util/path" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { classNames } from "../util/lang" import { i18n } from "../i18n" -function PageTitle({ fileData, cfg, displayClass }: QuartzComponentProps) { +const PageTitle: QuartzComponent = ({ fileData, cfg, displayClass }: QuartzComponentProps) => { const title = cfg?.pageTitle ?? i18n(cfg.locale).propertyDefaults.title const baseDir = pathToRoot(fileData.slug!) return ( diff --git a/quartz/components/RecentNotes.tsx b/quartz/components/RecentNotes.tsx index f8f6de41f..549b025d3 100644 --- a/quartz/components/RecentNotes.tsx +++ b/quartz/components/RecentNotes.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" import { QuartzPluginData } from "../plugins/vfile" import { byDateAndAlphabetical } from "./PageList" @@ -24,7 +24,12 @@ const defaultOptions = (cfg: GlobalConfiguration): Options => ({ }) export default ((userOpts?: Partial) => { - function RecentNotes({ allFiles, fileData, displayClass, cfg }: QuartzComponentProps) { + const RecentNotes: QuartzComponent = ({ + allFiles, + fileData, + displayClass, + cfg, + }: QuartzComponentProps) => { const opts = { ...defaultOptions(cfg), ...userOpts } const pages = allFiles.filter(opts.filter).sort(opts.sort) const remaining = Math.max(0, pages.length - opts.limit) diff --git a/quartz/components/Search.tsx b/quartz/components/Search.tsx index a07dbc4fd..01e5a353d 100644 --- a/quartz/components/Search.tsx +++ b/quartz/components/Search.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import style from "./styles/search.scss" // @ts-ignore import script from "./scripts/search.inline" @@ -14,7 +14,7 @@ const defaultOptions: SearchOptions = { } export default ((userOpts?: Partial) => { - function Search({ displayClass, cfg }: QuartzComponentProps) { + const Search: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => { const opts = { ...defaultOptions, ...userOpts } const searchPlaceholder = i18n(cfg.locale).components.search.searchBarPlaceholder return ( diff --git a/quartz/components/TableOfContents.tsx b/quartz/components/TableOfContents.tsx index 2abc74b53..77ff0eb10 100644 --- a/quartz/components/TableOfContents.tsx +++ b/quartz/components/TableOfContents.tsx @@ -1,4 +1,4 @@ -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import legacyStyle from "./styles/legacyToc.scss" import modernStyle from "./styles/toc.scss" import { classNames } from "../util/lang" @@ -15,7 +15,11 @@ const defaultOptions: Options = { layout: "modern", } -function TableOfContents({ fileData, displayClass, cfg }: QuartzComponentProps) { +const TableOfContents: QuartzComponent = ({ + fileData, + displayClass, + cfg, +}: QuartzComponentProps) => { if (!fileData.toc) { return null } @@ -56,7 +60,7 @@ function TableOfContents({ fileData, displayClass, cfg }: QuartzComponentProps) TableOfContents.css = modernStyle TableOfContents.afterDOMLoaded = script -function LegacyTableOfContents({ fileData, cfg }: QuartzComponentProps) { +const LegacyTableOfContents: QuartzComponent = ({ fileData, cfg }: QuartzComponentProps) => { if (!fileData.toc) { return null } diff --git a/quartz/components/TagList.tsx b/quartz/components/TagList.tsx index e5dd1a3ae..04a483b6c 100644 --- a/quartz/components/TagList.tsx +++ b/quartz/components/TagList.tsx @@ -1,8 +1,8 @@ import { pathToRoot, slugTag } from "../util/path" -import { QuartzComponentConstructor, QuartzComponentProps } from "./types" +import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import { classNames } from "../util/lang" -function TagList({ fileData, displayClass }: QuartzComponentProps) { +const TagList: QuartzComponent = ({ fileData, displayClass }: QuartzComponentProps) => { const tags = fileData.frontmatter?.tags const baseDir = pathToRoot(fileData.slug!) if (tags && tags.length > 0) { From 2041341d9fd9a3b674d7fa7286ad5b6e99ce80e5 Mon Sep 17 00:00:00 2001 From: Aaron Bull Schaefer Date: Wed, 14 Feb 2024 09:41:44 -0800 Subject: [PATCH 10/31] docs: workaround for shallow clones on Cloudflare Pages (#868) Rather than recommend a different hosting provider, Cloudflare Pages users that prioritize the `git` method for their `CreatedModifiedDate` configuration can preface the build command with a means of fetching the required repository history. See: - https://gohugo.io/methods/page/gitinfo/#hosting-considerations --- docs/hosting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hosting.md b/docs/hosting.md index e6340d293..bae7ed899 100644 --- a/docs/hosting.md +++ b/docs/hosting.md @@ -30,7 +30,7 @@ Press "Save and deploy" and Cloudflare should have a deployed version of your si To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/). > [!warning] -> Cloudflare Pages only allows shallow `git` clones so if you rely on `git` for timestamps, it is recommended you either add dates to your frontmatter (see [[authoring content#Syntax]]) or use another hosting provider. +> Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz build`). ## GitHub Pages From 6c8023463d0e4ea68be3216c454775fd87d3e370 Mon Sep 17 00:00:00 2001 From: David Fischer Date: Wed, 14 Feb 2024 21:41:13 +0100 Subject: [PATCH 11/31] Add support for image popovers (#854) * feat(popover): Add support for images * fix: run prettier * feat(popover): use switch logic for content types & adjust styles * feat(popover): Add content type data tag for popover-inner class --- docs/features/popover previews.md | 2 ++ quartz/components/scripts/popover.inline.ts | 40 +++++++++++++++------ quartz/components/styles/popover.scss | 11 ++++++ 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/docs/features/popover previews.md b/docs/features/popover previews.md index f88222402..066604758 100644 --- a/docs/features/popover previews.md +++ b/docs/features/popover previews.md @@ -8,6 +8,8 @@ By default, Quartz only fetches previews for pages inside your vault due to [COR When [[creating components|creating your own components]], you can include this `popover-hint` class to also include it in the popover. +Similar to Obsidian, [[quartz layout.png|images referenced using wikilinks]] can also be viewed as popups. + ## Configuration - Remove popovers: set the `enablePopovers` field in `quartz.config.ts` to be `false`. diff --git a/quartz/components/scripts/popover.inline.ts b/quartz/components/scripts/popover.inline.ts index 0251834cb..d0346b05b 100644 --- a/quartz/components/scripts/popover.inline.ts +++ b/quartz/components/scripts/popover.inline.ts @@ -37,29 +37,47 @@ async function mouseEnterHandler( targetUrl.hash = "" targetUrl.search = "" - const contents = await fetch(`${targetUrl}`) - .then((res) => res.text()) - .catch((err) => { - console.error(err) - }) + const response = await fetch(`${targetUrl}`).catch((err) => { + console.error(err) + }) // bailout if another popover exists if (hasAlreadyBeenFetched()) { return } - if (!contents) return - const html = p.parseFromString(contents, "text/html") - normalizeRelativeURLs(html, targetUrl) - const elts = [...html.getElementsByClassName("popover-hint")] - if (elts.length === 0) return + if (!response) return + const contentType = response.headers.get("Content-Type") + const contentTypeCategory = contentType?.split("/")[0] ?? "text" const popoverElement = document.createElement("div") popoverElement.classList.add("popover") const popoverInner = document.createElement("div") popoverInner.classList.add("popover-inner") popoverElement.appendChild(popoverInner) - elts.forEach((elt) => popoverInner.appendChild(elt)) + + popoverInner.dataset.contentType = contentTypeCategory + + switch (contentTypeCategory) { + case "image": + const img = document.createElement("img") + + response.blob().then((blob) => { + img.src = URL.createObjectURL(blob) + }) + img.alt = targetUrl.pathname + + popoverInner.appendChild(img) + break + default: + const contents = await response.text() + const html = p.parseFromString(contents, "text/html") + normalizeRelativeURLs(html, targetUrl) + const elts = [...html.getElementsByClassName("popover-hint")] + if (elts.length === 0) return + + elts.forEach((elt) => popoverInner.appendChild(elt)) + } setPosition(popoverElement) link.appendChild(popoverElement) diff --git a/quartz/components/styles/popover.scss b/quartz/components/styles/popover.scss index e46292a21..141b89ddf 100644 --- a/quartz/components/styles/popover.scss +++ b/quartz/components/styles/popover.scss @@ -38,6 +38,17 @@ white-space: normal; } + & > .popover-inner[data-content-type="image"] { + padding: 0; + max-height: 100%; + + img { + margin: 0; + border-radius: 0; + display: block; + } + } + h1 { font-size: 1.5rem; } From 78a408c96a221629ce1a8b70a17ed4981aad1336 Mon Sep 17 00:00:00 2001 From: kabirgh <15871468+kabirgh@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:50:33 +0000 Subject: [PATCH 12/31] feat: implement getDependencyGraph for FolderPage (#849) --- quartz/plugins/emitters/folderPage.tsx | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/quartz/plugins/emitters/folderPage.tsx b/quartz/plugins/emitters/folderPage.tsx index 690fa56f7..bf69d2987 100644 --- a/quartz/plugins/emitters/folderPage.tsx +++ b/quartz/plugins/emitters/folderPage.tsx @@ -38,12 +38,21 @@ 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 - // TODO implement - return new DepGraph() + // nested/file.md --> nested/index.html + // nested/file2.md ------^ + const graph = new DepGraph() + + content.map(([_tree, vfile]) => { + const slug = vfile.data.slug + const folderName = path.dirname(slug ?? "") as SimpleSlug + if (slug && folderName !== "." && folderName !== "tags") { + graph.addEdge(vfile.data.filePath!, joinSegments(folderName, "index.html") as FilePath) + } + }) + + return graph }, async emit(ctx, content, resources): Promise { const fps: FilePath[] = [] From 823d9529224d70056be9dbac29dbbc66f75ae5e8 Mon Sep 17 00:00:00 2001 From: kabirgh <15871468+kabirgh@users.noreply.github.com> Date: Fri, 16 Feb 2024 00:50:48 +0000 Subject: [PATCH 13/31] feat: implement getDependencyGraph for AliasRedirects emitter (#860) --- quartz/plugins/emitters/aliases.ts | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/quartz/plugins/emitters/aliases.ts b/quartz/plugins/emitters/aliases.ts index fb25a448e..af3578ebe 100644 --- a/quartz/plugins/emitters/aliases.ts +++ b/quartz/plugins/emitters/aliases.ts @@ -9,9 +9,30 @@ export const AliasRedirects: QuartzEmitterPlugin = () => ({ getQuartzComponents() { return [] }, - async getDependencyGraph(_ctx, _content, _resources) { - // TODO implement - return new DepGraph() + async getDependencyGraph(ctx, content, _resources) { + const graph = new DepGraph() + + const { argv } = ctx + for (const [_tree, file] of content) { + const dir = path.posix.relative(argv.directory, path.dirname(file.data.filePath!)) + const aliases = file.data.frontmatter?.aliases ?? [] + const slugs = aliases.map((alias) => path.posix.join(dir, alias) as FullSlug) + const permalink = file.data.frontmatter?.permalink + if (typeof permalink === "string") { + slugs.push(permalink as FullSlug) + } + + for (let slug of slugs) { + // fix any slugs that have trailing slash + if (slug.endsWith("/")) { + slug = joinSegments(slug, "index") as FullSlug + } + + graph.addEdge(file.data.filePath!, joinSegments(argv.output, slug + ".html") as FilePath) + } + } + + return graph }, async emit(ctx, content, _resources): Promise { const { argv } = ctx From 5af707ea20e8106857750e1d6a0e43cf18679749 Mon Sep 17 00:00:00 2001 From: kabirgh <15871468+kabirgh@users.noreply.github.com> Date: Sat, 17 Feb 2024 17:45:01 +0000 Subject: [PATCH 14/31] fix/feat(fast rebuild): re-render transclusions in normal and fastRebuild mode (#842) * Re-render transclusions in normal watch mode * Include transclusions in ContentPage getDependencyGraph * Address PR comments --- quartz/components/renderPage.tsx | 26 +++++-------- quartz/plugins/emitters/contentPage.tsx | 49 +++++++++++++++++++++++-- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx index 33671d21d..5394d6f4c 100644 --- a/quartz/components/renderPage.tsx +++ b/quartz/components/renderPage.tsx @@ -3,10 +3,9 @@ import { QuartzComponent, QuartzComponentProps } from "./types" import HeaderConstructor from "./Header" import BodyConstructor from "./Body" import { JSResourceToScriptElement, StaticResources } from "../util/resources" -import { FullSlug, RelativeURL, joinSegments, normalizeHastElement } from "../util/path" +import { clone, FullSlug, RelativeURL, joinSegments, normalizeHastElement } from "../util/path" import { visit } from "unist-util-visit" import { Root, Element, ElementContent } from "hast" -import { QuartzPluginData } from "../plugins/vfile" import { GlobalConfiguration } from "../cfg" import { i18n } from "../i18n" @@ -52,18 +51,6 @@ export function pageResources( } } -let pageIndex: Map | undefined = undefined -function getOrComputeFileIndex(allFiles: QuartzPluginData[]): Map { - if (!pageIndex) { - pageIndex = new Map() - for (const file of allFiles) { - pageIndex.set(file.slug!, file) - } - } - - return pageIndex -} - export function renderPage( cfg: GlobalConfiguration, slug: FullSlug, @@ -71,14 +58,18 @@ export function renderPage( components: RenderComponents, pageResources: StaticResources, ): string { + // make a deep copy of the tree so we don't remove the transclusion references + // for the file cached in contentMap in build.ts + const root = clone(componentData.tree) as Root + // process transcludes in componentData - visit(componentData.tree as Root, "element", (node, _index, _parent) => { + visit(root, "element", (node, _index, _parent) => { if (node.tagName === "blockquote") { const classNames = (node.properties?.className ?? []) as string[] if (classNames.includes("transclude")) { const inner = node.children[0] as Element const transcludeTarget = inner.properties["data-slug"] as FullSlug - const page = getOrComputeFileIndex(componentData.allFiles).get(transcludeTarget) + const page = componentData.allFiles.find((f) => f.slug === transcludeTarget) if (!page) { return } @@ -181,6 +172,9 @@ export function renderPage( } }) + // set componentData.tree to the edited html that has transclusions rendered + componentData.tree = root + const { head: Head, header, diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx index e531b36e8..904a8a8ca 100644 --- a/quartz/plugins/emitters/contentPage.tsx +++ b/quartz/plugins/emitters/contentPage.tsx @@ -1,16 +1,56 @@ +import path from "path" +import { visit } from "unist-util-visit" +import { Root } from "hast" +import { VFile } from "vfile" import { QuartzEmitterPlugin } from "../types" import { QuartzComponentProps } from "../../components/types" import HeaderConstructor from "../../components/Header" import BodyConstructor from "../../components/Body" import { pageResources, renderPage } from "../../components/renderPage" import { FullPageLayout } from "../../cfg" -import { FilePath, joinSegments, pathToRoot } from "../../util/path" +import { Argv } from "../../util/ctx" +import { FilePath, isRelativeURL, joinSegments, pathToRoot } from "../../util/path" import { defaultContentPageLayout, sharedPageComponents } from "../../../quartz.layout" import { Content } from "../../components" import chalk from "chalk" import { write } from "./helpers" import DepGraph from "../../depgraph" +// get all the dependencies for the markdown file +// eg. images, scripts, stylesheets, transclusions +const parseDependencies = (argv: Argv, hast: Root, file: VFile): string[] => { + const dependencies: string[] = [] + + visit(hast, "element", (elem): void => { + let ref: string | null = null + + if ( + ["script", "img", "audio", "video", "source", "iframe"].includes(elem.tagName) && + elem?.properties?.src + ) { + ref = elem.properties.src.toString() + } else if (["a", "link"].includes(elem.tagName) && elem?.properties?.href) { + // transclusions will create a tags with relative hrefs + ref = elem.properties.href.toString() + } + + // if it is a relative url, its a local file and we need to add + // it to the dependency graph. otherwise, ignore + if (ref === null || !isRelativeURL(ref)) { + return + } + + let fp = path.join(file.data.filePath!, path.relative(argv.directory, ref)).replace(/\\/g, "/") + // markdown files have the .md extension stripped in hrefs, add it back here + if (!fp.split("/").pop()?.includes(".")) { + fp += ".md" + } + dependencies.push(fp) + }) + + return dependencies +} + export const ContentPage: QuartzEmitterPlugin> = (userOpts) => { const opts: FullPageLayout = { ...sharedPageComponents, @@ -29,13 +69,16 @@ export const ContentPage: QuartzEmitterPlugin> = (userOp return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, async getDependencyGraph(ctx, content, _resources) { - // TODO handle transclusions const graph = new DepGraph() - for (const [_tree, file] of content) { + for (const [tree, file] of content) { const sourcePath = file.data.filePath! const slug = file.data.slug! graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath) + + parseDependencies(ctx.argv, tree as Root, file).forEach((dep) => { + graph.addEdge(dep as FilePath, sourcePath) + }) } return graph From fa2ea2896f0977253733334199d28e509351e621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Silviu=20Loren=C8=9B?= <124451350+smilorent@users.noreply.github.com> Date: Sat, 17 Feb 2024 20:23:45 +0200 Subject: [PATCH 15/31] feat: add user-defined config for syntax highlighting plugin (#869) * feat: add user-defined options to syntax highlighting plugin * feat: add default syntax highlighting config to `quartz.config.ts` * chore: refactor according to @aarnphm's review Co-authored-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> * chore: run Prettier on `quartz/plugins/transformers/syntax.ts` * Update quartz/plugins/transformers/syntax.ts Co-authored-by: Jacky Zhao * Update syntax.ts --------- Co-authored-by: Aaron Pham <29749331+aarnphm@users.noreply.github.com> Co-authored-by: Jacky Zhao --- quartz.config.ts | 11 ++++++- quartz/plugins/transformers/syntax.ts | 47 +++++++++++++++++---------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/quartz.config.ts b/quartz.config.ts index 4e36e9408..8c479ac78 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -53,7 +53,16 @@ const config: QuartzConfig = { priority: ["frontmatter", "filesystem"], }), Plugin.Latex({ renderEngine: "katex" }), - Plugin.SyntaxHighlighting(), + Plugin.SyntaxHighlighting({ + // uses themes bundled with Shikiji, see https://shikiji.netlify.app/themes + theme: { + light: "github-light", + dark: "github-dark", + }, + // set this to 'true' to use the background color of the Shikiji theme + // if set to 'false', will use Quartz theme colors for background + keepBackground: false, + }), Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }), Plugin.GitHubFlavoredMarkdown(), Plugin.TableOfContents(), diff --git a/quartz/plugins/transformers/syntax.ts b/quartz/plugins/transformers/syntax.ts index e84772962..f11734e5f 100644 --- a/quartz/plugins/transformers/syntax.ts +++ b/quartz/plugins/transformers/syntax.ts @@ -1,20 +1,33 @@ import { QuartzTransformerPlugin } from "../types" -import rehypePrettyCode, { Options as CodeOptions } from "rehype-pretty-code" +import rehypePrettyCode, { Options as CodeOptions, Theme as CodeTheme } from "rehype-pretty-code" -export const SyntaxHighlighting: QuartzTransformerPlugin = () => ({ - name: "SyntaxHighlighting", - htmlPlugins() { - return [ - [ - rehypePrettyCode, - { - keepBackground: false, - theme: { - dark: "github-dark", - light: "github-light", - }, - } satisfies Partial, - ], - ] +interface Theme extends Record { + light: CodeTheme + dark: CodeTheme +} + +interface Options { + theme?: Theme + keepBackground?: boolean +} + +const defaultOptions: Options = { + theme: { + light: "github-light", + dark: "github-dark", }, -}) + keepBackground: false, +} + +export const SyntaxHighlighting: QuartzTransformerPlugin = ( + userOpts?: Partial, +) => { + const opts: Partial = { ...defaultOptions, ...userOpts } + + return { + name: "SyntaxHighlighting", + htmlPlugins() { + return [[rehypePrettyCode, opts]] + }, + } +} From 06e3f8b93d5fbe96e7a05e4eb6be97b6a2d7ead0 Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sat, 17 Feb 2024 10:34:46 -0800 Subject: [PATCH 16/31] fix(style): introduce semiBoldWeight and various improvements to reduce CLS --- quartz/components/Head.tsx | 12 ++++++------ quartz/components/styles/explorer.scss | 4 ++-- quartz/plugins/emitters/componentResources.ts | 9 ++++----- quartz/styles/base.scss | 2 +- quartz/styles/callouts.scss | 2 +- quartz/styles/variables.scss | 1 + 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/quartz/components/Head.tsx b/quartz/components/Head.tsx index a3c0800ab..3cb6bea66 100644 --- a/quartz/components/Head.tsx +++ b/quartz/components/Head.tsx @@ -21,6 +21,12 @@ export default (() => { {title} + {cfg.theme.cdnCaching && ( + <> + + + + )} @@ -30,12 +36,6 @@ export default (() => { - {cfg.theme.cdnCaching && ( - <> - - - - )} {css.map((href) => ( ))} diff --git a/quartz/components/styles/explorer.scss b/quartz/components/styles/explorer.scss index 34f180cf2..55ea8aa88 100644 --- a/quartz/components/styles/explorer.scss +++ b/quartz/components/styles/explorer.scss @@ -87,7 +87,7 @@ svg { color: var(--secondary); font-family: var(--headerFont); font-size: 0.95rem; - font-weight: $boldWeight; + font-weight: $semiBoldWeight; line-height: 1.5rem; display: inline-block; } @@ -112,7 +112,7 @@ svg { font-size: 0.95rem; display: inline-block; color: var(--secondary); - font-weight: $boldWeight; + font-weight: $semiBoldWeight; margin: 0; line-height: 1.5rem; pointer-events: none; diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts index 67bc69c3d..046841689 100644 --- a/quartz/plugins/emitters/componentResources.ts +++ b/quartz/plugins/emitters/componentResources.ts @@ -196,10 +196,6 @@ export const ComponentResources: QuartzEmitterPlugin = (opts?: Partial< const cfg = ctx.cfg.configuration // component specific scripts and styles const componentResources = getComponentResources(ctx) - // important that this goes *after* component scripts - // as the "nav" event gets triggered here and we should make sure - // that everyone else had the chance to register a listener for it - let googleFontsStyleSheet = "" if (fontOrigin === "local") { // let the user do it themselves in css @@ -247,12 +243,15 @@ export const ComponentResources: QuartzEmitterPlugin = (opts?: Partial< } } + // important that this goes *after* component scripts + // as the "nav" event gets triggered here and we should make sure + // that everyone else had the chance to register a listener for it addGlobalPageResources(ctx, resources, componentResources) const stylesheet = joinStyles( ctx.cfg.configuration.theme, - ...componentResources.css, googleFontsStyleSheet, + ...componentResources.css, styles, ) const [prescript, postscript] = await Promise.all([ diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss index f0e7c14d1..6c8f836ab 100644 --- a/quartz/styles/base.scss +++ b/quartz/styles/base.scss @@ -54,7 +54,7 @@ ul, } a { - font-weight: $boldWeight; + font-weight: $semiBoldWeight; text-decoration: none; transition: color 0.2s ease; color: var(--secondary); diff --git a/quartz/styles/callouts.scss b/quartz/styles/callouts.scss index 7fa52c506..b1fd180ce 100644 --- a/quartz/styles/callouts.scss +++ b/quartz/styles/callouts.scss @@ -157,6 +157,6 @@ } .callout-title-inner { - font-weight: $boldWeight; + font-weight: $semiBoldWeight; } } diff --git a/quartz/styles/variables.scss b/quartz/styles/variables.scss index 8384b9c4e..e45cc9158 100644 --- a/quartz/styles/variables.scss +++ b/quartz/styles/variables.scss @@ -5,4 +5,5 @@ $sidePanelWidth: 380px; $topSpacing: 6rem; $fullPageWidth: $pageWidth + 2 * $sidePanelWidth; $boldWeight: 700; +$semiBoldWeight: 600; $normalWeight: 400; From a6690c6503ca6b2957a4476671c7239212b81b1a Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sat, 17 Feb 2024 10:57:59 -0800 Subject: [PATCH 17/31] fix(style): bold should use semibold --- quartz/styles/base.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss index 6c8f836ab..92798a2da 100644 --- a/quartz/styles/base.scss +++ b/quartz/styles/base.scss @@ -53,6 +53,10 @@ ul, } } +strong { + font-weight: $semiBoldWeight; +} + a { font-weight: $semiBoldWeight; text-decoration: none; From aa24a62ae77ed1bd3edd4b617cd76d7a056c7f1c Mon Sep 17 00:00:00 2001 From: Jacky Zhao Date: Sat, 17 Feb 2024 11:12:35 -0800 Subject: [PATCH 18/31] fix(breadcrumbs): calculate trailing slash for tag hierarchies (closes #873) --- quartz/components/Breadcrumbs.tsx | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/quartz/components/Breadcrumbs.tsx b/quartz/components/Breadcrumbs.tsx index b1a924aa8..9ccfb9a6a 100644 --- a/quartz/components/Breadcrumbs.tsx +++ b/quartz/components/Breadcrumbs.tsx @@ -1,6 +1,6 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types" import breadcrumbsStyle from "./styles/breadcrumbs.scss" -import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" +import { FullSlug, SimpleSlug, joinSegments, resolveRelative } from "../util/path" import { QuartzPluginData } from "../plugins/vfile" import { classNames } from "../util/lang" @@ -82,8 +82,12 @@ export default ((opts?: Partial) => { // Split slug into hierarchy/parts const slugParts = fileData.slug?.split("/") if (slugParts) { + // is tag breadcrumb? + const isTagPath = slugParts[0] === "tags" + // full path until current part let currentPath = "" + for (let i = 0; i < slugParts.length - 1; i++) { let curPathSegment = slugParts[i] @@ -97,10 +101,15 @@ export default ((opts?: Partial) => { } // Add current slug to full path - currentPath += slugParts[i] + "/" + currentPath = joinSegments(currentPath, slugParts[i]) + const includeTrailingSlash = !isTagPath || i < 1 // Format and add current crumb - const crumb = formatCrumb(curPathSegment, fileData.slug!, currentPath as SimpleSlug) + const crumb = formatCrumb( + curPathSegment, + fileData.slug!, + (currentPath + (includeTrailingSlash ? "/" : "")) as SimpleSlug, + ) crumbs.push(crumb) } From 8c5c5f9130c65fcc48412a24b0a6c98b254f1934 Mon Sep 17 00:00:00 2001 From: makondratev <69584771+makondratev@users.noreply.github.com> Date: Sun, 18 Feb 2024 21:54:37 +0300 Subject: [PATCH 19/31] feat(i18n): add Russian (#886) --- quartz/i18n/index.ts | 2 + quartz/i18n/locales/ru-RU.ts | 95 ++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+) create mode 100644 quartz/i18n/locales/ru-RU.ts diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index c4fa4251c..1e4853f40 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -8,6 +8,7 @@ import ro from "./locales/ro-RO" import es from "./locales/es-ES" import ar from "./locales/ar-SA" import uk from "./locales/uk-UA" +import ru from "./locales/ru-RU" export const TRANSLATIONS = { "en-US": en, @@ -40,6 +41,7 @@ export const TRANSLATIONS = { "ar-DZ": ar, "ar-MR": ar, "uk-UA": uk, + "ru-RU": ru, } as const export const defaultTranslation = "en-US" diff --git a/quartz/i18n/locales/ru-RU.ts b/quartz/i18n/locales/ru-RU.ts new file mode 100644 index 000000000..8ead3cabe --- /dev/null +++ b/quartz/i18n/locales/ru-RU.ts @@ -0,0 +1,95 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "Без названия", + description: "Описание отсутствует", + }, + components: { + callout: { + note: "Заметка", + abstract: "Резюме", + info: "Инфо", + todo: "Сделать", + tip: "Подсказка", + success: "Успех", + question: "Вопрос", + warning: "Предупреждение", + failure: "Неудача", + danger: "Опасность", + bug: "Баг", + example: "Пример", + quote: "Цитата", + }, + backlinks: { + title: "Обратные ссылки", + noBacklinksFound: "Обратные ссылки отсутствуют", + }, + themeToggle: { + lightMode: "Светлый режим", + darkMode: "Тёмный режим", + }, + explorer: { + title: "Проводник", + }, + footer: { + createdWith: "Создано с помощью", + }, + graph: { + title: "Вид графа", + }, + recentNotes: { + title: "Недавние заметки", + seeRemainingMore: ({ remaining }) => + `Посмотреть оставш${getForm(remaining, "уюся", "иеся", "иеся")} ${remaining} →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `Переход из ${targetSlug}`, + linkToOriginal: "Ссылка на оригинал", + }, + search: { + title: "Поиск", + searchBarPlaceholder: "Найти что-нибудь", + }, + tableOfContents: { + title: "Оглавление", + }, + contentMeta: { + readingTime: ({ minutes }) => `время чтения ~${minutes} мин.`, + }, + }, + pages: { + rss: { + recentNotes: "Недавние заметки", + lastFewNotes: ({ count }) => + `Последн${getForm(count, "яя", "ие", "ие")} ${count} замет${getForm(count, "ка", "ки", "ок")}`, + }, + error: { + title: "Страница не найдена", + notFound: "Эта страница приватная или не существует", + }, + folderContent: { + folder: "Папка", + itemsUnderFolder: ({ count }) => + `в этой папке ${count} элемент${getForm(count, "", "а", "ов")}`, + }, + tagContent: { + tag: "Тег", + tagIndex: "Индекс тегов", + itemsUnderTag: ({ count }) => `с этим тегом ${count} элемент${getForm(count, "", "а", "ов")}`, + showingFirst: ({ count }) => + `Показыва${getForm(count, "ется", "ются", "ются")} ${count} тег${getForm(count, "", "а", "ов")}`, + totalTags: ({ count }) => `Всего ${count} тег${getForm(count, "", "а", "ов")}`, + }, + }, +} as const satisfies Translation + +function getForm(number: number, form1: string, form2: string, form5: string): string { + const remainder100 = number % 100 + const remainder10 = remainder100 % 10 + + if (remainder100 >= 10 && remainder100 <= 20) return form5 + if (remainder10 > 1 && remainder10 < 5) return form2 + if (remainder10 == 1) return form1 + return form5 +} From b1a105371bffdea6ca10a010292248ef9aff3ce2 Mon Sep 17 00:00:00 2001 From: JONG HWAN KIM <99215801+JongDeug@users.noreply.github.com> Date: Mon, 19 Feb 2024 07:37:59 +0900 Subject: [PATCH 20/31] feat(i18n): add Korean (#889) * feat(i18n): add Korean * feat(i18n): add Korean --- quartz/i18n/index.ts | 2 + quartz/i18n/locales/ko-KR.ts | 81 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 quartz/i18n/locales/ko-KR.ts diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index 1e4853f40..5224f667b 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -9,6 +9,7 @@ import es from "./locales/es-ES" import ar from "./locales/ar-SA" import uk from "./locales/uk-UA" import ru from "./locales/ru-RU" +import ko from "./locales/ko-KR" export const TRANSLATIONS = { "en-US": en, @@ -42,6 +43,7 @@ export const TRANSLATIONS = { "ar-MR": ar, "uk-UA": uk, "ru-RU": ru, + "ko-KR": ko, } as const export const defaultTranslation = "en-US" diff --git a/quartz/i18n/locales/ko-KR.ts b/quartz/i18n/locales/ko-KR.ts new file mode 100644 index 000000000..ed859a90e --- /dev/null +++ b/quartz/i18n/locales/ko-KR.ts @@ -0,0 +1,81 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "제목 없음", + description: "설명 없음", + }, + components: { + callout: { + note: "노트", + abstract: "개요", + info: "정보", + todo: "할일", + tip: "팁", + success: "성공", + question: "질문", + warning: "주의", + failure: "실패", + danger: "위험", + bug: "버그", + example: "예시", + quote: "인용", + }, + backlinks: { + title: "백링크", + noBacklinksFound: "백링크가 없습니다.", + }, + themeToggle: { + lightMode: "라이트 모드", + darkMode: "다크 모드", + }, + explorer: { + title: "탐색기", + }, + footer: { + createdWith: "Created with", + }, + graph: { + title: "그래프 뷰", + }, + recentNotes: { + title: "최근 게시글", + seeRemainingMore: ({ remaining }) => `${remaining}건 더보기 →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `${targetSlug}의 포함`, + linkToOriginal: "원본 링크", + }, + search: { + title: "검색", + searchBarPlaceholder: "검색어를 입력하세요", + }, + tableOfContents: { + title: "목차", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} min read`, + }, + }, + pages: { + rss: { + recentNotes: "최근 게시글", + lastFewNotes: ({ count }) => `최근 ${count} 건`, + }, + error: { + title: "Not Found", + notFound: "페이지가 존재하지 않거나 비공개 설정이 되어 있습니다.", + }, + folderContent: { + folder: "폴더", + itemsUnderFolder: ({ count }) => `${count}건의 페이지`, + }, + tagContent: { + tag: "태그", + tagIndex: "태그 목록", + itemsUnderTag: ({ count }) => `${count}건의 페이지`, + showingFirst: ({ count }) => `처음 ${count}개의 태그`, + totalTags: ({ count }) => `총 ${count}개의 태그를 찾았습니다.`, + }, + }, +} as const satisfies Translation From 739c2e2cc8db456514f81def7fa8c519656fdaa7 Mon Sep 17 00:00:00 2001 From: s-crypt <41712656+s-crypt@users.noreply.github.com> Date: Sun, 18 Feb 2024 20:26:04 -0800 Subject: [PATCH 21/31] perf(cdn): CDNJS instead of JSDelivr (#891) --- docs/advanced/making plugins.md | 4 ++-- quartz/plugins/transformers/latex.ts | 4 ++-- quartz/plugins/transformers/ofm.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/advanced/making plugins.md b/docs/advanced/making plugins.md index 565f5bdba..d9ed9e33e 100644 --- a/docs/advanced/making plugins.md +++ b/docs/advanced/making plugins.md @@ -84,10 +84,10 @@ export const Latex: QuartzTransformerPlugin = (opts?: Options) => { externalResources() { if (engine === "katex") { return { - css: ["https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css"], + css: ["https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css"], js: [ { - src: "https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/contrib/copy-tex.min.js", + src: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.7/contrib/copy-tex.min.js", loadTime: "afterDOMReady", contentType: "external", }, diff --git a/quartz/plugins/transformers/latex.ts b/quartz/plugins/transformers/latex.ts index ab10a4fbb..c9f6bff0d 100644 --- a/quartz/plugins/transformers/latex.ts +++ b/quartz/plugins/transformers/latex.ts @@ -26,12 +26,12 @@ export const Latex: QuartzTransformerPlugin = (opts?: Options) => { return { css: [ // base css - "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css", + "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/katex.min.css", ], js: [ { // fix copy behaviour: https://github.com/KaTeX/KaTeX/blob/main/contrib/copy-tex/README.md - src: "https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/copy-tex.min.js", + src: "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.16.9/contrib/copy-tex.min.js", loadTime: "afterDOMReady", contentType: "external", }, diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts index e110e403f..6aad23052 100644 --- a/quartz/plugins/transformers/ofm.ts +++ b/quartz/plugins/transformers/ofm.ts @@ -619,7 +619,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin let mermaidImport = undefined document.addEventListener('nav', async () => { if (document.querySelector("code.mermaid")) { - mermaidImport ||= await import('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs') + mermaidImport ||= await import('https://cdnjs.cloudflare.com/ajax/libs/mermaid/10.7.0/mermaid.esm.min.mjs') const mermaid = mermaidImport.default const darkMode = document.documentElement.getAttribute('saved-theme') === 'dark' mermaid.initialize({ From efd46f84de2d8dcc630b96de5454027bfbbf5f6e Mon Sep 17 00:00:00 2001 From: Eiko Wagenknecht Date: Mon, 19 Feb 2024 09:08:36 +0100 Subject: [PATCH 22/31] fix(frontmatter): delimiters parameter was not passed (#885) * fix: delimiters parameter was not passed Signed-off-by: Eiko Wagenknecht * fix: remove unneeded undefined --------- Signed-off-by: Eiko Wagenknecht --- quartz/plugins/transformers/frontmatter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quartz/plugins/transformers/frontmatter.ts b/quartz/plugins/transformers/frontmatter.ts index 9371df81e..7073d43bd 100644 --- a/quartz/plugins/transformers/frontmatter.ts +++ b/quartz/plugins/transformers/frontmatter.ts @@ -8,12 +8,12 @@ import { QuartzPluginData } from "../vfile" import { i18n } from "../../i18n" export interface Options { - delims: string | string[] + delimiters: string | [string, string] language: "yaml" | "toml" } const defaultOptions: Options = { - delims: "---", + delimiters: "---", language: "yaml", } From d9e8ffc78c54a59047df56d8000b2f6289eb9be0 Mon Sep 17 00:00:00 2001 From: Leonardo Ledda <35930217+LeddaZ@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:50:01 +0100 Subject: [PATCH 23/31] feat(i18n): Add Italian (#893) Signed-off-by: Leonardo Ledda --- quartz/i18n/index.ts | 2 + quartz/i18n/locales/it-IT.ts | 83 ++++++++++++++++++++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 quartz/i18n/locales/it-IT.ts diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index 5224f667b..3861bf73c 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -1,6 +1,7 @@ import { Translation, CalloutTranslation } from "./locales/definition" import en from "./locales/en-US" import fr from "./locales/fr-FR" +import it from "./locales/it-IT" import ja from "./locales/ja-JP" import de from "./locales/de-DE" import nl from "./locales/nl-NL" @@ -14,6 +15,7 @@ import ko from "./locales/ko-KR" export const TRANSLATIONS = { "en-US": en, "fr-FR": fr, + "it-IT": it, "ja-JP": ja, "de-DE": de, "nl-NL": nl, diff --git a/quartz/i18n/locales/it-IT.ts b/quartz/i18n/locales/it-IT.ts new file mode 100644 index 000000000..a0cc04283 --- /dev/null +++ b/quartz/i18n/locales/it-IT.ts @@ -0,0 +1,83 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "Senza titolo", + description: "Nessuna descrizione", + }, + components: { + callout: { + note: "Nota", + abstract: "Astratto", + info: "Info", + todo: "Da fare", + tip: "Consiglio", + success: "Completato", + question: "Domanda", + warning: "Attenzione", + failure: "Errore", + danger: "Pericolo", + bug: "Bug", + example: "Esempio", + quote: "Citazione", + }, + backlinks: { + title: "Link entranti", + noBacklinksFound: "Nessun link entrante", + }, + themeToggle: { + lightMode: "Tema chiaro", + darkMode: "Tema scuro", + }, + explorer: { + title: "Esplora", + }, + footer: { + createdWith: "Creato con", + }, + graph: { + title: "Vista grafico", + }, + recentNotes: { + title: "Note recenti", + seeRemainingMore: ({ remaining }) => `Vedi ${remaining} altro →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `Transclusione di ${targetSlug}`, + linkToOriginal: "Link all'originale", + }, + search: { + title: "Cerca", + searchBarPlaceholder: "Cerca qualcosa", + }, + tableOfContents: { + title: "Tabella dei contenuti", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes} minuti`, + }, + }, + pages: { + rss: { + recentNotes: "Note recenti", + lastFewNotes: ({ count }) => `Ultime ${count} note`, + }, + error: { + title: "Non trovato", + notFound: "Questa pagina è privata o non esiste.", + }, + folderContent: { + folder: "Cartella", + itemsUnderFolder: ({ count }) => + count === 1 ? "1 oggetto in questa cartella" : `${count} oggetti in questa cartella.`, + }, + tagContent: { + tag: "Etichetta", + tagIndex: "Indice etichette", + itemsUnderTag: ({ count }) => + count === 1 ? "1 oggetto con questa etichetta" : `${count} oggetti con questa etichetta.`, + showingFirst: ({ count }) => `Prime ${count} etichette.`, + totalTags: ({ count }) => `Trovate ${count} etichette totali.`, + }, + }, +} as const satisfies Translation From 3e09b05468c372e85518ff76d8d6d9a415f61fac Mon Sep 17 00:00:00 2001 From: kon-foo <25391223+kon-foo@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:50:40 +0100 Subject: [PATCH 24/31] docs: add self-hosting section (#883) * Add Self-Hosting section Add Nginx section * run prettier --- docs/hosting.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/hosting.md b/docs/hosting.md index bae7ed899..eeb930849 100644 --- a/docs/hosting.md +++ b/docs/hosting.md @@ -228,3 +228,25 @@ pages: When `.gitlab-ci.yaml` is committed, GitLab will build and deploy the website as a GitLab Page. You can find the url under `Deploy > Pages` in the sidebar. By default, the page is private and only visible when logged in to a GitLab account with access to the repository but can be opened in the settings under `Deploy` -> `Pages`. + +## Self-Hosting + +Copy the `public` directory to your web server and configure it to serve the files. You can use any web server to host your site. Since Quartz generates links that do not include the `.html` extension, you need to let your web server know how to deal with it. + +### Using Nginx + +Here's an example of how to do this with Nginx: + +```nginx title="nginx.conf" +server { + listen 80; + server_name example.com; + root /path/to/quartz/public; + index index.html; + error_page 404 /404.html; + + location / { + try_files $uri $uri.html $uri/ =404; + } +} +``` From e85ea490003870c5a6c004bb2e6bd6d76769a2ce Mon Sep 17 00:00:00 2001 From: KylinDC Date: Tue, 20 Feb 2024 02:31:09 +0800 Subject: [PATCH 25/31] feat(i18n): add Simplified Chinese (#896) --- quartz/i18n/index.ts | 2 + quartz/i18n/locales/zh-CN.ts | 81 ++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 quartz/i18n/locales/zh-CN.ts diff --git a/quartz/i18n/index.ts b/quartz/i18n/index.ts index 3861bf73c..38d356280 100644 --- a/quartz/i18n/index.ts +++ b/quartz/i18n/index.ts @@ -11,6 +11,7 @@ import ar from "./locales/ar-SA" import uk from "./locales/uk-UA" import ru from "./locales/ru-RU" import ko from "./locales/ko-KR" +import zh from "./locales/zh-CN" export const TRANSLATIONS = { "en-US": en, @@ -46,6 +47,7 @@ export const TRANSLATIONS = { "uk-UA": uk, "ru-RU": ru, "ko-KR": ko, + "zh-CN": zh, } as const export const defaultTranslation = "en-US" diff --git a/quartz/i18n/locales/zh-CN.ts b/quartz/i18n/locales/zh-CN.ts new file mode 100644 index 000000000..43d011197 --- /dev/null +++ b/quartz/i18n/locales/zh-CN.ts @@ -0,0 +1,81 @@ +import { Translation } from "./definition" + +export default { + propertyDefaults: { + title: "无题", + description: "无描述", + }, + components: { + callout: { + note: "笔记", + abstract: "摘要", + info: "提示", + todo: "待办", + tip: "提示", + success: "成功", + question: "问题", + warning: "警告", + failure: "失败", + danger: "危险", + bug: "错误", + example: "示例", + quote: "引用", + }, + backlinks: { + title: "反向链接", + noBacklinksFound: "无法找到反向链接", + }, + themeToggle: { + lightMode: "亮色模式", + darkMode: "暗色模式", + }, + explorer: { + title: "探索", + }, + footer: { + createdWith: "Created with", + }, + graph: { + title: "关系图谱", + }, + recentNotes: { + title: "最近的笔记", + seeRemainingMore: ({ remaining }) => `查看更多${remaining}篇笔记 →`, + }, + transcludes: { + transcludeOf: ({ targetSlug }) => `包含${targetSlug}`, + linkToOriginal: "指向原始笔记的链接", + }, + search: { + title: "搜索", + searchBarPlaceholder: "搜索些什么", + }, + tableOfContents: { + title: "目录", + }, + contentMeta: { + readingTime: ({ minutes }) => `${minutes}分钟阅读`, + }, + }, + pages: { + rss: { + recentNotes: "最近的笔记", + lastFewNotes: ({ count }) => `最近的${count}条笔记`, + }, + error: { + title: "无法找到", + notFound: "私有笔记或笔记不存在。", + }, + folderContent: { + folder: "文件夹", + itemsUnderFolder: ({ count }) => `此文件夹下有${count}条笔记。`, + }, + tagContent: { + tag: "标签", + tagIndex: "标签索引", + itemsUnderTag: ({ count }) => `此标签下有${count}条笔记。`, + showingFirst: ({ count }) => `显示前${count}个标签。`, + totalTags: ({ count }) => `总共有${count}个标签。`, + }, + }, +} as const satisfies Translation From a67a8d7aa9da06d8f87d0f48bac630728a4ea394 Mon Sep 17 00:00:00 2001 From: kabirgh <15871468+kabirgh@users.noreply.github.com> Date: Mon, 19 Feb 2024 18:58:15 +0000 Subject: [PATCH 26/31] feat: implement getDependencyGraph for TagPage (#872) * feat: implement getDependencyGraph for TagPage * Only add file to dg if it has at least 1 tag --- quartz/plugins/emitters/tagPage.tsx | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/quartz/plugins/emitters/tagPage.tsx b/quartz/plugins/emitters/tagPage.tsx index 332c758d5..3eb6975f7 100644 --- a/quartz/plugins/emitters/tagPage.tsx +++ b/quartz/plugins/emitters/tagPage.tsx @@ -35,9 +35,26 @@ export const TagPage: QuartzEmitterPlugin> = (userOpts) getQuartzComponents() { return [Head, Header, Body, ...header, ...beforeBody, pageBody, ...left, ...right, Footer] }, - async getDependencyGraph(ctx, _content, _resources) { - // TODO implement - return new DepGraph() + async getDependencyGraph(ctx, content, _resources) { + const graph = new DepGraph() + + for (const [_tree, file] of content) { + const sourcePath = file.data.filePath! + const tags = (file.data.frontmatter?.tags ?? []).flatMap(getAllSegmentPrefixes) + // if the file has at least one tag, it is used in the tag index page + if (tags.length > 0) { + tags.push("index") + } + + for (const tag of tags) { + graph.addEdge( + sourcePath, + joinSegments(ctx.argv.output, "tags", tag + ".html") as FilePath, + ) + } + } + + return graph }, async emit(ctx, content, resources): Promise { const fps: FilePath[] = [] From 0493942c79f8528ca8bef6cd8e2f634275f03119 Mon Sep 17 00:00:00 2001 From: kon-foo <25391223+kon-foo@users.noreply.github.com> Date: Mon, 19 Feb 2024 20:04:27 +0100 Subject: [PATCH 27/31] fix: remove assets via globs to avoid volume mount lock (#877) * Fix docker volume lock issue by altering asset cleanup method Modified build process to prevent the deletion of the output directory. * Add fsOps utility for filesystem operations * Use cleanDirectory in build process to fix volume lock issue * applied prettier * handle ENOENT error when output dir does not exist * remove native function in favor of rimraf * use path.join to concatenate paths --- quartz/build.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quartz/build.ts b/quartz/build.ts index 452a2f1ae..3d95f315f 100644 --- a/quartz/build.ts +++ b/quartz/build.ts @@ -60,7 +60,7 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { const release = await mut.acquire() perf.addEvent("clean") - await rimraf(output) + await rimraf(path.join(output, "*"), { glob: true }) console.log(`Cleaned output directory \`${output}\` in ${perf.timeSince("clean")}`) perf.addEvent("glob") @@ -375,7 +375,7 @@ async function rebuildFromEntrypoint( // TODO: we can probably traverse the link graph to figure out what's safe to delete here // instead of just deleting everything - await rimraf(argv.output) + await rimraf(path.join(argv.output, ".*"), { glob: true }) await emitContent(ctx, filteredContent) console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`)) } catch (err) { From 637e336cdaa8cf8eb918257c236c53ccc5dc5ae8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:46:27 -0800 Subject: [PATCH 28/31] chore(deps-dev): bump @types/node from 20.11.16 to 20.11.19 (#899) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.11.16 to 20.11.19. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development 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 7d1d9737e..4d0ef1a69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,7 +73,7 @@ "@types/d3": "^7.4.3", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.11.16", + "@types/node": "^20.11.19", "@types/pretty-time": "^1.1.5", "@types/source-map-support": "^0.5.10", "@types/ws": "^8.5.10", @@ -1088,9 +1088,9 @@ } }, "node_modules/@types/node": { - "version": "20.11.16", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", - "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "version": "20.11.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.19.tgz", + "integrity": "sha512-7xMnVEcZFu0DikYjWOlRq7NTPETrm7teqUT2WkQjrTIkEgUyyGdWsj/Zg8bEJt5TNklzbPD1X3fqfsHw3SpapQ==", "dev": true, "dependencies": { "undici-types": "~5.26.4" diff --git a/package.json b/package.json index f89bb2a0b..2a567358b 100644 --- a/package.json +++ b/package.json @@ -95,7 +95,7 @@ "@types/d3": "^7.4.3", "@types/hast": "^3.0.4", "@types/js-yaml": "^4.0.9", - "@types/node": "^20.11.16", + "@types/node": "^20.11.19", "@types/pretty-time": "^1.1.5", "@types/source-map-support": "^0.5.10", "@types/ws": "^8.5.10", From f1619620d5cd285b4a4dabf69a9dd1d95de2f36c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:47:00 -0800 Subject: [PATCH 29/31] chore(deps): bump globby from 14.0.0 to 14.0.1 (#897) Bumps [globby](https://github.com/sindresorhus/globby) from 14.0.0 to 14.0.1. - [Release notes](https://github.com/sindresorhus/globby/releases) - [Commits](https://github.com/sindresorhus/globby/compare/v14.0.0...v14.0.1) --- updated-dependencies: - dependency-name: globby 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 | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4d0ef1a69..e2ae90e7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "esbuild-sass-plugin": "^2.16.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", - "globby": "^14.0.0", + "globby": "^14.0.1", "gray-matter": "^4.0.3", "hast-util-to-html": "^9.0.0", "hast-util-to-jsx-runtime": "^2.3.0", @@ -743,9 +743,9 @@ } }, "node_modules/@sindresorhus/merge-streams": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", - "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", "engines": { "node": ">=18" }, @@ -2301,11 +2301,11 @@ } }, "node_modules/globby": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", - "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", "dependencies": { - "@sindresorhus/merge-streams": "^1.0.0", + "@sindresorhus/merge-streams": "^2.1.0", "fast-glob": "^3.3.2", "ignore": "^5.2.4", "path-type": "^5.0.0", diff --git a/package.json b/package.json index 2a567358b..d469d7b01 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "esbuild-sass-plugin": "^2.16.1", "flexsearch": "0.7.43", "github-slugger": "^2.0.0", - "globby": "^14.0.0", + "globby": "^14.0.1", "gray-matter": "^4.0.3", "hast-util-to-html": "^9.0.0", "hast-util-to-jsx-runtime": "^2.3.0", From 779c501d9eb6393539f0be7653dbdc09f1b9ebe9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 13:47:07 -0800 Subject: [PATCH 30/31] chore(deps): bump preact from 10.19.4 to 10.19.5 (#898) Bumps [preact](https://github.com/preactjs/preact) from 10.19.4 to 10.19.5. - [Release notes](https://github.com/preactjs/preact/releases) - [Commits](https://github.com/preactjs/preact/compare/10.19.4...10.19.5) --- updated-dependencies: - dependency-name: preact 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 e2ae90e7c..4a8b58336 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "mdast-util-to-hast": "^13.1.0", "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", - "preact": "^10.19.4", + "preact": "^10.19.5", "preact-render-to-string": "^6.3.1", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", @@ -4454,9 +4454,9 @@ } }, "node_modules/preact": { - "version": "10.19.4", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.4.tgz", - "integrity": "sha512-dwaX5jAh0Ga8uENBX1hSOujmKWgx9RtL80KaKUFLc6jb4vCEAc3EeZ0rnQO/FO4VgjfPMfoLFWnNG8bHuZ9VLw==", + "version": "10.19.5", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.19.5.tgz", + "integrity": "sha512-OPELkDmSVbKjbFqF9tgvOowiiQ9TmsJljIzXRyNE8nGiis94pwv1siF78rQkAP1Q1738Ce6pellRg/Ns/CtHqQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" diff --git a/package.json b/package.json index d469d7b01..54c67fbff 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,7 @@ "mdast-util-to-hast": "^13.1.0", "mdast-util-to-string": "^4.0.0", "micromorph": "^0.4.5", - "preact": "^10.19.4", + "preact": "^10.19.5", "preact-render-to-string": "^6.3.1", "pretty-bytes": "^6.1.1", "pretty-time": "^1.1.0", From b6cf3df84f452c22ac9ddaf452b0ecbe0828086f Mon Sep 17 00:00:00 2001 From: Eiko Wagenknecht Date: Mon, 19 Feb 2024 22:49:07 +0100 Subject: [PATCH 31/31] fix: correctly parse falsy js as title (#900) --- quartz/plugins/transformers/frontmatter.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quartz/plugins/transformers/frontmatter.ts b/quartz/plugins/transformers/frontmatter.ts index 7073d43bd..79aa5f313 100644 --- a/quartz/plugins/transformers/frontmatter.ts +++ b/quartz/plugins/transformers/frontmatter.ts @@ -57,9 +57,9 @@ export const FrontMatter: QuartzTransformerPlugin | undefined> }, }) - if (data.title) { + if (data.title != null && data.title.toString() !== "") { data.title = data.title.toString() - } else if (data.title === null || data.title === undefined) { + } else { data.title = file.stem ?? i18n(cfg.configuration.locale).propertyDefaults.title }