mirror of
https://github.com/Since-3/since3-website.git
synced 2026-10-12 19:51:16 +00:00
68 lines
1.3 KiB
TypeScript
68 lines
1.3 KiB
TypeScript
"use client"
|
|
|
|
import { useRef } from "react"
|
|
import {
|
|
motion,
|
|
useReducedMotion,
|
|
useScroll,
|
|
useTransform,
|
|
type MotionValue,
|
|
} from "motion/react"
|
|
|
|
import { cn } from "@/lib/utils"
|
|
|
|
function Word({
|
|
children,
|
|
progress,
|
|
range,
|
|
}: {
|
|
children: string
|
|
progress: MotionValue<number>
|
|
range: [number, number]
|
|
}) {
|
|
const opacity = useTransform(progress, range, [0.14, 1])
|
|
return (
|
|
<motion.span style={{ opacity }} className="inline">
|
|
{children}{" "}
|
|
</motion.span>
|
|
)
|
|
}
|
|
|
|
/** A statement whose words light up one after another while scrolling. */
|
|
export function ScrollStatement({
|
|
text,
|
|
className,
|
|
}: {
|
|
text: string
|
|
className?: string
|
|
}) {
|
|
const ref = useRef<HTMLParagraphElement>(null)
|
|
const reduced = useReducedMotion()
|
|
const { scrollYProgress } = useScroll({
|
|
target: ref,
|
|
offset: ["start 0.85", "end 0.5"],
|
|
})
|
|
const words = text.split(" ")
|
|
|
|
if (reduced) {
|
|
return (
|
|
<p ref={ref} className={className}>
|
|
{text}
|
|
</p>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<p ref={ref} className={cn(className)}>
|
|
{words.map((word, index) => (
|
|
<Word
|
|
key={index}
|
|
progress={scrollYProgress}
|
|
range={[index / words.length, (index + 1) / words.length]}
|
|
>
|
|
{word}
|
|
</Word>
|
|
))}
|
|
</p>
|
|
)
|
|
}
|