140 lines
7.1 KiB
TypeScript
140 lines
7.1 KiB
TypeScript
'use client';
|
|
|
|
import React, { useEffect, useRef, useState } from 'react';
|
|
|
|
const recs = [
|
|
{ rank: '01', label: 'Double points at Starbucks', match: '98%', tag: 'Near you · 0.3km' },
|
|
{ rank: '02', label: 'Nike Air sale ends tonight', match: '94%', tag: 'Trending · Fashion' },
|
|
{ rank: '03', label: 'Decathlon weekend special', match: '91%', tag: 'Sports · 1.4km' },
|
|
{ rank: '04', label: 'Zara new arrivals — 15% off', match: '87%', tag: 'Your style' },
|
|
];
|
|
|
|
export default function AIRecommendationsSection() {
|
|
const [active, setActive] = useState(false);
|
|
const [hovered, setHovered] = useState<number | null>(null);
|
|
const panelRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const el = panelRef.current;
|
|
if (!el) return;
|
|
if (el.hasAttribute('data-active')) setActive(true);
|
|
const obs = new MutationObserver(() => {
|
|
if (el.hasAttribute('data-active')) setActive(true);
|
|
});
|
|
obs.observe(el, { attributes: true, attributeFilter: ['data-active'] });
|
|
return () => obs.disconnect();
|
|
}, []);
|
|
|
|
return (
|
|
<section ref={panelRef} className="fp-panel fp-light" style={{ background: '#ffffff' }}>
|
|
<div className="fp-shell">
|
|
<div className="fp-split" style={{ gridTemplateColumns: '0.85fr 1.15fr' }}>
|
|
|
|
{/* Left — editorial */}
|
|
<div>
|
|
<div style={{ marginBottom: 28 }}><span className="fp-kicker fp-rise">AI Intelligence · 05</span></div>
|
|
|
|
<h2 style={{
|
|
fontSize: 'clamp(40px, 5vw, 72px)', fontWeight: 900, letterSpacing: '-0.05em', lineHeight: 0.94,
|
|
color: '#171512', margin: '0 0 28px', fontFamily: 'Sora, sans-serif',
|
|
}}>
|
|
<span className="fp-mask"><span>Built for</span></span>
|
|
<span className="fp-mask"><span style={{ color: '#f4be28' }}>you,</span></span>
|
|
<span className="fp-mask"><span>by data.</span></span>
|
|
</h2>
|
|
|
|
<p className="fp-rise" style={{
|
|
fontSize: 15, lineHeight: 1.8, color: '#4f463a', fontFamily: 'Sora, sans-serif', margin: '0 0 36px', maxWidth: 340,
|
|
}}>
|
|
Our recommendation engine learns your taste from every transaction and surfaces offers uniquely matched to you — getting sharper with every visit.
|
|
</p>
|
|
|
|
{/* Stat chips — brand gold palette */}
|
|
<div className="fp-rise" style={{ display: 'flex', gap: 14, transitionDelay: '0.2s' }}>
|
|
{[
|
|
{ val: '94%', lbl: 'match accuracy' },
|
|
{ val: '3ms', lbl: 'response time' },
|
|
].map((s, i) => (
|
|
<div key={i} style={{ padding: '16px 20px', borderRadius: 16, background: '#fff7e0', border: '2px solid #f4be28', minWidth: 110 }}>
|
|
<div style={{ fontSize: 28, fontWeight: 900, color: '#bc7122', fontFamily: 'Sora, sans-serif', letterSpacing: '-0.03em' }}>{s.val}</div>
|
|
<div style={{ fontSize: 11, color: 'rgba(23,21,18,0.55)', fontFamily: 'Sora, sans-serif', marginTop: 4 }}>{s.lbl}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Right — recommendation cards */}
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 4, padding: '0 2px' }}>
|
|
<span style={{ fontSize: 12, fontWeight: 700, letterSpacing: '0.1em', textTransform: 'uppercase', color: '#171512', fontFamily: 'Sora, sans-serif' }}>Recommended for you</span>
|
|
<span style={{ fontSize: 11, color: '#bc7122', fontFamily: 'Sora, sans-serif', fontWeight: 700,
|
|
display: 'inline-flex', alignItems: 'center', gap: 5,
|
|
background: '#fff7e0', border: '1px solid #f4be28', borderRadius: 100, padding: '4px 10px',
|
|
}}>
|
|
<span style={{ display: 'inline-block', animation: 'fpSpinSlow 3s linear infinite' }}>↻</span> Updating
|
|
</span>
|
|
</div>
|
|
|
|
{recs.map((rec, i) => (
|
|
<div
|
|
key={i}
|
|
onMouseEnter={() => setHovered(i)}
|
|
onMouseLeave={() => setHovered(null)}
|
|
style={{
|
|
display: 'flex', alignItems: 'center', gap: 14, padding: '16px 18px', borderRadius: 16,
|
|
background: hovered === i ? '#fff7e0' : '#fafafa',
|
|
border: `2px solid ${hovered === i ? '#f4be28' : 'rgba(23,21,18,0.07)'}`,
|
|
cursor: 'default',
|
|
transition: 'all 0.4s cubic-bezier(0.16,1,0.3,1)',
|
|
transform: `translateX(${active ? 0 : 48}px)`, opacity: active ? 1 : 0,
|
|
transitionDelay: `${0.12 + i * 0.1}s`,
|
|
}}
|
|
>
|
|
{/* Rank */}
|
|
<span style={{ fontSize: 11, fontWeight: 800, color: 'rgba(23,21,18,0.25)', fontFamily: 'Sora, sans-serif', flexShrink: 0 }}>{rec.rank}</span>
|
|
|
|
{/* Gold accent bar */}
|
|
<div style={{ width: 4, height: 42, borderRadius: 100, background: '#f4be28', flexShrink: 0 }} />
|
|
|
|
{/* Info */}
|
|
<div style={{ flex: 1, minWidth: 0 }}>
|
|
<div style={{ fontSize: 14, fontWeight: 700, color: '#171512', fontFamily: 'Sora, sans-serif', marginBottom: 3 }}>{rec.label}</div>
|
|
<div style={{ fontSize: 11, color: 'rgba(23,21,18,0.45)', fontFamily: 'Sora, sans-serif' }}>{rec.tag}</div>
|
|
</div>
|
|
|
|
{/* Match badge — brand gold */}
|
|
<div style={{
|
|
padding: '6px 14px', borderRadius: 100, flexShrink: 0,
|
|
background: '#fff7e0', border: '1.5px solid #f4be28',
|
|
textAlign: 'center',
|
|
}}>
|
|
<div style={{ fontSize: 14, fontWeight: 900, color: '#bc7122', fontFamily: 'Sora, sans-serif' }}>{rec.match}</div>
|
|
<div style={{ fontSize: 9, color: 'rgba(23,21,18,0.4)', fontFamily: 'Sora, sans-serif' }}>match</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
{/* Confidence bar */}
|
|
<div style={{ padding: '16px 2px 0' }}>
|
|
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
|
|
<span style={{ fontSize: 12, fontWeight: 600, color: '#171512', fontFamily: 'Sora, sans-serif' }}>Model confidence</span>
|
|
<span style={{
|
|
fontSize: 11, fontWeight: 700, color: '#bc7122', fontFamily: 'Sora, sans-serif',
|
|
background: '#fff7e0', border: '1px solid #f4be28', borderRadius: 100, padding: '3px 10px',
|
|
}}>High</span>
|
|
</div>
|
|
<div style={{ height: 10, background: 'rgba(23,21,18,0.07)', borderRadius: 100, overflow: 'hidden' }}>
|
|
<div style={{
|
|
height: '100%', width: active ? '92%' : '0%', borderRadius: 100,
|
|
background: 'linear-gradient(90deg, #f4be28, #bc7122)',
|
|
transition: 'width 1.4s cubic-bezier(0.22,1,0.36,1) 0.8s',
|
|
}} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
}
|