diff --git a/package-lock.json b/package-lock.json
index 347ab5210..c35b7077b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -48297,7 +48297,7 @@
},
"packages/components": {
"name": "@portaljs/components",
- "version": "0.4.0",
+ "version": "0.5.3",
"dependencies": {
"@githubocto/flat-ui": "^0.14.1",
"@heroicons/react": "^2.0.17",
diff --git a/packages/core/package.json b/packages/core/package.json
index be989016b..72de0c00d 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@portaljs/core",
- "version": "1.0.8",
+ "version": "1.0.9",
"description": "Core Portal.JS components, configs and utils.",
"repository": {
"type": "git",
diff --git a/packages/core/src/ui/analytics/GoogleAnalytics.tsx b/packages/core/src/ui/analytics/GoogleAnalytics.tsx
new file mode 100644
index 000000000..9130cb560
--- /dev/null
+++ b/packages/core/src/ui/analytics/GoogleAnalytics.tsx
@@ -0,0 +1,36 @@
+import Script from 'next/script.js'
+
+export interface GoogleAnalyticsProps {
+ googleAnalyticsId: string
+}
+
+export const GA = ({ googleAnalyticsId }: GoogleAnalyticsProps) => {
+ return (
+ <>
+
+
+
+ >
+ )
+}
+
+// https://developers.google.com/analytics/devguides/collection/gtagjs/events
+export const logEvent = (action, category, label, value) => {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ window.gtag?.('event', action, {
+ event_category: category,
+ event_label: label,
+ value: value,
+ })
+}
diff --git a/packages/core/src/ui/analytics/Plausible.tsx b/packages/core/src/ui/analytics/Plausible.tsx
new file mode 100644
index 000000000..9b2361bf6
--- /dev/null
+++ b/packages/core/src/ui/analytics/Plausible.tsx
@@ -0,0 +1,41 @@
+import Script from 'next/script.js'
+
+export interface PlausibleProps {
+ plausibleDataDomain: string
+ dataApi?: string
+ src?: string
+}
+
+/**
+ * Plausible analytics component.
+ * To proxy the requests through your own domain, you can use the dataApi and src attribute.
+ * See [Plausible docs](https://plausible.io/docs/proxy/guides/nextjs#step-2-adjust-your-deployed-script)
+ * for more information.
+ *
+ */
+export const Plausible = ({
+ plausibleDataDomain,
+ dataApi = undefined,
+ src = 'https://plausible.io/js/plausible.js',
+}: PlausibleProps) => {
+ return (
+ <>
+
+
+ >
+ )
+}
+
+// https://plausible.io/docs/custom-event-goals
+export const logEvent = (eventName, ...rest) => {
+ return window.plausible?.(eventName, ...rest)
+}
diff --git a/packages/core/src/ui/analytics/Posthog.tsx b/packages/core/src/ui/analytics/Posthog.tsx
new file mode 100644
index 000000000..51b3066fd
--- /dev/null
+++ b/packages/core/src/ui/analytics/Posthog.tsx
@@ -0,0 +1,25 @@
+import Script from 'next/script.js'
+
+export interface PosthogProps {
+ posthogProjectApiKey: string
+ apiHost?: string
+}
+
+/**
+ * Posthog analytics component.
+ * See [Posthog docs](https://posthog.com/docs/libraries/js#option-1-add-javascript-snippet-to-your-html-badgerecommendedbadge) for more information.
+ *
+ */
+export const Posthog = ({
+ posthogProjectApiKey,
+ apiHost = 'https://app.posthog.com',
+}: PosthogProps) => {
+ return (
+
+ )
+}
diff --git a/packages/core/src/ui/analytics/SimpleAnalytics.tsx b/packages/core/src/ui/analytics/SimpleAnalytics.tsx
new file mode 100644
index 000000000..49096c209
--- /dev/null
+++ b/packages/core/src/ui/analytics/SimpleAnalytics.tsx
@@ -0,0 +1,29 @@
+import Script from 'next/script.js'
+
+export interface SimpleAnalyticsProps {
+ src?: string
+}
+
+export const SimpleAnalytics = ({
+ src = 'https://scripts.simpleanalyticscdn.com/latest.js',
+}: SimpleAnalyticsProps) => {
+ return (
+ <>
+
+
+ >
+ )
+}
+
+// https://docs.simpleanalytics.com/events
+export const logEvent = (eventName, callback) => {
+ if (callback) {
+ return window.sa_event?.(eventName, callback)
+ } else {
+ return window.sa_event?.(eventName)
+ }
+}
diff --git a/packages/core/src/ui/analytics/Umami.tsx b/packages/core/src/ui/analytics/Umami.tsx
new file mode 100644
index 000000000..5614b71a5
--- /dev/null
+++ b/packages/core/src/ui/analytics/Umami.tsx
@@ -0,0 +1,20 @@
+import Script from 'next/script.js'
+
+export interface UmamiProps {
+ umamiWebsiteId: string
+ src?: string
+}
+
+export const Umami = ({
+ umamiWebsiteId,
+ src = 'https://analytics.umami.is/script.js',
+}: UmamiProps) => {
+ return (
+
+ )
+}
diff --git a/packages/core/src/ui/analytics/index.tsx b/packages/core/src/ui/analytics/index.tsx
new file mode 100644
index 000000000..8c1b59703
--- /dev/null
+++ b/packages/core/src/ui/analytics/index.tsx
@@ -0,0 +1,82 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+import { GA, GoogleAnalyticsProps } from "./GoogleAnalytics";
+import { Plausible, PlausibleProps } from "./Plausible";
+import { SimpleAnalytics, SimpleAnalyticsProps } from "./SimpleAnalytics";
+import { Umami, UmamiProps } from "./Umami";
+import { Posthog, PosthogProps } from "./Posthog";
+
+declare global {
+ interface Window {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ gtag?: (...args: any[]) => void;
+ plausible?: (...args: any[]) => void;
+ sa_event?: (...args: any[]) => void;
+ }
+}
+
+export interface AnalyticsConfig {
+ googleAnalytics?: GoogleAnalyticsProps;
+ plausibleAnalytics?: PlausibleProps;
+ umamiAnalytics?: UmamiProps;
+ posthogAnalytics?: PosthogProps;
+ simpleAnalytics?: SimpleAnalyticsProps;
+}
+
+/**
+ * @example
+ * const analytics: AnalyticsConfig = {
+ * plausibleDataDomain: '', // e.g. tailwind-nextjs-starter-blog.vercel.app
+ * simpleAnalytics: false, // true or false
+ * umamiWebsiteId: '', // e.g. 123e4567-e89b-12d3-a456-426614174000
+ * posthogProjectApiKey: '', // e.g. AhnJK8392ndPOav87as450xd
+ * googleAnalyticsId: '', // e.g. UA-000000-2 or G-XXXXXXX
+ * }
+ */
+export interface AnalyticsProps {
+ analyticsConfig: AnalyticsConfig;
+}
+
+const isProduction = true || process.env["NODE_ENV"] === "production";
+
+/**
+ * Supports Plausible, Simple Analytics, Umami, Posthog or Google Analytics.
+ * All components default to the hosted service, but can be configured to use a self-hosted
+ * or proxied version of the script by providing the `src` / `apiHost` props.
+ *
+ * Note: If you want to use an analytics provider you have to add it to the
+ * content security policy in the `next.config.js` file.
+ * @param {AnalyticsProps} { analytics }
+ * @return {*}
+ */
+export const Analytics = ({ analyticsConfig }: AnalyticsProps) => {
+ return (
+ <>
+ {isProduction && analyticsConfig.plausibleAnalytics && (
+
+ )}
+ {isProduction && analyticsConfig.simpleAnalytics && (
+
+ )}
+ {isProduction && analyticsConfig.posthogAnalytics && (
+
+ )}
+ {isProduction && analyticsConfig.umamiAnalytics && (
+
+ )}
+ {isProduction && analyticsConfig.googleAnalytics && (
+
+ )}
+ >
+ );
+};
+
+export { GA, Plausible, SimpleAnalytics, Umami, Posthog };
+
+export type {
+ GoogleAnalyticsProps,
+ PlausibleProps,
+ UmamiProps,
+ PosthogProps,
+ SimpleAnalyticsProps,
+};
diff --git a/packages/core/src/ui/index.ts b/packages/core/src/ui/index.ts
index cb9b5abff..376deba3f 100644
--- a/packages/core/src/ui/index.ts
+++ b/packages/core/src/ui/index.ts
@@ -21,3 +21,4 @@ export { SiteToc, NavItem, NavGroup } from "./SiteToc";
export { Comments, CommentsConfig } from "./Comments";
export { AuthorConfig } from "./types";
export { Hero } from "./Hero";
+export { Analytics, AnalyticsConfig } from "./analytics";
diff --git a/packages/core/src/utils/gtag.ts b/packages/core/src/utils/gtag.ts
index 59b2baf89..d8dbc3bf9 100644
--- a/packages/core/src/utils/gtag.ts
+++ b/packages/core/src/utils/gtag.ts
@@ -7,6 +7,8 @@ export const pageview = ({
analyticsID: string;
}) => {
if (typeof window.gtag !== undefined) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
window.gtag("config", analyticsID, {
page_path: url,
});
@@ -16,6 +18,8 @@ export const pageview = ({
// https://developers.google.com/analytics/devguides/collection/gtagjs/events
export const event = ({ action, category, label, value }) => {
if (typeof window.gtag !== undefined) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
window.gtag("event", action, {
event_category: category,
event_label: label,