feat: support analytics (google/umami/plausible/datafast/openpanel)
This commit is contained in:
parent
257feba5bd
commit
c04499a353
24
env.example
24
env.example
@ -67,3 +67,27 @@ NEXT_PUBLIC_STRIPE_PRICE_PRO_MONTHLY=""
|
||||
NEXT_PUBLIC_STRIPE_PRICE_PRO_YEARLY=""
|
||||
# Lifetime plan - one-time payment
|
||||
NEXT_PUBLIC_STRIPE_PRICE_LIFETIME=""
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Analytics
|
||||
# -----------------------------------------------------------------------------
|
||||
# Google Analytics (https://analytics.google.com)
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID=""
|
||||
# -----------------------------------------------------------------------------
|
||||
# Umami Analytics (https://umami.is)
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_UMAMI_WEBSITE_ID=""
|
||||
# -----------------------------------------------------------------------------
|
||||
# OpenPanel Analytics (https://openpanel.dev)
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_OPENPANEL_CLIENT_ID=""
|
||||
# -----------------------------------------------------------------------------
|
||||
# Plausible Analytics (https://plausible.io)
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_PLAUSIBLE_DOMAIN=""
|
||||
# -----------------------------------------------------------------------------
|
||||
# DataFast Analytics (https://datafa.st)
|
||||
# -----------------------------------------------------------------------------
|
||||
NEXT_PUBLIC_DATAFAST_ANALYTICS_ID=""
|
||||
NEXT_PUBLIC_DATAFAST_ANALYTICS_DOMAIN=""
|
||||
|
@ -28,6 +28,8 @@
|
||||
"@fumadocs/content-collections": "^1.1.8",
|
||||
"@hookform/resolvers": "^4.1.0",
|
||||
"@neondatabase/serverless": "^0.10.4",
|
||||
"@next/third-parties": "^15.3.0",
|
||||
"@openpanel/nextjs": "^1.0.7",
|
||||
"@orama/orama": "^3.1.4",
|
||||
"@orama/tokenizers": "^3.1.4",
|
||||
"@radix-ui/react-accordion": "^1.2.3",
|
||||
|
49
pnpm-lock.yaml
generated
49
pnpm-lock.yaml
generated
@ -47,6 +47,12 @@ importers:
|
||||
'@neondatabase/serverless':
|
||||
specifier: ^0.10.4
|
||||
version: 0.10.4
|
||||
'@next/third-parties':
|
||||
specifier: ^15.3.0
|
||||
version: 15.3.0(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)
|
||||
'@openpanel/nextjs':
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
'@orama/orama':
|
||||
specifier: ^3.1.4
|
||||
version: 3.1.4
|
||||
@ -1809,6 +1815,12 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@next/third-parties@15.3.0':
|
||||
resolution: {integrity: sha512-fHgeIG5Pf/kW2Yi3man7r4y2f3uYA2sKIA9ylBvD/q9kg8sNWODBm4pYRatdIGosNkHZjVoNUlK85AQ0SP3Rkw==}
|
||||
peerDependencies:
|
||||
next: ^13.0.0 || ^14.0.0 || ^15.0.0
|
||||
react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0
|
||||
|
||||
'@noble/ciphers@0.6.0':
|
||||
resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==}
|
||||
|
||||
@ -1819,6 +1831,19 @@ packages:
|
||||
'@one-ini/wasm@0.1.1':
|
||||
resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==}
|
||||
|
||||
'@openpanel/nextjs@1.0.7':
|
||||
resolution: {integrity: sha512-XygTPiVlxUkcnZ3DYYwnWiogDgCL1hFK5G8nxokdrFKKuM0XQ+9mFElW/+dKgnVfmV2QiP1aAscudHAlRSUQhg==}
|
||||
peerDependencies:
|
||||
next: ^12.0.0 || ^13.0.0 || ^14.0.0 || ^15.0.0
|
||||
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||
|
||||
'@openpanel/sdk@1.0.0':
|
||||
resolution: {integrity: sha512-FNmmfjdXoC/VHEjA+WkrQ4lyM5lxEmV7xDd57uj4E+lIS0sU3DLG2mV/dpS8AscnZbUvuMn3kPhiLCqYzuv/gg==}
|
||||
|
||||
'@openpanel/web@1.0.1':
|
||||
resolution: {integrity: sha512-cVZ7Kr9SicczJ/RDIfEtZs8+1iGDzwkabVA/j3NqSl8VSucsC8m1+LVbjmCDzCJNnK4yVn6tEcc9PJRi2rtllw==}
|
||||
|
||||
'@opentelemetry/api@1.9.0':
|
||||
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
@ -5265,6 +5290,9 @@ packages:
|
||||
text-table@0.2.0:
|
||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||
|
||||
third-party-capital@1.0.20:
|
||||
resolution: {integrity: sha512-oB7yIimd8SuGptespDAZnNkzIz+NWaJCu2RMsbs4Wmp9zSDUM8Nhi3s2OOcqYuv3mN4hitXc8DVx+LyUmbUDiA==}
|
||||
|
||||
throttleit@2.1.0:
|
||||
resolution: {integrity: sha512-nt6AMGKW1p/70DF/hGBdJB57B8Tspmbp5gfJ8ilhLnt7kkr2ye7hzD6NVG8GGErk2HWF34igrL2CXmNIkzKqKw==}
|
||||
engines: {node: '>=18'}
|
||||
@ -6963,12 +6991,31 @@ snapshots:
|
||||
'@next/swc-win32-x64-msvc@15.2.1':
|
||||
optional: true
|
||||
|
||||
'@next/third-parties@15.3.0(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
react: 19.0.0
|
||||
third-party-capital: 1.0.20
|
||||
|
||||
'@noble/ciphers@0.6.0': {}
|
||||
|
||||
'@noble/hashes@1.7.1': {}
|
||||
|
||||
'@one-ini/wasm@0.1.1': {}
|
||||
|
||||
'@openpanel/nextjs@1.0.7(next@15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)':
|
||||
dependencies:
|
||||
'@openpanel/web': 1.0.1
|
||||
next: 15.2.1(@babel/core@7.24.5)(@opentelemetry/api@1.9.0)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
|
||||
react: 19.0.0
|
||||
react-dom: 19.0.0(react@19.0.0)
|
||||
|
||||
'@openpanel/sdk@1.0.0': {}
|
||||
|
||||
'@openpanel/web@1.0.1':
|
||||
dependencies:
|
||||
'@openpanel/sdk': 1.0.0
|
||||
|
||||
'@opentelemetry/api@1.9.0': {}
|
||||
|
||||
'@orama/orama@3.1.4': {}
|
||||
@ -11112,6 +11159,8 @@ snapshots:
|
||||
|
||||
text-table@0.2.0: {}
|
||||
|
||||
third-party-capital@1.0.20: {}
|
||||
|
||||
throttleit@2.1.0: {}
|
||||
|
||||
tiny-invariant@1.3.3: {}
|
||||
|
36
src/analytics/analytics.tsx
Normal file
36
src/analytics/analytics.tsx
Normal file
@ -0,0 +1,36 @@
|
||||
import GoogleAnalytics from "./google-analytics";
|
||||
import { UmamiAnalytics } from "./umami-analytics";
|
||||
import { PlausibleAnalytics } from "./plausible-analytics";
|
||||
import DataFastAnalytics from "./data-fast-analytics";
|
||||
import OpenPanelAnalytics from "./open-panel-analytics";
|
||||
|
||||
/**
|
||||
* Analytics Components all in one
|
||||
*
|
||||
* 1. all the analytics components only work in production
|
||||
* 2. only work if the environment variable for the analytics is set
|
||||
*/
|
||||
export function Analytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* google analytics */}
|
||||
<GoogleAnalytics />
|
||||
|
||||
{/* umami analytics */}
|
||||
<UmamiAnalytics />
|
||||
|
||||
{/* plausible analytics */}
|
||||
<PlausibleAnalytics />
|
||||
|
||||
{/* datafast analytics */}
|
||||
<DataFastAnalytics />
|
||||
|
||||
{/* openpanel analytics */}
|
||||
<OpenPanelAnalytics />
|
||||
</>
|
||||
);
|
||||
}
|
35
src/analytics/data-fast-analytics.tsx
Normal file
35
src/analytics/data-fast-analytics.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
"use client";
|
||||
|
||||
import Script from "next/script";
|
||||
|
||||
/**
|
||||
* DataFast Analytics
|
||||
*
|
||||
* https://datafa.st
|
||||
*/
|
||||
export default function DataFastAnalytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const domain = process.env.NEXT_PUBLIC_DATAFAST_DOMAIN;
|
||||
if (!domain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const websiteId = process.env.NEXT_PUBLIC_DATAFAST_WEBSITE_ID;
|
||||
if (!websiteId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
defer
|
||||
data-website-id={websiteId}
|
||||
data-domain={domain}
|
||||
src="https://datafa.st/js/script.js"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
22
src/analytics/google-analytics.tsx
Normal file
22
src/analytics/google-analytics.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { GoogleAnalytics as NextGoogleAnalytics } from "@next/third-parties/google";
|
||||
|
||||
/**
|
||||
* Google Analytics
|
||||
*
|
||||
* https://analytics.google.com
|
||||
* https://nextjs.org/docs/app/building-your-application/optimizing/third-party-libraries#google-analytics
|
||||
*/
|
||||
export default function GoogleAnalytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const analyticsId = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID;
|
||||
if (!analyticsId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <NextGoogleAnalytics gaId={analyticsId} />;
|
||||
}
|
26
src/analytics/open-panel-analytics.tsx
Normal file
26
src/analytics/open-panel-analytics.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
import { OpenPanelComponent } from "@openpanel/nextjs";
|
||||
|
||||
/**
|
||||
* OpenPanel Analytics (https://openpanel.dev)
|
||||
*
|
||||
* https://docs.openpanel.dev/docs/sdks/nextjs#options
|
||||
*/
|
||||
export default function OpenPanelAnalytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const clientId = process.env.NEXT_PUBLIC_OPENPANEL_CLIENT_ID;
|
||||
if (!clientId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<OpenPanelComponent
|
||||
clientId={clientId}
|
||||
trackScreenViews={true}
|
||||
trackAttributes={true}
|
||||
trackOutgoingLinks={true}
|
||||
/>
|
||||
);
|
||||
}
|
28
src/analytics/plausible-analytics.tsx
Normal file
28
src/analytics/plausible-analytics.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import Script from "next/script";
|
||||
|
||||
/**
|
||||
* Plausible Analytics
|
||||
*
|
||||
* https://plausible.io
|
||||
*/
|
||||
export function PlausibleAnalytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const domain = process.env.NEXT_PUBLIC_PLAUSIBLE_DOMAIN as string;
|
||||
if (!domain) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Script
|
||||
defer
|
||||
type="text/javascript"
|
||||
data-domain={domain}
|
||||
src="https://plausible.io/js/script.js"
|
||||
/>
|
||||
);
|
||||
}
|
28
src/analytics/umami-analytics.tsx
Normal file
28
src/analytics/umami-analytics.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
"use client";
|
||||
|
||||
import Script from "next/script";
|
||||
|
||||
/**
|
||||
* Umami Analytics
|
||||
*
|
||||
* https://umami.is
|
||||
*/
|
||||
export function UmamiAnalytics() {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const websiteId = process.env.NEXT_PUBLIC_UMAMI_WEBSITE_ID as string;
|
||||
if (!websiteId) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Script
|
||||
async
|
||||
type="text/javascript"
|
||||
data-website-id={websiteId}
|
||||
src="https://cloud.umami.is/script.js"
|
||||
/>
|
||||
);
|
||||
}
|
@ -8,6 +8,8 @@ import { Toaster } from 'sonner';
|
||||
import { Providers } from './providers';
|
||||
|
||||
import '@/styles/globals.css';
|
||||
import { TailwindIndicator } from '@/components/layout/tailwind-indicator';
|
||||
import { Analytics } from '@/analytics/analytics';
|
||||
|
||||
interface LocaleLayoutProps {
|
||||
children: ReactNode;
|
||||
@ -49,8 +51,8 @@ export default async function LocaleLayout({
|
||||
{children}
|
||||
|
||||
<Toaster richColors position="top-right" offset={64} />
|
||||
|
||||
{/* <TailwindIndicator /> */}
|
||||
<TailwindIndicator />
|
||||
<Analytics />
|
||||
</Providers>
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user