nicholai 890bdf13e4 Feat: Add public landing page for non-authenticated users
- Create /home route with SEO metadata and JSON-LD structured data
- Add hero section with dual CTAs (sign-up and PWA install)
- Add features section showcasing dual tracking, health timeline, achievements, savings
- Add animated phone demo with rotating screens (auto-advance, pause on hover)
- Add final CTA section and footer with affiliate disclosure
- Extract usePWAInstall hook for reusable PWA install logic
- Enhance theme-context with system preference auto-detection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 19:30:46 -07:00

268 lines
10 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { Cigarette, Leaf, Heart, Trophy, DollarSign, TrendingDown, CheckCircle } from 'lucide-react';
const DEMO_SCREENS = [
{
id: 'logging',
title: 'Log Your Usage',
subtitle: 'Track daily consumption with ease',
content: (
<div className="space-y-4">
<div className="flex justify-between items-center p-3 rounded-xl bg-white/5 border border-white/10">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-red-500/20 flex items-center justify-center">
<Cigarette className="h-4 w-4 text-red-400" />
</div>
<span className="font-medium">Nicotine</span>
</div>
<div className="text-2xl font-bold">3</div>
</div>
<div className="flex justify-between items-center p-3 rounded-xl bg-white/5 border border-white/10">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-green-500/20 flex items-center justify-center">
<Leaf className="h-4 w-4 text-green-400" />
</div>
<span className="font-medium">Marijuana</span>
</div>
<div className="text-2xl font-bold">0</div>
</div>
<div className="text-center text-xs text-muted-foreground mt-4">
<TrendingDown className="h-4 w-4 inline mr-1 text-green-400" />
Down 40% from last week
</div>
</div>
),
},
{
id: 'health',
title: 'Health Recovery',
subtitle: 'Watch your body heal',
content: (
<div className="space-y-3">
<div className="space-y-1">
<div className="flex justify-between text-xs">
<span>Blood Pressure Normalizes</span>
<CheckCircle className="h-3 w-3 text-green-400" />
</div>
<div className="h-2 rounded-full bg-white/10 overflow-hidden">
<div className="h-full w-full bg-gradient-to-r from-teal-500 to-cyan-400 rounded-full" />
</div>
</div>
<div className="space-y-1">
<div className="flex justify-between text-xs">
<span>Oxygen Levels Rise</span>
<CheckCircle className="h-3 w-3 text-green-400" />
</div>
<div className="h-2 rounded-full bg-white/10 overflow-hidden">
<div className="h-full w-full bg-gradient-to-r from-teal-500 to-cyan-400 rounded-full" />
</div>
</div>
<div className="space-y-1">
<div className="flex justify-between text-xs">
<span>Circulation Improves</span>
<span className="text-yellow-400">1 week to go</span>
</div>
<div className="h-2 rounded-full bg-white/10 overflow-hidden">
<div className="h-full w-3/4 bg-gradient-to-r from-teal-500 to-cyan-400 rounded-full" />
</div>
</div>
<div className="space-y-1">
<div className="flex justify-between text-xs">
<span>Heart Attack Risk Drops</span>
<span className="text-muted-foreground">2 weeks to go</span>
</div>
<div className="h-2 rounded-full bg-white/10 overflow-hidden">
<div className="h-full w-1/2 bg-gradient-to-r from-teal-500 to-cyan-400 rounded-full" />
</div>
</div>
</div>
),
},
{
id: 'achievements',
title: 'Achievements',
subtitle: 'Celebrate every milestone',
content: (
<div className="grid grid-cols-3 gap-2">
{[
{ name: 'First Step', unlocked: true },
{ name: 'Hat Trick', unlocked: true },
{ name: 'Week Warrior', unlocked: true },
{ name: 'Fighter', unlocked: false },
{ name: 'Monthly Master', unlocked: false },
{ name: 'Goal Crusher', unlocked: false },
].map((badge) => (
<div
key={badge.name}
className={`aspect-square rounded-xl flex flex-col items-center justify-center p-2 text-center ${
badge.unlocked
? 'bg-gradient-to-br from-yellow-500/30 to-amber-600/20 border border-yellow-500/50'
: 'bg-white/5 border border-white/10 opacity-50'
}`}
>
<Trophy
className={`h-5 w-5 mb-1 ${badge.unlocked ? 'text-yellow-400' : 'text-muted-foreground'}`}
/>
<span className="text-[10px] leading-tight">{badge.name}</span>
</div>
))}
</div>
),
},
{
id: 'savings',
title: 'Money Saved',
subtitle: 'Track your financial wins',
content: (
<div className="text-center space-y-4">
<div className="w-16 h-16 rounded-2xl bg-emerald-500/20 flex items-center justify-center mx-auto">
<DollarSign className="h-8 w-8 text-emerald-400" />
</div>
<div>
<div className="text-4xl font-black text-emerald-400">$127.50</div>
<div className="text-sm text-muted-foreground">saved this month</div>
</div>
<div className="grid grid-cols-2 gap-2 text-xs">
<div className="p-2 rounded-lg bg-white/5 border border-white/10">
<div className="font-bold">$4.25</div>
<div className="text-muted-foreground">per day</div>
</div>
<div className="p-2 rounded-lg bg-white/5 border border-white/10">
<div className="font-bold">$1,530</div>
<div className="text-muted-foreground">per year</div>
</div>
</div>
</div>
),
},
];
export function DemoSection() {
const [activeScreen, setActiveScreen] = useState(0);
const [isPaused, setIsPaused] = useState(false);
useEffect(() => {
if (isPaused) return;
const interval = setInterval(() => {
setActiveScreen((prev) => (prev + 1) % DEMO_SCREENS.length);
}, 4000);
return () => clearInterval(interval);
}, [isPaused]);
return (
<section
id="demo"
aria-labelledby="demo-heading"
className="py-20 px-4 relative overflow-hidden"
>
{/* Background accents */}
<div className="absolute top-1/2 left-0 w-96 h-96 bg-primary/10 rounded-full blur-[120px] -translate-y-1/2 pointer-events-none" />
<div className="absolute top-1/2 right-0 w-96 h-96 bg-purple-500/10 rounded-full blur-[120px] -translate-y-1/2 pointer-events-none" />
<div className="container mx-auto max-w-6xl relative z-10">
{/* Section Header */}
<div className="text-center mb-12">
<h2
id="demo-heading"
className="text-3xl sm:text-4xl font-bold mb-4"
>
See It In{' '}
<span className="bg-gradient-to-r from-primary via-purple-500 to-pink-500 bg-clip-text text-transparent">
Action
</span>
</h2>
<p className="text-muted-foreground max-w-2xl mx-auto">
A quick look at how QuitTraq helps you track progress and stay motivated.
</p>
</div>
<div className="flex flex-col lg:flex-row items-center gap-12 lg:gap-16">
{/* Phone Mockup */}
<div
className="relative mx-auto lg:mx-0"
onMouseEnter={() => setIsPaused(true)}
onMouseLeave={() => setIsPaused(false)}
onTouchStart={() => setIsPaused(true)}
onTouchEnd={() => setIsPaused(false)}
>
{/* Phone frame glow */}
<div className="absolute inset-0 bg-gradient-to-br from-primary/30 to-purple-500/30 rounded-[3rem] blur-2xl opacity-50" />
{/* Phone frame */}
<div className="relative w-[280px] sm:w-[320px] aspect-[9/16] rounded-[2.5rem] overflow-hidden border-4 border-white/10 bg-background shadow-2xl shadow-black/30">
{/* Notch */}
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-24 h-6 bg-black rounded-b-2xl z-20" />
{/* Screen content */}
<div className="absolute inset-0 p-4 pt-10">
{/* Screen header */}
<div className="text-center mb-4">
<h3 className="text-lg font-bold">{DEMO_SCREENS[activeScreen].title}</h3>
<p className="text-xs text-muted-foreground">
{DEMO_SCREENS[activeScreen].subtitle}
</p>
</div>
{/* Screen content with transition */}
<div className="animate-fade-in" key={activeScreen}>
{DEMO_SCREENS[activeScreen].content}
</div>
</div>
{/* Bottom gradient overlay */}
<div className="absolute bottom-0 left-0 right-0 h-20 bg-gradient-to-t from-background to-transparent pointer-events-none" />
</div>
</div>
{/* Description and indicators */}
<div className="flex-1 text-center lg:text-left">
<div className="space-y-6">
{/* Screen descriptions */}
{DEMO_SCREENS.map((screen, index) => (
<button
key={screen.id}
onClick={() => setActiveScreen(index)}
className={`w-full text-left p-4 rounded-xl transition-all duration-300 ${
activeScreen === index
? 'bg-primary/10 border border-primary/30'
: 'hover:bg-white/5 border border-transparent'
}`}
>
<h4
className={`font-semibold mb-1 ${
activeScreen === index ? 'text-primary' : 'text-foreground'
}`}
>
{screen.title}
</h4>
<p className="text-sm text-muted-foreground">{screen.subtitle}</p>
</button>
))}
</div>
{/* Dot indicators (mobile) */}
<div className="flex justify-center gap-2 mt-6 lg:hidden">
{DEMO_SCREENS.map((_, index) => (
<button
key={index}
onClick={() => setActiveScreen(index)}
className={`w-2 h-2 rounded-full transition-all ${
activeScreen === index
? 'w-6 bg-primary'
: 'bg-white/20 hover:bg-white/40'
}`}
aria-label={`Go to screen ${index + 1}`}
/>
))}
</div>
</div>
</div>
</div>
</section>
);
}