From bcde2abcb20ad02a0c3f1430b9d620ee60e6cb63 Mon Sep 17 00:00:00 2001
From: dralagen <dralagen@dralagen.fr>
Date: Wed, 19 Mar 2025 04:47:35 +0000
Subject: [PATCH] fix(transformer): find last modified date form commit on submodule (#1831)

---
 quartz/plugins/emitters/componentResources.ts |  227 ++++++++++++++++++++++++++++++++++----------------------
 1 files changed, 136 insertions(+), 91 deletions(-)

diff --git a/quartz/plugins/emitters/componentResources.ts b/quartz/plugins/emitters/componentResources.ts
index 81d3af2..5dd67e6 100644
--- a/quartz/plugins/emitters/componentResources.ts
+++ b/quartz/plugins/emitters/componentResources.ts
@@ -1,4 +1,4 @@
-import { FilePath, FullSlug, joinSegments } from "../../util/path"
+import { FullSlug, joinSegments } from "../../util/path"
 import { QuartzEmitterPlugin } from "../types"
 
 // @ts-ignore
@@ -9,11 +9,15 @@
 import popoverStyle from "../../components/styles/popover.scss"
 import { BuildCtx } from "../../util/ctx"
 import { QuartzComponent } from "../../components/types"
-import { googleFontHref, joinStyles } from "../../util/theme"
+import {
+  googleFontHref,
+  googleFontSubsetHref,
+  joinStyles,
+  processGoogleFonts,
+} from "../../util/theme"
 import { Features, transform } from "lightningcss"
 import { transform as transpile } from "esbuild"
 import { write } from "./helpers"
-import DepGraph from "../../depgraph"
 
 type ComponentResources = {
   css: string[]
@@ -24,7 +28,7 @@
 function getComponentResources(ctx: BuildCtx): ComponentResources {
   const allComponents: Set<QuartzComponent> = new Set()
   for (const emitter of ctx.cfg.plugins.emitters) {
-    const components = emitter.getQuartzComponents(ctx)
+    const components = emitter.getQuartzComponents?.(ctx) ?? []
     for (const component of components) {
       allComponents.add(component)
     }
@@ -36,17 +40,21 @@
     afterDOMLoaded: new Set<string>(),
   }
 
+  function normalizeResource(resource: string | string[] | undefined): string[] {
+    if (!resource) return []
+    if (Array.isArray(resource)) return resource
+    return [resource]
+  }
+
   for (const component of allComponents) {
     const { css, beforeDOMLoaded, afterDOMLoaded } = component
-    if (css) {
-      componentResources.css.add(css)
-    }
-    if (beforeDOMLoaded) {
-      componentResources.beforeDOMLoaded.add(beforeDOMLoaded)
-    }
-    if (afterDOMLoaded) {
-      componentResources.afterDOMLoaded.add(afterDOMLoaded)
-    }
+    const normalizedCss = normalizeResource(css)
+    const normalizedBeforeDOMLoaded = normalizeResource(beforeDOMLoaded)
+    const normalizedAfterDOMLoaded = normalizeResource(afterDOMLoaded)
+
+    normalizedCss.forEach((c) => componentResources.css.add(c))
+    normalizedBeforeDOMLoaded.forEach((b) => componentResources.beforeDOMLoaded.add(b))
+    normalizedAfterDOMLoaded.forEach((a) => componentResources.afterDOMLoaded.add(a))
   }
 
   return {
@@ -82,7 +90,7 @@
     componentResources.afterDOMLoaded.push(`
       const gtagScript = document.createElement("script")
       gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
-      gtagScript.async = true
+      gtagScript.defer = true
       document.head.appendChild(gtagScript)
 
       window.dataLayer = window.dataLayer || [];
@@ -116,25 +124,69 @@
       const umamiScript = document.createElement("script")
       umamiScript.src = "${cfg.analytics.host ?? "https://analytics.umami.is"}/script.js"
       umamiScript.setAttribute("data-website-id", "${cfg.analytics.websiteId}")
-      umamiScript.async = true
-
+      umamiScript.setAttribute("data-auto-track", "false")
+      umamiScript.defer = true
       document.head.appendChild(umamiScript)
+
+      document.addEventListener("nav", () => {
+        umami.track();
+      })
     `)
   } else if (cfg.analytics?.provider === "goatcounter") {
     componentResources.afterDOMLoaded.push(`
       const goatcounterScript = document.createElement("script")
       goatcounterScript.src = "${cfg.analytics.scriptSrc ?? "https://gc.zgo.at/count.js"}"
-      goatcounterScript.async = true
+      goatcounterScript.defer = true
       goatcounterScript.setAttribute("data-goatcounter",
         "https://${cfg.analytics.websiteId}.${cfg.analytics.host ?? "goatcounter.com"}/count")
       document.head.appendChild(goatcounterScript)
+
+      window.goatcounter = { no_onload: true }
+      document.addEventListener("nav", () => {
+        goatcounter.count({ path: location.pathname })
+      })
     `)
   } else if (cfg.analytics?.provider === "posthog") {
     componentResources.afterDOMLoaded.push(`
       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||[]);
-      posthog.init('${cfg.analytics.apiKey}',{api_host:'${cfg.analytics.host ?? "https://app.posthog.com"}'})\`
+      posthog.init('${cfg.analytics.apiKey}', {
+        api_host: '${cfg.analytics.host ?? "https://app.posthog.com"}',
+        capture_pageview: false,
+      })\`
       document.head.appendChild(posthogScript)
+
+      document.addEventListener("nav", () => {
+        posthog.capture('$pageview', { path: location.pathname })
+      })
+    `)
+  } else if (cfg.analytics?.provider === "tinylytics") {
+    const siteId = cfg.analytics.siteId
+    componentResources.afterDOMLoaded.push(`
+      const tinylyticsScript = document.createElement("script")
+      tinylyticsScript.src = "https://tinylytics.app/embed/${siteId}.js?spa"
+      tinylyticsScript.defer = true
+      document.head.appendChild(tinylyticsScript)
+
+      document.addEventListener("nav", () => {
+        window.tinylytics.triggerUpdate()
+      })
+    `)
+  } else if (cfg.analytics?.provider === "cabin") {
+    componentResources.afterDOMLoaded.push(`
+      const cabinScript = document.createElement("script")
+      cabinScript.src = "${cfg.analytics.host ?? "https://scripts.withcabin.com"}/hello.js"
+      cabinScript.defer = true
+      document.head.appendChild(cabinScript)
+    `)
+  } else if (cfg.analytics?.provider === "clarity") {
+    componentResources.afterDOMLoaded.push(`
+      const clarityScript = document.createElement("script")
+      clarityScript.innerHTML= \`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
+      t=l.createElement(r);t.defer=1;t.src="https://www.clarity.ms/tag/"+i;
+      y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
+      })(window, document, "clarity", "script", "${cfg.analytics.projectId}");\`
+      document.head.appendChild(clarityScript)
     `)
   }
 
@@ -155,14 +207,7 @@
 export const ComponentResources: QuartzEmitterPlugin = () => {
   return {
     name: "ComponentResources",
-    getQuartzComponents() {
-      return []
-    },
-    async getDependencyGraph(_ctx, _content, _resources) {
-      return new DepGraph<FilePath>()
-    },
-    async emit(ctx, _content, _resources): Promise<FilePath[]> {
-      const promises: Promise<FilePath>[] = []
+    async *emit(ctx, _content, _resources) {
       const cfg = ctx.cfg.configuration
       // component specific scripts and styles
       const componentResources = getComponentResources(ctx)
@@ -171,42 +216,42 @@
         // let the user do it themselves in css
       } else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
         // when cdnCaching is true, we link to google fonts in Head.tsx
-        let match
+        const theme = ctx.cfg.configuration.theme
+        const response = await fetch(googleFontHref(theme))
+        googleFontsStyleSheet = await response.text()
 
-        const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
+        if (theme.typography.title) {
+          const title = ctx.cfg.configuration.pageTitle
+          const response = await fetch(googleFontSubsetHref(theme, title))
+          googleFontsStyleSheet += `\n${await response.text()}`
+        }
 
-        googleFontsStyleSheet = await (
-          await fetch(googleFontHref(ctx.cfg.configuration.theme))
-        ).text()
-
-        while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
-          // match[0] is the `url(path)`, match[1] is the `path`
-          const url = match[1]
-          // the static name of this file.
-          const [filename, ext] = url.split("/").pop()!.split(".")
-
-          googleFontsStyleSheet = googleFontsStyleSheet.replace(
-            url,
-            `https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
+        if (!cfg.baseUrl) {
+          throw new Error(
+            "baseUrl must be defined when using Google Fonts without cfg.theme.cdnCaching",
           )
+        }
 
-          promises.push(
-            fetch(url)
-              .then((res) => {
-                if (!res.ok) {
-                  throw new Error(`Failed to fetch font`)
-                }
-                return res.arrayBuffer()
-              })
-              .then((buf) =>
-                write({
-                  ctx,
-                  slug: joinSegments("static", "fonts", filename) as FullSlug,
-                  ext: `.${ext}`,
-                  content: Buffer.from(buf),
-                }),
-              ),
-          )
+        const { processedStylesheet, fontFiles } = await processGoogleFonts(
+          googleFontsStyleSheet,
+          cfg.baseUrl,
+        )
+        googleFontsStyleSheet = processedStylesheet
+
+        // Download and save font files
+        for (const fontFile of fontFiles) {
+          const res = await fetch(fontFile.url)
+          if (!res.ok) {
+            throw new Error(`Failed to fetch font ${fontFile.filename}`)
+          }
+
+          const buf = await res.arrayBuffer()
+          yield write({
+            ctx,
+            slug: joinSegments("static", "fonts", fontFile.filename) as FullSlug,
+            ext: `.${fontFile.extension}`,
+            content: Buffer.from(buf),
+          })
         }
       }
 
@@ -221,45 +266,45 @@
         ...componentResources.css,
         styles,
       )
+
       const [prescript, postscript] = await Promise.all([
         joinScripts(componentResources.beforeDOMLoaded),
         joinScripts(componentResources.afterDOMLoaded),
       ])
 
-      promises.push(
-        write({
-          ctx,
-          slug: "index" as FullSlug,
-          ext: ".css",
-          content: transform({
-            filename: "index.css",
-            code: Buffer.from(stylesheet),
-            minify: true,
-            targets: {
-              safari: (15 << 16) | (6 << 8), // 15.6
-              ios_saf: (15 << 16) | (6 << 8), // 15.6
-              edge: 115 << 16,
-              firefox: 102 << 16,
-              chrome: 109 << 16,
-            },
-            include: Features.MediaQueries,
-          }).code.toString(),
-        }),
-        write({
-          ctx,
-          slug: "prescript" as FullSlug,
-          ext: ".js",
-          content: prescript,
-        }),
-        write({
-          ctx,
-          slug: "postscript" as FullSlug,
-          ext: ".js",
-          content: postscript,
-        }),
-      )
+      yield write({
+        ctx,
+        slug: "index" as FullSlug,
+        ext: ".css",
+        content: transform({
+          filename: "index.css",
+          code: Buffer.from(stylesheet),
+          minify: true,
+          targets: {
+            safari: (15 << 16) | (6 << 8), // 15.6
+            ios_saf: (15 << 16) | (6 << 8), // 15.6
+            edge: 115 << 16,
+            firefox: 102 << 16,
+            chrome: 109 << 16,
+          },
+          include: Features.MediaQueries,
+        }).code.toString(),
+      })
 
-      return await Promise.all(promises)
+      yield write({
+        ctx,
+        slug: "prescript" as FullSlug,
+        ext: ".js",
+        content: prescript,
+      })
+
+      yield write({
+        ctx,
+        slug: "postscript" as FullSlug,
+        ext: ".js",
+        content: postscript,
+      })
     },
+    async *partialEmit() {},
   }
 }

--
Gitblit v1.10.0