// hero.jsx — 3 variations du HERO de la landing // Toutes partagent le titre "Fais un vœu. Ton territoire l'exauce." // V1: Constellation cinétique (signature) — la carte au centre, contenu autour // V2: Typographie géante "à la Apple" — mot par mot révélé, constellation discrète // V3: Photo immersive aurore — collage cinématique de placeholders function useAnimatedCounter(target, durationMs = 1800) { const [v, setV] = React.useState(0); React.useEffect(() => { const start = performance.now(); let raf; const tick = (now) => { const t = Math.min(1, (now - start) / durationMs); // Ease-out cubic const eased = 1 - Math.pow(1 - t, 3); setV(Math.round(target * eased)); if (t < 1) raf = requestAnimationFrame(tick); }; raf = requestAnimationFrame(tick); return () => cancelAnimationFrame(raf); }, [target]); return v; } function MagneticButton({ children, href, primary = true, ...rest }) { const ref = React.useRef(null); const onMove = (e) => { const el = ref.current; if (!el) return; const rect = el.getBoundingClientRect(); const x = e.clientX - rect.left - rect.width / 2; const y = e.clientY - rect.top - rect.height / 2; el.style.transform = `translate(${x * 0.18}px, ${y * 0.22}px) scale(1.02)`; }; const onLeave = () => { const el = ref.current; if (el) el.style.transform = ""; }; const Cmp = href ? "a" : "button"; return ( {children} ); } function LiveCounter({ base = 1240 }) { const v = useAnimatedCounter(base, 2200); return (
{v.toLocaleString("fr-FR")} vœux exaucés cette semaine
); } function HeroEyebrow() { return (
V1 La Pévèle Augmentée — Le Génie Territorial
); } function HeroActions() { return (
Commencer Voir comment ça marche
); } /* ─── V1 : Constellation cinétique ────────────────────────────────────── */ function HeroConstellation() { return (

Fais un vœu.
Ton territoire
l'exauce.

La Pévèle Carembault s'illumine quand 100 000 habitants se relient. 38 communes, 10 univers, un seul geste : le Vœu. Le Génie matche localement. Le territoire exauce.

); } /* ─── V2 : Typographie géante "Apple" ─────────────────────────────────── */ function HeroTypographic() { // Mots révélés en cascade const words = ["Fais", "un", "vœu."]; const words2 = ["Ton", "territoire", "l'exauce."]; return (
{/* Discrete constellation top right */}

{words.map((w, i) => ( {w} ))}
{words2.map((w, i) => ( {w} ))}

Le réseau d'intentions de la Pévèle Carembault. Un vœu local. Un match en moins de 60 secondes. Un Exaucement.

); } /* ─── V3 : Photo immersive aurore ─────────────────────────────────────── */ // Placeholder cards — fallback dégradé aurore + emoji du brief (jamais vide) const PH_CARDS = [ { emoji: "🥖", label: "Pain frais — Orchies", grad: "linear-gradient(135deg, #F59E0B, #FB7185)", pos: { top: "8%", left: "0%", width: 220, height: 280, rotate: -4 } }, { emoji: "🌱", label: "Plantation collective", grad: "linear-gradient(135deg, #10B981, #34D399)", pos: { top: "0%", right: "10%", width: 260, height: 200, rotate: 3 } }, { emoji: "🤝", label: "Coup de main voisin", grad: "linear-gradient(135deg, #7C5CFF, #22D3EE)", pos: { top: "44%", left: "18%", width: 240, height: 190, rotate: -2 } }, { emoji: "🎻", label: "Concert au village", grad: "linear-gradient(135deg, #F472B6, #A78BFA)", pos: { top: "38%", right: "0%", width: 280, height: 220, rotate: 4 } }, { emoji: "🌅", label: "Pévèle, golden hour", grad: "linear-gradient(135deg, #F5B544, #FB7185)", pos: { bottom: "0%", left: "8%", width: 300, height: 200, rotate: 2 } }, { emoji: "🛠", label: "Atelier réparation", grad: "linear-gradient(135deg, #22D3EE, #60A5FA)", pos: { bottom: "4%", right: "16%", width: 230, height: 170, rotate: -3 } }, ]; function PhotoCard({ card, delay = 0 }) { const { pos, grad, emoji, label } = card; return (
{emoji}
{label}
); } function HeroImmersive() { return (

Fais un vœu.
Ton territoire
l'exauce.

Mille visages, trente-huit communes, dix univers. Ici, on ne poste pas — on demande, on aide, on s'exauce. Et le territoire s'illumine.

{PH_CARDS.map((c, i) => ( ))}
); } window.HeroConstellation = HeroConstellation; window.HeroTypographic = HeroTypographic; window.HeroImmersive = HeroImmersive; window.MagneticButton = MagneticButton; window.useAnimatedCounter = useAnimatedCounter;