feat: trim integration pages from 75 to 25 + migrate to MDX
- Add dedicatedPage flag to integration registry (25 true, 50 false) - Delete hardcoded nextjs/react/vue/wordpress route pages (wrong metadata) - Hub page routes non-dedicated integrations to /integrations/script-tag - Add 301 redirects for 50 removed slugs → /integrations/script-tag - Migrate guide content from TSX to MDX (content/integrations/*.mdx) - Add gray-matter, next-mdx-remote, remark-gfm dependencies - Add content loader (lib/integration-content.ts) matching ciphera-website pattern - Add prebuild script for integration guide index generation - Sitemap reduced from 83 to 35 URLs with real lastmod dates - Remove seoDescription from registry (now in MDX frontmatter)
This commit is contained in:
@@ -1,46 +1,56 @@
|
||||
/**
|
||||
* @file Dynamic route for individual integration guide pages.
|
||||
*
|
||||
* Handles all 50 integration routes via [slug].
|
||||
* Renders MDX content from content/integrations/*.mdx via next-mdx-remote.
|
||||
* Exports generateStaticParams for static generation and
|
||||
* generateMetadata for per-page SEO (title, description, OG, JSON-LD).
|
||||
*/
|
||||
|
||||
import type { Metadata } from 'next'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { MDXRemote } from 'next-mdx-remote/rsc'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { CodeBlock } from '@ciphera-net/ui'
|
||||
import { integrations, getIntegration } from '@/lib/integrations'
|
||||
import { getGuideContent } from '@/lib/integration-guides'
|
||||
import { getIntegrationGuide } from '@/lib/integration-content'
|
||||
import { IntegrationGuide } from '@/components/IntegrationGuide'
|
||||
|
||||
// * ─── Static Params ───────────────────────────────────────────────
|
||||
export function generateStaticParams() {
|
||||
return integrations.map((i) => ({ slug: i.id }))
|
||||
// * ─── MDX Components ────────────────────────────────────────────
|
||||
const mdxComponents = {
|
||||
CodeBlock,
|
||||
}
|
||||
|
||||
// * ─── SEO Metadata ────────────────────────────────────────────────
|
||||
// * ─── Static Params ─────────────────────────────────────────────
|
||||
export function generateStaticParams() {
|
||||
return integrations
|
||||
.filter((i) => i.dedicatedPage)
|
||||
.map((i) => ({ slug: i.id }))
|
||||
}
|
||||
|
||||
// * ─── SEO Metadata ──────────────────────────────────────────────
|
||||
interface PageProps {
|
||||
params: Promise<{ slug: string }>
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: PageProps): Promise<Metadata> {
|
||||
const { slug } = await params
|
||||
const integration = getIntegration(slug)
|
||||
if (!integration) return {}
|
||||
const guide = getIntegrationGuide(slug)
|
||||
if (!guide) return {}
|
||||
|
||||
const title = `How to Add Pulse Analytics to ${integration.name} | Pulse by Ciphera`
|
||||
const description = integration.seoDescription
|
||||
const url = `https://pulse.ciphera.net/integrations/${integration.id}`
|
||||
const title = `How to Add Pulse Analytics to ${guide.title} | Pulse by Ciphera`
|
||||
const description = guide.description
|
||||
const url = `https://pulse.ciphera.net/integrations/${guide.slug}`
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
keywords: [
|
||||
`${integration.name} analytics`,
|
||||
`${integration.name} Pulse`,
|
||||
`${guide.title} analytics`,
|
||||
`${guide.title} Pulse`,
|
||||
'privacy-first analytics',
|
||||
'website analytics',
|
||||
'Ciphera Pulse',
|
||||
integration.name,
|
||||
guide.title,
|
||||
],
|
||||
alternates: { canonical: url },
|
||||
openGraph: {
|
||||
@@ -58,21 +68,19 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>
|
||||
}
|
||||
}
|
||||
|
||||
// * ─── Page Component ──────────────────────────────────────────────
|
||||
// * ─── Page Component ────────────────────────────────────────────
|
||||
export default async function IntegrationPage({ params }: PageProps) {
|
||||
const { slug } = await params
|
||||
const integration = getIntegration(slug)
|
||||
if (!integration) return notFound()
|
||||
|
||||
const content = getGuideContent(slug)
|
||||
if (!content) return notFound()
|
||||
const guide = getIntegrationGuide(slug)
|
||||
if (!integration || !guide) return notFound()
|
||||
|
||||
// * HowTo JSON-LD for rich search snippets
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'HowTo',
|
||||
name: `How to Add Pulse Analytics to ${integration.name}`,
|
||||
description: integration.seoDescription,
|
||||
description: guide.description,
|
||||
step: [
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
@@ -104,7 +112,11 @@ export default async function IntegrationPage({ params }: PageProps) {
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
<IntegrationGuide integration={integration}>
|
||||
{content}
|
||||
<MDXRemote
|
||||
source={guide.content}
|
||||
components={mdxComponents}
|
||||
options={{ mdxOptions: { remarkPlugins: [remarkGfm] } }}
|
||||
/>
|
||||
</IntegrationGuide>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -1,128 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||
|
||||
export default function NextJsIntegrationPage() {
|
||||
return (
|
||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||
{/* * --- ATMOSPHERE (Background) --- */}
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||
<div
|
||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||
<Link
|
||||
href="/integrations"
|
||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||
Back to Integrations
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||
<svg viewBox="0 0 128 128" className="w-10 h-10 invert">
|
||||
<path d="M64 0C28.7 0 0 28.7 0 64s28.7 64 64 64 64-28.7 64-64S99.3 0 64 0zm27.6 93.9c-.8.9-2.2 1-3.1.2L42.8 52.8V88c0 1.3-1.1 2.3-2.3 2.3h-7.4c-1.3 0-2.3-1.1-2.3-2.3V40c0-1.3 1.1-2.3 2.3-2.3h7.4c1 0 1.9.6 2.2 1.5l48.6 44.8V40c0-1.3 1.1-2.3 2.3-2.3h7.4c1.3 0 2.3 1.1 2.3 2.3v48c0 1.3-1.1 2.3-2.3 2.3h-6.8c-.9 0-1.7-.5-2.1-1.3z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
||||
Next.js Integration
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="lead text-xl text-neutral-400">
|
||||
The best way to add Pulse to your Next.js application is using the built-in <code>next/script</code> component.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
|
||||
<h3>Using App Router (Recommended)</h3>
|
||||
<p>
|
||||
Add the script to your root layout file (usually <code>app/layout.tsx</code> or <code>app/layout.js</code>).
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">app/layout.tsx</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`import Script from 'next/script'
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<Script
|
||||
defer
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
data-domain="your-site.com"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
</head>
|
||||
<body>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Using Pages Router</h3>
|
||||
<p>
|
||||
If you are using the older Pages Router, add the script to your custom <code>_app.tsx</code> or <code>_document.tsx</code>.
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">pages/_app.tsx</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`import Script from 'next/script'
|
||||
import type { AppProps } from 'next/app'
|
||||
|
||||
export default function App({ Component, pageProps }: AppProps) {
|
||||
return (
|
||||
<>
|
||||
<Script
|
||||
defer
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
data-domain="your-site.com"
|
||||
strategy="afterInteractive"
|
||||
/>
|
||||
<Component {...pageProps} />
|
||||
</>
|
||||
)
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Configuration Options</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<strong>data-domain</strong>: The domain name you added to your Pulse dashboard (e.g., <code>example.com</code>).
|
||||
</li>
|
||||
<li>
|
||||
<strong>src</strong>: The URL of our tracking script: <code>https://pulse.ciphera.net/script.js</code>
|
||||
</li>
|
||||
<li>
|
||||
<strong>strategy</strong>: We recommend <code>afterInteractive</code> to ensure it loads quickly without blocking hydration.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -244,7 +244,7 @@ export default function IntegrationsPage() {
|
||||
transition={{ duration: 0.4, delay: i * 0.05 }}
|
||||
>
|
||||
<Link
|
||||
href={`/integrations/${integration!.id}`}
|
||||
href={integration!.dedicatedPage ? `/integrations/${integration!.id}` : '/integrations/script-tag'}
|
||||
className="group flex items-center gap-3 p-4 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-0.5 hover:shadow-lg h-full"
|
||||
>
|
||||
<div className="p-2 bg-neutral-800 rounded-lg shrink-0 group-hover:scale-110 transition-transform duration-300 [&_svg]:w-6 [&_svg]:h-6">
|
||||
@@ -283,7 +283,7 @@ export default function IntegrationsPage() {
|
||||
transition={{ duration: 0.5, delay: i * 0.05 }}
|
||||
>
|
||||
<Link
|
||||
href={`/integrations/${integration.id}`}
|
||||
href={integration.dedicatedPage ? `/integrations/${integration.id}` : '/integrations/script-tag'}
|
||||
className="group relative p-6 bg-neutral-900/50 backdrop-blur-sm border border-neutral-800 rounded-2xl hover:border-brand-orange/50 transition-all duration-300 hover:-translate-y-1 hover:shadow-xl block h-full focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-orange focus-visible:ring-offset-2"
|
||||
>
|
||||
<div className="flex items-start justify-between mb-6">
|
||||
|
||||
@@ -1,118 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||
|
||||
export default function ReactIntegrationPage() {
|
||||
return (
|
||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||
{/* * --- ATMOSPHERE (Background) --- */}
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||
<div
|
||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||
<Link
|
||||
href="/integrations"
|
||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||
Back to Integrations
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#61DAFB] fill-current">
|
||||
<path d="M64 10.6c18.4 0 34.6 5.8 44.6 14.8 6.4 5.8 10.2 12.8 10.2 20.6 0 21.6-28.6 41.2-64 41.2-1.6 0-3.2-.1-4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11 11.2-5.6 20.2-13 26.2-21.4-6.4-5.8-15.4-10-25.6-12.2-10.2-2.2-21.4-3.4-33-3.4-1.6 0-3.2.1-4.8.2 1.2-10.8 6.2-20.2 13.8-27.6 8.8-8.6 20.6-13.4 33.2-13.4 2.2 0 4.4.2 6.4.4-10.2 12.8-15.6 29.2-15.6 46.2 0 2.6.2 5.2.4 7.8-13.6 1.6-26.2 5.4-37.4 11-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11zm-33.4 62c-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8 13.6-1.6 26.2-5.4 37.4-11zm-15.2-16.6c-6.4-5.8-10.2-12.8-10.2-20.6 0-21.6 28.6-41.2 64-41.2 1.6 0 3.2.1 4.8.2 1.2-10.8 6.2-20.2 13.8-27.6 8.8-8.6 20.6-13.4 33.2-13.4 2.2 0 4.4.2 6.4.4-10.2 12.8-15.6 29.2-15.6 46.2 0 2.6.2 5.2.4 7.8-13.6 1.6-26.2 5.4-37.4 11-11.2 5.6-20.2 13-26.2 21.4 6.4 5.8 15.4 10 25.6 12.2 10.2 2.2 21.4 3.4 33 3.4 1.6 0 3.2-.1 4.8-.2-1.2 10.8-6.2 20.2-13.8 27.6-8.8 8.6-20.6 13.4-33.2 13.4-2.2 0-4.4-.2-6.4-.4 10.2-12.8 15.6-29.2 15.6-46.2 0-2.6-.2-5.2-.4-7.8z" />
|
||||
<circle cx="64" cy="64" r="10.6" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
||||
React Integration
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="lead text-xl text-neutral-400">
|
||||
For standard React SPAs (Create React App, Vite, etc.), you can simply add the script tag to your <code>index.html</code>.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
|
||||
<h3>Method 1: index.html (Recommended)</h3>
|
||||
<p>
|
||||
The simplest way is to add the script tag directly to the <code><head></code> of your <code>index.html</code> file.
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">public/index.html</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
<!-- Pulse Analytics -->
|
||||
<script
|
||||
defer
|
||||
data-domain="your-site.com"
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
></script>
|
||||
|
||||
<title>My React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
</body>
|
||||
</html>`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Method 2: Programmatic Injection</h3>
|
||||
<p>
|
||||
If you need to load the script dynamically (e.g., only in production), you can use a <code>useEffect</code> hook in your main App component.
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">src/App.tsx</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`import { useEffect } from 'react'
|
||||
|
||||
function App() {
|
||||
useEffect(() => {
|
||||
// Only load in production
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
const script = document.createElement('script')
|
||||
script.defer = true
|
||||
script.setAttribute('data-domain', 'your-site.com')
|
||||
script.src = 'https://pulse.ciphera.net/script.js'
|
||||
document.head.appendChild(script)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<h1>Hello World</h1>
|
||||
</div>
|
||||
)
|
||||
}`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
147
app/integrations/script-tag/page.tsx
Normal file
147
app/integrations/script-tag/page.tsx
Normal file
@@ -0,0 +1,147 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||
import { CodeBlock } from '@ciphera-net/ui'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Add Pulse Analytics to Any Website | Pulse by Ciphera',
|
||||
description: 'Add privacy-first analytics to any website with a single script tag. Works with any platform, CMS, or framework.',
|
||||
alternates: { canonical: 'https://pulse.ciphera.net/integrations/script-tag' },
|
||||
openGraph: {
|
||||
title: 'Add Pulse Analytics to Any Website | Pulse by Ciphera',
|
||||
description: 'Add privacy-first analytics to any website with a single script tag.',
|
||||
url: 'https://pulse.ciphera.net/integrations/script-tag',
|
||||
siteName: 'Pulse by Ciphera',
|
||||
type: 'article',
|
||||
},
|
||||
}
|
||||
|
||||
export default function ScriptTagPage() {
|
||||
const jsonLd = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'HowTo',
|
||||
name: 'How to Add Pulse Analytics to Any Website',
|
||||
description: 'Add privacy-first analytics to any website with a single script tag.',
|
||||
step: [
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
name: 'Copy the script tag',
|
||||
text: 'Copy the Pulse tracking script with your domain.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
name: 'Paste into your HTML head',
|
||||
text: 'Add the script tag inside the <head> section of your website.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
name: 'Deploy and verify',
|
||||
text: 'Deploy your site and check the Pulse dashboard for incoming data.',
|
||||
},
|
||||
],
|
||||
tool: {
|
||||
'@type': 'HowToTool',
|
||||
name: 'Pulse by Ciphera',
|
||||
url: 'https://pulse.ciphera.net',
|
||||
},
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
type="application/ld+json"
|
||||
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
|
||||
/>
|
||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||
<div
|
||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||
<Link
|
||||
href="/integrations"
|
||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||
Back to Integrations
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||
<svg className="w-10 h-10 text-brand-orange" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M17.25 6.75 22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3-4.5 16.5" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-white">
|
||||
Script Tag Integration
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="lead text-xl text-neutral-400">
|
||||
Add Pulse to any website by pasting a single script tag into your HTML.
|
||||
This works with any platform, CMS, or static site.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
|
||||
<h2>Installation</h2>
|
||||
<p>
|
||||
Add the following script tag inside the <code><head></code> section of your website:
|
||||
</p>
|
||||
|
||||
<CodeBlock filename="index.html">{`<head>
|
||||
<!-- ... other head elements ... -->
|
||||
<script
|
||||
defer
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
data-domain="your-site.com"
|
||||
></script>
|
||||
</head>`}</CodeBlock>
|
||||
|
||||
<h2>Configuration</h2>
|
||||
<ul>
|
||||
<li><code>data-domain</code> — your site's domain as shown in your Pulse dashboard (e.g. <code>example.com</code>), without <code>https://</code></li>
|
||||
<li><code>defer</code> — loads the script without blocking page rendering</li>
|
||||
</ul>
|
||||
|
||||
<h2>Where to paste the script</h2>
|
||||
<p>
|
||||
Most platforms have a “Custom Code”, “Code Injection”, or “Header Scripts”
|
||||
section in their settings. Look for one of these:
|
||||
</p>
|
||||
<ul>
|
||||
<li><strong>Squarespace:</strong> Settings → Developer Tools → Code Injection → Header</li>
|
||||
<li><strong>Wix:</strong> Settings → Custom Code → Head</li>
|
||||
<li><strong>Webflow:</strong> Project Settings → Custom Code → Head Code</li>
|
||||
<li><strong>Ghost:</strong> Settings → Code Injection → Site Header</li>
|
||||
<li><strong>Any HTML site:</strong> Paste directly into your <code><head></code> tag</li>
|
||||
</ul>
|
||||
|
||||
<h2>Verify installation</h2>
|
||||
<p>
|
||||
After deploying, visit your site and check the Pulse dashboard. You should
|
||||
see your first page view within a few seconds.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
<h3>Optional: Frustration Tracking</h3>
|
||||
<p>
|
||||
Detect rage clicks and dead clicks by adding the frustration tracking
|
||||
add-on after the core script:
|
||||
</p>
|
||||
<CodeBlock filename="index.html">{`<script defer src="https://pulse.ciphera.net/script.frustration.js"></script>`}</CodeBlock>
|
||||
<p>
|
||||
No extra configuration needed. Add <code>data-no-rage</code> or{' '}
|
||||
<code>data-no-dead</code> to disable individual signals.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||
|
||||
export default function VueIntegrationPage() {
|
||||
return (
|
||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||
{/* * --- ATMOSPHERE (Background) --- */}
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||
<div
|
||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||
<Link
|
||||
href="/integrations"
|
||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||
Back to Integrations
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#4FC08D] fill-current">
|
||||
<path d="M82.8 24.6h27.8L64 103.4 17.4 24.6h27.8L64 59.4l18.8-34.8z" />
|
||||
<path d="M64 24.6H39L64 67.4l25-42.8H64z" fill="#35495E" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
||||
Vue.js Integration
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="lead text-xl text-neutral-400">
|
||||
Integrating Pulse with Vue.js is straightforward. You can add the script to your <code>index.html</code> file.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
|
||||
<h3>Method 1: index.html (Recommended)</h3>
|
||||
<p>
|
||||
Add the script tag to the <code><head></code> section of your <code>index.html</code> file. This works for both Vue 2 and Vue 3 projects created with Vue CLI or Vite.
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">index.html</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<!-- Pulse Analytics -->
|
||||
<script
|
||||
defer
|
||||
data-domain="your-site.com"
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
></script>
|
||||
|
||||
<title>My Vue App</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Method 2: Nuxt.js</h3>
|
||||
<p>
|
||||
For Nuxt.js applications, you should add the script to your <code>nuxt.config.js</code> or <code>nuxt.config.ts</code> file.
|
||||
</p>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">nuxt.config.ts</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`export default defineNuxtConfig({
|
||||
app: {
|
||||
head: {
|
||||
script: [
|
||||
{
|
||||
src: 'https://pulse.ciphera.net/script.js',
|
||||
defer: true,
|
||||
'data-domain': 'your-site.com'
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
})`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import Link from 'next/link'
|
||||
import { ArrowLeftIcon } from '@ciphera-net/ui'
|
||||
|
||||
export default function WordPressIntegrationPage() {
|
||||
return (
|
||||
<div className="relative min-h-screen flex flex-col overflow-hidden">
|
||||
{/* * --- ATMOSPHERE (Background) --- */}
|
||||
<div className="absolute inset-0 -z-10 pointer-events-none">
|
||||
<div className="absolute bottom-0 right-1/4 w-[500px] h-[500px] bg-neutral-400/10 rounded-full blur-[128px] opacity-40" />
|
||||
<div
|
||||
className="absolute inset-0 bg-grid-pattern opacity-[0.05]"
|
||||
style={{ maskImage: 'radial-gradient(ellipse at center, black 0%, transparent 70%)' }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex-grow w-full max-w-4xl mx-auto px-4 pt-20 pb-10 z-10">
|
||||
<Link
|
||||
href="/integrations"
|
||||
className="inline-flex items-center text-sm text-neutral-500 hover:text-brand-orange mb-8 transition-colors"
|
||||
>
|
||||
<ArrowLeftIcon className="w-4 h-4 mr-2" />
|
||||
Back to Integrations
|
||||
</Link>
|
||||
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
<div className="p-3 bg-neutral-800 rounded-xl">
|
||||
<svg viewBox="0 0 128 128" className="w-10 h-10 text-[#21759B] fill-current">
|
||||
<path d="M116.6 64c0-19.2-10.4-36-26-45.2l28.6 78.4c-1 3.2-2.2 6.2-3.6 9.2-11.4 12.4-27.8 20.2-46 20.2-6.2 0-12.2-.8-17.8-2.4l26.2-76.4c1.2.2 2.4.4 3.6.4 5.4 0 13.8-.8 13.8-.8 2.8-.2 3.2 4 .4 4.2 0 0-2.8.2-6 .4l19 56.6 5.4-18c2.4-7.4 4.2-12.8 4.2-17.4 0-6-2.2-10.2-7.6-12.6-2.8-1.2-2.2-5.4 1.4-5.4h4.4zM64 121.2c-15.8 0-30.2-6.4-40.8-16.8L46.6 36.8c-2.8-.2-5.8-.4-5.8-.4-2.8-.2-2.4-4.4.4-4.2 0 0 8.4.8 13.6.8 5.4 0 13.6-.8 13.6-.8 2.8-.2 3.2 4 .4 4.2 0 0-2.8.2-5.8.4l18.2 54.4 10.6-31.8L64 121.2zM11.4 64c0 17 8.2 32.2 20.8 41.8L18.8 66.8c-.8-3.4-1.2-6.6-1.2-9.2 0-6.8 2.6-13 6.2-17.8C15.6 47.4 11.4 55.2 11.4 64zM64 6.8c16.2 0 30.8 6.8 41.4 17.6-1.4-.2-2.8-.2-4.2-.2-7.8 0-14.2 1.4-14.2 1.4-2.8.6-2.2 4.8.6 4.2 0 0 5-1 10.6-1 2.2 0 4.6.2 6.6.4L88.2 53 71.4 6.8h-7.4z" />
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold tracking-tight text-white">
|
||||
WordPress Integration
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="lead text-xl text-neutral-400">
|
||||
You can add Pulse to your WordPress site without installing any heavy plugins, or by using a simple code snippet plugin.
|
||||
</p>
|
||||
|
||||
<hr className="my-8 border-neutral-800" />
|
||||
|
||||
<h3>Method 1: Using a Plugin (Easiest)</h3>
|
||||
<ol>
|
||||
<li>Install a plugin like "Insert Headers and Footers" (WPCode).</li>
|
||||
<li>Go to the plugin settings and find the "Scripts in Header" section.</li>
|
||||
<li>Paste the following code snippet:</li>
|
||||
</ol>
|
||||
|
||||
<div className="bg-neutral-900 rounded-xl overflow-hidden border border-neutral-800 my-6">
|
||||
<div className="flex items-center px-4 py-2 bg-neutral-800 border-b border-neutral-800">
|
||||
<span className="text-xs text-neutral-400 font-mono">Header Script</span>
|
||||
</div>
|
||||
<div className="p-4 overflow-x-auto">
|
||||
<pre className="text-sm font-mono text-neutral-300">
|
||||
{`<script
|
||||
defer
|
||||
data-domain="your-site.com"
|
||||
src="https://pulse.ciphera.net/script.js"
|
||||
></script>`}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Method 2: Edit Theme Files (Advanced)</h3>
|
||||
<p>
|
||||
If you are comfortable editing your theme files, you can add the script directly to your <code>header.php</code> file.
|
||||
</p>
|
||||
<ol>
|
||||
<li>Go to Appearance > Theme File Editor.</li>
|
||||
<li>Select <code>header.php</code> from the right sidebar.</li>
|
||||
<li>Paste the script tag just before the closing <code></head></code> tag.</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user