feat: Introduce InstallSection component and refine existing UI for the marketing page, layout, and various components.

This commit is contained in:
2026-02-08 16:50:30 +00:00
parent 80aaf16bba
commit 4ec9355510
10 changed files with 231 additions and 56 deletions

View File

@@ -1,64 +1,130 @@
import React from 'react';
import React, { useEffect, useRef } from 'react';
import { Mail, Lock, Check } from 'lucide-react';
import { animate, stagger, random } from 'animejs';
const Hero: React.FC = () => {
const leftContentRef = useRef<HTMLDivElement>(null);
const glow1Ref = useRef<HTMLDivElement>(null);
const glow2Ref = useRef<HTMLDivElement>(null);
const cardRef = useRef<HTMLDivElement>(null);
const streakRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (leftContentRef.current) {
// Staggered entry for left content
animate(leftContentRef.current.children, {
translateY: [20, 0],
opacity: [0, 1],
delay: stagger(150, { start: 300 }),
easing: 'easeOutQuad',
duration: 800
});
}
if (cardRef.current) {
// Elastic entry for the card
animate(cardRef.current, {
translateX: [100, 0],
opacity: [0, 1],
delay: 600,
easing: 'outElastic(1, .8)'
});
}
if (streakRef.current) {
// Bouncy entry for streak badge
animate(streakRef.current, {
scale: [0, 1],
opacity: [0, 1],
delay: 1000,
easing: 'outElastic(1, .8)',
}).then(() => {
// Floating animation after entry
animate(streakRef.current!, {
translateY: [-10, 0],
loop: true,
direction: 'alternate',
easing: 'inOutSine',
duration: 2000
});
});
}
if (glow1Ref.current) {
// Ambient glow animation
animate(glow1Ref.current, {
translateX: () => random(-30, 30),
translateY: () => random(-30, 30),
scale: [1, 1.2],
duration: 4000,
easing: 'inOutQuad',
loop: true,
direction: 'alternate'
});
}
if (glow2Ref.current) {
animate(glow2Ref.current, {
translateX: () => random(-30, 30),
translateY: () => random(-30, 30),
scale: [1, 1.3],
duration: 5000,
easing: 'inOutQuad',
loop: true,
direction: 'alternate'
});
}
}, []);
return (
<header className="relative pt-32 pb-20 lg:pt-48 lg:pb-32 overflow-hidden mesh-gradient">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 relative z-10">
<div className="grid lg:grid-cols-2 gap-12 items-center">
{/* Left Content */}
<div className="space-y-8 text-center lg:text-left">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-semibold uppercase tracking-wider">
<div ref={leftContentRef} className="space-y-8 text-center lg:text-left">
<div className="opacity-0 inline-flex items-center gap-2 px-3 py-1 rounded-full bg-primary/10 border border-primary/20 text-primary text-xs font-semibold uppercase tracking-wider">
<span className="w-2 h-2 rounded-full bg-primary animate-pulse"></span>
New: AI Deck Generation
</div>
<h1 className="text-5xl lg:text-7xl font-display font-bold leading-tight tracking-tight text-white">
<h1 className="opacity-0 text-5xl lg:text-7xl font-display font-bold leading-tight tracking-tight text-white">
<span className="text-transparent bg-clip-text bg-gradient-to-r from-primary to-emerald-400">
Stop Doomscrolling
</span>
<br/>
<br />
Until You Study<br />
</h1>
<p className="text-lg text-gray-400 max-w-2xl mx-auto lg:mx-0 leading-relaxed">
<p className="opacity-0 text-lg text-gray-400 max-w-2xl mx-auto lg:mx-0 leading-relaxed">
Stop doom scrolling and start learning. Nemia blocks distracting apps until you complete your daily study goals using scientifically-backed spaced repetition.
</p>
<form
action="https://getlaunchlist.com/s/pAqdup"
method="POST"
className="flex flex-col sm:flex-row gap-3 justify-center lg:justify-start max-w-md mx-auto lg:mx-0"
>
<div className="relative flex-grow">
<Mail className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-500" size={20} />
<input
type="email"
name="email"
placeholder="Enter your email"
required
className="w-full bg-surface-dark border border-gray-700 rounded-xl py-4 pl-12 pr-4 text-white focus:outline-none focus:border-primary transition-colors"
/>
</div>
<button
type="submit"
className="bg-primary text-gray-900 px-8 py-4 rounded-xl font-bold text-lg hover:brightness-110 transition-all shadow-glow flex items-center justify-center gap-2 whitespace-nowrap"
<div className="opacity-0 flex flex-col sm:flex-row gap-3 justify-center lg:justify-start pt-4">
<a
href="#install"
className="bg-primary text-gray-900 px-8 py-4 rounded-xl font-bold text-lg hover:brightness-110 transition-all shadow-glow flex items-center justify-center gap-2"
onClick={(e) => {
(window as { umami?: { track?: (eventName: string, data?: Record<string, unknown>) => void } })
.umami?.track?.('hero_cta_clicked', { location: 'hero' });
e.preventDefault();
document.querySelector('#install')?.scrollIntoView({ behavior: 'smooth' });
}}
>
<span>Join Waitlist</span>
</button>
</form>
<span>Get it now</span>
</a>
</div>
</div>
{/* Right Visual (Mockups) */}
<div className="relative mx-auto w-full max-w-md lg:max-w-full">
{/* Background Glows */}
<div className="absolute -top-10 -right-10 w-72 h-72 bg-purple-500/20 rounded-full blur-3xl"></div>
<div className="absolute -bottom-10 -left-10 w-72 h-72 bg-primary/20 rounded-full blur-3xl"></div>
<div ref={glow1Ref} className="absolute -top-10 -right-10 w-72 h-72 bg-purple-500/20 rounded-full blur-3xl"></div>
<div ref={glow2Ref} className="absolute -bottom-10 -left-10 w-72 h-72 bg-primary/20 rounded-full blur-3xl"></div>
{/* Main Focus Mode Card */}
<div className="relative bg-surface-dark border border-gray-700 rounded-3xl p-6 shadow-2xl transform rotate-3 hover:rotate-0 transition-transform duration-500">
<div ref={cardRef} className="opacity-0 relative bg-surface-dark border border-gray-700 rounded-3xl p-6 shadow-2xl transform rotate-3 hover:rotate-0 transition-transform duration-500">
<div className="flex justify-between items-center mb-8">
<h3 className="text-xl font-bold text-white">Focus Mode</h3>
<div className="bg-red-500/10 text-red-500 px-3 py-1 rounded-full text-xs font-bold flex items-center gap-1">
@@ -97,7 +163,7 @@ const Hero: React.FC = () => {
</div>
{/* Streak Badge (Floating) */}
<div className="absolute -bottom-6 -left-6 bg-surface-accent text-white p-4 rounded-xl shadow-xl flex items-center gap-3 animate-bounce border border-gray-700 z-20">
<div ref={streakRef} className="opacity-0 absolute -bottom-6 -left-6 bg-surface-accent text-white p-4 rounded-xl shadow-xl flex items-center gap-3 border border-gray-700 z-20">
<div className="bg-green-500 rounded-full p-1">
<Check size={14} className="text-white" />
</div>