mirror of
https://github.com/perfect-panel/ppanel-web.git
synced 2026-02-16 05:11:10 -05:00
68 lines
1.8 KiB
TypeScript
68 lines
1.8 KiB
TypeScript
'use client';
|
|
|
|
import { motion, MotionValue, useScroll, useTransform } from 'framer-motion';
|
|
import { FC, ReactNode, useRef } from 'react';
|
|
|
|
import { cn } from '../../lib/utils';
|
|
|
|
interface TextRevealByWordProps {
|
|
text: string;
|
|
className?: string;
|
|
}
|
|
|
|
export const TextRevealByWord: FC<TextRevealByWordProps> = ({ text, className }) => {
|
|
const targetRef = useRef<HTMLDivElement | null>(null);
|
|
|
|
const { scrollYProgress } = useScroll({
|
|
target: targetRef,
|
|
});
|
|
const words = text.split(' ');
|
|
|
|
return (
|
|
<div ref={targetRef} className={cn('relative z-0 h-[200vh]', className)}>
|
|
<div
|
|
className={
|
|
'sticky top-0 mx-auto flex h-[50%] max-w-4xl items-center bg-transparent px-[1rem] py-[5rem]'
|
|
}
|
|
>
|
|
<p
|
|
ref={targetRef}
|
|
className={
|
|
'flex flex-wrap p-5 text-2xl font-bold text-black/20 md:p-8 md:text-3xl lg:p-10 lg:text-4xl xl:text-5xl dark:text-white/20'
|
|
}
|
|
>
|
|
{words.map((word, i) => {
|
|
const start = i / words.length;
|
|
const end = start + 1 / words.length;
|
|
return (
|
|
<Word key={i} progress={scrollYProgress} range={[start, end]}>
|
|
{word}
|
|
</Word>
|
|
);
|
|
})}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface WordProps {
|
|
children: ReactNode;
|
|
progress: MotionValue<number>;
|
|
range: [number, number];
|
|
}
|
|
|
|
const Word: FC<WordProps> = ({ children, progress, range }) => {
|
|
const opacity = useTransform(progress, range, [0, 1]);
|
|
return (
|
|
<span className='xl:lg-3 relative mx-1 lg:mx-2.5'>
|
|
<span className={'absolute opacity-30'}>{children}</span>
|
|
<motion.span style={{ opacity: opacity }} className={'text-black dark:text-white'}>
|
|
{children}
|
|
</motion.span>
|
|
</span>
|
|
);
|
|
};
|
|
|
|
export default TextRevealByWord;
|