Initial commit 🚀

This commit is contained in:
Felix Klement committed 2026-10-09 14:00:40 +02:00
commit fd58a8d32f
235 files changed
+19775

No files matched your search

+63
View File
@@ -0,0 +1,63 @@
---
/**
* The Matomo opt-out on the privacy page, in the site's own type rather than Matomo's embed. It
* asks the tracker already on the page: optUserOut stores the one cookie the tracker keeps with
* cookies disabled (mtm_consent_removed), forgetUserOptOut removes it. If the tracker never
* arrives (a content blocker, or a development build), the page says so: nothing is counted.
*/
import { t, type Lang } from '../i18n/ui';
interface Props { lang: Lang }
const { lang } = Astro.props;
const o = t(lang).legal.optOut;
---
<div class="optout" data-optout data-status-in={o.in} data-status-out={o.out} data-status-dnt={o.dnt} data-status-missing={o.missing} data-label-out={o.stop} data-label-in={o.resume}>
<p class="optout__status" role="status" data-optout-status>{o.checking}</p>
<button class="button button--small" type="button" data-optout-toggle hidden></button>
<noscript><p class="optout__status">{o.noscript}</p></noscript>
</div>
<style>
.optout { display: grid; gap: var(--space-4); justify-items: start; }
.optout__status { color: var(--ink-muted); }
.optout .button { font: inherit; font-size: var(--step-small); font-weight: var(--weight-medium); border: 0; cursor: pointer; }
</style>
<script>
type Tracker = { isUserOptedOut(): boolean; optUserOut(): void; forgetUserOptOut(): void };
type Paq = { push(cmd: unknown[]): void };
const root = document.querySelector<HTMLElement>('[data-optout]');
const status = root?.querySelector<HTMLElement>('[data-optout-status]');
const toggle = root?.querySelector<HTMLButtonElement>('[data-optout-toggle]');
if (root && status && toggle) {
const d = root.dataset;
const dnt = navigator.doNotTrack === '1' || (window as { doNotTrack?: string }).doNotTrack === '1';
let tracker: Tracker | undefined;
const render = () => {
if (dnt) { status.textContent = d.statusDnt!; toggle.hidden = true; return; }
if (!tracker) { status.textContent = d.statusMissing!; toggle.hidden = true; return; }
const out = tracker.isUserOptedOut();
status.textContent = out ? d.statusOut! : d.statusIn!;
toggle.textContent = out ? d.labelIn! : d.labelOut!;
toggle.hidden = false;
};
toggle.addEventListener('click', () => {
if (!tracker) return;
if (tracker.isUserOptedOut()) tracker.forgetUserOptOut(); else tracker.optUserOut();
render();
});
// A function pushed onto _paq runs with the tracker as `this` once matomo.js has loaded.
const paq = (window as { _paq?: Paq })._paq;
if (paq && !dnt) {
paq.push([function (this: Tracker) { tracker = this; render(); }]);
// If it has not arrived in a few seconds, it is blocked or not part of this build.
window.setTimeout(() => { if (!tracker) render(); }, 4000);
} else {
render();
}
}
</script>