"use client";
import type { MotionValue } from "framer-motion";
import {
AnimatePresence,
motion,
useMotionValueEvent,
useScroll,
useTransform,
} from "framer-motion";
import React, { useLayoutEffect, useRef, useState } from "react";
import { cn } from "@/lib/utils";
interface Statistics {
value: string;
label: string;
}
interface Feature {
id: string;
title: string;
subtitle: string;
statistics: Statistics;
visual: string;
}
interface Testimonial {
quote: string;
companyLogo: string;
author: string;
designation: string;
}
interface TestimonialCardProps {
testimonial: Testimonial;
}
const TestimonialCard = ({ testimonial }: TestimonialCardProps) => {
return (
«{testimonial.quote}»
{testimonial.author}{" "}
{testimonial.designation}
);
};
interface ScrollProgressIndicatorProps {
totalFeatures: number;
activeIndex: number;
scrollYProgress: MotionValue;
}
const ScrollProgressIndicator = ({
totalFeatures,
activeIndex,
scrollYProgress,
}: ScrollProgressIndicatorProps) => {
const segmentStart = activeIndex / totalFeatures;
const segmentEnd = (activeIndex + 1) / totalFeatures;
const width = useTransform(
scrollYProgress,
[segmentStart, segmentEnd],
["0%", "100%"],
);
return (
{Array.from({ length: totalFeatures }).map((_, index) => {
return (
index && "bg-foreground",
)}
>
{activeIndex === index ? (
) : null}
);
})}
);
};
interface FeatureCardProps {
feature: Feature;
index: number;
testimonial: Testimonial;
totalFeatures: number;
scrollYProgress: MotionValue;
}
const FeatureCard = ({
feature,
index,
testimonial,
totalFeatures,
scrollYProgress,
}: FeatureCardProps) => {
return (
{feature.title}
{feature.subtitle}
{feature.statistics.value}
{feature.statistics.label}

{index === 0 ?
: null}
);
};
interface Feature322Props {
features?: Feature[];
testimonial?: Testimonial;
className?: string;
}
const DEFAULT_FEATURES: Feature[] = [
{
id: "performance",
title: "طبقهبندی خودکار",
subtitle: "درخواستها را خودکار دستهبندی کنید و به تیم مناسب بفرستید.",
statistics: {
value: "اتوماسیون AI",
label: "دستیار کسبوکار",
},
visual:
"/block-media/shadcnblocks/block/photos/christopher-gower-vjMgqUkS8q8-unsplash.jpg",
},
{
id: "security",
title: "پیشبینی ریزش",
subtitle: "مشتریان در معرض ریزش را زودتر شناسایی کنید.",
statistics: {
value: "هوش مصنوعی",
label: "پیشنهاد هوشمند",
},
visual:
"/block-media/shadcnblocks/block/photos/daniel-leone-g30P1zcOzXo-unsplash.jpg",
},
{
id: "analytics",
title: "جستجوی معنایی",
subtitle: "متنهای طولانی را در چند ثانیه به نکات کلیدی تبدیل کنید.",
statistics: {
value: "اتوماسیون AI",
label: "دستیار کسبوکار",
},
visual:
"/block-media/shadcnblocks/block/photos/jason-leung-6uoj7DL6BFk-unsplash.jpg",
},
{
id: "integration",
title: "تولید محتوا",
subtitle: "بهترین پاسخ را بر اساس زمینه مکالمه پیشنهاد دهید.",
statistics: {
value: "هوش مصنوعی",
label: "پیشنهاد هوشمند",
},
visual:
"/block-media/shadcnblocks/block/photos/ivan-bandura-Kj2tYAl4HZg-unsplash.jpg",
},
];
const DEFAULT_TESTIMONIAL: Testimonial = {
quote:
"مدلهای هوشمند الگوهای پنهان در داده فروش و پشتیبانی را پیدا میکنند. تیمها با پیشنهادهای عملی، سریعتر اقدام میکنند.",
companyLogo:
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-4.svg",
author: "اتوماسیون AI",
designation: "با هوش مصنوعی سریعتر تصمیم بگیرید",
};
function getActiveFeatureIndex(progress: number, total: number) {
if (total <= 0) return 0;
if (progress >= 1) return total - 1;
return Math.min(total - 1, Math.floor(progress * total));
}
const Feature322 = ({
className,
features = DEFAULT_FEATURES,
testimonial = DEFAULT_TESTIMONIAL,
}: Feature322Props) => {
const scrollRef = useRef(null);
const [stageHeight, setStageHeight] = useState(0);
const { scrollYProgress } = useScroll({
container: scrollRef,
});
const [activeIndex, setActiveIndex] = useState(0);
useLayoutEffect(() => {
const scrollContainer = scrollRef.current;
if (!scrollContainer) return;
const updateStageHeight = () => {
setStageHeight(scrollContainer.clientHeight);
};
updateStageHeight();
const observer = new ResizeObserver(updateStageHeight);
observer.observe(scrollContainer);
return () => observer.disconnect();
}, []);
const scrollSegmentCount = Math.max(features.length - 1, 1);
const scrollSpacerHeight =
stageHeight > 0 ? stageHeight * scrollSegmentCount : undefined;
useMotionValueEvent(scrollYProgress, "change", (latest) => {
const nextIndex = getActiveFeatureIndex(latest, features.length);
setActiveIndex((prev) => (prev === nextIndex ? prev : nextIndex));
});
const activeFeature = features[activeIndex] ?? features[0];
return (
{/* Desktop: sticky stage + scroll spacer */}
0
? { height: stageHeight }
: { minHeight: "28rem" }
}
>
{activeFeature ? (
) : null}
{/* Mobile / tablet: stacked cards, no crossfade thrash */}
{features.map((feature, index) => (
))}
);
};
export { Feature322 };