website-monitor/frontend/components/landing/LandingSections.tsx

589 lines
25 KiB
TypeScript

'use client'
import { motion, type Variants } from 'framer-motion'
import Link from 'next/link'
import { Button } from '@/components/ui/button'
import {
Check, ArrowRight, Shield, Search, FileCheck, TrendingUp,
Target, Filter, Bell, Eye, Slack, Webhook, History,
Zap, Lock, ChevronRight, Star, Accessibility
} from 'lucide-react'
import { useState, useEffect } from 'react'
import { SEODemoVisual } from './SEODemoVisual'
import { CompetitorDemoVisual } from './CompetitorDemoVisual'
import { PolicyDemoVisual } from './PolicyDemoVisual'
import { WaitlistForm } from './WaitlistForm'
import { MagneticButton } from './MagneticElements'
import { BackgroundGradient, FloatingElements, InteractiveGrid, GlowEffect, SectionDivider } from './BackgroundEffects'
// Animation Variants
const fadeInUp: Variants = {
hidden: { opacity: 0, y: 30, filter: 'blur(4px)' },
visible: (i: number = 0) => ({
opacity: 1,
y: 0,
filter: 'blur(0px)',
transition: {
delay: i * 0.15,
duration: 0.7,
ease: [0.22, 1, 0.36, 1]
}
})
}
// ============================================
// 1. HERO SECTION
// ============================================
export function HeroSection() {
return (
<section id="hero" className="relative overflow-hidden pt-32 pb-24 lg:pt-40 lg:pb-32 gradient-velvet">
{/* Background Elements */}
<div className="absolute inset-0 grain-texture" />
<div className="absolute right-0 top-20 -z-10 h-[600px] w-[600px] rounded-full bg-[hsl(var(--primary))] opacity-8 blur-[120px]" />
<div className="absolute left-0 bottom-0 -z-10 h-[400px] w-[400px] rounded-full bg-[hsl(var(--teal))] opacity-8 blur-[100px]" />
<div className="mx-auto max-w-7xl px-6 relative z-10">
<div className="grid lg:grid-cols-[60%_40%] gap-16 items-center">
{/* Left: Content */}
<motion.div
initial="hidden"
animate="visible"
className="flex flex-col gap-8"
>
{/* Overline */}
<motion.div variants={fadeInUp} custom={0}>
<div className="inline-flex items-center gap-2 rounded-full bg-[hsl(var(--teal))]/10 border border-[hsl(var(--teal))]/20 px-4 py-1.5 text-sm font-medium text-[hsl(var(--teal))]">
<span className="relative flex h-2 w-2">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-[hsl(var(--teal))] opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-[hsl(var(--teal))]"></span>
</span>
Website Change Monitor for SEO & Growth Teams
</div>
</motion.div>
{/* Hero Headline */}
<motion.h1
variants={fadeInUp}
custom={1}
className="text-5xl lg:text-7xl font-display font-bold leading-[1.08] tracking-tight text-foreground"
>
Monitor website changes &{' '}
<span className="text-[hsl(var(--primary))]">price drops automatically.</span>
</motion.h1>
{/* Subheadline */}
<motion.p
variants={fadeInUp}
custom={2}
className="text-xl lg:text-2xl text-muted-foreground font-body leading-relaxed max-w-2xl"
>
Less noise. More signal. Visual proof included.
</motion.p>
{/* Feature Bullets */}
<motion.div
variants={fadeInUp}
custom={3}
className="grid md:grid-cols-2 gap-4 max-w-2xl"
>
{[
'Auto-filter cookie banners & timestamps',
'Keyword alerts when it matters',
'Slack/Webhook integration',
'Audit-proof history & snapshots'
].map((feature, i) => (
<div key={i} className="flex items-start gap-3">
<div className="mt-0.5 flex-shrink-0 flex h-5 w-5 items-center justify-center rounded-full bg-[hsl(var(--teal))]/20">
<Check className="h-3 w-3 text-[hsl(var(--teal))]" strokeWidth={3} />
</div>
<span className="text-foreground text-sm font-medium leading-tight">{feature}</span>
</div>
))}
</motion.div>
{/* Waitlist Form */}
<motion.div
variants={fadeInUp}
custom={4}
className="w-full max-w-lg"
>
<WaitlistForm id="waitlist-form" />
</motion.div>
{/* Trust Signals */}
<motion.div
variants={fadeInUp}
custom={5}
className="flex flex-wrap items-center gap-6 text-sm text-muted-foreground"
>
<div className="flex items-center gap-2">
<Lock className="h-4 w-4" />
<span>No credit card</span>
</div>
<span></span>
<div className="flex items-center gap-2">
<Shield className="h-4 w-4" />
<span>No spam, ever</span>
</div>
<span></span>
<div className="flex items-center gap-2">
<Star className="h-4 w-4 fill-current" />
<span>Early access</span>
</div>
</motion.div>
</motion.div>
{/* Right: Animated Visual - Noise → Signal */}
<motion.div
initial={{ opacity: 0, x: 40 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.9, delay: 0.3 }}
className="relative"
>
<NoiseToSignalVisual />
</motion.div>
</div>
</div>
</section>
)
}
// ============================================
// 1b. TRUST SECTION - "As seen on..."
// ============================================
function TrustSectionDeprecated() {
const logos = [
{ name: 'SEO Clarity', color: 'text-muted-foreground' },
{ name: 'Search Engine Journal', color: 'text-muted-foreground' },
{ name: 'Moz', color: 'text-muted-foreground' },
{ name: 'Ahrefs', color: 'text-muted-foreground' },
{ name: 'Semrush', color: 'text-muted-foreground' }
]
return (
<section className="py-12 border-y border-border/50 bg-secondary/10">
<div className="mx-auto max-w-7xl px-6">
<p className="text-center text-[10px] font-bold uppercase tracking-[0.2em] text-muted-foreground/80 mb-8">
The Essential Toolkit for Industry Leaders
</p>
<div className="flex flex-wrap justify-center items-center gap-x-12 gap-y-8 opacity-40 grayscale hover:grayscale-0 transition-all duration-700">
{logos.map((logo, i) => (
<motion.div
key={i}
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ delay: i * 0.1, duration: 0.8 }}
className={`text-xl font-display font-black tracking-tighter ${logo.color}`}
>
{logo.name}
</motion.div>
))}
</div>
</div>
</section>
)
}
// Noise → Signal Animation Component
function NoiseToSignalVisual() {
const [phase, setPhase] = useState(0)
const [isPaused, setIsPaused] = useState(false)
const [particles, setParticles] = useState<{ id: number; x: number; y: number }[]>([])
useEffect(() => {
if (isPaused) return
const interval = setInterval(() => {
setPhase(p => {
const nextPhase = (p + 1) % 4
if (p === 0 && nextPhase === 1) {
triggerParticles()
}
return nextPhase
})
}, 2500)
return () => clearInterval(interval)
}, [isPaused])
const triggerParticles = () => {
const newParticles = Array.from({ length: 8 }, (_, i) => ({
id: Date.now() + i,
x: Math.random() * 100,
y: Math.random() * 100
}))
setParticles(newParticles)
setTimeout(() => setParticles([]), 1000)
}
return (
<motion.div
className="relative aspect-[4/3] min-h-[320px] rounded-3xl border-2 border-border bg-card/50 backdrop-blur-sm shadow-2xl overflow-hidden cursor-pointer group"
style={{ perspective: '1000px' }}
whileHover={{ rotateY: 2, rotateX: -2, scale: 1.02 }}
transition={{ duration: 0.3 }}
onHoverStart={() => setIsPaused(true)}
onHoverEnd={() => setIsPaused(false)}
>
{/* Pulsing Glow Border */}
{phase >= 1 && (
<motion.div
className="absolute inset-0 rounded-3xl"
animate={{
boxShadow: [
'0 0 0px hsl(var(--teal))',
'0 0 20px hsl(var(--teal) / 0.5)',
'0 0 0px hsl(var(--teal))'
]
}}
transition={{ duration: 2, repeat: Infinity }}
/>
)}
{/* Particles */}
{particles.map(particle => (
<motion.div
key={particle.id}
className="absolute w-1 h-1 rounded-full bg-[hsl(var(--teal))]"
initial={{ x: `${particle.x}%`, y: `${particle.y}%`, opacity: 1, scale: 1 }}
animate={{
y: `${particle.y - 20}%`,
opacity: 0,
scale: 0
}}
transition={{ duration: 0.8 }}
/>
))}
{/* Mock Browser Header */}
<div className="flex items-center gap-2 border-b border-border bg-secondary/30 px-4 py-3">
<div className="flex gap-1.5">
<div className="h-2.5 w-2.5 rounded-full bg-red-400" />
<div className="h-2.5 w-2.5 rounded-full bg-yellow-400" />
<div className="h-2.5 w-2.5 rounded-full bg-green-400" />
</div>
<div className="flex-1 mx-4 px-3 py-1 rounded-md bg-background/50 text-xs text-muted-foreground font-mono text-center">
competitor-site.com/pricing
</div>
{isPaused && (
<motion.div
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
className="text-[10px] text-muted-foreground font-medium"
>
PAUSED
</motion.div>
)}
</div>
{/* Content Area */}
<div className="p-8 space-y-4 relative">
<motion.div
className="absolute top-4 left-4 px-3 py-1 rounded-full bg-background/80 backdrop-blur-sm border border-border text-xs font-mono font-semibold"
animate={{
opacity: phase === 0 ? 1 : 0.5,
scale: phase === 0 ? 1 : 0.95
}}
>
Noise: {phase === 0 ? '67%' : '0%'}
</motion.div>
{/* Phase 0: Noisy Page */}
<motion.div
animate={{
opacity: phase === 0 ? 1 : 0,
scale: phase === 0 ? 1 : 0.98
}}
transition={{ duration: 0.5 }}
className="space-y-3"
>
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/30 border border-border/40 relative overflow-hidden">
<span className="text-xs text-muted-foreground">🍪 Cookie Banner</span>
<span className="text-xs text-red-500 font-semibold">NOISE</span>
</div>
<div className="p-4 rounded-lg bg-background border border-border">
<p className="text-sm font-semibold text-foreground mb-2">Enterprise Plan</p>
<p className="text-2xl font-bold text-[hsl(var(--burgundy))]">$99/mo</p>
</div>
<div className="flex items-center justify-between p-3 rounded-lg bg-muted/30 border border-border/40 relative overflow-hidden">
<span className="text-xs text-muted-foreground"> Last updated: 10:23 AM</span>
<span className="text-xs text-red-500 font-semibold">NOISE</span>
</div>
</motion.div>
{/* Phase 1-3: Signal */}
{phase >= 1 && (
<motion.div
initial={{ opacity: 0, scale: 0.85 }}
animate={{ opacity: 1, scale: 1 }}
className="absolute inset-0 flex items-center justify-center p-8"
>
<div className="w-full p-6 rounded-2xl bg-white dark:bg-zinc-950 border-2 border-[hsl(var(--teal))] shadow-2xl relative">
<div className="flex items-center justify-between mb-2">
<span className="text-xs font-bold uppercase tracking-wider text-[hsl(var(--teal))]"> SIGNAL DETECTED</span>
<div className="flex items-center gap-1.5 text-xs text-[hsl(var(--teal))]">
<Filter className="h-3 w-3" /> Filtered
</div>
</div>
<p className="text-sm font-semibold text-muted-foreground mb-3">Enterprise Plan</p>
<div className="flex items-baseline gap-3">
<p className="text-3xl font-bold text-foreground">$99/mo</p>
{phase >= 2 && (
<motion.p
initial={{ opacity: 0, x: -10 }}
animate={{ opacity: 1, x: 0 }}
className="text-3xl text-[hsl(var(--burgundy))] font-bold"
>
$79/mo
</motion.p>
)}
</div>
{phase >= 3 && (
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
className="mt-4 inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-[hsl(var(--burgundy))]/10 border border-[hsl(var(--burgundy))]/30"
>
<Bell className="h-3 w-3 text-[hsl(var(--burgundy))]" />
<span className="text-[10px] font-bold text-[hsl(var(--burgundy))] uppercase tracking-wider">Alert Sent</span>
</motion.div>
)}
</div>
</motion.div>
)}
{/* Phase Indicator */}
<div className="absolute bottom-4 right-4 flex gap-1.5">
{[0, 1, 2, 3].map(i => (
<div
key={i}
className={`h-1.5 rounded-full transition-all duration-300 ${phase === i ? 'w-6 bg-[hsl(var(--teal))]' : 'w-1.5 bg-border'}`}
/>
))}
</div>
</div>
</motion.div>
)
}
// ============================================
// 2. USE CASE SHOWCASE
// ============================================
export function UseCaseShowcase() {
const useCases = [
{
icon: <Search className="h-7 w-7" />,
title: 'SEO Monitoring',
problem: 'Your rankings drop before you know why.',
example: 'Track when competitors update meta descriptions or add new content sections that outrank you.',
color: 'teal',
demoComponent: <SEODemoVisual />
},
{
icon: <TrendingUp className="h-7 w-7" />,
title: 'Competitor Intelligence',
problem: 'Competitor launches slip past your radar.',
example: 'Monitor pricing pages, product launches, and promotional campaigns in real-time.',
color: 'primary',
demoComponent: <CompetitorDemoVisual />
},
{
icon: <FileCheck className="h-7 w-7" />,
title: 'Policy & Compliance',
problem: 'Regulatory updates appear without warning.',
example: 'Track policy changes, terms updates, and legal text modifications with audit-proof history.',
color: 'burgundy',
demoComponent: <PolicyDemoVisual />
}
]
return (
<section className="py-32 relative overflow-hidden">
<div className="absolute inset-0 bg-[linear-gradient(to_right,hsl(var(--border))_1px,transparent_1px),linear-gradient(to_bottom,hsl(var(--border))_1px,transparent_1px)] bg-[size:4rem_4rem] opacity-30 [mask-image:radial-gradient(ellipse_80%_50%_at_50%_50%,#000_70%,transparent_100%)]" />
<div className="mx-auto max-w-7xl px-6 relative z-10">
<div className="text-center mb-20">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="inline-flex items-center gap-2 rounded-full bg-secondary border border-border px-4 py-1.5 text-sm font-medium text-foreground mb-6"
>
<Eye className="h-4 w-4" /> Who This Is For
</motion.div>
<motion.h2
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="text-4xl lg:text-5xl font-display font-bold text-foreground mb-6"
>
Built for teams who need results, <span className="text-muted-foreground">not demos.</span>
</motion.h2>
</div>
<div className="grid md:grid-cols-3 gap-8 max-w-6xl mx-auto">
{useCases.map((useCase, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: i * 0.15 }}
className="group relative glass-card rounded-3xl p-8 shadow-xl transition-all"
>
<div className={`inline-flex h-14 w-14 items-center justify-center rounded-2xl bg-[hsl(var(--${useCase.color}))]/10 text-[hsl(var(--${useCase.color}))] border border-[hsl(var(--${useCase.color}))]/20 mb-6`}>
{useCase.icon}
</div>
<h3 className="text-2xl font-display font-bold text-foreground mb-4">{useCase.title}</h3>
<p className="text-sm font-semibold text-muted-foreground mb-6">{useCase.problem}</p>
<div className="rounded-xl overflow-hidden border border-border/50 shadow-inner mb-6 h-[280px]">
{useCase.demoComponent}
</div>
<div className="pt-4 border-t border-border">
<p className="text-xs uppercase tracking-wider font-bold text-muted-foreground mb-2">Example:</p>
<p className="text-sm text-foreground leading-relaxed">{useCase.example}</p>
</div>
</motion.div>
))}
</div>
</div>
</section>
)
}
// ============================================
// 3. HOW IT WORKS
// ============================================
export function HowItWorks() {
const stages = [
{ icon: <Target className="h-6 w-6" />, title: 'Set URL', desc: 'Add the page you want to monitor' },
{ icon: <Zap className="h-6 w-6" />, title: 'Check regularly', desc: 'Automated checks at your chosen frequency' },
{ icon: <Filter className="h-6 w-6" />, title: 'Remove noise', desc: 'AI filters out irrelevant changes' },
{ icon: <Bell className="h-6 w-6" />, title: 'Get alerted', desc: 'Receive notifications that matter' }
]
return (
<section className="py-32 relative overflow-hidden">
<div className="mx-auto max-w-7xl px-6 relative z-10">
<div className="text-center mb-20">
<h2 className="text-4xl lg:text-5xl font-display font-bold text-foreground mb-6">How it works</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">Four simple steps to never miss an important change again.</p>
</div>
<div className="grid lg:grid-cols-4 gap-8">
{stages.map((stage, i) => (
<motion.div
key={i}
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ delay: i * 0.1 }}
className="relative flex flex-col items-center text-center group"
>
<div className="absolute -top-4 left-1/2 -translate-x-1/2 text-8xl font-display font-bold text-border/20 pointer-events-none">
{String(i + 1).padStart(2, '0')}
</div>
<div className="relative z-10 mb-6 flex h-20 w-20 items-center justify-center rounded-full border-2 border-border bg-card shadow-lg transition-all group-hover:border-[hsl(var(--primary))]">
<div className="text-[hsl(var(--primary))]">{stage.icon}</div>
</div>
<h3 className="text-lg font-bold text-foreground mb-2">{stage.title}</h3>
<p className="text-sm text-muted-foreground max-w-[200px]">{stage.desc}</p>
</motion.div>
))}
</div>
</div>
</section>
)
}
// ============================================
// 4. DIFFERENTIATORS
// ============================================
export function Differentiators() {
const features = [
{ feature: 'Noise Filtering', others: 'Basic', us: 'AI-powered + custom rules', icon: <Filter className="h-5 w-5" /> },
{ feature: 'Keyword Alerts', others: 'Limited', us: 'Regex + thresholds', icon: <Search className="h-5 w-5" /> },
{ feature: 'Integrations', others: 'Email only', us: 'Slack, Webhooks, Teams', icon: <Slack className="h-5 w-5" /> },
{ feature: 'History & Proof', others: '7-30 days', us: 'Unlimited snapshots', icon: <History className="h-5 w-5" /> },
{ feature: 'Setup Time', others: '15+ min', us: '2 minutes', icon: <Zap className="h-5 w-5" /> },
{ feature: 'Pricing', others: '$29-99/mo', us: 'Free plan + fair scaling', icon: <Shield className="h-5 w-5" /> }
]
return (
<section className="py-32 relative overflow-hidden">
<div className="mx-auto max-w-6xl px-6 relative z-10">
<div className="text-center mb-20">
<h2 className="text-4xl lg:text-5xl font-display font-bold text-foreground mb-6">
{"Why we're"} <span className="text-[hsl(var(--teal))]">different</span>
</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">{"Not all monitoring tools are created equal. Here's what sets us apart."}</p>
</div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
{features.map((item, i) => (
<motion.div
key={i}
initial={{ opacity: 0, scale: 0.95 }}
whileInView={{ opacity: 1, scale: 1 }}
viewport={{ once: true }}
transition={{ delay: i * 0.05 }}
className="glass-card rounded-2xl p-6 hover:border-[hsl(var(--teal))]/30 transition-all"
>
<div className="inline-flex h-12 w-12 items-center justify-center rounded-xl bg-[hsl(var(--teal))]/10 text-[hsl(var(--teal))] mb-4">
{item.icon}
</div>
<h3 className="text-lg font-bold text-foreground mb-4">{item.feature}</h3>
<div className="space-y-3">
<div className="flex items-start gap-2">
<span className="text-xs uppercase tracking-wider font-bold text-muted-foreground flex-shrink-0 mt-0.5">Others:</span>
<span className="text-sm text-muted-foreground">{item.others}</span>
</div>
<div className="flex items-start gap-2 p-3 rounded-lg bg-[hsl(var(--teal))]/5 border border-[hsl(var(--teal))]/20">
<Check className="h-4 w-4 text-[hsl(var(--teal))] flex-shrink-0 mt-0.5" strokeWidth={3} />
<span className="text-sm font-semibold text-foreground">{item.us}</span>
</div>
</div>
</motion.div>
))}
</div>
</div>
</section>
)
}
// ============================================
// 6. FINAL CTA
// ============================================
export function FinalCTA() {
return (
<section className="relative overflow-hidden py-32">
<div className="absolute inset-0 gradient-velvet opacity-90" />
<div className="absolute inset-0 grain-texture" />
<div className="mx-auto max-w-4xl px-6 text-center relative z-10">
<motion.div
initial={{ opacity: 0, y: 20 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
className="space-y-8"
>
<h2 className="text-5xl lg:text-6xl font-display font-bold leading-tight text-foreground">
Stop missing the changes <span className="text-[hsl(var(--primary))]">that matter.</span>
</h2>
<p className="text-xl lg:text-2xl text-muted-foreground max-w-2xl mx-auto">
Join the waitlist and be first to experience monitoring that actually works.
</p>
<div className="pt-4 max-w-lg mx-auto">
<WaitlistForm />
</div>
<div className="flex flex-wrap items-center justify-center gap-6 text-sm text-muted-foreground">
<div className="flex items-center gap-2">
<Star className="h-4 w-4 fill-current text-[hsl(var(--primary))]" />
<span>Join the waitlist for early access</span>
</div>
</div>
</motion.div>
</div>
</section>
)
}