diff --git a/app/components/PostHog.tsx b/app/components/PostHog.tsx new file mode 100644 index 0000000..e45ea9f --- /dev/null +++ b/app/components/PostHog.tsx @@ -0,0 +1,26 @@ +"use client" + +import posthog from "posthog-js" +import { useEffect } from "react" + +export function PostHog() { + useEffect(() => { + if (location.hostname !== "docs.gitbutler.com") return + posthog.init("phc_yJx46mXv6kA5KTuM2eEQ6IwNTgl5YW3feKV5gi7mfGG", { + api_host: "https://eu.posthog.com", + defaults: "2026-06-25", + cookie_persisted_properties: ["app_distinct_id"] + }) + recordAppDistinctId() + }, []) + return null +} + +function recordAppDistinctId() { + const url = new URL(location.href) + const appDistinctId = url.searchParams.get("did") + if (!appDistinctId) return + posthog.register({ app_distinct_id: appDistinctId }) + url.searchParams.delete("did") + history.replaceState(history.state, "", url) +} diff --git a/app/layout.tsx b/app/layout.tsx index 453b567..a65351c 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -6,6 +6,7 @@ import type { ReactNode } from "react" import "@gitbutler/design-core/fonts" import Script from "next/script" +import { PostHog } from "@/app/components/PostHog" import WebMcpTools from "@/app/components/WebMcpTools" import { getSiteUrl } from "@/app/utils/site" @@ -21,6 +22,7 @@ export default function Layout({ children }: { children: ReactNode }) { return ( + {children} diff --git a/package.json b/package.json index ec5380a..98e0463 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "glob": "^12.0.0", "next": "15.5.18", "pdfkit": "^0.17.2", + "posthog-js": "1.417.1", "prettier": "^3.3.3", "puppeteer": "^24.36.1", "react": "^18.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 914a0f7..8ae3f21 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,9 @@ importers: pdfkit: specifier: ^0.17.2 version: 0.17.2 + posthog-js: + specifier: 1.417.1 + version: 1.417.1 prettier: specifier: ^3.3.3 version: 3.3.3 @@ -712,6 +715,15 @@ packages: resolution: {integrity: sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@posthog/browser-common@0.5.0': + resolution: {integrity: sha512-8DaxVZS1bQPbA514RePurLNbYjei3P4jhnC206DwVv5XThmZM3QdlsXenI2ujE3pLbgQ79hYn9o1Kda8I3WK/Q==} + + '@posthog/core@1.48.4': + resolution: {integrity: sha512-Bff4EVy6x1FrJIdhrEZYGJuyarwZkKC0fOncRobpPgJWMQc83W2U/6ChYPQYcA1Vp3wzAOVCOSigs6fMqojM5Q==} + + '@posthog/types@1.405.0': + resolution: {integrity: sha512-4rZ/taVXKQxs9Jrf7ZjlCRgrOSL69oKAgIWJQa5kRNJ6wll1UANbrJTSY+Su1e88LIG4zZVjKKKjyQHCkHdHcw==} + '@puppeteer/browsers@2.11.2': resolution: {integrity: sha512-GBY0+2lI9fDrjgb5dFL9+enKXqyOPok9PXg/69NVkjW3bikbK9RQrNrI3qccQXmDNN7ln4j/yL89Qgvj/tfqrw==} engines: {node: '>=18'} @@ -2001,6 +2013,9 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + core-js@3.50.0: + resolution: {integrity: sha512-BRWgOLKkFeCgRudR6zrs8p9XJZcE14grzKMMssoYrk6krtuEZ7MTKPIY5RzOnqsEKIR9kst7wNzphttraT+Yqw==} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -2299,6 +2314,9 @@ packages: resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} engines: {node: '>=0.10.0'} + dompurify@3.4.14: + resolution: {integrity: sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==} + dompurify@3.4.3: resolution: {integrity: sha512-VVwJidIJcp1hpg2OMXML3ZVRPYSZiq4aX7qBh83BSIpOaRDqI+qxhXjjIWnpzkOXhmp0L81lnoME1mnCc9H48A==} @@ -2647,6 +2665,9 @@ packages: fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + fflate@0.4.9: + resolution: {integrity: sha512-zdxgIEddhfsyCaWpJ2SdXEP8ZMrKJ6+5jl4OupODcywU0IhRk6gdXuVGcPICyfx2H97hVK7xmJtRLPjkxAX8Vw==} + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} @@ -3800,6 +3821,17 @@ packages: resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.417.1: + resolution: {integrity: sha512-QpZnHA2PieGq9+W03LBw23DnN9CD1zM37DcXnpZkg+C5iAwYXLiZs8qof0Yi/BhY35PYuhVmv93nhztyHjVaJw==} + + preact@10.29.8: + resolution: {integrity: sha512-ej2aVZ+vZ8WO7tvlQWRM9N63A0KzF9q4mWJfDUHgYaIofWY9hu74QdnQrjoPMmZi2/nZ5gN0bJCQF49xQqx09Q==} + peerDependencies: + preact-render-to-string: '>=5' + peerDependenciesMeta: + preact-render-to-string: + optional: true + prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -3904,6 +3936,9 @@ packages: engines: {node: '>=18'} hasBin: true + query-selector-shadow-dom@1.0.1: + resolution: {integrity: sha512-lT5yCqEBgfoMYpf3F2xQRK7zEr1rhIIZuceDK6+xRkJQ4NMbHTwXqk4NkwDwQMNqXgG9r9fyHnzwNVs6zV5KRw==} + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -4564,6 +4599,12 @@ packages: vfile@6.0.1: resolution: {integrity: sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==} + web-vitals@5.3.0: + resolution: {integrity: sha512-q6LWsLatGYZp5VGBIOvbTj6JBV2nOmC8KvWztXBmwJcfFAzhwKwbOxhUH306XY3CcaZDUlSmSuNPBsCn0bFu+g==} + + web-vitals@6.0.0: + resolution: {integrity: sha512-Guaibvy/+uNtL6Bsu4jmMJGzuSl91oeRH5iO9pPRbYftnFUr3yqT1TUNX/OE4o9HexuEMU3Kb/Wg7iKhlffZUA==} + webdriver-bidi-protocol@0.4.0: resolution: {integrity: sha512-U9VIlNRrq94d1xxR9JrCEAx5Gv/2W7ERSv8oWRoNe/QYbfccS0V3h/H6qeNeCRJxXGMhhnkqvwNrvPAYeuP9VA==} @@ -5099,6 +5140,17 @@ snapshots: '@pkgr/core@0.1.1': {} + '@posthog/browser-common@0.5.0': + dependencies: + '@posthog/core': 1.48.4 + '@posthog/types': 1.405.0 + + '@posthog/core@1.48.4': + dependencies: + '@posthog/types': 1.405.0 + + '@posthog/types@1.405.0': {} + '@puppeteer/browsers@2.11.2': dependencies: debug: 4.4.3 @@ -6537,6 +6589,8 @@ snapshots: concat-map@0.0.1: {} + core-js@3.50.0: {} + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -6847,6 +6901,10 @@ snapshots: dependencies: esutils: 2.0.3 + dompurify@3.4.14: + optionalDependencies: + '@types/trusted-types': 2.0.7 + dompurify@3.4.3: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -7383,6 +7441,8 @@ snapshots: dependencies: pend: 1.2.0 + fflate@0.4.9: {} + file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 @@ -8987,6 +9047,23 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.417.1: + dependencies: + '@posthog/browser-common': 0.5.0 + '@posthog/core': 1.48.4 + '@posthog/types': 1.405.0 + core-js: 3.50.0 + dompurify: 3.4.14 + fflate: 0.4.9 + preact: 10.29.8 + query-selector-shadow-dom: 1.0.1 + web-vitals: 5.3.0 + web-vitals-soft-navs: web-vitals@6.0.0 + transitivePeerDependencies: + - preact-render-to-string + + preact@10.29.8: {} + prelude-ls@1.2.1: {} prettier-linter-helpers@1.0.0: @@ -9067,6 +9144,8 @@ snapshots: - typescript - utf-8-validate + query-selector-shadow-dom@1.0.1: {} + queue-microtask@1.2.3: {} queue@6.0.2: @@ -9916,6 +9995,10 @@ snapshots: unist-util-stringify-position: 4.0.0 vfile-message: 4.0.2 + web-vitals@5.3.0: {} + + web-vitals@6.0.0: {} + webdriver-bidi-protocol@0.4.0: {} which-boxed-primitive@1.0.2: