Live Preview — NutriFlow Hero
SaaS B2B para clínicas y dietistas

Nutrición
sin fricción

Planifica, monitoriza y fideliza a tus pacientes desde una sola plataforma. Automatiza el seguimiento y enfócate en lo que importa.

📋
Planes IA
Generados en segundos con IA nutricional
📊
Seguimiento
Dashboards en tiempo real por paciente
🔔
Alertas
Notificaciones automáticas de desviación
HeroSection.tsx
useGSAP
 1 // NutriFlow — HeroSection.tsx
 2 // Patrón: useGSAP + scope + contextSafe + SSR-safe
 3
 4 import { useRef } from "react"
 5 import gsap from "gsap"
 6 import { useGSAP } from "@gsap/react"
 7
 8 // ✅ Registrar el plugin una vez, fuera del componente
 9 gsap.registerPlugin(useGSAP)
10
11 export default function HeroSection() {
12
13   // ✅ Ref al contenedor raíz para acotar selectores
14   const containerRef = useRef<HTMLElement>(null)
15   const btnRef = useRef<HTMLButtonElement>(null)
16
17   useGSAP((context, contextSafe) => {
18
19     // ── 1. Entrada del título ─────────────────────
20     gsap.from(".hero-title", {
21       opacity: 0,
22       y: 32,
23       duration: 0.8,
24       ease: "power3.out",
25       delay: 0.2
26     })
27
28     // ── 2. Cards con stagger ──────────────────────
29     gsap.from(".feature-card", {
30       opacity: 0,
31       y: 24,
32       duration: 0.6,
33       stagger: 0.15,
34       ease: "back.out(1.4)",
35       delay: 0.5
36     })
37
38     // ── 3. Pulse loop en CTA ──────────────────────
39     gsap.to(btnRef.current, {
40       boxShadow: "0 0 0 10px rgba(99,102,241,0.2)",
41       duration: 1.2,
42       repeat: -1,
43       yoyo: true,
44       ease: "sine.inOut",
45       delay: 1.8
46     })
47
48     // ── 4. contextSafe para click handler ─────────
49     // ✅ Animaciones creadas DESPUÉS de useGSAP
50     //    deben envolverse en contextSafe()
51     const onCtaClick = contextSafe!(() => {
52       gsap.timeline()
53         .to(btnRef.current, {
54           scale: 0.93,
55           duration: 0.1
56         })
57         .to(btnRef.current, {
58           scale: 1,
59           duration: 0.4,
60           ease: "elastic.out(1.2, 0.5)"
61         })
62     })
63
64     btnRef.current?.addEventListener("click", onCtaClick)
65
66     // ✅ Limpieza del event listener en cleanup
67     return () => {
68       btnRef.current?.removeEventListener("click", onCtaClick)
69     }
70
71   }, {
72     // ✅ scope limita selectores al contenedor
73     scope: containerRef
74     // ✅ Cleanup automático al desmontar el componente
75     //    (useGSAP revierte tweens y ScrollTriggers)
76   })
77
78   return (
79     <section ref={containerRef} className="hero-section">
80       <h1 className="hero-title">
81         Nutrición<br />
82         <span className="gradient">sin fricción</span>
83       </h1>
84
85       <div className="cards">
86         {features.map((f) => (
87           <div key={f.id} className="feature-card">
88             <span>{f.icon}</span>
89             <strong>{f.title}</strong>
90           </div>
91         ))}
92       </div>
93
94       <button ref={btnRef} className="btn-cta">
95         Empieza gratis — 14 días →
96       </button>
97     </section>
98   )
99 }
100
GSAP 3.12 React 18 TypeScript Next.js 14
useGSAP · contextSafe · scope · cleanup automático · SSR-safe a0a28e24