269 lines
9.3 KiB
TypeScript
269 lines
9.3 KiB
TypeScript
"use client";
|
||
import { motion } from "motion/react";
|
||
import React, { useState } from "react";
|
||
|
||
import { cn } from "@/lib/utils";
|
||
|
||
const FEATURES = [
|
||
{
|
||
id: "instant",
|
||
number: "۱",
|
||
title: "لاگ اجرا",
|
||
description:
|
||
"با هر رویداد مثل ثبت فرم یا تغییر وضعیت، اقدام بعدی را خودکار اجرا کنید.",
|
||
image: "/block-media/shadcnblocks/block/guri3/img11.jpeg",
|
||
imageAlt: "سازنده گردشکار",
|
||
imageOrder: "order-1",
|
||
contentOrder: "order-2",
|
||
},
|
||
{
|
||
id: "one-time",
|
||
number: "۲",
|
||
title: "قالب آماده",
|
||
description:
|
||
"مسیر متفاوت برای شرایط مختلف تعریف کنید و تصمیمگیری را سریعتر کنید.",
|
||
image: "/block-media/shadcnblocks/block/guri3/img12.jpeg",
|
||
imageAlt: "نمای اتوماسیون فرایند",
|
||
imageOrder: "order-2",
|
||
contentOrder: "order-1",
|
||
},
|
||
{
|
||
id: "developer",
|
||
number: "۰۳",
|
||
title: "اتصال ابزار",
|
||
description:
|
||
"تیم را در لحظه از تغییر وضعیت باخبر کنید تا هیچ موردی رها نشود.",
|
||
image: "/block-media/shadcnblocks/block/guri3/img14.jpeg",
|
||
imageAlt: "لاگ اجرای خودکار",
|
||
imageOrder: "order-1",
|
||
contentOrder: "order-2",
|
||
},
|
||
] as const;
|
||
|
||
interface Feature270Props {
|
||
className?: string;
|
||
}
|
||
|
||
const Feature270 = ({ className }: Feature270Props) => {
|
||
return (
|
||
<section
|
||
dir="rtl"
|
||
lang="fa"
|
||
className={cn(
|
||
"relative h-full w-full min-w-0 overflow-hidden py-32",
|
||
className,
|
||
)}
|
||
>
|
||
<div className="relative container min-w-0">
|
||
<div className="w-full min-w-0 space-y-5 text-start lg:w-3/5">
|
||
<h1 className="mb-6 w-full max-w-lg text-2xll font-semibold tracking-tighter text-balance lg:text-2xll">
|
||
فرایندها را استاندارد و سریع کنید
|
||
</h1>
|
||
<p className="max-w-2xl text-pretty break-words opacity-50 md:mb-20">
|
||
قوانین ساده تعریف کنید تا وظایف تکراری بدون دخالت دست انجام شود. تیم روی تصمیمهای مهم تمرکز میکند و سرعت اجرا بالاتر میرود.
|
||
</p>
|
||
</div>
|
||
<div className="relative grid h-[95rem] min-w-0 items-center justify-between gap-3 md:h-[68rem] md:grid-cols-2 lg:h-[32rem] lg:grid-cols-3">
|
||
{FEATURES.map((feature) => (
|
||
<PinContainer
|
||
key={feature.id}
|
||
title="بیشتر بدانید"
|
||
href="https://www.ShadcnBlocks/blocks"
|
||
className="w-full min-w-0 rounded-3xl bg-muted/70! p-4"
|
||
containerClassName="w-full min-w-0 max-w-full"
|
||
>
|
||
<div className="flex min-w-0 flex-col text-start">
|
||
<div className={cn("min-w-0", feature.imageOrder)}>
|
||
<img
|
||
src={feature.image}
|
||
height="1000"
|
||
width="1000"
|
||
className="h-70 w-full max-w-full rounded-3xl object-cover group-hover/card:shadow-xl"
|
||
alt={feature.imageAlt}
|
||
/>
|
||
</div>
|
||
<div className={cn("mt-4 w-full min-w-0 p-3", feature.contentOrder)}>
|
||
<p className="leading-none tracking-tighter opacity-50">
|
||
{feature.number}
|
||
</p>
|
||
<h2 className="my-3 text-3xl leading-none font-semibold tracking-tighter text-balance break-words">
|
||
{feature.title}
|
||
</h2>
|
||
<p className="text-pretty break-words leading-5 opacity-50">
|
||
{feature.description}
|
||
</p>
|
||
</div>
|
||
</div>
|
||
</PinContainer>
|
||
))}
|
||
</div>
|
||
</div>
|
||
</section>
|
||
);
|
||
};
|
||
|
||
export { Feature270 };
|
||
|
||
// Below is the modified component from Aceternity UI
|
||
// Original source: npx shadcn@latest add https://ui.aceternity.com/registry/3d-pin.json
|
||
// Modified to follow our coding standards and design system
|
||
// We respect copyright and attribution to the original creators
|
||
|
||
export const PinContainer = ({
|
||
children,
|
||
title,
|
||
href,
|
||
className,
|
||
containerClassName,
|
||
}: {
|
||
children: React.ReactNode;
|
||
title?: string;
|
||
href?: string;
|
||
className?: string;
|
||
containerClassName?: string;
|
||
}) => {
|
||
const [transform, setTransform] = useState(
|
||
"translate(-50%,-50%) rotateX(0deg)",
|
||
);
|
||
|
||
const onMouseEnter = () => {
|
||
setTransform("translate(-50%,-50%) rotateX(40deg) scale(0.8)");
|
||
};
|
||
const onMouseLeave = () => {
|
||
setTransform("translate(-50%,-50%) rotateX(0deg) scale(1)");
|
||
};
|
||
|
||
return (
|
||
<a
|
||
className={cn(
|
||
"group/pin relative z-50 block w-full min-w-0 max-w-full cursor-pointer",
|
||
containerClassName,
|
||
)}
|
||
onMouseEnter={onMouseEnter}
|
||
onMouseLeave={onMouseLeave}
|
||
href={href || "/"}
|
||
>
|
||
<div
|
||
style={{
|
||
perspective: "1000px",
|
||
transform: "rotateX(70deg) translateZ(0deg)",
|
||
}}
|
||
className="absolute top-1/2 left-1/2 mt-4 ml-[0.09375rem] w-full max-w-full -translate-x-1/2 -translate-y-1/2"
|
||
>
|
||
<div
|
||
style={{
|
||
transform: transform,
|
||
}}
|
||
className="absolute top-1/2 left-1/2 flex w-full max-w-full items-start justify-start overflow-hidden rounded-2xl transition duration-700"
|
||
>
|
||
<div className={cn("relative z-50 min-w-0 w-full", className)}>
|
||
{children}
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<PinPerspective title={title} />
|
||
</a>
|
||
);
|
||
};
|
||
|
||
export const PinPerspective = ({
|
||
title,
|
||
}: {
|
||
title?: string;
|
||
href?: string;
|
||
}) => {
|
||
return (
|
||
<motion.div className="pointer-events-none z-[60] flex h-80 w-full max-w-full items-center justify-center opacity-0 transition duration-500 group-hover/pin:opacity-100">
|
||
<div className="inset-0 -mt-7 h-full w-full min-w-0 flex-none overflow-hidden">
|
||
<div className="absolute inset-x-0 top-0 flex justify-center">
|
||
<span className="relative z-10 flex items-center gap-2 rounded-full bg-zinc-950 px-4 py-0.5 ring-1 ring-white/10">
|
||
<span className="relative z-20 inline-block py-0.5 text-xs font-bold text-white">
|
||
{title}
|
||
</span>
|
||
|
||
<span className="absolute -bottom-0 left-[1.125rem] h-px w-[calc(100%-2.25rem)] bg-gradient-to-r from-emerald-400/0 via-emerald-400/90 to-emerald-400/0 transition-opacity duration-500 group-hover/btn:opacity-40"></span>
|
||
</span>
|
||
</div>
|
||
|
||
<div
|
||
style={{
|
||
perspective: "1000px",
|
||
transform: "rotateX(70deg) translateZ(0)",
|
||
}}
|
||
className="absolute top-1/2 left-1/2 mt-4 ml-[0.09375rem] -translate-x-1/2 -translate-y-1/2"
|
||
>
|
||
<>
|
||
<motion.div
|
||
initial={{
|
||
opacity: 0,
|
||
scale: 0,
|
||
x: "-50%",
|
||
y: "-50%",
|
||
}}
|
||
animate={{
|
||
opacity: [0, 1, 0.5, 0],
|
||
scale: 1,
|
||
|
||
z: 0,
|
||
}}
|
||
transition={{
|
||
duration: 6,
|
||
repeat: Infinity,
|
||
delay: 0,
|
||
}}
|
||
className="absolute top-1/2 left-1/2 h-[11.25rem] w-[11.25rem] rounded-[50%] bg-sky-500/[0.08] shadow-[0_8px_16px_rgb(0_0_0/0.4)]"
|
||
></motion.div>
|
||
<motion.div
|
||
initial={{
|
||
opacity: 0,
|
||
scale: 0,
|
||
x: "-50%",
|
||
y: "-50%",
|
||
}}
|
||
animate={{
|
||
opacity: [0, 1, 0.5, 0],
|
||
scale: 1,
|
||
|
||
z: 0,
|
||
}}
|
||
transition={{
|
||
duration: 6,
|
||
repeat: Infinity,
|
||
delay: 2,
|
||
}}
|
||
className="absolute top-1/2 left-1/2 h-[11.25rem] w-[11.25rem] rounded-[50%] bg-sky-500/[0.08] shadow-[0_8px_16px_rgb(0_0_0/0.4)]"
|
||
></motion.div>
|
||
<motion.div
|
||
initial={{
|
||
opacity: 0,
|
||
scale: 0,
|
||
x: "-50%",
|
||
y: "-50%",
|
||
}}
|
||
animate={{
|
||
opacity: [0, 1, 0.5, 0],
|
||
scale: 1,
|
||
|
||
z: 0,
|
||
}}
|
||
transition={{
|
||
duration: 6,
|
||
repeat: Infinity,
|
||
delay: 4,
|
||
}}
|
||
className="absolute top-1/2 left-1/2 h-[11.25rem] w-[11.25rem] rounded-[50%] bg-sky-500/[0.08] shadow-[0_8px_16px_rgb(0_0_0/0.4)]"
|
||
></motion.div>
|
||
</>
|
||
</div>
|
||
|
||
<>
|
||
<motion.div className="absolute right-1/2 bottom-1/2 h-20 w-px translate-y-[14px] bg-gradient-to-b from-transparent to-cyan-500 blur-[2px] group-hover/pin:h-40" />
|
||
<motion.div className="absolute right-1/2 bottom-1/2 h-20 w-px translate-y-[14px] bg-gradient-to-b from-transparent to-cyan-500 group-hover/pin:h-40" />
|
||
<motion.div className="absolute right-1/2 bottom-1/2 z-40 h-[4px] w-[4px] translate-x-[1.5px] translate-y-[14px] rounded-full bg-cyan-600 blur-[3px]" />
|
||
<motion.div className="absolute right-1/2 bottom-1/2 z-40 h-[2px] w-[2px] translate-x-[0.5px] translate-y-[14px] rounded-full bg-cyan-300" />
|
||
</>
|
||
</div>
|
||
</motion.div>
|
||
);
|
||
};
|