From 626d148a8c76b93c9188f25449d213eb4ce5c70b Mon Sep 17 00:00:00 2001 From: ZVN DEV <78920650+zvndev@users.noreply.github.com> Date: Fri, 2 Oct 2026 01:22:30 -0400 Subject: [PATCH] Add Little Friend analytics to whenny.dev Production deployments render the Little Friend tag (journey mode, with session replay) in the root layout. Previews and local dev render nothing, because the tag depends on VERCEL_ENV being production. - install.copy fires after an install command is copied (home page command blocks, CLI lines, module chips, and the docs installation section and code blocks), with method create, cli or package. The command text is never sent. - github.click and npm.click for links to GitHub and npm. - data-lf click ids on the home nav, calls to action and footer. - CSP: script-src adds https://cdn.littlefriend.io, and a connect-src of 'self' https://in.littlefriend.io replaces the default-src fallback. Co-Authored-By: Claude Opus 5.5 (1M context) --- apps/example/app/docs/page.tsx | 4 ++++ apps/example/app/layout.tsx | 18 ++++++++++++++++ apps/example/app/little-friend.tsx | 26 +++++++++++++++++++++++ apps/example/app/page.tsx | 16 ++++++++------ apps/example/lib/little-friend.ts | 34 ++++++++++++++++++++++++++++++ apps/example/next.config.js | 2 +- 6 files changed, 93 insertions(+), 7 deletions(-) create mode 100644 apps/example/app/little-friend.tsx create mode 100644 apps/example/lib/little-friend.ts diff --git a/apps/example/app/docs/page.tsx b/apps/example/app/docs/page.tsx index 57d832f..00e829e 100644 --- a/apps/example/app/docs/page.tsx +++ b/apps/example/app/docs/page.tsx @@ -2,6 +2,7 @@ import Link from 'next/link' import { useState } from 'react' +import { trackCopy } from '@/lib/little-friend' type Section = 'installation' | 'upgrading' | 'quickstart' | 'core' | 'formatting' | 'relative' | 'smart' | 'compare' | 'duration' | 'timezone' | 'calendar' | 'natural' | 'react' | 'config' | 'cli' @@ -11,6 +12,7 @@ function CodeBlock({ children, title }: { children: string; title?: string }) { const copyToClipboard = async () => { await navigator.clipboard.writeText(children) + trackCopy(children) setCopied(true) setTimeout(() => setCopied(false), 2000) } @@ -246,6 +248,7 @@ function InstallationSection() { const copyCommand = async () => { await navigator.clipboard.writeText(addCommand) + trackCopy(addCommand) setCopied(true) setTimeout(() => setCopied(false), 2000) } @@ -264,6 +267,7 @@ function InstallationSection() {