feat(recorrido): la conversación se responde al bajar, y el lector puede gobernarla
Cada respuesta llega cuando su par alcanza el centro de la pantalla: la regla dorada se dibuja y el bloque entra. El estado solo avanza, así que nada se apaga por detrás del lector. El scroll no es el único mando — hover y foco de teclado llevan al mismo sitio. Corrige un fallo que las pruebas no podían ver: Framer resuelve la variante escribiendo `opacity: 1` en el style inline, que gana a la clase opacity-0 de Tailwind. El revelado no ocurría; solo se animaba la regla, que es un transform que Framer no toca. La entrada y el revelado viven ahora en elementos distintos, con una prueba que lo fija. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a200346780
commit
90a35714f2
3 files changed
+194
-33
No files matched your search
@@ -1,5 +1,6 @@
|
||||
'use client';
|
||||
|
||||
import { useCallback, useState } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Container } from '@/components/primitives/Container';
|
||||
import { FondoPuntos } from '@/components/primitives/FondoPuntos';
|
||||
@@ -10,6 +11,15 @@ import { fadeInUp, staggerContainer, viewportOnce, usePrefersReducedMotion, moti
|
||||
|
||||
export function PuntosInflexion() {
|
||||
const reduced = usePrefersReducedMotion();
|
||||
|
||||
// How far down the conversation the reader has got. It only ever moves
|
||||
// forward: an answer that faded back out on the way past would leave the page
|
||||
// emptier the further you read. Scroll drives it, and so do hover and
|
||||
// keyboard focus, so the reader can also run the conversation themselves
|
||||
// instead of only being carried through it.
|
||||
const [alcanzado, setAlcanzado] = useState(0);
|
||||
const activar = useCallback((n: number) => setAlcanzado((previo) => Math.max(previo, n)), []);
|
||||
|
||||
return (
|
||||
<section className="bg-gris-claro relative overflow-hidden">
|
||||
<FondoPuntos className="-bottom-6 -right-12 w-80 md:w-[32rem] text-azul-profundo/10" distance={32} />
|
||||
@@ -32,13 +42,21 @@ export function PuntosInflexion() {
|
||||
|
||||
{/* The conversation. One <li> per exchange, read top to bottom — no
|
||||
carousel at any breakpoint, because "te bajas" is the whole shape
|
||||
the dueña asked for. The stagger reaches ParDialogo's two halves
|
||||
through React context, so each pair arrives in two beats: the
|
||||
situation, then the answer. */}
|
||||
the dueña asked for. Each answer arrives when the reader reaches its
|
||||
pair, so the section answers as you go down instead of sitting there
|
||||
already answered. The stagger reaches ParDialogo's two halves
|
||||
through React context. */}
|
||||
<motion.ul variants={staggerContainer} initial="hidden" whileInView="visible" viewport={viewportOnce} {...motionProps(reduced)}
|
||||
className="mt-8 list-none p-0 flex flex-col gap-12 md:gap-16">
|
||||
className="mt-8 list-none p-0 flex flex-col gap-16 md:gap-24">
|
||||
{puntosInflexion.items.map((item, i) => (
|
||||
<ParDialogo key={item.name} n={i + 1} {...item} />
|
||||
<ParDialogo
|
||||
key={item.name}
|
||||
n={i + 1}
|
||||
{...item}
|
||||
activo={i + 1 <= alcanzado}
|
||||
reducido={reduced}
|
||||
onActivar={activar}
|
||||
/>
|
||||
))}
|
||||
</motion.ul>
|
||||
</Container>
|
||||
|
||||
Reference in new issue
Block a user