117 lines
4.4 KiB
TypeScript
117 lines
4.4 KiB
TypeScript
'use client';
|
|
|
|
import React, { useLayoutEffect, useEffect, useRef } from 'react';
|
|
import { gsap } from 'gsap';
|
|
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
|
|
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
|
|
|
const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect;
|
|
|
|
const words = [
|
|
{ text: 'Effortless.', size: 'clamp(58px, 9vw, 134px)', color: '#ffffff' },
|
|
{ text: 'Invisible.', size: 'clamp(50px, 7.5vw, 112px)', color: 'rgba(255,255,255,0.35)' },
|
|
{ text: 'Yours.', size: 'clamp(58px, 9vw, 134px)', color: '#f4be28' },
|
|
];
|
|
|
|
const steps = [
|
|
{ n: '01', label: 'Walk into any partner store' },
|
|
{ n: '02', label: 'Pay the way you always do' },
|
|
];
|
|
|
|
export default function ExperienceSection() {
|
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
const cardRef = useRef<HTMLDivElement>(null);
|
|
|
|
useIsomorphicLayoutEffect(() => {
|
|
if (typeof window === 'undefined') return;
|
|
const section = panelRef.current;
|
|
const card = cardRef.current;
|
|
if (!section || !card) return;
|
|
|
|
const ctx = gsap.context(() => {
|
|
gsap.fromTo(card,
|
|
{ x: 200, opacity: 0 },
|
|
{
|
|
x: 0,
|
|
opacity: 1,
|
|
ease: 'power2.out',
|
|
scrollTrigger: {
|
|
trigger: section,
|
|
start: 'top 92%',
|
|
end: 'top 25%',
|
|
scrub: 1.2,
|
|
}
|
|
}
|
|
);
|
|
}, section);
|
|
|
|
return () => ctx.revert();
|
|
}, []);
|
|
|
|
return (
|
|
<section ref={panelRef} className="fp-panel" style={{ background: '#07070d' }}>
|
|
<div className="fp-shell">
|
|
|
|
<div style={{ marginBottom: 'clamp(36px, 5vh, 60px)' }}>
|
|
<span className="fp-kicker fp-rise">The Experience<span className="fp-kicker-num">07</span></span>
|
|
</div>
|
|
|
|
<div className="fp-split" style={{ gridTemplateColumns: '1.1fr 0.9fr', alignItems: 'center' }}>
|
|
|
|
{/* Giant words */}
|
|
<div>
|
|
{words.map((w, i) => (
|
|
<span key={i} className="fp-mask" style={{ display: 'block' }}>
|
|
<span style={{
|
|
display: 'block', fontSize: w.size, fontWeight: 900, fontFamily: 'Sora, sans-serif',
|
|
color: w.color, letterSpacing: '-0.05em', lineHeight: 0.96,
|
|
}}>{w.text}</span>
|
|
</span>
|
|
))}
|
|
</div>
|
|
|
|
<div ref={cardRef} style={{
|
|
background: '#f4be28',
|
|
padding: 'clamp(28px, 4.5vw, 44px)',
|
|
borderRadius: '28px',
|
|
boxShadow: '0 24px 48px rgba(244, 190, 40, 0.12)',
|
|
width: '100%',
|
|
opacity: 0,
|
|
}}>
|
|
<p style={{
|
|
fontSize: 16, lineHeight: 1.85, color: 'rgba(7, 7, 13, 0.75)', fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 360,
|
|
fontWeight: 500,
|
|
}}>
|
|
No plastic cards. No coupon hunting. No app open required at checkout. Loyaly works quietly in the background while you shop the way you always have.
|
|
</p>
|
|
|
|
<div style={{ display: 'flex', flexDirection: 'column' }}>
|
|
{steps.map((s, i) => (
|
|
<div key={i} style={{
|
|
display: 'flex', gap: 20, alignItems: 'center', padding: '20px 0',
|
|
borderBottom: i < steps.length - 1 ? '1px solid rgba(7, 7, 13, 0.1)' : 'none',
|
|
}}>
|
|
<span style={{ fontSize: 13, fontWeight: 800, color: '#07070d', fontFamily: 'Sora, sans-serif', letterSpacing: '0.06em', flexShrink: 0, width: 24 }}>{s.n}</span>
|
|
<span style={{ fontSize: 16, fontWeight: 700, color: '#07070d', fontFamily: 'Sora, sans-serif', lineHeight: 1.4 }}>{s.label}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
|
|
<div style={{ marginTop: 36, display: 'flex', alignItems: 'center', gap: 12 }}>
|
|
<div style={{ display: 'flex' }}>
|
|
{['#ff7b39', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => (
|
|
<div key={i} style={{ width: 30, height: 30, borderRadius: '50%', background: c, border: '2px solid #f4be28', marginLeft: i > 0 ? -9 : 0 }} />
|
|
))}
|
|
</div>
|
|
<span style={{ fontSize: 13, color: 'rgba(7, 7, 13, 0.65)', fontFamily: 'Sora, sans-serif', fontWeight: 500 }}>
|
|
Joined by <span style={{ color: '#07070d', fontWeight: 800 }}>50,000+</span> shoppers
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|