208 lines
12 KiB
TypeScript
208 lines
12 KiB
TypeScript
import React, { useRef } from 'react';
|
|
import { motion, useScroll, useTransform } from 'framer-motion';
|
|
import { ChevronRight, Zap, Activity, User } from 'lucide-react';
|
|
import { PhoneFrame } from './PhoneFrame';
|
|
|
|
export const Hero: React.FC = () => {
|
|
const targetRef = useRef(null);
|
|
const { scrollYProgress } = useScroll({
|
|
target: targetRef,
|
|
offset: ["start start", "end start"]
|
|
});
|
|
|
|
const y = useTransform(scrollYProgress, [0, 1], [0, 150]);
|
|
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0]);
|
|
|
|
return (
|
|
<section ref={targetRef} className="relative min-h-screen pt-32 pb-20 lg:pt-40 overflow-hidden flex flex-col justify-center items-center">
|
|
|
|
{/* Ambient Background */}
|
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-full h-[1000px] bg-gradient-radial from-primary-500/10 via-transparent to-transparent opacity-50 pointer-events-none" />
|
|
|
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10 w-full">
|
|
<div className="flex flex-col items-center text-center">
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.6, ease: "easeOut" }}
|
|
className="mb-8"
|
|
>
|
|
<div className="inline-flex items-center gap-2 px-4 py-1.5 rounded-full bg-white/5 border border-white/10 backdrop-blur-md hover:bg-white/10 transition-colors cursor-default">
|
|
<span className="flex h-2 w-2 rounded-full bg-primary-400 shadow-[0_0_10px_#22d3ee]"></span>
|
|
<span className="text-sm font-medium text-gray-300 tracking-wide">
|
|
Now Available on iOS & Android
|
|
</span>
|
|
<ChevronRight className="w-3 h-3 text-gray-500" />
|
|
</div>
|
|
</motion.div>
|
|
|
|
<h1 className="text-6xl sm:text-7xl lg:text-8xl font-extrabold tracking-tighter text-white mb-8 leading-[1] max-w-5xl">
|
|
<motion.span
|
|
initial={{ opacity: 0, y: 40 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.1 }}
|
|
className="block"
|
|
>
|
|
Make Every
|
|
</motion.span>
|
|
<motion.span
|
|
initial={{ opacity: 0, y: 40 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.2 }}
|
|
className="block text-transparent bg-clip-text bg-gradient-to-r from-white via-gray-200 to-gray-400"
|
|
>
|
|
Workout Count.
|
|
</motion.span>
|
|
</h1>
|
|
|
|
<motion.p
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.4 }}
|
|
className="text-xl md:text-2xl text-gray-400 mb-12 leading-relaxed max-w-2xl"
|
|
>
|
|
Stop using rearview mirrors. FitMate is your <span className="text-primary-400">GPS</span>.
|
|
We turn training data into a shame-free game plan for your <em>next</em> meal.
|
|
</motion.p>
|
|
|
|
<motion.div
|
|
initial={{ opacity: 0, y: 20 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
transition={{ duration: 0.8, delay: 0.5 }}
|
|
className="flex flex-col sm:flex-row items-center gap-4 mb-16"
|
|
>
|
|
{/* App Store Button */}
|
|
<button
|
|
onClick={() => alert('Redirecting to App Store...')}
|
|
className="group flex items-center gap-3 bg-white text-black px-6 py-3 rounded-xl hover:scale-105 transition-all duration-300 shadow-[0_0_40px_rgba(255,255,255,0.2)] cursor-pointer"
|
|
>
|
|
<svg className="w-6 h-6" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M18.71 19.5c-.83 1.24-1.71 2.45-3.05 2.47-1.34.03-1.77-.79-3.29-.79-1.53 0-2 .77-3.27.82-1.31.05-2.3-1.3-3.14-2.53-2.14-3.08-2.67-7.36-1.97-10.32 1-4.24 3.7-6.76 6.7-1.48.68-1.26.68-1.44.68-1.44.68.85 1.51.85 3.5.7 4.98.82 2.38-.03 3.22-1.33 3.22-1.33.94 2.66 4.41 2.66 4.41s-1.71 3.73-2.62 5.09zM12 5.31c-.77 1.35-2.76 1.78-4.09 1.6-.57-2.02.6-4.24 2.38-5.11 1.78-.87 3.77-.9 4.07 1.61.03.65.03.65-2.36 1.9z"/>
|
|
</svg>
|
|
<div className="text-left">
|
|
<div className="text-[10px] font-medium uppercase tracking-wide opacity-80">Download on the</div>
|
|
<div className="text-sm font-bold leading-none">App Store</div>
|
|
</div>
|
|
</button>
|
|
|
|
{/* Google Play Button */}
|
|
<button
|
|
onClick={() => alert('Redirecting to Play Store...')}
|
|
className="group flex items-center gap-3 bg-white/5 border border-white/10 text-white px-6 py-3 rounded-xl hover:bg-white/10 hover:scale-105 transition-all duration-300 backdrop-blur-sm cursor-pointer"
|
|
>
|
|
<svg className="w-6 h-6" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M3,20.5V3.5C3,2.91,3.34,2.39,3.84,2.15L13.69,12L3.84,21.85C3.34,21.6,3,21.09,3,20.5M16.81,15.12L6.05,21.34L14.54,12.85L16.81,15.12M20.16,10.81C20.5,11.08,20.75,11.5,20.75,12C20.75,12.5,20.53,12.92,20.16,13.19L17.89,14.5L15.39,12L17.89,9.5L20.16,10.81M6.05,2.66L16.81,8.88L14.54,11.15L6.05,2.66Z" />
|
|
</svg>
|
|
<div className="text-left">
|
|
<div className="text-[10px] font-medium uppercase tracking-wide opacity-60">Get it on</div>
|
|
<div className="text-sm font-bold leading-none">Google Play</div>
|
|
</div>
|
|
</button>
|
|
</motion.div>
|
|
</div>
|
|
|
|
{/* Parallax Phone Mockup */}
|
|
<motion.div
|
|
style={{ y, opacity }}
|
|
className="mt-4 relative w-full max-w-[340px] mx-auto perspective-1000"
|
|
>
|
|
{/* Glow behind phone */}
|
|
<div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-[120%] h-[80%] bg-primary-500/30 blur-[120px] rounded-full" />
|
|
|
|
<PhoneFrame className="h-[700px]">
|
|
<div className="h-full w-full pt-14 pb-8 px-6 flex flex-col relative z-10 bg-black">
|
|
|
|
{/* Header */}
|
|
<div className="flex justify-between items-end mb-6">
|
|
<div>
|
|
<div className="text-gray-400 text-xs font-semibold uppercase tracking-wide">Wednesday</div>
|
|
<h1 className="text-3xl font-bold text-white tracking-tight">Leg Day <span className="text-primary-500">.</span></h1>
|
|
</div>
|
|
<div className="w-9 h-9 rounded-full bg-[#2C2C2E] flex items-center justify-center border border-white/10">
|
|
<User size={16} className="text-gray-400" />
|
|
</div>
|
|
</div>
|
|
|
|
{/* Segmented Control Lookalike */}
|
|
<div className="bg-[#1C1C1E] p-1 rounded-lg mb-8 flex relative">
|
|
<div className="absolute top-1 bottom-1 left-1 w-[calc(50%-4px)] bg-[#636366] rounded-[6px] shadow-sm z-0" />
|
|
<div className="flex-1 py-1.5 text-[13px] font-semibold rounded-md relative z-10 text-center text-white">
|
|
Training Day
|
|
</div>
|
|
<div className="flex-1 py-1.5 text-[13px] font-semibold rounded-md relative z-10 text-center text-gray-400">
|
|
Rest Day
|
|
</div>
|
|
</div>
|
|
|
|
{/* Main Ring */}
|
|
<div className="flex justify-center mb-8">
|
|
<div className="relative w-52 h-52 flex items-center justify-center">
|
|
{/* Static SVG for Hero to save perf */}
|
|
<svg className="w-full h-full transform -rotate-90 drop-shadow-2xl">
|
|
<defs>
|
|
<linearGradient id="heroGradient" x1="0%" y1="0%" x2="100%" y2="0%">
|
|
<stop offset="0%" stopColor="#06b6d4" />
|
|
<stop offset="100%" stopColor="#22d3ee" />
|
|
</linearGradient>
|
|
</defs>
|
|
<circle cx="104" cy="104" r="84" stroke="#1C1C1E" strokeWidth="18" fill="none" />
|
|
<circle
|
|
cx="104" cy="104" r="84"
|
|
stroke="url(#heroGradient)"
|
|
strokeWidth="18"
|
|
fill="none"
|
|
strokeLinecap="round"
|
|
strokeDasharray="420 527"
|
|
className="filter drop-shadow-[0_0_10px_rgba(34,211,238,0.3)]"
|
|
/>
|
|
</svg>
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
|
<div className="text-5xl font-bold text-white tracking-tighter font-sans">2,850</div>
|
|
<div className="text-primary-400 text-sm font-semibold uppercase tracking-wide mt-1">kcal Left</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Cards */}
|
|
<div className="grid grid-cols-2 gap-4 mb-4">
|
|
<div className="bg-[#1C1C1E] rounded-2xl p-4 relative overflow-hidden border border-white/5">
|
|
<div className="absolute top-0 right-0 p-2 opacity-20"><Activity /></div>
|
|
<div className="text-[13px] font-medium text-gray-400 mb-1">Carbs</div>
|
|
<div className="text-2xl font-bold text-white mb-2">320g</div>
|
|
<div className="w-full bg-gray-800 h-1.5 rounded-full overflow-hidden">
|
|
<div className="h-full bg-primary-500 w-[85%]" />
|
|
</div>
|
|
</div>
|
|
<div className="bg-[#1C1C1E] rounded-2xl p-4 relative overflow-hidden border border-white/5">
|
|
<div className="absolute top-0 right-0 p-2 opacity-20"><Zap /></div>
|
|
<div className="text-[13px] font-medium text-gray-400 mb-1">Protein</div>
|
|
<div className="text-2xl font-bold text-white mb-2">200g</div>
|
|
<div className="w-full bg-gray-800 h-1.5 rounded-full overflow-hidden">
|
|
<div className="h-full bg-purple-500 w-[65%]" />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Insight Card */}
|
|
<div className="bg-gradient-to-br from-[#1C1C1E] to-[#111] border border-white/5 rounded-2xl p-4 flex-1 min-h-0 relative overflow-hidden">
|
|
<div className="absolute top-0 left-0 w-full h-1 bg-gradient-to-r from-primary-500 to-transparent" />
|
|
<div className="flex items-center gap-2 mb-3">
|
|
<div className="p-1.5 bg-primary-500/10 rounded-lg text-primary-400">
|
|
<Zap size={14} fill="currentColor" />
|
|
</div>
|
|
<span className="text-sm font-bold text-white">Co-Pilot Insight</span>
|
|
</div>
|
|
<p className="text-[13px] text-gray-300 leading-relaxed">
|
|
Squat volume is high. I've increased pre-workout carbs by 40g. Drink 500ml water now.
|
|
</p>
|
|
</div>
|
|
|
|
</div>
|
|
</PhoneFrame>
|
|
</motion.div>
|
|
|
|
</div>
|
|
</section>
|
|
);
|
|
}; |