mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-24 21:34:06 -06:00
Merge branch 'jackyzha0:v4' into fix-deduplicate-aliases
This commit is contained in:
commit
036c309c4b
@ -62,7 +62,7 @@ The following properties can be used to customize your link previews:
|
|||||||
| `socialDescription` | `description` | Description to be used for preview. |
|
| `socialDescription` | `description` | Description to be used for preview. |
|
||||||
| `socialImage` | `image`, `cover` | Link to preview image. |
|
| `socialImage` | `image`, `cover` | Link to preview image. |
|
||||||
|
|
||||||
The `socialImage` property should contain a link to an image relative to `quartz/static`. If you have a folder for all your images in `quartz/static/my-images`, an example for `socialImage` could be `"my-images/cover.png"`.
|
The `socialImage` property should contain a link to an image either relative to `quartz/static`, or a full URL. If you have a folder for all your images in `quartz/static/my-images`, an example for `socialImage` could be `"my-images/cover.png"`. Alternatively, you can use a fully qualified URL like `"https://example.com/cover.png"`.
|
||||||
|
|
||||||
> [!info] Info
|
> [!info] Info
|
||||||
>
|
>
|
||||||
|
|||||||
@ -18,7 +18,7 @@ const config: QuartzConfig = {
|
|||||||
locale: "en-US",
|
locale: "en-US",
|
||||||
baseUrl: "quartz.jzhao.xyz",
|
baseUrl: "quartz.jzhao.xyz",
|
||||||
ignorePatterns: ["private", "templates", ".obsidian"],
|
ignorePatterns: ["private", "templates", ".obsidian"],
|
||||||
defaultDateType: "created",
|
defaultDateType: "modified",
|
||||||
theme: {
|
theme: {
|
||||||
fontOrigin: "googleFonts",
|
fontOrigin: "googleFonts",
|
||||||
cdnCaching: true,
|
cdnCaching: true,
|
||||||
|
|||||||
@ -88,89 +88,108 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
|
|||||||
if (cfg.analytics?.provider === "google") {
|
if (cfg.analytics?.provider === "google") {
|
||||||
const tagId = cfg.analytics.tagId
|
const tagId = cfg.analytics.tagId
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const gtagScript = document.createElement("script")
|
const gtagScript = document.createElement('script');
|
||||||
gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
|
gtagScript.src = 'https://www.googletagmanager.com/gtag/js?id=${tagId}';
|
||||||
gtagScript.defer = true
|
gtagScript.defer = true;
|
||||||
document.head.appendChild(gtagScript)
|
gtagScript.onload = () => {
|
||||||
|
window.dataLayer = window.dataLayer || [];
|
||||||
window.dataLayer = window.dataLayer || [];
|
function gtag() {
|
||||||
function gtag() { dataLayer.push(arguments); }
|
dataLayer.push(arguments);
|
||||||
gtag("js", new Date());
|
}
|
||||||
gtag("config", "${tagId}", { send_page_view: false });
|
gtag('js', new Date());
|
||||||
|
gtag('config', '${tagId}', { send_page_view: false });
|
||||||
document.addEventListener("nav", () => {
|
gtag('event', 'page_view', { page_title: document.title, page_location: location.href });
|
||||||
gtag("event", "page_view", {
|
document.addEventListener('nav', () => {
|
||||||
page_title: document.title,
|
gtag('event', 'page_view', { page_title: document.title, page_location: location.href });
|
||||||
page_location: location.href,
|
|
||||||
});
|
});
|
||||||
});`)
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(gtagScript);
|
||||||
|
`)
|
||||||
} else if (cfg.analytics?.provider === "plausible") {
|
} else if (cfg.analytics?.provider === "plausible") {
|
||||||
const plausibleHost = cfg.analytics.host ?? "https://plausible.io"
|
const plausibleHost = cfg.analytics.host ?? "https://plausible.io"
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const plausibleScript = document.createElement("script")
|
const plausibleScript = document.createElement('script');
|
||||||
plausibleScript.src = "${plausibleHost}/js/script.manual.js"
|
plausibleScript.src = '${plausibleHost}/js/script.manual.js';
|
||||||
plausibleScript.setAttribute("data-domain", location.hostname)
|
plausibleScript.setAttribute('data-domain', location.hostname);
|
||||||
plausibleScript.defer = true
|
plausibleScript.defer = true;
|
||||||
document.head.appendChild(plausibleScript)
|
plausibleScript.onload = () => {
|
||||||
|
window.plausible = window.plausible || function () { (window.plausible.q = window.plausible.q || []).push(arguments); };
|
||||||
|
plausible('pageview');
|
||||||
|
document.addEventListener('nav', () => {
|
||||||
|
plausible('pageview');
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }
|
document.head.appendChild(plausibleScript);
|
||||||
|
|
||||||
document.addEventListener("nav", () => {
|
|
||||||
plausible("pageview")
|
|
||||||
})
|
|
||||||
`)
|
`)
|
||||||
} else if (cfg.analytics?.provider === "umami") {
|
} else if (cfg.analytics?.provider === "umami") {
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const umamiScript = document.createElement("script")
|
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.setAttribute("data-website-id", "${cfg.analytics.websiteId}");
|
||||||
umamiScript.setAttribute("data-auto-track", "false")
|
umamiScript.setAttribute("data-auto-track", "false");
|
||||||
umamiScript.defer = true
|
umamiScript.defer = true;
|
||||||
document.head.appendChild(umamiScript)
|
umamiScript.onload = () => {
|
||||||
|
|
||||||
document.addEventListener("nav", () => {
|
|
||||||
umami.track();
|
umami.track();
|
||||||
})
|
document.addEventListener("nav", () => {
|
||||||
|
umami.track();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(umamiScript);
|
||||||
`)
|
`)
|
||||||
} else if (cfg.analytics?.provider === "goatcounter") {
|
} else if (cfg.analytics?.provider === "goatcounter") {
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const goatcounterScript = document.createElement("script")
|
const goatcounterScript = document.createElement('script');
|
||||||
goatcounterScript.src = "${cfg.analytics.scriptSrc ?? "https://gc.zgo.at/count.js"}"
|
goatcounterScript.src = "${cfg.analytics.scriptSrc ?? "https://gc.zgo.at/count.js"}";
|
||||||
goatcounterScript.defer = true
|
goatcounterScript.defer = true;
|
||||||
goatcounterScript.setAttribute("data-goatcounter",
|
goatcounterScript.setAttribute(
|
||||||
"https://${cfg.analytics.websiteId}.${cfg.analytics.host ?? "goatcounter.com"}/count")
|
'data-goatcounter',
|
||||||
document.head.appendChild(goatcounterScript)
|
"https://${cfg.analytics.websiteId}.${cfg.analytics.host ?? "goatcounter.com"}/count"
|
||||||
|
);
|
||||||
|
goatcounterScript.onload = () => {
|
||||||
|
window.goatcounter = { no_onload: true };
|
||||||
|
goatcounter.count({ path: location.pathname });
|
||||||
|
document.addEventListener('nav', () => {
|
||||||
|
goatcounter.count({ path: location.pathname });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
window.goatcounter = { no_onload: true }
|
document.head.appendChild(goatcounterScript);
|
||||||
document.addEventListener("nav", () => {
|
|
||||||
goatcounter.count({ path: location.pathname })
|
|
||||||
})
|
|
||||||
`)
|
`)
|
||||||
} else if (cfg.analytics?.provider === "posthog") {
|
} else if (cfg.analytics?.provider === "posthog") {
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const posthogScript = document.createElement("script")
|
const posthogScript = document.createElement("script");
|
||||||
posthogScript.innerHTML= \`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
|
posthogScript.innerHTML= \`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
|
||||||
posthog.init('${cfg.analytics.apiKey}', {
|
posthog.init('${cfg.analytics.apiKey}', {
|
||||||
api_host: '${cfg.analytics.host ?? "https://app.posthog.com"}',
|
api_host: '${cfg.analytics.host ?? "https://app.posthog.com"}',
|
||||||
capture_pageview: false,
|
capture_pageview: false,
|
||||||
})\`
|
})\`
|
||||||
document.head.appendChild(posthogScript)
|
posthogScript.onload = () => {
|
||||||
|
posthog.capture('$pageview', { path: location.pathname });
|
||||||
|
|
||||||
|
document.addEventListener('nav', () => {
|
||||||
|
posthog.capture('$pageview', { path: location.pathname });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
document.addEventListener("nav", () => {
|
document.head.appendChild(posthogScript);
|
||||||
posthog.capture('$pageview', { path: location.pathname })
|
|
||||||
})
|
|
||||||
`)
|
`)
|
||||||
} else if (cfg.analytics?.provider === "tinylytics") {
|
} else if (cfg.analytics?.provider === "tinylytics") {
|
||||||
const siteId = cfg.analytics.siteId
|
const siteId = cfg.analytics.siteId
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
const tinylyticsScript = document.createElement("script")
|
const tinylyticsScript = document.createElement('script');
|
||||||
tinylyticsScript.src = "https://tinylytics.app/embed/${siteId}.js?spa"
|
tinylyticsScript.src = 'https://tinylytics.app/embed/${siteId}.js?spa';
|
||||||
tinylyticsScript.defer = true
|
tinylyticsScript.defer = true;
|
||||||
document.head.appendChild(tinylyticsScript)
|
tinylyticsScript.onload = () => {
|
||||||
|
window.tinylytics.triggerUpdate();
|
||||||
document.addEventListener("nav", () => {
|
document.addEventListener('nav', () => {
|
||||||
window.tinylytics.triggerUpdate()
|
window.tinylytics.triggerUpdate();
|
||||||
})
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
document.head.appendChild(tinylyticsScript);
|
||||||
`)
|
`)
|
||||||
} else if (cfg.analytics?.provider === "cabin") {
|
} else if (cfg.analytics?.provider === "cabin") {
|
||||||
componentResources.afterDOMLoaded.push(`
|
componentResources.afterDOMLoaded.push(`
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { QuartzEmitterPlugin } from "../types"
|
import { QuartzEmitterPlugin } from "../types"
|
||||||
import { i18n } from "../../i18n"
|
import { i18n } from "../../i18n"
|
||||||
import { unescapeHTML } from "../../util/escape"
|
import { unescapeHTML } from "../../util/escape"
|
||||||
import { FullSlug, getFileExtension, joinSegments, QUARTZ } from "../../util/path"
|
import { FullSlug, getFileExtension, isAbsoluteURL, joinSegments, QUARTZ } from "../../util/path"
|
||||||
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
|
import { ImageOptions, SocialImageOptions, defaultImage, getSatoriFonts } from "../../util/og"
|
||||||
import sharp from "sharp"
|
import sharp from "sharp"
|
||||||
import satori, { SatoriOptions } from "satori"
|
import satori, { SatoriOptions } from "satori"
|
||||||
@ -144,13 +144,19 @@ export const CustomOgImages: QuartzEmitterPlugin<Partial<SocialImageOptions>> =
|
|||||||
additionalHead: [
|
additionalHead: [
|
||||||
(pageData) => {
|
(pageData) => {
|
||||||
const isRealFile = pageData.filePath !== undefined
|
const isRealFile = pageData.filePath !== undefined
|
||||||
const userDefinedOgImagePath = pageData.frontmatter?.socialImage
|
let userDefinedOgImagePath = pageData.frontmatter?.socialImage
|
||||||
|
|
||||||
|
if (userDefinedOgImagePath) {
|
||||||
|
userDefinedOgImagePath = isAbsoluteURL(userDefinedOgImagePath)
|
||||||
|
? userDefinedOgImagePath
|
||||||
|
: `https://${baseUrl}/static/${userDefinedOgImagePath}`
|
||||||
|
}
|
||||||
|
|
||||||
const generatedOgImagePath = isRealFile
|
const generatedOgImagePath = isRealFile
|
||||||
? `https://${baseUrl}/${pageData.slug!}-og-image.webp`
|
? `https://${baseUrl}/${pageData.slug!}-og-image.webp`
|
||||||
: undefined
|
: undefined
|
||||||
const defaultOgImagePath = `https://${baseUrl}/static/og-image.png`
|
const defaultOgImagePath = `https://${baseUrl}/static/og-image.png`
|
||||||
const ogImagePath = userDefinedOgImagePath ?? generatedOgImagePath ?? defaultOgImagePath
|
const ogImagePath = userDefinedOgImagePath ?? generatedOgImagePath ?? defaultOgImagePath
|
||||||
|
|
||||||
const ogImageMimeType = `image/${getFileExtension(ogImagePath) ?? "png"}`
|
const ogImageMimeType = `image/${getFileExtension(ogImagePath) ?? "png"}`
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -38,6 +38,17 @@ describe("typeguards", () => {
|
|||||||
assert(!path.isRelativeURL("./abc/def.md"))
|
assert(!path.isRelativeURL("./abc/def.md"))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test("isAbsoluteURL", () => {
|
||||||
|
assert(path.isAbsoluteURL("https://example.com"))
|
||||||
|
assert(path.isAbsoluteURL("http://example.com"))
|
||||||
|
assert(path.isAbsoluteURL("ftp://example.com/a/b/c"))
|
||||||
|
assert(path.isAbsoluteURL("http://host/%25"))
|
||||||
|
assert(path.isAbsoluteURL("file://host/twoslashes?more//slashes"))
|
||||||
|
|
||||||
|
assert(!path.isAbsoluteURL("example.com/abc/def"))
|
||||||
|
assert(!path.isAbsoluteURL("abc"))
|
||||||
|
})
|
||||||
|
|
||||||
test("isFullSlug", () => {
|
test("isFullSlug", () => {
|
||||||
assert(path.isFullSlug("index"))
|
assert(path.isFullSlug("index"))
|
||||||
assert(path.isFullSlug("abc/def"))
|
assert(path.isFullSlug("abc/def"))
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { slug as slugAnchor } from "github-slugger"
|
import { slug as slugAnchor } from "github-slugger"
|
||||||
import type { Element as HastElement } from "hast"
|
import type { Element as HastElement } from "hast"
|
||||||
import { clone } from "./clone"
|
import { clone } from "./clone"
|
||||||
|
|
||||||
// this file must be isomorphic so it can't use node libs (e.g. path)
|
// this file must be isomorphic so it can't use node libs (e.g. path)
|
||||||
|
|
||||||
export const QUARTZ = "quartz"
|
export const QUARTZ = "quartz"
|
||||||
@ -39,6 +40,15 @@ export function isRelativeURL(s: string): s is RelativeURL {
|
|||||||
return validStart && validEnding && ![".md", ".html"].includes(getFileExtension(s) ?? "")
|
return validStart && validEnding && ![".md", ".html"].includes(getFileExtension(s) ?? "")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAbsoluteURL(s: string): boolean {
|
||||||
|
try {
|
||||||
|
new URL(s)
|
||||||
|
} catch {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
export function getFullSlug(window: Window): FullSlug {
|
export function getFullSlug(window: Window): FullSlug {
|
||||||
const res = window.document.body.dataset.slug! as FullSlug
|
const res = window.document.body.dataset.slug! as FullSlug
|
||||||
return res
|
return res
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user