2026-07-11 21:21:29 +03:30
"use client" ;
import { Cpu , Zap } from "lucide-react" ;
import { motion } from "motion/react" ;
import type { RefObject } from "react" ;
import React , { useRef } from "react" ;
import { useEffect , useId , useState } from "react" ;
import { cn } from "@/lib/utils" ;
interface Feature250Props {
className? : string ;
}
const Feature250 = ({ className } : Feature250Props ) => {
return (
2026-07-23 06:55:21 +03:30
< section
dir = "rtl"
lang = "fa"
className = { cn ( "relative w-full min-w-0 overflow-hidden py-32" , className )}
>
< div className = "container min-w-0" >
2026-07-11 21:21:29 +03:30
< p className = "mx-auto mb-4 max-w-sm text-center text-pretty text-muted-foreground md:text-xl" >
با سگمنتبندی دقیق، پیام مناسب را به مخاطب مناسب برسانید . داده رفتاری نشان میدهد کدام محتوا بیشترین تأثیر را روی تبدیل دارد .
</ p >
2026-07-23 06:55:21 +03:30
< h1 className = "mx-auto mb-2 max-w-3xl text-center text-xl font-medium tracking-tighter text-balance break-words md:text-2xll lg:mb-5 lg:text-2xll" >
2026-07-11 21:21:29 +03:30
کمپینهایی بسازید که واقعاً تبدیل میشوند
</ h1 >
< AnimatedBeamIllustration />
</ div >
</ section >
);
};
export { Feature250 };
const REVERSE = false ;
const DURATION = 4 ;
function AnimatedBeamIllustration() {
const containerRef = useRef < HTMLDivElement >( null );
const div1Ref = useRef < HTMLDivElement >( null );
const div2Ref = useRef < HTMLDivElement >( null );
const div3Ref = useRef < HTMLDivElement >( null );
const div4Ref = useRef < HTMLDivElement >( null );
const div5Ref = useRef < HTMLDivElement >( null );
const div6Ref = useRef < HTMLDivElement >( null );
const div7Ref = useRef < HTMLDivElement >( null );
return (
< div
2026-07-23 06:55:21 +03:30
className = "relative flex w-full min-w-0 max-w-full items-center justify-center overflow-hidden p-6 sm:p-10"
2026-07-11 21:21:29 +03:30
ref = { containerRef }
>
2026-07-23 06:55:21 +03:30
< div className = "flex w-full min-w-0 flex-col items-center justify-between gap-10 lg:flex-row" >
{ /* Reserve width on lg so absolute nodes/beams stay inside the frame (avoid lg:w-0 bleed). */ }
< div className = "relative z-10 flex h-100 w-full min-w-0 items-center justify-center rounded-3xl lg:w-56 lg:shrink-0" >
2026-07-11 21:21:29 +03:30
< div
ref = { div1Ref }
2026-07-23 06:55:21 +03:30
className = "absolute start-2 top-40 z-10 flex size-18 -translate-y-1/2 items-center justify-center rounded-full bg-background p-1 lg:start-2 lg:top-1/2"
2026-07-11 21:21:29 +03:30
>
< div className = "flex size-10 items-center justify-center rounded-lg border border-border bg-background p-[5px]" >
< div className = "flex size-full items-center justify-center rounded-md border border-border bg-muted" >
< Cpu size = { 16 } />
</ div >
</ div >
</ div >
< div
ref = { div2Ref }
2026-07-23 06:55:21 +03:30
className = "absolute end-2 top-40 z-10 flex size-18 -translate-y-1/2 items-center justify-center rounded-full bg-background p-1 lg:start-16 lg:top-20"
2026-07-11 21:21:29 +03:30
>
< div className = "flex size-10 items-center justify-center rounded-lg border border-border bg-background p-[5px]" >
< div className = "flex size-full items-center justify-center rounded-md border border-border bg-muted" >
< Cpu size = { 16 } />
</ div >
</ div >
</ div >
< div
ref = { div3Ref }
2026-07-23 06:55:21 +03:30
className = "absolute start-6 bottom-4 z-10 flex size-18 items-center justify-center rounded-full bg-background p-1 lg:start-16 lg:bottom-4"
2026-07-11 21:21:29 +03:30
>
< div className = "flex size-10 items-center justify-center rounded-lg border border-border bg-background p-[5px]" >
< div className = "flex size-full items-center justify-center rounded-md border border-border bg-muted" >
< Cpu size = { 16 } />
</ div >
</ div >
</ div >
< div
ref = { div4Ref }
2026-07-23 06:55:21 +03:30
className = "absolute end-6 bottom-4 z-10 flex size-18 items-center justify-center rounded-full bg-background p-1 lg:start-36 lg:top-4"
2026-07-11 21:21:29 +03:30
>
< div className = "flex size-10 items-center justify-center rounded-lg border border-border bg-background p-[5px]" >
< div className = "flex size-full items-center justify-center rounded-md border border-border bg-muted" >
< Cpu size = { 16 } />
</ div >
</ div >
</ div >
< div
ref = { div5Ref }
2026-07-23 06:55:21 +03:30
className = "absolute start-1/2 top-20 z-10 flex size-18 -translate-x-1/2 items-center justify-center rounded-full bg-background p-1 rtl:translate-x-1/2 lg:start-36 lg:top-auto lg:bottom-4 lg:translate-x-0 rtl:lg:translate-x-0"
2026-07-11 21:21:29 +03:30
>
< div className = "flex size-10 items-center justify-center rounded-lg border border-border bg-background p-[5px]" >
< div className = "flex size-full items-center justify-center rounded-md border border-border bg-muted" >
< Cpu size = { 16 } />
</ div >
</ div >
</ div >
</ div >
< div
ref = { div6Ref }
2026-07-23 06:55:21 +03:30
className = "z-10 flex size-32 shrink-0 items-center justify-center rounded-3xl border bg-muted lg:size-42"
2026-07-11 21:21:29 +03:30
>
< img
src = "/block-media/shadcnblocks/block/block-1.svg"
className = "size-14 lg:size-18 dark:invert"
alt = "تحلیل عملکرد کمپین"
/>
</ div >
< div
ref = { div7Ref }
2026-07-23 06:55:21 +03:30
className = "z-10 mt-24 flex size-15 shrink-0 items-center justify-center rounded-xl border bg-muted lg:mt-0"
2026-07-11 21:21:29 +03:30
>
< Zap fill = "currentColor" />
</ div >
</ div >
< div className = "block lg:hidden" >
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div3Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
endYOffset = { - 60 }
endXOffset = { - 10 }
curvature = { 10 }
containerRef = { containerRef }
fromRef = { div1Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div5Ref }
toRef = { div6Ref }
direction = "vertical"
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
endYOffset = { - 60 }
endXOffset = { 10 }
curvature = { 10 }
containerRef = { containerRef }
fromRef = { div2Ref }
toRef = { div6Ref }
reverse = { ! REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div4Ref }
toRef = { div6Ref }
reverse = { ! REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div6Ref }
toRef = { div7Ref }
direction = "vertical"
reverse = { REVERSE }
/>
</ div >
< div className = "hidden lg:block" >
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div1Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
2026-07-23 06:55:21 +03:30
endYOffset = { - 24 }
endXOffset = { 24 }
2026-07-11 21:21:29 +03:30
duration = { DURATION }
2026-07-23 06:55:21 +03:30
curvature = { - 80 }
2026-07-11 21:21:29 +03:30
containerRef = { containerRef }
fromRef = { div2Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
2026-07-23 06:55:21 +03:30
endYOffset = { 24 }
curvature = { 80 }
2026-07-11 21:21:29 +03:30
containerRef = { containerRef }
fromRef = { div3Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
2026-07-23 06:55:21 +03:30
endYOffset = { - 24 }
endXOffset = { - 24 }
curvature = { - 100 }
2026-07-11 21:21:29 +03:30
containerRef = { containerRef }
fromRef = { div4Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
2026-07-23 06:55:21 +03:30
endXOffset = { - 24 }
endYOffset = { 24 }
curvature = { 100 }
2026-07-11 21:21:29 +03:30
containerRef = { containerRef }
fromRef = { div5Ref }
toRef = { div6Ref }
reverse = { REVERSE }
/>
< AnimatedBeam
duration = { DURATION }
containerRef = { containerRef }
fromRef = { div6Ref }
toRef = { div7Ref }
reverse = { REVERSE }
/>
</ div >
</ div >
);
}
/*
animated-beam.tsx with direction support.
The original code is from https://magicui.design/docs/components/animated-beam which doesn't support vertical animations. This is a modified version of the original code to support that.
*/
export interface AnimatedBeamProps {
className? : string ;
containerRef : RefObject < HTMLElement | null >; // Container ref
fromRef : RefObject < HTMLElement | null >;
toRef : RefObject < HTMLElement | null >;
curvature? : number ;
reverse? : boolean ;
direction ?: "horizontal" | "vertical" ;
pathColor? : string ;
pathWidth? : number ;
pathOpacity? : number ;
gradientStartColor? : string ;
gradientStopColor? : string ;
delay? : number ;
duration? : number ;
startXOffset? : number ;
startYOffset? : number ;
endXOffset? : number ;
endYOffset? : number ;
}
const AnimatedBeam : React.FC < AnimatedBeamProps > = ({
className ,
containerRef ,
fromRef ,
toRef ,
curvature = 0 ,
reverse = false , // Include the reverse prop
direction = "horizontal" ,
duration = Math . random () * 3 + 4 ,
delay = 0 ,
pathColor = "gray" ,
pathWidth = 2 ,
pathOpacity = 0.2 ,
gradientStartColor = "#ffaa40" ,
gradientStopColor = "#9c40ff" ,
startXOffset = 0 ,
startYOffset = 0 ,
endXOffset = 0 ,
endYOffset = 0 ,
}) => {
const id = useId ();
const [ pathD , setPathD ] = useState ( "" );
const [ svgDimensions , setSvgDimensions ] = useState ({ width : 0 , height : 0 });
// Calculate the gradient coordinates based on the direction and reverse prop
const gradientCoordinates =
direction === "vertical"
? reverse
? {
x1 : [ "0%" , "0%" ],
x2 : [ "0%" , "0%" ],
y1 : [ "90%" , "-10%" ],
y2 : [ "100%" , "0%" ],
}
: {
x1 : [ "0%" , "0%" ],
x2 : [ "0%" , "0%" ],
y1 : [ "10%" , "110%" ],
y2 : [ "0%" , "100%" ],
}
: reverse
? {
x1 : [ "90%" , "-10%" ],
x2 : [ "100%" , "0%" ],
y1 : [ "0%" , "0%" ],
y2 : [ "0%" , "0%" ],
}
: {
x1 : [ "10%" , "110%" ],
x2 : [ "0%" , "100%" ],
y1 : [ "0%" , "0%" ],
y2 : [ "0%" , "0%" ],
};
useEffect (() => {
const updatePath = () => {
if ( containerRef . current && fromRef . current && toRef . current ) {
const containerRect = containerRef . current . getBoundingClientRect ();
const rectA = fromRef . current . getBoundingClientRect ();
const rectB = toRef . current . getBoundingClientRect ();
const svgWidth = containerRect . width ;
const svgHeight = containerRect . height ;
setSvgDimensions ({ width : svgWidth , height : svgHeight });
const startX =
rectA . left - containerRect . left + rectA . width / 2 + startXOffset ;
const startY =
rectA . top - containerRect . top + rectA . height / 2 + startYOffset ;
const endX =
rectB . left - containerRect . left + rectB . width / 2 + endXOffset ;
const endY =
rectB . top - containerRect . top + rectB . height / 2 + endYOffset ;
let d : string ;
if ( direction === "vertical" ) {
const controlX = startX - curvature ;
d = `M ${ startX } , ${ startY } Q ${ controlX } , ${
( startY + endY ) / 2
} ${ endX } , ${ endY } ` ;
} else {
const controlY = startY - curvature ;
d = `M ${ startX } , ${ startY } Q ${
( startX + endX ) / 2
} , ${ controlY } ${ endX } , ${ endY } ` ;
}
setPathD ( d );
}
};
// Initialize ResizeObserver
const resizeObserver = new ResizeObserver (( entries ) => {
// For all entries, recalculate the path
for ( const _ of entries ) {
updatePath ();
}
});
// Observe the container element
if ( containerRef . current ) {
resizeObserver . observe ( containerRef . current );
}
// Call the updatePath initially to set the initial path
updatePath ();
// Clean up the observer on component unmount
return () => {
resizeObserver . disconnect ();
};
}, [
containerRef ,
fromRef ,
toRef ,
curvature ,
startXOffset ,
startYOffset ,
endXOffset ,
endYOffset ,
direction ,
]);
return (
< svg
fill = "none"
width = { svgDimensions . width }
height = { svgDimensions . height }
xmlns = "http://www.w3.org/2000/svg"
className = { cn (
2026-07-23 06:55:21 +03:30
"pointer-events-none absolute start-0 top-0 max-w-full overflow-hidden transform-gpu stroke-2" ,
2026-07-11 21:21:29 +03:30
className ,
)}
viewBox = { `0 0 ${ svgDimensions . width } ${ svgDimensions . height } ` }
>
< path
d = { pathD }
stroke = { pathColor }
strokeWidth = { pathWidth }
strokeOpacity = { pathOpacity }
strokeLinecap = "round"
/>
< path
d = { pathD }
strokeWidth = { pathWidth }
stroke = { `url(# ${ id } )` }
strokeOpacity = "1"
strokeLinecap = "round"
/>
< defs >
< motion.linearGradient
className = "transform-gpu"
id = { id }
gradientUnits = "userSpaceOnUse"
initial = {{
x1 : "0%" ,
x2 : "0%" ,
y1 : "0%" ,
y2 : "0%" ,
}}
animate = {{
x1 : gradientCoordinates.x1 ,
x2 : gradientCoordinates.x2 ,
y1 : gradientCoordinates.y1 ,
y2 : gradientCoordinates.y2 ,
}}
transition = {{
delay ,
duration ,
ease : [ 0.16 , 1 , 0.3 , 1 ], // https://easings.net/#easeOutExpo
repeat : Infinity ,
repeatDelay : 0 ,
}}
>
< stop stopColor = { gradientStartColor } stopOpacity = "0" ></ stop >
< stop stopColor = { gradientStartColor }></ stop >
< stop offset = "32.5%" stopColor = { gradientStopColor }></ stop >
< stop
offset = "100%"
stopColor = { gradientStopColor }
stopOpacity = "0"
></ stop >
</ motion.linearGradient >
</ defs >
</ svg >
);
};