From 94c8403476ee03eeaf0ad07993a3005150a6f5a2 Mon Sep 17 00:00:00 2001 From: Sarina Li Date: Thu, 16 Oct 2025 16:08:58 -0400 Subject: [PATCH 1/5] page events --- docs/package.json | 1 + docs/pnpm-lock.yaml | 47 +++++++++++++++ docs/src/app/api/posthog/[...path]/route.ts | 65 +++++++++++++++++++++ docs/src/app/layout.tsx | 13 ++++- docs/src/providers/posthog-provider.tsx | 41 +++++++++++++ 5 files changed, 164 insertions(+), 3 deletions(-) create mode 100644 docs/src/app/api/posthog/[...path]/route.ts create mode 100644 docs/src/providers/posthog-provider.tsx diff --git a/docs/package.json b/docs/package.json index c6c083c9..d94c168e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -16,6 +16,7 @@ "mermaid": "^11.8.1", "next": "15.3.3", "next-themes": "^0.4.6", + "posthog-js": "^1.276.0", "react": "^19.1.0", "react-dom": "^19.1.0", "remark": "^15.0.1", diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index 21945e6b..21932097 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -29,6 +29,9 @@ importers: next-themes: specifier: ^0.4.6 version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + posthog-js: + specifier: ^1.276.0 + version: 1.276.0 react: specifier: ^19.1.0 version: 19.1.0 @@ -489,6 +492,9 @@ packages: resolution: {integrity: sha512-6yB0117ZjsgNevZw3LP+bkrZa9mU/POPVaXgzMPOBbBc35w2P3R+1vMMhEfC06kYCpd5bf0jodBaTkYQW5TVeQ==} engines: {node: '>= 20.0.0'} + '@posthog/core@1.3.0': + resolution: {integrity: sha512-hxLL8kZNHH098geedcxCz8y6xojkNYbmJEW+1vFXsmPcExyCXIUUJ/34X6xa9GcprKxd0Wsx3vfJQLQX4iVPhw==} + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} @@ -1221,6 +1227,9 @@ packages: confbox@0.2.2: resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + core-js@3.46.0: + resolution: {integrity: sha512-vDMm9B0xnqqZ8uSBpZ8sNtRtOdmfShrvT6h2TuQGLs0Is+cR0DYbj/KWP6ALVNbWPpqA/qPLoOuppJN07humpA==} + cose-base@1.0.3: resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} @@ -1492,6 +1501,9 @@ packages: picomatch: optional: true + fflate@0.4.8: + resolution: {integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==} + fumadocs-core@15.5.1: resolution: {integrity: sha512-5eJPJw+BFWFdgrtWPQ9aAZAhhsyuZAwth8OjBd9R77sXoIoae4Y4lJZMq3BeSpJZcuIAOVbSCS+pJhsBAoXJ8g==} peerDependencies: @@ -2012,6 +2024,20 @@ packages: resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} + posthog-js@1.276.0: + resolution: {integrity: sha512-FYZE1037LrAoKKeUU0pUL7u8WwNK2BVeg5TFApwquVPUdj9h7u5Z077A313hPN19Ar+7Y+VHxqYqdHc4VNsVgw==} + peerDependencies: + '@rrweb/types': 2.0.0-alpha.17 + rrweb-snapshot: 2.0.0-alpha.17 + peerDependenciesMeta: + '@rrweb/types': + optional: true + rrweb-snapshot: + optional: true + + preact@10.27.2: + resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==} + prettier@3.6.2: resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} @@ -2317,6 +2343,9 @@ packages: vscode-uri@3.0.8: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + web-vitals@4.2.4: + resolution: {integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==} + yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} @@ -2642,6 +2671,8 @@ snapshots: '@orama/orama@3.1.7': {} + '@posthog/core@1.3.0': {} + '@radix-ui/number@1.1.1': {} '@radix-ui/primitive@1.1.2': {} @@ -3378,6 +3409,8 @@ snapshots: confbox@0.2.2: {} + core-js@3.46.0: {} + cose-base@1.0.3: dependencies: layout-base: 1.0.2 @@ -3702,6 +3735,8 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fflate@0.4.8: {} + fumadocs-core@15.5.1(@types/react@19.1.8)(next@15.3.3(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): dependencies: '@formatjs/intl-localematcher': 0.6.1 @@ -4566,6 +4601,16 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 + posthog-js@1.276.0: + dependencies: + '@posthog/core': 1.3.0 + core-js: 3.46.0 + fflate: 0.4.8 + preact: 10.27.2 + web-vitals: 4.2.4 + + preact@10.27.2: {} + prettier@3.6.2: {} property-information@7.1.0: {} @@ -4934,6 +4979,8 @@ snapshots: vscode-uri@3.0.8: {} + web-vitals@4.2.4: {} + yallist@5.0.0: {} zod@3.25.76: {} diff --git a/docs/src/app/api/posthog/[...path]/route.ts b/docs/src/app/api/posthog/[...path]/route.ts new file mode 100644 index 00000000..8db38f2f --- /dev/null +++ b/docs/src/app/api/posthog/[...path]/route.ts @@ -0,0 +1,65 @@ +import { NextRequest, NextResponse } from 'next/server'; + +export async function GET( + request: NextRequest, + { params }: { params: Promise<{ path: string[] }> } +) { + const { path } = await params; + const url = new URL(request.url); + + const targetUrl = `${process.env.NEXT_PUBLIC_POSTHOG_HOST}/${path.join('/')}${url.search}`; + + try { + const response = await fetch(targetUrl, { + method: 'GET', + headers: { + 'Content-Type': request.headers.get('Content-Type') || 'application/json', + }, + }); + + const data = await response.arrayBuffer(); + return new NextResponse(data, { + status: response.status, + headers: { + 'Content-Type': response.headers.get('Content-Type') || 'application/json', + }, + }); + } catch (error) { + console.error('PostHog proxy error:', error); + return new NextResponse('Error proxying request', { status: 500 }); + } +} + +export async function POST( + request: NextRequest, + { params }: { params: Promise<{ path: string[] }> } +) { + const { path } = await params; + const url = new URL(request.url); + + const targetUrl = `${process.env.NEXT_PUBLIC_POSTHOG_HOST}/${path.join('/')}${url.search}`; + + try { + const body = await request.arrayBuffer(); + const contentType = request.headers.get('Content-Type') || 'application/x-www-form-urlencoded'; + + const response = await fetch(targetUrl, { + method: 'POST', + headers: { + 'Content-Type': contentType, + }, + body, + }); + + const data = await response.arrayBuffer(); + return new NextResponse(data, { + status: response.status, + headers: { + 'Content-Type': response.headers.get('Content-Type') || 'application/json', + }, + }); + } catch (error) { + console.error('PostHog proxy error:', error); + return new NextResponse('Error proxying request', { status: 500 }); + } +} diff --git a/docs/src/app/layout.tsx b/docs/src/app/layout.tsx index 2fdc4fea..0aa16d29 100644 --- a/docs/src/app/layout.tsx +++ b/docs/src/app/layout.tsx @@ -2,6 +2,8 @@ import './global.css'; import { RootProvider } from 'fumadocs-ui/provider'; import { Inter } from 'next/font/google'; import type { ReactNode } from 'react'; +import { PHProvider, PostHogPageView } from '@/providers/posthog-provider'; +import { Suspense } from 'react'; const inter = Inter({ subsets: ['latin'], @@ -14,9 +16,14 @@ export default function Layout({ children }: { children: ReactNode }) { - - {children} - + + + + + + {children} + + ); diff --git a/docs/src/providers/posthog-provider.tsx b/docs/src/providers/posthog-provider.tsx new file mode 100644 index 00000000..aa298e5b --- /dev/null +++ b/docs/src/providers/posthog-provider.tsx @@ -0,0 +1,41 @@ +'use client'; + +import posthog from 'posthog-js'; +import { PostHogProvider } from 'posthog-js/react'; +import { useEffect } from 'react'; +import { usePathname, useSearchParams } from 'next/navigation'; + +if (typeof window !== 'undefined') { + posthog.init(process.env.NEXT_PUBLIC_POSTHOG_API_KEY!, { + api_host: '/docs/api/posthog', + ui_host: process.env.NEXT_PUBLIC_POSTHOG_HOST, + person_profiles: 'always', + capture_pageview: false, + capture_pageleave: true, + }); +} + +export function PHProvider({ children }: { children: React.ReactNode }) { + return {children}; +} + +export function PostHogPageView(): null { + const pathname = usePathname(); + const searchParams = useSearchParams(); + + useEffect(() => { + if (pathname) { + let url = window.origin + pathname; + if (searchParams && searchParams.toString()) { + url = url + `?${searchParams.toString()}`; + } + + console.log('[PostHog] Capturing pageview:', url); + posthog.capture('$pageview', { + $current_url: url, + }); + } + }, [pathname, searchParams]); + + return null; +} From 07c6b98581833753579db5c0eeaa5ac1be74e707 Mon Sep 17 00:00:00 2001 From: Sarina Li Date: Thu, 16 Oct 2025 16:28:25 -0400 Subject: [PATCH 2/5] cookie policy + external links --- docs/src/app/layout.tsx | 6 ++ docs/src/components/analytics-tracker.tsx | 71 +++++++++++++++++++++++ docs/src/components/cookie-consent.tsx | 44 ++++++++++++++ docs/src/components/footer.tsx | 16 +++++ docs/src/mdx-components.tsx | 10 ++++ docs/src/providers/posthog-provider.tsx | 1 - 6 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 docs/src/components/analytics-tracker.tsx create mode 100644 docs/src/components/cookie-consent.tsx create mode 100644 docs/src/components/footer.tsx diff --git a/docs/src/app/layout.tsx b/docs/src/app/layout.tsx index 0aa16d29..e821184e 100644 --- a/docs/src/app/layout.tsx +++ b/docs/src/app/layout.tsx @@ -3,6 +3,9 @@ import { RootProvider } from 'fumadocs-ui/provider'; import { Inter } from 'next/font/google'; import type { ReactNode } from 'react'; import { PHProvider, PostHogPageView } from '@/providers/posthog-provider'; +import { AnalyticsTracker } from '@/components/analytics-tracker'; +import { CookieConsent } from '@/components/cookie-consent'; +import { Footer } from '@/components/footer'; import { Suspense } from 'react'; const inter = Inter({ @@ -20,9 +23,12 @@ export default function Layout({ children }: { children: ReactNode }) { + {children} +