Skip to content
53 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Analytics asks first in the EU, EEA, UK and Switzerland, and loads only when the page is idle1/**
2 * Asking a visitor from the EU, EEA, UK or Switzerland before site
3 * analytics runs (lib/analytics-consent.ts): both answers are one click,
4 * and nothing is fetched or stored for analytics until they agree. The
5 * footer's "Cookie choices" asks again (components/footer.tsx).
6 */
7import { useEffect, useState, useSyncExternalStore } from "react";
8import { Link } from "react-router";
9
10import { analyticsHere, choice, choose, consentRequired, onChoice } from "../lib/analytics-consent";
11
12/** Whether this visitor is asked at all, known only once the page is in the browser. */
13export function useAsksFirst(): boolean {
14 const [asks, setAsks] = useState(false);
15 useEffect(() => setAsks(analyticsHere() && consentRequired()), []);
16 return asks;
17}
18
19export function AnalyticsConsent() {
20 const asks = useAsksFirst();
21 const chosen = useSyncExternalStore(onChoice, choice, () => null);
22 if (!asks || chosen) return null;
23 return (
24 <section
25 aria-label="Analytics cookie"
26 className="fixed inset-x-3 bottom-3 z-[60] mx-auto max-w-lg rounded-2xl bg-surface p-4 text-sm shadow-2xl shadow-black/50 ring-1 ring-line-strong sm:inset-x-auto sm:right-4 sm:bottom-4"
27 >
28 <p className="leading-6 text-fg-soft">
29 May g1t count how its pages are used? It sets one analytics cookie, and names inside your workspaces are
30 removed before anything is sent.{" "}
31 <Link to="/policies/privacy#how-the-site-is-used" className="text-accent hover:underline">
32 What is sent
33 </Link>
34 </p>
35 <div className="mt-3 flex gap-2">
36 <button
37 type="button"
38 onClick={() => choose("yes")}
39 className="flex-1 rounded-lg bg-fg px-3 py-2 font-medium text-bg transition-colors hover:bg-white"
40 >
41 Allow
42 </button>
43 <button
44 type="button"
45 onClick={() => choose("no")}
46 className="flex-1 rounded-lg px-3 py-2 font-medium text-fg ring-1 ring-line-strong transition-colors hover:bg-raised"
47 >
48 No thanks
49 </button>
50 </div>
51 </section>
52 );
53}