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

View File

@ -7,54 +7,84 @@
*/
---
<svg
id="twinkle-star"
class="template"
width="149"
height="149"
viewBox="0 0 149 149"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="absolute left-full animate-twinkle"
<svg
id="twinkle-star"
class="template"
width="149"
height="149"
viewBox="0 0 149 149"
fill="none"
xmlns="http://www.w3.org/2000/svg"
class="absolute left-full animate-twinkle"
>
<circle cx="74" cy="74" r="11" fill="white"/>
<rect y="141.421" width="200" height="10" transform="rotate(-45 0 141.421)" fill="url(#paint0_linear_4_2)"/>
<rect x="7.07107" width="200" height="10" transform="rotate(45 7.07107 0)" fill="url(#paint1_linear_4_2)"/>
<defs>
<linearGradient id="paint0_linear_4_2" x1="0" y1="146.421" x2="200" y2="146.421" gradientUnits="userSpaceOnUse">
<stop stop-color="#1E1E1E"/>
<stop offset="0.445" stop-color="white"/>
<stop offset="0.58721" stop-color="white"/>
<stop offset="1" stop-color="#1E1E1E"/>
</linearGradient>
<linearGradient id="paint1_linear_4_2" x1="7.07107" y1="5" x2="207.071" y2="5" gradientUnits="userSpaceOnUse">
<stop stop-color="#1E1E1E"/>
<stop offset="0.42" stop-color="white"/>
<stop offset="0.555" stop-color="white"/>
<stop offset="1" stop-color="#1E1E1E"/>
</linearGradient>
</defs>
<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)"></rect>
<defs>
<linearGradient
id="paint0_linear_4_2"
x1="0"
y1="146.421"
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
id="paint1_linear_4_2"
x1="7.07107"
y1="5"
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>
</defs>
</svg>
<script is:inline>
// Generate a twinkle star and append it to the galaxy, remove it after animation.
function generateTwinkleStar() {
// Clone the twinkle star template and set its attributes.
const twinkleStar = document.getElementById("twinkle-star").cloneNode(true);
twinkleStar.style.position = "absolute";
twinkleStar.style.left = Math.floor(Math.random() * window.innerWidth) + "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.classList.add("twinkle");
document.getElementById("galaxy").appendChild(twinkleStar);
// Generate a twinkle star and append it to the galaxy, remove it after animation.
function generateTwinkleStar() {
// Clone the twinkle star template and set its attributes.
const twinkleStar = document
.getElementById("twinkle-star")
?.cloneNode(true);
twinkleStar.style.position = "absolute";
twinkleStar.style.left =
Math.floor(Math.random() * window.innerWidth) + "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.classList.add("twinkle");
document.getElementById("galaxy").appendChild(twinkleStar);
// Remove the twinkle star after the animation is completed.
setTimeout(() => {
twinkleStar.remove();
}, 2500);
}
// Remove the twinkle star after the animation is completed.
setTimeout(() => {
twinkleStar.remove();
}, 2500);
}
setInterval(generateTwinkleStar, 5000);
setInterval(generateTwinkleStar, 5000);
</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>;
}
}