convert-next.js
This commit is contained in:
248
src/components/for-people/HeroSection.tsx
Normal file
248
src/components/for-people/HeroSection.tsx
Normal file
@@ -0,0 +1,248 @@
|
||||
'use client';
|
||||
|
||||
import React, { useRef, useEffect, useCallback } from 'react';
|
||||
import Link from 'next/link';
|
||||
|
||||
function useMagnetic<T extends HTMLElement>(strength = 12) {
|
||||
const ref = useRef<T | null>(null);
|
||||
useEffect(() => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const onMove = (e: MouseEvent) => {
|
||||
const rect = el.getBoundingClientRect();
|
||||
const x = ((e.clientX - rect.left) / rect.width - 0.5) * strength * 2;
|
||||
const y = ((e.clientY - rect.top) / rect.height - 0.5) * strength * 2;
|
||||
el.style.transform = `translate(${x}px, ${y}px)`;
|
||||
};
|
||||
const onLeave = () => { el.style.transform = 'translate(0,0)'; };
|
||||
el.addEventListener('mousemove', onMove);
|
||||
el.addEventListener('mouseleave', onLeave);
|
||||
return () => {
|
||||
el.removeEventListener('mousemove', onMove);
|
||||
el.removeEventListener('mouseleave', onLeave);
|
||||
};
|
||||
}, [strength]);
|
||||
return ref;
|
||||
}
|
||||
|
||||
export default function HeroSection() {
|
||||
const magPrimary = useMagnetic<HTMLAnchorElement>(10);
|
||||
const magSecondary = useMagnetic<HTMLButtonElement>(8);
|
||||
const stageRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Pointer parallax for the phone stage
|
||||
const onStageMove = useCallback((e: React.MouseEvent<HTMLDivElement>) => {
|
||||
const el = stageRef.current; if (!el) return;
|
||||
const r = el.getBoundingClientRect();
|
||||
const px = (e.clientX - r.left) / r.width - 0.5;
|
||||
const py = (e.clientY - r.top) / r.height - 0.5;
|
||||
el.style.setProperty('--rx', `${(-py * 8).toFixed(2)}deg`);
|
||||
el.style.setProperty('--ry', `${(px * 10).toFixed(2)}deg`);
|
||||
el.style.setProperty('--tx', `${(px * 18).toFixed(1)}px`);
|
||||
el.style.setProperty('--ty', `${(py * 18).toFixed(1)}px`);
|
||||
}, []);
|
||||
const onStageLeave = useCallback(() => {
|
||||
const el = stageRef.current; if (!el) return;
|
||||
el.style.setProperty('--rx', '0deg');
|
||||
el.style.setProperty('--ry', '0deg');
|
||||
el.style.setProperty('--tx', '0px');
|
||||
el.style.setProperty('--ty', '0px');
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<section className="fp-panel" style={{ background: 'radial-gradient(ellipse 90% 80% at 78% 42%, #1a1040 0%, #0a0a12 55%, #06060b 100%)' }}>
|
||||
|
||||
{/* Ambient orbs + grid */}
|
||||
<div className="fp-deco" style={{ position: 'absolute', inset: 0, zIndex: 0 }}>
|
||||
<div style={{
|
||||
position: 'absolute', top: '14%', left: '58%', width: 460, height: 460, borderRadius: '50%',
|
||||
background: 'radial-gradient(circle, rgba(244,190,40,0.13) 0%, transparent 70%)', animation: 'fpOrbFloat 7s ease-in-out infinite',
|
||||
}} />
|
||||
<div style={{
|
||||
position: 'absolute', bottom: '8%', right: '6%', width: 280, height: 280, borderRadius: '50%',
|
||||
background: 'radial-gradient(circle, rgba(130,88,200,0.18) 0%, transparent 70%)', animation: 'fpOrb2Float 9s ease-in-out infinite',
|
||||
}} />
|
||||
<div style={{
|
||||
position: 'absolute', inset: 0,
|
||||
backgroundImage: 'linear-gradient(rgba(255,255,255,0.018) 1px, transparent 1px), linear-gradient(90deg, rgba(255,255,255,0.018) 1px, transparent 1px)',
|
||||
backgroundSize: '80px 80px', maskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 0%, transparent 80%)',
|
||||
WebkitMaskImage: 'radial-gradient(ellipse 70% 70% at 50% 50%, #000 0%, transparent 80%)',
|
||||
}} />
|
||||
</div>
|
||||
|
||||
<div className="fp-shell">
|
||||
<div className="fp-split">
|
||||
|
||||
{/* Text column */}
|
||||
<div>
|
||||
<div className="fp-content fp-eyebrow" style={{ marginBottom: 26 }}>
|
||||
<span className="fp-kicker">For People · By Loyaly</span>
|
||||
</div>
|
||||
|
||||
<h1 className="fp-headline" style={{
|
||||
fontSize: 'clamp(40px, 5.4vw, 82px)', fontWeight: 800, lineHeight: 1.02,
|
||||
letterSpacing: '-0.045em', color: '#fff', margin: '0 0 28px', fontFamily: 'Sora, sans-serif',
|
||||
}}>
|
||||
<span className="fp-mask"><span>Shop Smart.</span></span>
|
||||
<span className="fp-mask"><span className="fp-shimmer">Live Rewarded.</span></span>
|
||||
</h1>
|
||||
|
||||
<p className="fp-content fp-subtext" style={{
|
||||
fontSize: 'clamp(16px, 1.4vw, 19px)', lineHeight: 1.7, fontWeight: 400,
|
||||
color: 'rgba(255,255,255,0.58)', maxWidth: 440, margin: '0 0 40px', fontFamily: 'Manrope, sans-serif',
|
||||
}}>
|
||||
Earn Loyaly Coins through daily activities, interactive games, and walking challenges — then redeem them at participating stores near you. Earn Online. Spend Offline.
|
||||
</p>
|
||||
|
||||
<div className="fp-content fp-cta" style={{ display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center' }}>
|
||||
<Link
|
||||
href="/contacts"
|
||||
ref={magPrimary}
|
||||
className="fp-btn fp-btn-primary fp-magnetic"
|
||||
>
|
||||
Download Free ↗
|
||||
</Link>
|
||||
<button
|
||||
ref={magSecondary}
|
||||
className="fp-btn fp-btn-ghost fp-magnetic"
|
||||
>
|
||||
See How It Works
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Trust row */}
|
||||
<div className="fp-content fp-cta" style={{ display: 'flex', alignItems: 'center', gap: 14, marginTop: 40 }}>
|
||||
<div style={{ display: 'flex' }}>
|
||||
{['#f4be28', '#4ade80', '#a855f7', '#3b82f6'].map((c, i) => (
|
||||
<div key={i} style={{ width: 30, height: 30, borderRadius: '50%', background: c, border: '2px solid #0a0a12', marginLeft: i > 0 ? -9 : 0, opacity: 0.9 }} />
|
||||
))}
|
||||
</div>
|
||||
<span style={{ fontSize: 13, color: 'rgba(255,255,255,0.42)', fontFamily: 'Manrope, sans-serif' }}>
|
||||
<strong style={{ color: 'rgba(255,255,255,0.75)', fontWeight: 700 }}>50,000+</strong> active shoppers earning daily
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Visual column — phone */}
|
||||
<div
|
||||
ref={stageRef}
|
||||
onMouseMove={onStageMove}
|
||||
onMouseLeave={onStageLeave}
|
||||
className="fp-deco"
|
||||
style={{
|
||||
position: 'relative', display: 'flex', justifyContent: 'center', alignItems: 'center',
|
||||
perspective: 1200,
|
||||
}}
|
||||
>
|
||||
<div style={{
|
||||
transformStyle: 'preserve-3d',
|
||||
transform: 'rotateX(var(--rx,0deg)) rotateY(var(--ry,0deg)) translate(var(--tx,0px), var(--ty,0px))',
|
||||
transition: 'transform 0.5s cubic-bezier(0.22,1,0.36,1)',
|
||||
position: 'relative',
|
||||
}}>
|
||||
{/* Glow ring */}
|
||||
<div style={{
|
||||
position: 'absolute', inset: -36, borderRadius: '56px',
|
||||
background: 'radial-gradient(circle at 50% 50%, rgba(244,190,40,0.2) 0%, transparent 70%)',
|
||||
animation: 'fpGlow 3s ease-in-out infinite',
|
||||
}} />
|
||||
{/* Phone shell */}
|
||||
<div style={{
|
||||
width: 268, height: 548, borderRadius: '48px',
|
||||
background: 'linear-gradient(160deg, #22223a 0%, #10101c 100%)',
|
||||
border: '1.5px solid rgba(255,255,255,0.1)',
|
||||
boxShadow: '0 70px 130px rgba(0,0,0,0.8), 0 0 0 1px rgba(255,255,255,0.06), inset 0 1px 0 rgba(255,255,255,0.1)',
|
||||
display: 'flex', flexDirection: 'column', overflow: 'hidden',
|
||||
animation: 'fpOrbFloat 6s ease-in-out infinite', position: 'relative',
|
||||
}}>
|
||||
{/* Shimmer sweep */}
|
||||
<div style={{ position: 'absolute', inset: 0, pointerEvents: 'none', zIndex: 20, overflow: 'hidden', borderRadius: '48px' }}>
|
||||
<div style={{
|
||||
position: 'absolute', top: '-20%', left: 0, width: '40%', height: '140%',
|
||||
background: 'linear-gradient(105deg, transparent 0%, rgba(255,255,255,0.07) 50%, transparent 100%)',
|
||||
animation: 'fpScreenShimmer 4.5s ease-in-out infinite', animationDelay: '1s',
|
||||
}} />
|
||||
</div>
|
||||
{/* Dynamic island */}
|
||||
<div style={{ display: 'flex', justifyContent: 'center', paddingTop: 16, paddingBottom: 4 }}>
|
||||
<div style={{ width: 96, height: 28, borderRadius: 20, background: '#080810', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
|
||||
<div style={{ width: 10, height: 10, borderRadius: '50%', background: '#1a1a28', border: '1px solid rgba(255,255,255,0.08)' }} />
|
||||
<div style={{ width: 6, height: 6, borderRadius: '50%', background: '#0d0d18' }} />
|
||||
</div>
|
||||
</div>
|
||||
{/* Header */}
|
||||
<div style={{ padding: '8px 22px 12px' }}>
|
||||
<div style={{ fontSize: 10, color: '#f4be28', fontWeight: 700, fontFamily: 'Manrope, sans-serif', letterSpacing: '0.12em', textTransform: 'uppercase' }}>Good Morning</div>
|
||||
<div style={{ fontSize: 16, color: '#fff', fontWeight: 800, fontFamily: 'Manrope, sans-serif', marginTop: 2 }}>Loyaly ✦</div>
|
||||
</div>
|
||||
{/* Points card */}
|
||||
<div style={{
|
||||
margin: '0 14px', borderRadius: 22, background: 'linear-gradient(135deg, #f4be28 0%, #e09820 100%)',
|
||||
padding: '18px 20px', boxShadow: '0 8px 24px rgba(244,190,40,0.35)', position: 'relative', overflow: 'hidden',
|
||||
}}>
|
||||
<div style={{ position: 'absolute', top: '-30%', right: '-10%', width: 110, height: 110, borderRadius: '50%', background: 'rgba(255,255,255,0.12)' }} />
|
||||
<div style={{ fontSize: 10, color: 'rgba(23,21,18,0.65)', fontWeight: 700, fontFamily: 'Manrope, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>Total Points</div>
|
||||
<div style={{ fontSize: 34, color: '#171512', fontWeight: 900, fontFamily: 'Manrope, sans-serif', letterSpacing: '-0.03em', marginTop: 2 }}>284</div>
|
||||
<div style={{ fontSize: 10, color: 'rgba(23,21,18,0.6)', fontFamily: 'Manrope, sans-serif', marginTop: 4 }}>≈ ₹284 redeemable</div>
|
||||
</div>
|
||||
{/* Activity */}
|
||||
<div style={{ padding: '14px 12px', display: 'flex', flexDirection: 'column', gap: 7, flex: 1 }}>
|
||||
{[
|
||||
{ store: 'Starbucks', pts: '+120', color: '#4ade80' },
|
||||
{ store: 'Nike Store', pts: '+85', color: '#4ade80' },
|
||||
{ store: 'H&M', pts: '−50', color: '#f87171' },
|
||||
].map((item, i) => (
|
||||
<div key={i} style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
background: 'rgba(255,255,255,0.04)', borderRadius: 12, padding: '10px 13px', border: '1px solid rgba(255,255,255,0.06)',
|
||||
}}>
|
||||
<span style={{ fontSize: 12, color: 'rgba(255,255,255,0.78)', fontFamily: 'Manrope, sans-serif' }}>{item.store}</span>
|
||||
<span style={{ fontSize: 12, color: item.color, fontWeight: 700, fontFamily: 'Manrope, sans-serif' }}>{item.pts}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* Nav dots */}
|
||||
<div style={{ display: 'flex', justifyContent: 'center', gap: 6, padding: '10px 0 20px' }}>
|
||||
{[1, 0, 0, 0].map((a, i) => (
|
||||
<div key={i} style={{ width: a ? 22 : 6, height: 4, borderRadius: 2, background: a ? '#f4be28' : 'rgba(255,255,255,0.2)' }} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Floating mini chips */}
|
||||
<div className="fp-glass" style={{
|
||||
position: 'absolute', top: '12%', left: '-12%', borderRadius: 16, padding: '12px 16px',
|
||||
display: 'flex', alignItems: 'center', gap: 10, animation: 'fpOrb2Float 7s ease-in-out infinite',
|
||||
}}>
|
||||
<div style={{ width: 30, height: 30, borderRadius: 9, background: 'rgba(74,222,128,0.16)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#4ade80', fontSize: 14, fontWeight: 800 }}>↑</div>
|
||||
<div>
|
||||
<div style={{ fontSize: 11, fontWeight: 700, color: '#fff', fontFamily: 'Manrope, sans-serif' }}>+120 pts</div>
|
||||
<div style={{ fontSize: 9, color: 'rgba(255,255,255,0.4)', fontFamily: 'Manrope, sans-serif' }}>just now</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="fp-glass" style={{
|
||||
position: 'absolute', bottom: '14%', right: '-14%', borderRadius: 16, padding: '12px 16px',
|
||||
animation: 'fpOrbFloat 8s ease-in-out infinite',
|
||||
}}>
|
||||
<div style={{ fontSize: 9, color: 'rgba(255,255,255,0.45)', fontFamily: 'Manrope, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase', marginBottom: 3 }}>Redeemable</div>
|
||||
<div style={{ fontSize: 17, fontWeight: 900, color: '#f4be28', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.02em' }}>₹284.00</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Scroll hint */}
|
||||
<div style={{
|
||||
position: 'absolute', bottom: 38, left: '50%', transform: 'translateX(-50%)',
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, zIndex: 10,
|
||||
color: 'rgba(255,255,255,0.3)', fontSize: 10, fontFamily: 'Manrope, sans-serif', letterSpacing: '0.16em', textTransform: 'uppercase',
|
||||
}}>
|
||||
<span>Scroll</span>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ animation: 'fpScrollHint 1.6s ease-in-out infinite' }}>
|
||||
<polyline points="6 9 12 15 18 9" />
|
||||
</svg>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user