Add Matomo integration

This commit is contained in:
Moritz Hölting 2024-04-05 01:54:16 +02:00
parent 718b3eccae
commit 49a6d9eaac
5 changed files with 224 additions and 44 deletions

View File

@ -3,6 +3,7 @@ import mdx from "@astrojs/mdx";
import sitemap from "@astrojs/sitemap"; import sitemap from "@astrojs/sitemap";
import tailwind from "@astrojs/tailwind"; import tailwind from "@astrojs/tailwind";
import solidJs from "@astrojs/solid-js"; import solidJs from "@astrojs/solid-js";
import matomo from "./src/integrations/matomo";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
@ -13,5 +14,14 @@ export default defineConfig({
sitemap(), sitemap(),
solidJs(), solidJs(),
tailwind({ applyBaseStyles: false }), 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,
}),
], ],
}); });

View File

@ -17,21 +17,45 @@
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
class="absolute left-full animate-twinkle" class="absolute left-full animate-twinkle"
> >
<circle cx="74" cy="74" r="11" fill="white"/> <circle cx="74" cy="74" r="11" fill="white"></circle>
<rect y="141.421" width="200" height="10" transform="rotate(-45 0 141.421)" fill="url(#paint0_linear_4_2)"/> <rect
<rect x="7.07107" width="200" height="10" transform="rotate(45 7.07107 0)" fill="url(#paint1_linear_4_2)"/> y="141.421"
width="200"
height="10"
transform="rotate(-45 0 141.421)"
fill="url(#paint0_linear_4_2)"></rect>
<rect
x="7.07107"
width="200"
height="10"
transform="rotate(45 7.07107 0)"
fill="url(#paint1_linear_4_2)"></rect>
<defs> <defs>
<linearGradient id="paint0_linear_4_2" x1="0" y1="146.421" x2="200" y2="146.421" gradientUnits="userSpaceOnUse"> <linearGradient
<stop stop-color="#1E1E1E"/> id="paint0_linear_4_2"
<stop offset="0.445" stop-color="white"/> x1="0"
<stop offset="0.58721" stop-color="white"/> y1="146.421"
<stop offset="1" stop-color="#1E1E1E"/> x2="200"
y2="146.421"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#1E1E1E"></stop>
<stop offset="0.445" stop-color="white"></stop>
<stop offset="0.58721" stop-color="white"></stop>
<stop offset="1" stop-color="#1E1E1E"></stop>
</linearGradient> </linearGradient>
<linearGradient id="paint1_linear_4_2" x1="7.07107" y1="5" x2="207.071" y2="5" gradientUnits="userSpaceOnUse"> <linearGradient
<stop stop-color="#1E1E1E"/> id="paint1_linear_4_2"
<stop offset="0.42" stop-color="white"/> x1="7.07107"
<stop offset="0.555" stop-color="white"/> y1="5"
<stop offset="1" stop-color="#1E1E1E"/> x2="207.071"
y2="5"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#1E1E1E"></stop>
<stop offset="0.42" stop-color="white"></stop>
<stop offset="0.555" stop-color="white"></stop>
<stop offset="1" stop-color="#1E1E1E"></stop>
</linearGradient> </linearGradient>
</defs> </defs>
</svg> </svg>
@ -40,11 +64,18 @@
// Generate a twinkle star and append it to the galaxy, remove it after animation. // Generate a twinkle star and append it to the galaxy, remove it after animation.
function generateTwinkleStar() { function generateTwinkleStar() {
// Clone the twinkle star template and set its attributes. // Clone the twinkle star template and set its attributes.
const twinkleStar = document.getElementById("twinkle-star").cloneNode(true); const twinkleStar = document
.getElementById("twinkle-star")
?.cloneNode(true);
twinkleStar.style.position = "absolute"; twinkleStar.style.position = "absolute";
twinkleStar.style.left = Math.floor(Math.random() * window.innerWidth) + "px"; twinkleStar.style.left =
twinkleStar.style.top = Math.floor(Math.random() * (window.innerHeight/3)) + "px"; Math.floor(Math.random() * window.innerWidth) + "px";
twinkleStar.style.width = window.innerWidth < 768 ? Math.floor(Math.random() * (15 - 7.5 + 1) + 7.5) : Math.floor(Math.random() * (30 - 15 + 1) + 15) + "px"; twinkleStar.style.top =
Math.floor(Math.random() * (window.innerHeight / 3)) + "px";
twinkleStar.style.width =
window.innerWidth < 768
? Math.floor(Math.random() * (15 - 7.5 + 1) + 7.5)
: Math.floor(Math.random() * (30 - 15 + 1) + 15) + "px";
twinkleStar.style.height = twinkleStar.style.width; twinkleStar.style.height = twinkleStar.style.width;
twinkleStar.classList.add("twinkle"); twinkleStar.classList.add("twinkle");
document.getElementById("galaxy").appendChild(twinkleStar); document.getElementById("galaxy").appendChild(twinkleStar);
@ -57,4 +88,3 @@
setInterval(generateTwinkleStar, 5000); setInterval(generateTwinkleStar, 5000);
</script> </script>

View File

@ -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"
);
}
},
},
};
}

View File

@ -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);
}

View File

@ -0,0 +1,8 @@
export {};
declare global {
interface Window {
_paq: Array<Array>;
_mtm: Array<Array>;
}
}