Files
reui-blocks/blocks/feature247.tsx
T

105 lines
2.8 KiB
TypeScript

"use client";
import type { MotionValue } from "motion/react";
import { motion, useScroll, useTransform } from "motion/react";
import type { ComponentPropsWithoutRef, FC, ReactNode } from "react";
import React from "react";
import { useRef } from "react";
import { cn } from "@/lib/utils";
const REVEAL_TEXT =
"گزارش سفارشی را بدون SQL بسازید و سریع منتشر کنید.";
const Feature247 = () => {
return (
<section dir="rtl" lang="fa" className="py-32">
<div className="container flex flex-col items-center justify-center">
<div className="flex max-w-4xl">
<TextReveal
title="تصمیم استراتژیک را داده‌محور کنید"
className="items-center justify-center text-center"
>
{REVEAL_TEXT}
</TextReveal>
</div>
</div>
</section>
);
};
export { Feature247 };
interface TextRevealProps extends ComponentPropsWithoutRef<"div"> {
children: string;
title?: string;
maxWidth?: string;
}
const TextReveal: FC<TextRevealProps> = ({
children,
title,
className,
maxWidth,
}) => {
const targetRef = useRef<HTMLDivElement | null>(null);
const { scrollYProgress } = useScroll({
target: targetRef,
});
const words = children.split(" ");
return (
<div
ref={targetRef}
className={cn("relative z-0 h-[200vh]", className)}
style={{ maxWidth: maxWidth || "56rem" }}
>
<div className="sticky top-0 mx-auto flex h-[50%] items-center bg-transparent px-4 py-20">
<div className="flex flex-col justify-center">
<span className="text-center text-lg font-medium tracking-tight text-foreground">
{title}
</span>
<span
className={cn(
"flex flex-wrap p-5 text-xl font-semibold text-balance text-black/20 md:p-8 md:text-3xl lg:p-10 lg:text-xl xl:text-2xll dark:text-white/20",
className,
)}
>
{words.map((word, i) => {
const start = i / words.length;
const end = start + 1 / words.length;
return (
<Word key={`${word}-${i}`} progress={scrollYProgress} range={[start, end]}>
{word}
</Word>
);
})}
</span>
</div>
</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="relative mx-1 lg:mx-1.5">
<span className="absolute opacity-30">{children}</span>
<motion.span
style={{ opacity }}
className="text-black dark:text-white"
>
{children}
</motion.span>
</span>
);
};