The Testimonials page presents client feedback as voices channeled from the beyond. Rather than a static list of quotes, a single testimonial occupies the full vertical center of the viewport at any one time. It appears from a blur — as if materializing from mist — holds for 8 seconds, then fades back out as the next voice takes its place. A large decorative quotation mark floats above the text, and the author credit fades in with a 1.5 s delay after the quote itself, giving it the air of a séance revelation.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/fortune-seeker/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Testimonials page lives at route/testimonials and is titled “Channeled Reviews”. Its opening quote — “Listen closely. The voices of past collaborators echo in the void.” — positions client feedback as supernatural endorsements rather than conventional reviews. An index state variable tracks the current testimonial, incremented every 8 seconds by a setInterval inside useEffect. The index wraps back to 0 using modulo arithmetic. AnimatePresence with mode="wait" ensures the outgoing testimonial fully completes its exit before the incoming one begins.
The
useEffect interval is cleaned up by returning clearInterval(intervalId) from the effect. This prevents memory leaks when the component unmounts (e.g., navigating away mid-cycle) and avoids the stale-closure pitfall by using the functional form of setState: setIndex(prev => (prev + 1) % testimonials.length).Layout & Components
AnimatePresence (mode=wait)
The testimonial block is wrapped in
AnimatePresence mode="wait". Each motion.div uses key={index} so React treats each new index as a distinct element, triggering the full enter/exit cycle. Without mode="wait", the incoming and outgoing testimonials would overlap during the transition.Blur-in transition
The
motion.div enters with initial: { opacity: 0, filter: "blur(10px)", scale: 0.9 } and animates to { opacity: 1, filter: "blur(0px)", scale: 1 }. The exit mirrors the entrance but expands slightly (scale: 1.1) to suggest the voice dissipating outward.Decorative quotation mark
A large
" character rendered in text-6xl text-gold/20 sits absolutely positioned above the testimonial text. It does not animate — it’s a purely decorative typographic element.Author credit fade-in
The author line is a nested
motion.div with initial: { opacity: 0 } and animate: { opacity: 1 } using transition: { delay: 1.5, duration: 1 }. The 1.5 s delay means the author identity is revealed only after the quote has fully appeared, mimicking the suspense of identifying a channeled spirit.Data Structure
Testimonials are defined as an array of objects. Add as many as needed — the interval cycle will include all of them:Animations
Blur-in / blur-out cycle
Blur-in / blur-out cycle
Each testimonial
motion.div uses a transition of duration: 2, ease: "easeInOut" for both entrance and exit. The 2 s duration is intentionally long — the slow materialisation is central to the channeling aesthetic. The blur travels from 10px to 0px on entry and 0px to 10px on exit.Scale breathe
Scale breathe
Alongside the blur, the scale animates from
0.9 (slightly shrunken) to 1.0 on entry, and from 1.0 to 1.1 (slightly expanded) on exit. This gives the impression of the quote “arriving” from a distance and “departing” by expanding past the viewer.animate-waver
animate-waver
The testimonial
motion.div also carries the animate-waver CSS class, which is defined as a custom Tailwind animation in the project’s config. It applies a subtle vertical float loop, making the visible quote appear to hover in the void rather than sitting rigidly on the page.Page title entrance
Page title entrance
The
h1 (“Channeled Reviews”) and quote paragraph use the standard initial: { opacity: 0, y: 20 } → animate: { opacity: 1, y: 0 } entrance shared across all Fortune Seeker pages. This is positioned absolutely at top: 32px so it stays visible regardless of the testimonial cycling below.Customization
Add more testimonials
Push new objects into the
testimonials array. Each must have a text (the quote) and an author string. The cycle duration of 8 seconds per testimonial is fixed in the setInterval call — adjust the 8000 value to increase or decrease display time per quote.Shorten transition time
The blur transition uses
duration: 2. For a snappier feel reduce to 1 or 1.2. Keep in mind the author’s delay: 1.5 — if you shorten the transition below 1.5, the author will not have time to fade in before the next cycle begins. Set delay to transitionDuration - 0.5 as a safe rule.Add manual navigation
Implement previous/next buttons by wiring two
onClick handlers that call setIndex(prev => (prev - 1 + testimonials.length) % testimonials.length) and setIndex(prev => (prev + 1) % testimonials.length). Render them as subtle gold arrow buttons flanking the testimonial container, and consider pausing the setInterval while the user is interacting manually.