feat: enhance landing page, for-people sections, blog main, and components including TheLoop and PhoneMockup
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
'use client';
|
||||
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import Image from 'next/image';
|
||||
import { gsap } from 'gsap';
|
||||
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
||||
import { PhoneFrame, PhoneBottomNav, BellIcon, FlameIcon } from './PhoneMockup';
|
||||
|
||||
if (typeof window !== 'undefined') gsap.registerPlugin(ScrollTrigger);
|
||||
|
||||
@@ -11,9 +13,6 @@ const feed = [
|
||||
{ store: 'Walking 5,000 steps', pts: +80, time: '1h ago', type: 'earn' },
|
||||
{ store: 'Spin Wheel Game', pts: +120, time: '3h ago', type: 'earn' },
|
||||
{ store: 'Selfie Booth', pts: +200, time: 'Yesterday', type: 'earn' },
|
||||
{ store: 'Scratch Card', pts: +40, time: 'Yesterday', type: 'earn' },
|
||||
{ store: 'Match Master', pts: +75, time: '2 days ago', type: 'earn' },
|
||||
{ store: 'Maze Challenge', pts: +95, time: '3 days ago', type: 'earn' },
|
||||
];
|
||||
|
||||
export default function EarnRewardsSection() {
|
||||
@@ -35,27 +34,20 @@ export default function EarnRewardsSection() {
|
||||
rowRefs.current.forEach((row, i) => {
|
||||
if (!row) return;
|
||||
const active = i === idx;
|
||||
row.style.background = active ? '#16a34a' : 'rgba(23,21,18,0.55)';
|
||||
row.style.borderColor = active ? '#16a34a' : 'rgba(255,255,255,0.14)';
|
||||
row.style.transform = active ? 'translateX(10px) scale(1.06)' : 'translateX(0) scale(1)';
|
||||
row.style.boxShadow = active ? '0 16px 40px -12px rgba(22,163,74,0.5)' : 'none';
|
||||
row.style.zIndex = active ? '2' : '1';
|
||||
row.style.background = active ? '#f0fdf4' : 'transparent';
|
||||
row.style.borderColor = active ? '#16a34a' : 'transparent';
|
||||
row.style.transform = active ? 'translateX(4px) scale(1.02)' : 'translateX(0) scale(1)';
|
||||
row.style.boxShadow = active ? '0 10px 24px -12px rgba(22,163,74,0.35)' : 'none';
|
||||
|
||||
// Flip inner text/icon colors for contrast per background
|
||||
const title = row.querySelector<HTMLElement>('.feed-title');
|
||||
if (title) title.style.color = '#ffffff';
|
||||
const time = row.querySelector<HTMLElement>('.feed-time');
|
||||
if (time) time.style.color = active ? 'rgba(255,255,255,0.75)' : 'rgba(255,255,255,0.55)';
|
||||
const icon = row.querySelector<HTMLElement>('.feed-icon');
|
||||
if (icon) {
|
||||
icon.style.background = active ? 'rgba(255,255,255,0.15)' : 'rgba(74,222,128,0.1)';
|
||||
icon.style.borderColor = active ? 'rgba(255,255,255,0.5)' : 'rgba(74,222,128,0.45)';
|
||||
icon.style.color = active ? '#ffffff' : '#4ade80';
|
||||
icon.style.background = active ? 'rgba(22,163,74,0.14)' : 'rgba(23,21,18,0.04)';
|
||||
icon.style.borderColor = active ? '#16a34a' : 'rgba(23,21,18,0.08)';
|
||||
icon.style.color = active ? '#16a34a' : '#9ca3af';
|
||||
}
|
||||
const points = row.querySelector<HTMLElement>('.feed-pts');
|
||||
if (points) {
|
||||
points.style.color = active ? '#ffffff' : '#4ade80';
|
||||
points.style.background = active ? 'rgba(255,255,255,0.15)' : 'rgba(74,222,128,0.12)';
|
||||
points.style.background = active ? 'rgba(22,163,74,0.14)' : 'rgba(22,163,74,0.08)';
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -103,7 +95,7 @@ export default function EarnRewardsSection() {
|
||||
background: '#f0fdf4', border: '1.5px solid #16a34a', borderRadius: 100, padding: '7px 16px',
|
||||
}}>
|
||||
<span style={{ width: 7, height: 7, borderRadius: '50%', background: '#16a34a', flexShrink: 0, animation: 'fpPulse 1.5s infinite' }} />
|
||||
<span style={{ fontSize: 11, fontWeight: 700, color: '#16a34a', fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>Live LYT balance</span>
|
||||
<span style={{ fontSize: 11, fontWeight: 700, color: '#16a34a', fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>Live LYTs balance</span>
|
||||
</div>
|
||||
|
||||
{/* Giant gold number */}
|
||||
@@ -125,7 +117,7 @@ export default function EarnRewardsSection() {
|
||||
<span style={{ fontSize: 13, color: '#4f463a', fontFamily: 'Sora, sans-serif' }}>redeemable value</span>
|
||||
</div>
|
||||
|
||||
<div style={{ marginBottom: 16 }}><span className="fp-kicker fp-rise">Earn<span className="fp-kicker-num">03</span></span></div>
|
||||
<div style={{ marginBottom: 16 }}><span className="fp-kicker fp-rise">Earn<span className="fp-kicker-num">04</span></span></div>
|
||||
|
||||
<h2 style={{
|
||||
fontSize: 'clamp(28px, 3.4vw, 48px)', fontWeight: 800, lineHeight: 1.08,
|
||||
@@ -139,83 +131,107 @@ export default function EarnRewardsSection() {
|
||||
<p className="fp-rise" style={{
|
||||
fontSize: 15, lineHeight: 1.8, color: '#4f463a', fontFamily: 'Sora, sans-serif', maxWidth: 380, margin: 0,
|
||||
}}>
|
||||
Earn LYT (Loyaly Tokens) through daily app login, completing 5,000-step walking challenges, playing Maze, Spin Wheel, Scratch Card, and Match Master games, or visiting Selfie Booths at partner malls. Every activity adds more LYT to your balance.
|
||||
Earn LYTs (Loyaly Tokens) through daily app login, completing 5,000-step walking challenges, playing Maze, Spin Wheel, Scratch Card, and Match Master games, or visiting Selfie Booths at partner malls. Every activity adds more LYTs to your balance.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Right — live feed */}
|
||||
<div className="fp-rise" style={{ transitionDelay: '0.15s' }}>
|
||||
{/* Feed header */}
|
||||
<div style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
marginBottom: 14, paddingBottom: 14, borderBottom: '2px solid #f4be28',
|
||||
}}>
|
||||
<span style={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.14em', textTransform: 'uppercase', color: '#171512', fontFamily: 'Sora, sans-serif' }}>Activity feed</span>
|
||||
<span style={{ fontSize: 11, color: '#16a34a', fontWeight: 700, fontFamily: 'Sora, sans-serif', display: 'flex', alignItems: 'center', gap: 5,
|
||||
background: '#f0fdf4', border: '1px solid #16a34a', borderRadius: 100, padding: '4px 10px',
|
||||
}}>
|
||||
<span style={{ width: 5, height: 5, borderRadius: '50%', background: '#16a34a', display: 'block', animation: 'fpPulse 1.5s infinite' }} />
|
||||
LIVE
|
||||
</span>
|
||||
</div>
|
||||
{/* Right — phone mockup, matches the in-app Earn / Home experience */}
|
||||
<div className="fp-rise" style={{ transitionDelay: '0.15s', display: 'flex', justifyContent: 'center' }}>
|
||||
<PhoneFrame floatClassName="erm-phone-shell">
|
||||
|
||||
{/* Feed rows */}
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
|
||||
{feed.map((tx, i) => (
|
||||
<div key={i} ref={el => { rowRefs.current[i] = el; }} style={{
|
||||
position: 'relative', zIndex: i === 0 ? 2 : 1,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
||||
padding: '12px 14px', borderRadius: 12,
|
||||
background: i === 0 ? '#16a34a' : 'rgba(23,21,18,0.55)',
|
||||
border: `1.5px solid ${i === 0 ? '#16a34a' : 'rgba(255,255,255,0.14)'}`,
|
||||
backdropFilter: 'blur(16px)',
|
||||
WebkitBackdropFilter: 'blur(16px)',
|
||||
transform: i === 0 ? 'translateX(10px) scale(1.06)' : 'translateX(0) scale(1)',
|
||||
boxShadow: i === 0 ? '0 16px 40px -12px rgba(22,163,74,0.5)' : 'none',
|
||||
transition: 'background 0.35s ease, border-color 0.35s ease, transform 0.35s cubic-bezier(0.34,1.56,0.64,1), box-shadow 0.35s ease',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
|
||||
<div className="feed-icon" style={{
|
||||
width: 36, height: 36, borderRadius: 10, flexShrink: 0,
|
||||
background: i === 0 ? 'rgba(255,255,255,0.15)' : 'rgba(74,222,128,0.1)',
|
||||
border: `1.5px solid ${i === 0 ? 'rgba(255,255,255,0.5)' : 'rgba(74,222,128,0.45)'}`,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
fontSize: 15, fontWeight: 900,
|
||||
color: i === 0 ? '#ffffff' : '#4ade80',
|
||||
transition: 'background 0.35s ease, border-color 0.35s ease, color 0.35s ease',
|
||||
}}>{tx.type === 'earn' ? '↑' : '↓'}</div>
|
||||
<div>
|
||||
<div className="feed-title" style={{ fontSize: 13, fontWeight: 700, color: '#ffffff', fontFamily: 'Sora, sans-serif', transition: 'color 0.35s ease' }}>{tx.store}</div>
|
||||
<div className="feed-time" style={{ fontSize: 11, color: i === 0 ? 'rgba(255,255,255,0.75)' : 'rgba(255,255,255,0.55)', fontFamily: 'Sora, sans-serif', marginTop: 1, transition: 'color 0.35s ease' }}>{tx.time}</div>
|
||||
</div>
|
||||
{/* Amber header */}
|
||||
<div style={{ background: 'linear-gradient(180deg, #fcd34d 0%, #f4be28 100%)', padding: '34px 16px 14px' }}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 }}>
|
||||
<Image src="/images/loyalyai.png" alt="Loyaly.AI" width={100} height={26} style={{ objectFit: 'contain', height: 16, width: 'auto' }} />
|
||||
<div style={{ width: 26, height: 26, borderRadius: '50%', background: 'rgba(255,255,255,0.55)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<BellIcon />
|
||||
</div>
|
||||
<span className="feed-pts" style={{
|
||||
fontSize: 15, fontWeight: 900, fontFamily: 'Sora, sans-serif',
|
||||
color: i === 0 ? '#ffffff' : '#4ade80', letterSpacing: '-0.02em',
|
||||
background: i === 0 ? 'rgba(255,255,255,0.15)' : 'rgba(74,222,128,0.12)',
|
||||
padding: '4px 10px', borderRadius: 8,
|
||||
transition: 'color 0.35s ease, background 0.35s ease',
|
||||
}}>
|
||||
{tx.pts > 0 ? '+' : ''}{tx.pts}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
|
||||
<FlameIcon />
|
||||
<span style={{ fontSize: 11.5, fontWeight: 600, color: '#171512', fontFamily: 'Sora, sans-serif' }}>6-day streak · keep it going!</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Summary strip */}
|
||||
<div style={{
|
||||
marginTop: 16, display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10,
|
||||
}}>
|
||||
{[
|
||||
{ label: 'Earned this month', val: '660 LYT', color: '#16a34a', bg: '#f0fdf4', border: '#16a34a' },
|
||||
{ label: 'Redeemable value', val: '₹660', color: '#f4be28', bg: '#fff7e0', border: '#f4be28' },
|
||||
].map((s, i) => (
|
||||
<div key={i} style={{ padding: '14px 16px', borderRadius: 14, background: s.bg, border: `1.5px solid ${s.border}` }}>
|
||||
<div style={{ fontSize: 11, color: 'rgba(23,21,18,0.5)', fontFamily: 'Sora, sans-serif', marginBottom: 4 }}>{s.label}</div>
|
||||
<div style={{ fontSize: 18, fontWeight: 900, color: s.color, fontFamily: 'Sora, sans-serif' }}>{s.val}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{/* Balance card */}
|
||||
<div style={{ margin: '14px 14px 0', borderRadius: 18, padding: '16px 18px', background: 'linear-gradient(135deg, #f4be28 0%, #e09820 100%)', position: 'relative', overflow: 'hidden' }}>
|
||||
<div style={{ position: 'absolute', top: '-30%', right: '-8%', width: 90, height: 90, borderRadius: '50%', background: 'rgba(255,255,255,0.14)' }} />
|
||||
<div style={{ fontSize: 10, color: 'rgba(23,21,18,0.65)', fontWeight: 700, fontFamily: 'Sora, sans-serif', letterSpacing: '0.1em', textTransform: 'uppercase' }}>Total LYTs</div>
|
||||
<div style={{ fontSize: 30, color: '#171512', fontWeight: 900, fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em', marginTop: 2 }}>284</div>
|
||||
<div style={{ fontSize: 10.5, color: 'rgba(23,21,18,0.6)', fontFamily: 'Sora, sans-serif', marginTop: 3 }}>≈ ₹284 redeemable</div>
|
||||
</div>
|
||||
|
||||
{/* Feed header */}
|
||||
<div style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
margin: '16px 14px 6px',
|
||||
}}>
|
||||
<span style={{ fontSize: 10.5, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: '#171512', fontFamily: 'Sora, sans-serif' }}>Activity feed</span>
|
||||
<span style={{ fontSize: 9.5, color: '#16a34a', fontWeight: 700, fontFamily: 'Sora, sans-serif', display: 'flex', alignItems: 'center', gap: 4,
|
||||
background: '#f0fdf4', border: '1px solid #16a34a', borderRadius: 100, padding: '3px 8px',
|
||||
}}>
|
||||
<span style={{ width: 4.5, height: 4.5, borderRadius: '50%', background: '#16a34a', display: 'block', animation: 'fpPulse 1.5s infinite' }} />
|
||||
LIVE
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Feed rows */}
|
||||
<div style={{ padding: '2px 10px', display: 'flex', flexDirection: 'column', gap: 3 }}>
|
||||
{feed.map((tx, i) => (
|
||||
<div key={i} ref={el => { rowRefs.current[i] = el; }} style={{
|
||||
display: 'grid', gridTemplateColumns: '32px minmax(0,1fr) auto', alignItems: 'center', gap: 10,
|
||||
padding: '8px 8px', borderRadius: 12,
|
||||
background: i === 0 ? '#f0fdf4' : 'transparent',
|
||||
border: `1px solid ${i === 0 ? '#16a34a' : 'transparent'}`,
|
||||
transform: i === 0 ? 'translateX(4px) scale(1.02)' : 'translateX(0) scale(1)',
|
||||
boxShadow: i === 0 ? '0 10px 24px -12px rgba(22,163,74,0.35)' : 'none',
|
||||
transition: 'background 0.35s ease, border-color 0.35s ease, transform 0.35s cubic-bezier(0.34,1.56,0.64,1), box-shadow 0.35s ease',
|
||||
}}>
|
||||
<div className="feed-icon" style={{
|
||||
width: 32, height: 32, borderRadius: 9, flexShrink: 0,
|
||||
background: i === 0 ? 'rgba(22,163,74,0.14)' : 'rgba(23,21,18,0.04)',
|
||||
border: `1.5px solid ${i === 0 ? '#16a34a' : 'rgba(23,21,18,0.08)'}`,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
||||
color: i === 0 ? '#16a34a' : '#9ca3af',
|
||||
transition: 'background 0.35s ease, border-color 0.35s ease, color 0.35s ease',
|
||||
}}>
|
||||
<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 19V5" /><path d="M5 12l7-7 7 7" /></svg>
|
||||
</div>
|
||||
<div style={{ minWidth: 0 }}>
|
||||
<div style={{
|
||||
fontSize: 11.5, fontWeight: 700, color: '#171512', fontFamily: 'Sora, sans-serif',
|
||||
overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
|
||||
}}>{tx.store}</div>
|
||||
<div style={{ fontSize: 9, color: '#9ca3af', fontFamily: 'Sora, sans-serif', marginTop: 1 }}>{tx.time}</div>
|
||||
</div>
|
||||
<span className="feed-pts" style={{
|
||||
fontSize: 12, fontWeight: 900, fontFamily: 'Sora, sans-serif',
|
||||
color: '#16a34a', letterSpacing: '-0.01em',
|
||||
background: i === 0 ? 'rgba(22,163,74,0.14)' : 'rgba(22,163,74,0.08)',
|
||||
padding: '3px 8px', borderRadius: 8, whiteSpace: 'nowrap',
|
||||
transition: 'background 0.35s ease',
|
||||
}}>
|
||||
+{tx.pts}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Summary strip */}
|
||||
<div style={{ margin: '10px 14px 12px', display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 8 }}>
|
||||
{[
|
||||
{ label: 'Earned this month', val: '660 LYTs', color: '#16a34a', bg: '#f0fdf4', border: '#16a34a' },
|
||||
{ label: 'Redeemable value', val: '₹660', color: '#bc7122', bg: '#fff7e0', border: '#f4be28' },
|
||||
].map((s, i) => (
|
||||
<div key={i} style={{ padding: '10px 12px', borderRadius: 12, background: s.bg, border: `1.5px solid ${s.border}` }}>
|
||||
<div style={{ fontSize: 8.5, color: 'rgba(23,21,18,0.5)', fontFamily: 'Sora, sans-serif', marginBottom: 3 }}>{s.label}</div>
|
||||
<div style={{ fontSize: 14, fontWeight: 900, color: s.color, fontFamily: 'Sora, sans-serif' }}>{s.val}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<PhoneBottomNav active="home" />
|
||||
</PhoneFrame>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user