From 49a6d9eaac50cf1eaea48e8f81081d653eee14a3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Moritz=20H=C3=B6lting?=
 <87192362+moritz-hoelting@users.noreply.github.com>
Date: Fri, 5 Apr 2024 01:54:16 +0200
Subject: [PATCH] Add Matomo integration
---
 astro.config.mjs                         |  10 ++
 src/components/TwinklingStars.astro      | 118 ++++++++++++++---------
 src/integrations/matomo/index.ts         |  71 ++++++++++++++
 src/integrations/matomo/matomo.ts        |  61 ++++++++++++
 src/integrations/matomo/types/index.d.ts |   8 ++
 5 files changed, 224 insertions(+), 44 deletions(-)
 create mode 100644 src/integrations/matomo/index.ts
 create mode 100644 src/integrations/matomo/matomo.ts
 create mode 100644 src/integrations/matomo/types/index.d.ts
diff --git a/astro.config.mjs b/astro.config.mjs
index b40751b..dc90792 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -3,6 +3,7 @@ import mdx from "@astrojs/mdx";
 import sitemap from "@astrojs/sitemap";
 import tailwind from "@astrojs/tailwind";
 import solidJs from "@astrojs/solid-js";
+import matomo from "./src/integrations/matomo";
 
 // https://astro.build/config
 export default defineConfig({
@@ -13,5 +14,14 @@ export default defineConfig({
         sitemap(),
         solidJs(),
         tailwind({ applyBaseStyles: false }),
+        matomo({
+            enabled: import.meta.env.PROD, // only enable in production
+            url: "https://analytics.hoelting.dev",
+            siteId: 3,
+            disableCookies: true,
+            enableCrossDomainLinking: true,
+            domains: ["*.hoelting.dev", "*.www.hoelting.dev"],
+            respectDoNotTrack: true,
+        }),
     ],
 });
diff --git a/src/components/TwinklingStars.astro b/src/components/TwinklingStars.astro
index 3650379..d8ada99 100644
--- a/src/components/TwinklingStars.astro
+++ b/src/components/TwinklingStars.astro
@@ -7,54 +7,84 @@
  */
 ---
 
-
 
 
-  
\ No newline at end of file
diff --git a/src/integrations/matomo/index.ts b/src/integrations/matomo/index.ts
new file mode 100644
index 0000000..4cd185d
--- /dev/null
+++ b/src/integrations/matomo/index.ts
@@ -0,0 +1,71 @@
+import type { AstroIntegration } from "astro";
+
+export type MatomoOptions = {
+    enabled: boolean;
+    url: string;
+    siteId: number;
+    trackerUrl?: string;
+    srcUrl?: string;
+    heartBeatTimer?: number;
+    setCookieDomain?: string;
+    disableCookies?: boolean;
+    preconnect?: boolean;
+    debug?: boolean;
+    respectDoNotTrack?: boolean;
+    domains?: string[];
+    enableCrossDomainLinking?: boolean;
+    customCampaignParameters?: {
+        name?: string;
+        keyword?: string;
+    };
+};
+
+export default function matomoIntegration(
+    options: MatomoOptions
+): AstroIntegration {
+    if (!options?.url.endsWith("/")) {
+        options.url += "/";
+    }
+
+    let script: string;
+
+    if (options?.enabled) {
+        script = `import { initMatomo, preconnectMatomo } from "@integrations/matomo/matomo"; initMatomo(${JSON.stringify(
+            options
+        )});`;
+
+        if (options?.preconnect) {
+            script += `preconnectMatomo(${JSON.stringify(options)});`;
+        }
+    } else {
+        console.info(
+            "\x1b[43m",
+            "Matomo",
+            "\x1b[0m",
+            "\x1b[34m",
+            "Is disabled.",
+            "\x1b[0m"
+        );
+
+        script = "";
+    }
+
+    return {
+        name: "matomo",
+        hooks: {
+            "astro:config:setup": async ({ injectScript }) => {
+                if (options?.enabled) {
+                    injectScript("page", script);
+                    console.info(
+                        "\x1b[42m",
+                        "Matomo",
+                        "\x1b[0m",
+                        "\x1b[34m",
+                        "was integrated successfully.",
+                        "\x1b[0m"
+                    );
+                }
+            },
+        },
+    };
+}
diff --git a/src/integrations/matomo/matomo.ts b/src/integrations/matomo/matomo.ts
new file mode 100644
index 0000000..0ef98ea
--- /dev/null
+++ b/src/integrations/matomo/matomo.ts
@@ -0,0 +1,61 @@
+import type { MatomoOptions } from ".";
+
+export function initMatomo(options: MatomoOptions): void {
+    const _paq = (window._paq = window._paq || []);
+
+    if (options?.disableCookies) _paq.push(["disableCookies"]);
+    if (options?.heartBeatTimer)
+        _paq.push(["enableHeartBeatTimer", options.heartBeatTimer]);
+    if (options?.setCookieDomain)
+        _paq.push(["setCookieDomain", options.setCookieDomain]);
+    if (options?.respectDoNotTrack) _paq.push(["setDoNotTrack", true]);
+    if (options?.domains) _paq.push(["setDomains", options.domains]);
+    if (options?.enableCrossDomainLinking)
+        _paq.push(["enableCrossDomainLinking"]);
+    if (options?.customCampaignParameters?.name)
+        _paq.push([
+            "setCampaignNameKey",
+            options.customCampaignParameters.name,
+        ]);
+    if (options?.customCampaignParameters?.keyword)
+        _paq.push([
+            "setCampaignKeywordKey",
+            options.customCampaignParameters.keyword,
+        ]);
+
+    _paq.push(["trackPageView"]);
+    _paq.push(["enableLinkTracking"]);
+
+    if (options?.debug) {
+        console.warn("Matomo debug mode enabled!");
+        window._mtm = window._mtm || [];
+        window._mtm.push(["enableDebugMode"]);
+    }
+
+    (function () {
+        const u = options?.url;
+
+        _paq.push(["setTrackerUrl", u + (options?.trackerUrl || "matomo.php")]);
+        _paq.push(["setSiteId", options?.siteId]);
+
+        const d = document,
+            g = d.createElement("script"),
+            s = d.getElementsByTagName("script")[0];
+
+        g.id = "matomo-script";
+        g.type = "text/javascript";
+        g.async = true;
+        g.defer = true;
+        g.src = u + (options?.srcUrl || "matomo.js");
+        if (s.parentNode != null && u) s.parentNode.insertBefore(g, s);
+    })();
+}
+
+export function preconnectMatomo(options: MatomoOptions): void {
+    if (!options?.url) return;
+
+    const link = document.createElement("link");
+    link.rel = "preconnect";
+    link.href = options?.url;
+    document.head.appendChild(link);
+}
diff --git a/src/integrations/matomo/types/index.d.ts b/src/integrations/matomo/types/index.d.ts
new file mode 100644
index 0000000..557c54c
--- /dev/null
+++ b/src/integrations/matomo/types/index.d.ts
@@ -0,0 +1,8 @@
+export {};
+
+declare global {
+    interface Window {
+        _paq: Array;
+        _mtm: Array;
+    }
+}