Initial import of 1407 block sources under blocks/
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
"use client";
|
||||
|
||||
import { motion, useInView } from "framer-motion";
|
||||
import { CornerDownRight } from "lucide-react";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
// Custom hook to get previous value
|
||||
const usePrevious = <T,>(value: T): T | undefined => {
|
||||
const [prev, setPrev] = useState<T | undefined>(undefined);
|
||||
const ref = useRef(value);
|
||||
|
||||
useEffect(() => {
|
||||
setPrev(ref.current);
|
||||
ref.current = value;
|
||||
}, [value]);
|
||||
|
||||
return prev;
|
||||
};
|
||||
|
||||
interface Process2Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Process2 = ({ className }: Process2Props) => {
|
||||
const process = [
|
||||
{
|
||||
step: "۱",
|
||||
title: "کشف و تحقیق",
|
||||
image: "/block-media/shadcnblocks/block/guri4/img11.png",
|
||||
description:
|
||||
"با درک اهداف کسبوکار، مخاطب هدف و چالشهای فعلی شما شروع میکنیم. این فاز شامل تحقیق، تحلیل و برنامهریزی استراتژیک برای شناسایی فرصتهاست.",
|
||||
},
|
||||
{
|
||||
step: "۲",
|
||||
title: "استراتژی و برنامهریزی",
|
||||
image: "/block-media/shadcnblocks/block/guri4/img12.png",
|
||||
description:
|
||||
"بر اساس یافتهها، استراتژی جامعی متناسب با اهداف شما توسعه میدهیم. این شامل تعریف رویکرد، زمانبندی و نقاط عطف کلیدی برای موفقیت است.",
|
||||
},
|
||||
{
|
||||
step: "۰۳",
|
||||
title: "اجرا و توسعه",
|
||||
image: "/block-media/shadcnblocks/block/guri4/img10.png",
|
||||
description:
|
||||
"استراتژی را از طریق پیادهسازی و توسعه دقیق به واقعیت تبدیل میکنیم. تیم ما بهصورت همکاری کار میکند تا هر جزئیات با نیازها و استانداردهای شما همخوان باشد.",
|
||||
},
|
||||
{
|
||||
step: "۰۴",
|
||||
title: "بهینهسازی و بهبود",
|
||||
image: "/block-media/shadcnblocks/block/guri4/img9.png",
|
||||
description:
|
||||
"عملکرد را بهطور مستمر پایش و بازخورد جمعآوری میکنیم تا راهحل را پالایش و بهبود دهیم. این فرآیند تکراری موفقیت و رشد بلندمدت را تضمین میکند.",
|
||||
},
|
||||
];
|
||||
|
||||
const [active, setActive] = useState<number>(0);
|
||||
const previousActive = usePrevious(active);
|
||||
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 gap-5 lg:grid-cols-2 lg:gap-20">
|
||||
<div className="top-10 h-fit w-fit gap-3 space-y-7 py-8 lg:sticky">
|
||||
<h1 className="relative w-fit text-2xll font-semibold tracking-tight lg:text-2xll">
|
||||
فرآیند ما
|
||||
</h1>
|
||||
<p className="text-start text-base text-foreground/50">
|
||||
از کشف نیازهای شما تا تحویل نهایی، هر مرحله با دقت و شفافیت پیش
|
||||
میرود تا بهترین نتیجه حاصل شود.
|
||||
</p>
|
||||
<div className="relative h-90 overflow-hidden border">
|
||||
{previousActive !== undefined && (
|
||||
<div className="absolute top-0 h-full w-full">
|
||||
<img
|
||||
src={process[previousActive].image}
|
||||
className="h-full w-full object-cover"
|
||||
alt={process[previousActive].title}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<motion.div
|
||||
initial={{ clipPath: "inset(0% 0% 0% 100%)" }}
|
||||
animate={{ clipPath: "inset(0% 0% 0% 0%)" }}
|
||||
key={active}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 150,
|
||||
damping: 20,
|
||||
}}
|
||||
className="h-full w-full"
|
||||
>
|
||||
<img
|
||||
src={process[active].image}
|
||||
className="h-full w-full object-cover"
|
||||
alt={process[active].title}
|
||||
/>
|
||||
</motion.div>
|
||||
</div>
|
||||
<Button
|
||||
variant="ghost"
|
||||
className="flex items-center justify-start gap-2"
|
||||
>
|
||||
<CornerDownRight className="text-orange-500 rtl:rotate-180" />
|
||||
تماس بگیرید
|
||||
</Button>
|
||||
</div>
|
||||
<ul className="relative w-full lg:ps-22">
|
||||
{process.map((step, index) => (
|
||||
<ProcessCard
|
||||
key={index}
|
||||
step={step}
|
||||
index={index}
|
||||
setActive={setActive}
|
||||
/>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const ProcessCard = ({
|
||||
step,
|
||||
index,
|
||||
setActive,
|
||||
}: {
|
||||
step: {
|
||||
step: string;
|
||||
title: string;
|
||||
image: string;
|
||||
description: string;
|
||||
};
|
||||
index: number;
|
||||
setActive: (index: number) => void;
|
||||
}) => {
|
||||
const ref = useRef<HTMLLIElement>(null);
|
||||
|
||||
const itemInView = useInView(ref, {
|
||||
amount: 0,
|
||||
margin: "0px 0px -60% 0px",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (itemInView) {
|
||||
setActive(index);
|
||||
}
|
||||
}, [itemInView, index, setActive]);
|
||||
|
||||
return (
|
||||
<li
|
||||
ref={ref}
|
||||
key={index}
|
||||
className="relative flex flex-col justify-between gap-12 border-b py-8 lg:py-16"
|
||||
>
|
||||
<div className="flex w-fit items-center justify-center px-4 py-1 text-9xl tracking-tighter">
|
||||
{step.step}
|
||||
</div>
|
||||
<div>
|
||||
<h3 className="mb-4 text-start text-xl font-semibold tracking-tighter lg:text-3xl">
|
||||
{step.title}
|
||||
</h3>
|
||||
<p className="text-start text-foreground/50">{step.description}</p>
|
||||
</div>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
export { Process2 };
|
||||
Reference in New Issue
Block a user