Your commit message

This commit is contained in:
2026-01-19 22:24:25 +01:00
parent 818779ab07
commit 9fa8045c26
15 changed files with 392 additions and 221 deletions

View File

@@ -34,23 +34,22 @@ export function CompetitorDemoVisual() {
{/* Price Card */}
<motion.div
className="p-4 rounded-xl border-2 bg-white relative overflow-hidden"
className="p-4 rounded-xl border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 relative overflow-hidden shadow-xl"
animate={{
borderColor: phase === 1 ? 'hsl(var(--teal))' : 'hsl(var(--border))',
borderColor: phase === 1 ? '#ef4444' : '#27272a',
boxShadow: phase === 1
? '0 0 20px hsl(var(--teal) / 0.3)'
: '0 1px 3px rgba(0,0,0,0.1)'
? '0 0 20px rgba(239, 68, 68, 0.2)'
: '0 1px 3px rgba(0,0,0,0.5)'
}}
transition={{ duration: 0.5 }}
>
{/* Shine effect on change */}
{phase === 1 && (
<motion.div
initial={{ x: '-100%' }}
initial={{ x: '-100%', skewX: -20 }}
animate={{ x: '200%' }}
transition={{ duration: 0.8, ease: 'easeInOut' }}
className="absolute inset-0 bg-gradient-to-r from-transparent via-white/50 to-transparent"
style={{ transform: 'skewX(-20deg)' }}
className="absolute inset-0 bg-gradient-to-r from-transparent via-red-500/10 to-transparent"
/>
)}
@@ -58,7 +57,7 @@ export function CompetitorDemoVisual() {
{/* Old Price */}
<motion.div
animate={{
opacity: phase === 1 ? 0.4 : 1,
opacity: phase === 1 ? 0.3 : 1,
scale: phase === 1 ? 0.95 : 1
}}
transition={{ duration: 0.3 }}
@@ -68,12 +67,12 @@ export function CompetitorDemoVisual() {
className="text-3xl font-bold"
animate={{
textDecoration: phase === 1 ? 'line-through' : 'none',
color: phase === 1 ? 'hsl(var(--muted-foreground))' : 'hsl(var(--foreground))'
color: phase === 1 ? '#ef4444' : '#f4f4f5'
}}
>
$99
</motion.span>
<span className="text-sm text-muted-foreground">/month</span>
<span className="text-sm text-zinc-500">/month</span>
</div>
</motion.div>
@@ -82,15 +81,17 @@ export function CompetitorDemoVisual() {
<motion.div
initial={{ opacity: 0, x: -10, scale: 0.9 }}
animate={{ opacity: 1, x: 0, scale: 1 }}
transition={{ delay: 0.2, type: 'spring', stiffness: 300, damping: 20 }}
className="flex items-center gap-2"
transition={{ delay: 0.1, type: 'spring', stiffness: 300, damping: 20 }}
className="flex items-center gap-3 mt-1"
>
<ArrowDown className="h-4 w-4 text-[hsl(var(--teal))]" />
<div className="flex items-center justify-center h-6 w-6 rounded-full bg-red-500/10">
<ArrowDown className="h-4 w-4 text-red-500" strokeWidth={3} />
</div>
<div className="flex items-baseline gap-2">
<span className="text-4xl font-bold text-[hsl(var(--teal))]">
<span className="text-5xl font-extrabold text-[#ff0000] tracking-tight">
$79
</span>
<span className="text-sm text-muted-foreground">/month</span>
<span className="text-sm font-medium text-red-500">/month</span>
</div>
</motion.div>
)}
@@ -98,12 +99,12 @@ export function CompetitorDemoVisual() {
{/* Savings Badge */}
{phase === 1 && (
<motion.div
initial={{ opacity: 0, scale: 0.8, rotate: -5 }}
initial={{ opacity: 0, scale: 0.8, rotate: -3 }}
animate={{ opacity: 1, scale: 1, rotate: 0 }}
transition={{ delay: 0.4, type: 'spring' }}
className="inline-flex items-center gap-1 px-2 py-1 rounded-full bg-[hsl(var(--teal))]/10 border border-[hsl(var(--teal))]/30"
transition={{ delay: 0.3, type: 'spring' }}
className="mt-2 inline-flex items-center gap-1.5 px-3 py-1 rounded-full bg-red-500/10 border border-red-500/20"
>
<span className="text-[9px] font-bold text-[hsl(var(--teal))] uppercase tracking-wider">
<span className="text-[10px] font-extrabold text-red-500 uppercase tracking-wider">
Save $240/year
</span>
</motion.div>
@@ -112,26 +113,28 @@ export function CompetitorDemoVisual() {
</motion.div>
{/* Alert Notification */}
{phase === 1 && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ delay: 0.6 }}
className="flex items-center gap-2 p-2 rounded-lg bg-[hsl(var(--burgundy))]/10 border border-[hsl(var(--burgundy))]/30"
>
<div className="relative flex-shrink-0">
<Bell className="h-3 w-3 text-[hsl(var(--burgundy))]" />
<motion.span
animate={{ scale: [1, 1.3, 1] }}
transition={{ duration: 1, repeat: Infinity }}
className="absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full bg-[hsl(var(--burgundy))]"
/>
</div>
<span className="text-[9px] font-semibold text-[hsl(var(--burgundy))]">
Alert sent to your team
</span>
</motion.div>
)}
{
phase === 1 && (
<motion.div
initial={{ opacity: 0, y: 10, scale: 0.95 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ delay: 0.6 }}
className="flex items-center gap-2 p-2 rounded-lg bg-red-500/10 border border-red-500/30"
>
<div className="relative flex-shrink-0">
<Bell className="h-3 w-3 text-red-500" />
<motion.span
animate={{ scale: [1, 1.3, 1] }}
transition={{ duration: 1, repeat: Infinity }}
className="absolute -top-0.5 -right-0.5 w-1.5 h-1.5 rounded-full bg-red-500"
/>
</div>
<span className="text-[9px] font-semibold text-red-500">
Alert sent to your team
</span>
</motion.div>
)
}
</div>
</div>
)

View File

@@ -42,9 +42,9 @@ const scaleIn: Variants = {
// ============================================
// 1. HERO SECTION - "Track competitor changes without the noise"
// ============================================
export function HeroSection({ isAuthenticated }: { isAuthenticated: boolean }) {
export function HeroSection() {
return (
<section className="relative overflow-hidden pt-32 pb-24 lg:pt-40 lg:pb-32 bg-[hsl(var(--section-bg-1))]">
<section id="hero" className="relative overflow-hidden pt-32 pb-24 lg:pt-40 lg:pb-32 bg-[hsl(var(--section-bg-1))]">
{/* 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]" />
@@ -109,23 +109,13 @@ export function HeroSection({ isAuthenticated }: { isAuthenticated: boolean }) {
))}
</motion.div>
{/* CTAs */}
{/* Waitlist Form */}
<motion.div
variants={fadeInUp}
custom={4}
className="flex flex-wrap gap-4"
className="w-full max-w-lg"
>
<MagneticButton strength={0.2}>
<Link href={isAuthenticated ? "/dashboard" : "/register"}>
<Button
size="lg"
className="h-14 rounded-full bg-[hsl(var(--primary))] px-8 text-white hover:bg-[hsl(var(--primary))]/90 shadow-2xl shadow-[hsl(var(--primary))]/25 transition-all hover:scale-105 hover:-translate-y-0.5 font-semibold text-base group"
>
{isAuthenticated ? 'Go to Dashboard' : 'Get Started Free'}
<ArrowRight className="ml-2 h-4 w-4 group-hover:translate-x-1 transition-transform" />
</Button>
</Link>
</MagneticButton>
<WaitlistForm />
</motion.div>
{/* Trust Signals */}
@@ -352,19 +342,19 @@ function NoiseToSignalVisual() {
className="absolute inset-0 flex items-center justify-center p-8"
>
<motion.div
className="w-full p-6 rounded-2xl bg-white border-2 border-[hsl(var(--teal))] shadow-2xl relative overflow-hidden"
className="w-full p-6 rounded-2xl bg-white dark:bg-zinc-950 border-2 border-[hsl(var(--teal))] dark:border-zinc-800 shadow-2xl relative overflow-hidden"
animate={{
boxShadow: [
'0 20px 60px hsl(var(--teal) / 0.2)',
'0 20px 80px hsl(var(--teal) / 0.3)',
'0 20px 60px hsl(var(--teal) / 0.2)'
'0 20px 60px rgba(20, 184, 166, 0.1)',
'0 20px 80px rgba(20, 184, 166, 0.2)',
'0 20px 60px rgba(20, 184, 166, 0.1)'
]
}}
transition={{ duration: 2, repeat: Infinity }}
>
{/* Animated corner accent */}
<motion.div
className="absolute top-0 right-0 w-20 h-20 bg-[hsl(var(--teal))]/10 rounded-bl-full"
className="absolute top-0 right-0 w-20 h-20 bg-[hsl(var(--teal))]/5 rounded-bl-full"
animate={{ scale: [1, 1.1, 1] }}
transition={{ duration: 2, repeat: Infinity }}
/>
@@ -372,20 +362,20 @@ function NoiseToSignalVisual() {
<div className="relative z-10">
<div className="flex items-center justify-between mb-2">
<motion.span
className="text-xs font-bold uppercase tracking-wider text-[hsl(var(--teal))]"
className="text-xs font-bold uppercase tracking-wider text-[hsl(var(--teal))] dark:text-[hsl(var(--teal))]"
animate={{ opacity: [1, 0.7, 1] }}
transition={{ duration: 1.5, repeat: Infinity }}
>
SIGNAL DETECTED
</motion.span>
<div className="flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--teal))]">
<div className="flex items-center gap-1.5 text-xs font-medium text-[hsl(var(--teal))] dark: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>
<p className="text-sm font-semibold text-muted-foreground dark:text-zinc-400 mb-3">Enterprise Plan</p>
<div className="flex items-baseline gap-3">
<p className="text-3xl font-bold text-foreground">$99/mo</p>
<p className="text-3xl font-bold text-foreground dark:text-zinc-600/50">$99/mo</p>
<motion.p
initial={{ opacity: 0, x: -10, scale: 0.9 }}
animate={{
@@ -394,12 +384,13 @@ function NoiseToSignalVisual() {
scale: phase >= 2 ? 1 : 0.9
}}
transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
className="text-lg text-[hsl(var(--burgundy))] font-bold flex items-center gap-1"
className="text-lg text-[hsl(var(--burgundy))] dark:text-red-500 font-bold flex items-center gap-1"
>
<span></span>
<motion.span
animate={{ scale: phase === 2 ? [1, 1.1, 1] : 1 }}
transition={{ duration: 0.5 }}
className="text-3xl"
>
$79/mo
</motion.span>
@@ -411,10 +402,10 @@ function NoiseToSignalVisual() {
<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"
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 dark:bg-red-500/10 dark:border-red-500/20"
>
<Bell className="h-3 w-3 text-[hsl(var(--burgundy))]" />
<span className="text-[10px] font-bold text-[hsl(var(--burgundy))] uppercase tracking-wider">
<Bell className="h-3 w-3 text-[hsl(var(--burgundy))] dark:text-red-500" />
<span className="text-[10px] font-bold text-[hsl(var(--burgundy))] dark:text-red-500 uppercase tracking-wider">
Alert Sent
</span>
</motion.div>
@@ -424,6 +415,7 @@ function NoiseToSignalVisual() {
</motion.div>
)}
{/* Phase Indicator */}
<div className="absolute bottom-4 right-4 flex gap-1.5">
{[0, 1, 2, 3].map(i => (
@@ -438,8 +430,8 @@ function NoiseToSignalVisual() {
/>
))}
</div>
</div>
</motion.div>
</div >
</motion.div >
)
}
@@ -742,14 +734,12 @@ export function SocialProof() {
]
return (
<section className="py-32 bg-gradient-to-b from-foreground to-[hsl(var(--foreground))]/95 relative overflow-hidden text-white">
{/* Background Pattern */}
<div className="absolute inset-0 opacity-5">
<div className="absolute inset-0" style={{
backgroundImage: `url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='1'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E")`,
backgroundSize: '60px 60px'
}} />
</div>
<section className="py-32 bg-[hsl(var(--section-bg-2))] relative overflow-hidden">
{/* Background Pattern - Subtle dots for light theme */}
<div className="absolute inset-0 opacity-[0.03]" style={{
backgroundImage: `radial-gradient(hsl(var(--foreground)) 1px, transparent 1px)`,
backgroundSize: '24px 24px'
}} />
<div className="mx-auto max-w-7xl px-6 relative z-10">
{/* Section Header */}
@@ -759,13 +749,13 @@ export function SocialProof() {
viewport={{ once: true }}
className="text-center mb-20"
>
<motion.h2 variants={fadeInUp} className="text-4xl lg:text-5xl font-display font-bold mb-6">
<motion.h2 variants={fadeInUp} className="text-4xl lg:text-5xl font-display font-bold text-foreground mb-6">
Built for teams who need results,{' '}
<span className="text-[hsl(var(--primary))]">not demos.</span>
</motion.h2>
</motion.div>
{/* Testimonial Cards - Minimal & Uniform */}
{/* Testimonial Cards - Light Theme */}
<div className="grid md:grid-cols-3 gap-8">
{testimonials.map((testimonial, i) => (
<motion.div
@@ -775,30 +765,28 @@ export function SocialProof() {
whileHover={{ y: -4 }}
viewport={{ once: true }}
transition={{ delay: i * 0.1, duration: 0.5 }}
className="relative group"
className="relative group h-full"
>
{/* Subtle gradient border glow */}
<div className="absolute -inset-0.5 bg-gradient-to-br from-[hsl(var(--primary))] to-[hsl(var(--teal))] rounded-3xl blur opacity-15 group-hover:opacity-25 transition-opacity duration-300" />
{/* Card Container */}
<div className="h-full flex flex-col rounded-3xl bg-white border border-zinc-200 shadow-sm p-8 hover:shadow-xl transition-all duration-300">
{/* Main Card - fixed height for uniformity */}
<div className="relative h-full flex flex-col rounded-3xl bg-white/10 backdrop-blur-sm border border-white/20 p-8 group-hover:bg-white/12 transition-colors duration-300">
{/* Large Quote Mark */}
<div className="text-5xl font-display text-[hsl(var(--primary))]/30 leading-none mb-3">
{/* Quote Mark */}
<div className="text-5xl font-display text-zinc-300 leading-none mb-4">
"
</div>
{/* Quote - flex-grow ensures cards align */}
<p className="font-body text-base leading-relaxed mb-6 text-white/90 font-medium italic flex-grow">
{/* Quote */}
<p className="font-body text-base leading-relaxed mb-8 text-zinc-900 font-medium italic flex-grow">
{testimonial.quote}
</p>
{/* Attribution - always at bottom */}
<div className="flex items-start justify-between mt-auto">
{/* Attribution */}
<div className="flex items-start justify-between mt-auto pt-6 border-t border-zinc-100">
<div>
<p className="font-bold text-white text-sm">{testimonial.author}</p>
<p className="text-xs text-white/70">{testimonial.role} at {testimonial.company}</p>
<p className="font-bold text-zinc-900 text-sm">{testimonial.author}</p>
<p className="text-xs text-zinc-500">{testimonial.role} at {testimonial.company}</p>
</div>
<div className="px-3 py-1 rounded-full bg-[hsl(var(--teal))]/20 border border-[hsl(var(--teal))]/30 text-[10px] font-bold uppercase tracking-wider text-[hsl(var(--teal))]">
<div className="px-3 py-1 rounded-full bg-zinc-100 border border-zinc-200 text-[10px] font-bold uppercase tracking-wider text-zinc-600">
{testimonial.useCase}
</div>
</div>
@@ -824,7 +812,7 @@ export function SocialProof() {
// ============================================
// 6. FINAL CTA - Get Started
// ============================================
export function FinalCTA({ isAuthenticated }: { isAuthenticated: boolean }) {
export function FinalCTA() {
return (
<section className="relative overflow-hidden py-32">
{/* Animated Gradient Mesh Background - More dramatic */}
@@ -869,23 +857,9 @@ export function FinalCTA({ isAuthenticated }: { isAuthenticated: boolean }) {
Join the waitlist and be first to experience monitoring that actually works.
</motion.p>
{/* Waitlist Form - replaces button */}
<motion.div variants={fadeInUp} custom={2} className="pt-4">
{isAuthenticated ? (
<MagneticButton strength={0.15}>
<Link href="/dashboard">
<Button
size="lg"
className="h-16 rounded-full bg-[hsl(var(--burgundy))] px-12 text-white hover:bg-[hsl(var(--burgundy))]/90 shadow-2xl shadow-[hsl(var(--burgundy))]/30 transition-all hover:scale-105 font-bold text-lg group"
>
Go to Dashboard
<ArrowRight className="ml-2 h-5 w-5 group-hover:translate-x-1 transition-transform" />
</Button>
</Link>
</MagneticButton>
) : (
<WaitlistForm />
)}
{/* Waitlist Form */}
<motion.div variants={fadeInUp} custom={2} className="pt-4 max-w-lg mx-auto">
<WaitlistForm />
</motion.div>
{/* Social Proof Indicator */}

View File

@@ -84,7 +84,7 @@ export function LiveStatsBar() {
]
return (
<section className="border-y border-border bg-gradient-to-r from-foreground/95 via-foreground to-foreground/95 py-8 overflow-hidden">
<section className="border-y border-border bg-gradient-to-r from-foreground/95 via-foreground to-foreground/95 dark:from-secondary dark:via-secondary dark:to-secondary py-8 overflow-hidden">
<div className="mx-auto max-w-7xl px-6">
{/* Desktop: Grid */}
<div className="hidden lg:grid lg:grid-cols-4 gap-8">

View File

@@ -37,23 +37,23 @@ export function PolicyDemoVisual() {
{/* Document Content */}
<motion.div
className="space-y-2 p-3 rounded-lg border-2 bg-white overflow-hidden"
className="space-y-2 p-3 rounded-lg border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950 overflow-hidden"
animate={{
borderColor: phase === 1 ? 'hsl(var(--teal))' : 'hsl(var(--border))',
borderColor: phase === 1 ? '#ef4444' : '#27272a',
boxShadow: phase === 1
? '0 0 20px hsl(var(--teal) / 0.3)'
: '0 1px 3px rgba(0,0,0,0.1)'
? '0 0 20px rgba(239, 68, 68, 0.2)'
: '0 1px 3px rgba(0,0,0,0.2)'
}}
transition={{ duration: 0.5 }}
>
{/* Section 4.2 */}
<div className="space-y-1.5">
<div className="text-[10px] font-bold text-[hsl(var(--primary))]">
<div className="text-[10px] font-bold text-zinc-300">
Section 4.2 - Data Retention
</div>
{/* Text Lines */}
<div className="space-y-1 text-[9px] text-muted-foreground leading-relaxed">
<div className="space-y-1 text-[9px] text-zinc-500 leading-relaxed">
<p>We will retain your personal data for</p>
{/* Changing text */}
@@ -63,10 +63,10 @@ export function PolicyDemoVisual() {
>
<motion.p
animate={{
backgroundColor: phase === 1 ? 'hsl(var(--burgundy) / 0.15)' : 'transparent',
backgroundColor: phase === 1 ? 'rgba(239, 68, 68, 0.1)' : 'transparent',
paddingLeft: phase === 1 ? '4px' : '0px',
paddingRight: phase === 1 ? '4px' : '0px',
color: phase === 1 ? 'hsl(var(--burgundy))' : 'hsl(var(--muted-foreground))',
color: phase === 1 ? '#ef4444' : 'inherit',
fontWeight: phase === 1 ? 600 : 400
}}
transition={{ duration: 0.4 }}
@@ -91,7 +91,7 @@ export function PolicyDemoVisual() {
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
transition={{ duration: 0.4 }}
className="absolute -left-1 top-0 bottom-0 w-0.5 bg-[hsl(var(--burgundy))] rounded-full origin-left"
className="absolute -left-1 top-0 bottom-0 w-0.5 bg-red-500 rounded-full origin-left"
/>
)}
</motion.div>
@@ -106,9 +106,9 @@ export function PolicyDemoVisual() {
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
transition={{ delay: 0.3 }}
className="pt-2 border-t border-border flex items-center justify-between"
className="pt-2 border-t border-zinc-800 flex items-center justify-between"
>
<div className="flex items-center gap-3 text-[8px] text-muted-foreground">
<div className="flex items-center gap-3 text-[8px] text-zinc-500">
<span className="flex items-center gap-1">
<span className="w-2 h-2 rounded bg-green-500/20 border border-green-500" />
+18 words
@@ -128,16 +128,16 @@ export function PolicyDemoVisual() {
initial={{ opacity: 0, y: 5, scale: 0.9 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
transition={{ delay: 0.5 }}
className="mt-3 flex items-center gap-2 p-2 rounded-lg bg-[hsl(var(--teal))]/10 border border-[hsl(var(--teal))]/30"
className="mt-3 flex items-center gap-2 p-2 rounded-lg bg-red-500/10 border border-red-500/30"
>
<div className="flex-shrink-0 flex items-center justify-center w-5 h-5 rounded-full bg-[hsl(var(--teal))] text-white">
<div className="flex-shrink-0 flex items-center justify-center w-5 h-5 rounded-full bg-red-500 text-white">
<Check className="h-3 w-3" strokeWidth={3} />
</div>
<div className="flex-1">
<div className="text-[9px] font-bold text-[hsl(var(--teal))]">
<div className="text-[9px] font-bold text-red-500">
Audit trail saved
</div>
<div className="text-[8px] text-muted-foreground">
<div className="text-[8px] text-red-500/80">
Snapshot archived for compliance
</div>
</div>

View File

@@ -57,36 +57,37 @@ export function SEODemoVisual() {
{/* SERP Snippet */}
<motion.div
className="space-y-2 p-3 rounded-lg bg-white border-2"
className="space-y-2 p-3 rounded-lg border border-zinc-200 dark:border-zinc-800 bg-white dark:bg-zinc-950"
animate={{
borderColor: phase === 0 ? 'hsl(var(--border))' : 'hsl(var(--teal))',
borderColor: phase === 0 ? '#27272a' : '#ef4444',
boxShadow: phase === 0
? '0 1px 3px rgba(0,0,0,0.1)'
: '0 0 20px hsl(var(--teal) / 0.3)'
? '0 1px 3px rgba(0,0,0,0.2)'
: '0 0 20px rgba(239, 68, 68, 0.2)'
}}
transition={{ duration: 0.5 }}
>
{/* URL */}
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded-full bg-primary" />
<span className="text-[10px] text-muted-foreground font-mono">
<div className="w-4 h-4 rounded-full bg-zinc-800" />
<span className="text-[10px] text-zinc-500 font-mono">
competitor.com/product
</span>
</div>
{/* Title */}
<h4 className="text-sm font-bold text-[hsl(var(--primary))] line-clamp-1">
<h4 className="text-sm font-bold text-zinc-300 line-clamp-1">
Best Enterprise Software Solution 2026
</h4>
{/* Meta Description with change highlighting */}
<motion.p
className="text-[11px] text-muted-foreground leading-relaxed relative"
className="text-[11px] text-zinc-500 leading-relaxed relative"
layout
>
<motion.span
animate={{
backgroundColor: phase === 1 ? 'hsl(var(--teal) / 0.2)' : 'transparent'
backgroundColor: phase === 1 ? 'rgba(239, 68, 68, 0.1)' : 'transparent',
color: phase === 1 ? '#ef4444' : 'inherit'
}}
transition={{ duration: 0.5 }}
className="inline-block rounded px-0.5"
@@ -99,9 +100,9 @@ export function SEODemoVisual() {
<motion.span
initial={{ opacity: 0, x: -5 }}
animate={{ opacity: 1, x: 0 }}
className="absolute -right-2 top-0 px-1.5 py-0.5 rounded bg-[hsl(var(--burgundy))] text-[8px] font-bold text-white"
className="absolute -right-2 top-0 px-1.5 py-0.5 rounded bg-red-500 text-[8px] font-bold text-white"
>
NEW
Changed
</motion.span>
)}
</motion.p>

View File

@@ -47,16 +47,34 @@ export function WaitlistForm() {
setIsSubmitting(true)
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1500))
try {
const apiUrl = process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001'
const response = await fetch(`${apiUrl}/api/waitlist`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email,
source: 'landing_page',
referrer: typeof window !== 'undefined' ? document.referrer : undefined,
}),
})
// Generate a random queue position
const position = Math.floor(Math.random() * 500) + 400
const data = await response.json()
setQueuePosition(position)
setIsSubmitting(false)
setIsSuccess(true)
triggerConfetti()
if (data.success) {
setQueuePosition(data.position || Math.floor(Math.random() * 500) + 430)
setIsSubmitting(false)
setIsSuccess(true)
triggerConfetti()
} else {
setIsSubmitting(false)
setError(data.message || 'Something went wrong. Please try again.')
}
} catch (err) {
console.error('Waitlist signup error:', err)
setIsSubmitting(false)
setError('Connection error. Please try again.')
}
}
if (isSuccess) {
@@ -193,11 +211,10 @@ export function WaitlistForm() {
}}
placeholder="Enter your email"
disabled={isSubmitting}
className={`w-full h-14 rounded-full px-6 text-base border-2 transition-all outline-none ${
error
className={`w-full h-14 rounded-full px-6 text-base border-2 transition-all outline-none ${error
? 'border-red-500 bg-red-50 focus:border-red-500 focus:ring-4 focus:ring-red-500/20'
: 'border-border bg-background focus:border-[hsl(var(--primary))] focus:ring-4 focus:ring-[hsl(var(--primary))]/20'
} disabled:opacity-50 disabled:cursor-not-allowed`}
} disabled:opacity-50 disabled:cursor-not-allowed`}
/>
<AnimatePresence>
{error && (