fix bug
This commit is contained in:
+2
-2
@@ -12,8 +12,8 @@ const Hero108 = ({ className }: Hero108Props) => {
|
||||
<section
|
||||
className={cn("bg-background py-12 font-sans md:py-20", className)}
|
||||
>
|
||||
<div className="container flex flex-col items-center gap-8 lg:flex-row">
|
||||
<div className="flex flex-col gap-10">
|
||||
<div className="container flex w-full flex-col items-center gap-8 lg:flex-row">
|
||||
<div className="flex w-full flex-col gap-10 lg:w-1/2">
|
||||
<h1 className="text-2xll font-semibold text-foreground md:text-2xll">
|
||||
درآمد غیرفعال{" "}
|
||||
<span className="relative inline-block">
|
||||
|
||||
+7
-4
@@ -97,7 +97,7 @@ const Hero187 = ({
|
||||
<div className="relative container grid gap-12 lg:grid-cols-[1fr_1.2fr]">
|
||||
<div className="absolute inset-x-0 bottom-0 z-10 h-px bg-linear-to-r from-transparent via-border to-border" />
|
||||
{/* Left side - Content */}
|
||||
<div className="space-y-8 lg:space-y-12">
|
||||
<div className="relative z-10 space-y-8 lg:space-y-12">
|
||||
<div>
|
||||
<h1 className="text-3xl font-semibold tracking-tight sm:text-xl md:text-2xll lg:text-2xll">
|
||||
{heading}
|
||||
@@ -152,19 +152,22 @@ const Hero187 = ({
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Right side - Carousel */}
|
||||
<div className="relative -mr-[max(2rem,calc((100vw-80rem)/2+2rem))] max-lg:translate-x-10">
|
||||
{/* Outer-edge carousel: bleed with -me so RTL/LTR both extend away from copy */}
|
||||
<div className="relative min-w-0 -me-[max(2rem,calc((100vw-80rem)/2+2rem))] max-lg:translate-x-10 rtl:max-lg:-translate-x-10">
|
||||
<Carousel
|
||||
dir="rtl"
|
||||
className="size-full [&>div]:size-full"
|
||||
setApi={setApi}
|
||||
opts={{
|
||||
loop: true,
|
||||
direction: "rtl",
|
||||
align: "start",
|
||||
}}
|
||||
plugins={[Autoplay({ delay: 4000, stopOnInteraction: true })]}
|
||||
>
|
||||
<CarouselContent className="size-full">
|
||||
{activeImages.map((image, index) => (
|
||||
<CarouselItem key={index}>
|
||||
<CarouselItem key={index} className="overflow-hidden">
|
||||
<img
|
||||
src={image.src}
|
||||
alt={image.alt}
|
||||
|
||||
+11
-9
@@ -95,12 +95,12 @@ const Hero211 = ({ className }: Hero211Props) => {
|
||||
<style>{css}</style>
|
||||
<div className="container">
|
||||
<div className="relative z-10 mx-auto flex max-w-2xl flex-col items-center justify-center gap-4">
|
||||
<h1 className="font-calSans text-center text-2xll lg:text-2xll">
|
||||
<h1 className="font-calSans text-center text-5xl leading-tight lg:text-6xl">
|
||||
کمتر زمان صرف کنید، بیشتر بسازید
|
||||
</h1>
|
||||
</h1>
|
||||
<p className="px-10 text-center text-muted-foreground lg:text-lg">
|
||||
صدها بلاک و کامپوننت آماده مبتنی بر رابط کاربری، استایلدهی مدرن و ری یو آی که مستقیماً در پروژههای شما قابل استفاده هستند.
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-16 flex h-full items-center justify-center">
|
||||
@@ -145,30 +145,32 @@ const Hero211 = ({ className }: Hero211Props) => {
|
||||
<div className="relative z-10 mx-auto mt-10 flex w-fit justify-center">
|
||||
<Button className="rounded-full px-4 py-2 active:scale-105">
|
||||
شروع رایگان
|
||||
</Button>
|
||||
</Button>
|
||||
{/* RTL: sit to the left of the button so handwriting doesn't cover it */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, translateY: 20 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
transition={{ duration: 0.3, delay: 1 }}
|
||||
className="absolute top-3 -right-30 h-1"
|
||||
className="pointer-events-none absolute top-0 -left-36 flex w-40 flex-col items-center sm:-left-44 sm:w-44"
|
||||
>
|
||||
<p className="font-handwriting text-xl tracking-tight">
|
||||
<p className="font-handwriting text-center text-lg leading-snug tracking-tight sm:text-xl">
|
||||
همین امروز نسخه رایگان را امتحان کنید
|
||||
</p>
|
||||
</p>
|
||||
<svg
|
||||
width="82"
|
||||
className="-translate-x-1/2 pe-4"
|
||||
height="45"
|
||||
viewBox="0 0 82 45"
|
||||
className="-mt-1 -scale-x-100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden
|
||||
>
|
||||
<motion.path
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 1 }}
|
||||
transition={{ duration: 1, delay: 1.2 }}
|
||||
d="M80.2759 1.95576C67.8687 20.6075 49.1102 55.0246 21.9767 39.1283C15.3299 35.2342 12.7124 29.0489 9.38472 22.4634C9.24096 22.1789 6.96955 15.0574 7.91833 15.4904C10.4589 16.65 25.535 23.253 15.8013 18.8782C14.7716 18.4154 8.31018 14.0924 7.25323 14.6265C4.37354 16.0816 2.6512 30.2469 1.58546 33.4898"
|
||||
stroke="#1C1C1C"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.40332"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
|
||||
+11
-9
@@ -67,10 +67,10 @@ const Hero212 = ({ className }: Hero212Props) => {
|
||||
<div className="mx-auto flex max-w-2xl flex-col items-center justify-center gap-4">
|
||||
<p className="z-10 px-10 text-center tracking-tight text-muted-foreground/40 lg:text-lg">
|
||||
صدها بلاک و کامپوننت آماده مبتنی بر رابط کاربری، استایلدهی مدرن و ری یو آی
|
||||
</p>
|
||||
<h1 className="font-playfair text-center text-2xll tracking-tighter italic lg:text-2xll">
|
||||
</p>
|
||||
<h1 className="font-playfair text-center text-5xl leading-tight tracking-tighter italic lg:text-6xl">
|
||||
تجربهای متفاوت خلق کنید
|
||||
</h1>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-16 flex h-full flex-col items-center justify-center">
|
||||
@@ -97,30 +97,32 @@ const Hero212 = ({ className }: Hero212Props) => {
|
||||
<div className="relative z-10 mx-auto mt-10 mb-12 flex w-fit justify-center">
|
||||
<Button className="rounded-full px-4 py-2 active:scale-105">
|
||||
شروع رایگان
|
||||
</Button>
|
||||
</Button>
|
||||
{/* RTL: sit to the left of the button so handwriting doesn't cover it */}
|
||||
<motion.div
|
||||
initial={{ opacity: 0, translateY: 20 }}
|
||||
animate={{ opacity: 1, translateY: 0 }}
|
||||
transition={{ duration: 0.3, delay: 1 }}
|
||||
className="absolute top-3 -right-30 h-1"
|
||||
className="pointer-events-none absolute top-0 -left-36 flex w-40 flex-col items-center sm:-left-44 sm:w-44"
|
||||
>
|
||||
<p className="font-handwriting text-xl tracking-tight">
|
||||
<p className="font-handwriting text-center text-lg leading-snug tracking-tight sm:text-xl">
|
||||
همین امروز نسخه رایگان را امتحان کنید
|
||||
</p>
|
||||
</p>
|
||||
<svg
|
||||
width="82"
|
||||
className="-translate-x-1/2 pe-4"
|
||||
height="45"
|
||||
viewBox="0 0 82 45"
|
||||
className="-mt-1 -scale-x-100"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
aria-hidden
|
||||
>
|
||||
<motion.path
|
||||
initial={{ pathLength: 0 }}
|
||||
animate={{ pathLength: 1 }}
|
||||
transition={{ duration: 1, delay: 1.2 }}
|
||||
d="M80.2759 1.95576C67.8687 20.6075 49.1102 55.0246 21.9767 39.1283C15.3299 35.2342 12.7124 29.0489 9.38472 22.4634C9.24096 22.1789 6.96955 15.0574 7.91833 15.4904C10.4589 16.65 25.535 23.253 15.8013 18.8782C14.7716 18.4154 8.31018 14.0924 7.25323 14.6265C4.37354 16.0816 2.6512 30.2469 1.58546 33.4898"
|
||||
stroke="#1C1C1C"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.40332"
|
||||
strokeLinecap="round"
|
||||
/>
|
||||
|
||||
+93
-70
@@ -12,81 +12,99 @@ interface Hero213Props {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const Hero213 = ({ className }: Hero213Props) => {
|
||||
const images = [
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw12.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "Joanna Doe",
|
||||
},
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw13.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "مریم چناری",
|
||||
},
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw14.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "Joanna Doe",
|
||||
},
|
||||
];
|
||||
const IMAGES = [
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw12.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "Joanna Doe",
|
||||
},
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw13.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "مریم چناری",
|
||||
},
|
||||
{
|
||||
src: "/block-media/shadcnblocks/block/lummi/bw14.jpeg",
|
||||
alt: "تصویر نمونه",
|
||||
name: "Joanna Doe",
|
||||
},
|
||||
] as const;
|
||||
|
||||
const Hero213 = ({ className }: Hero213Props) => {
|
||||
const [currentIndex, setCurrentIndex] = useState(0);
|
||||
const nextIndex = (currentIndex + 1) % IMAGES.length;
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setCurrentIndex((prevIndex) => (prevIndex + 1) % images.length);
|
||||
setCurrentIndex((prev) => (prev + 1) % IMAGES.length);
|
||||
}, 2500);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [currentIndex, images.length]);
|
||||
}, [currentIndex]);
|
||||
|
||||
return (
|
||||
<section className={cn("py-32", className)}>
|
||||
<section className={cn("overflow-x-hidden py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="mx-auto flex max-w-2xl flex-col items-center justify-center gap-4">
|
||||
<h1 className="font-calSans text-center text-2xll lg:text-2xll">
|
||||
<h1 className="font-calSans text-center text-5xl leading-tight lg:text-6xl">
|
||||
مجموعه بلاکهای آماده <br />
|
||||
برای رابط کاربری و استایلدهی مدرن
|
||||
</h1>
|
||||
<p className="px-10 text-center text-muted-foreground lg:text-lg">
|
||||
صدها کامپوننت استاندارد و قابل سفارشیسازی که مستقیماً در پروژههای شما قابل استفاده هستند.
|
||||
</p>
|
||||
</h1>
|
||||
<p className="px-10 text-center leading-relaxed text-muted-foreground lg:text-lg">
|
||||
صدها کامپوننت استاندارد و قابل سفارشیسازی که مستقیماً در پروژههای
|
||||
شما قابل استفاده هستند.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-4">
|
||||
<div className="relative z-10 mx-auto my-7 flex w-fit cursor-pointer items-center justify-center gap-8 rounded-full bg-muted px-4 py-2 md:my-0 lg:translate-y-12 lg:py-3 xl:px-8 xl:py-4">
|
||||
<GalleryVerticalEnd className="size-4 opacity-40 hover:opacity-100 lg:size-6" />
|
||||
<Signature className="size-4 opacity-40 hover:opacity-100 lg:size-6" />
|
||||
<Figma className="size-4 opacity-40 hover:opacity-100 lg:size-6" />
|
||||
</div>
|
||||
<MaskedDiv maskType="type-3">
|
||||
<AnimatePresence mode="popLayout">
|
||||
<motion.img
|
||||
key={currentIndex}
|
||||
className="h-full w-full object-cover"
|
||||
src={images[currentIndex].src}
|
||||
alt={images[currentIndex].alt}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 1.5 }}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
</MaskedDiv>
|
||||
|
||||
<div className="absolute bottom-22 -left-8 hidden h-36 w-32 items-center justify-center overflow-hidden rounded-4xl border lg:flex xl:bottom-28 xl:h-42 2xl:-left-28 2xl:h-52 2xl:w-62 2xl:rounded-[4rem]">
|
||||
<AnimatePresence mode="popLayout">
|
||||
<motion.img
|
||||
key={currentIndex}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 1.5 }}
|
||||
src={images[currentIndex + 1]?.src || images[currentIndex].src}
|
||||
alt={images[currentIndex + 1]?.alt || images[currentIndex].alt}
|
||||
className="h-full w-full object-cover"
|
||||
/>
|
||||
</AnimatePresence>
|
||||
{/* Shared box = mask bounds, so the tile can sit in the cutout precisely */}
|
||||
<div className="relative w-full">
|
||||
<MaskedDiv maskType="type-3">
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.img
|
||||
key={currentIndex}
|
||||
className="absolute inset-0 size-full object-cover"
|
||||
src={IMAGES[currentIndex].src}
|
||||
alt={IMAGES[currentIndex].alt}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
</MaskedDiv>
|
||||
|
||||
{/*
|
||||
type-3 cutout ≈ left 0–12.5%, bottom pocket ≈ 29% of height.
|
||||
Tile sized under that so a white gutter remains vs the concave edge.
|
||||
left/bottom 0 align with the mask’s outer edges (like the reference).
|
||||
*/}
|
||||
<div
|
||||
className={cn(
|
||||
"absolute bottom-0 left-0 z-20 hidden overflow-hidden border border-border bg-background",
|
||||
"aspect-[4/5] w-[11.2%] min-w-[6.5rem] max-w-[15.5rem]",
|
||||
"rounded-[1.75rem] lg:block xl:rounded-[2.25rem] 2xl:rounded-[2.75rem]",
|
||||
)}
|
||||
>
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
<motion.img
|
||||
key={nextIndex}
|
||||
src={IMAGES[nextIndex].src}
|
||||
alt={IMAGES[nextIndex].alt}
|
||||
className="absolute inset-0 size-full object-cover"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: 0.8 }}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -103,7 +121,7 @@ interface SvgPath {
|
||||
}
|
||||
|
||||
interface MaskedDivProps {
|
||||
children: React.ReactElement<HTMLImageElement | HTMLVideoElement>;
|
||||
children: React.ReactNode;
|
||||
maskType?: MaskType;
|
||||
className?: string;
|
||||
backgroundColor?: string;
|
||||
@@ -121,9 +139,10 @@ const svgPaths: Record<MaskType, SvgPath> = {
|
||||
height: 381,
|
||||
width: 850,
|
||||
},
|
||||
// Height matches path bounds (max Y ≈ 765) so the cutout sits on the true bottom edge
|
||||
"type-3": {
|
||||
path: "M0.680664 112.659C0.680664 50.805 50.823 0.662672 112.677 0.662672H413.07C456.315 0.662672 497.495 19.1588 526.221 51.4846V51.4846C554.948 83.8104 596.128 102.307 639.373 102.307H711.793C752.427 102.307 790.787 83.5522 815.744 51.4846V51.4846C840.7 19.417 879.06 0.662644 919.695 0.662597L1225.01 0.66224C1286.86 0.662168 1337.01 50.8046 1337.01 112.658V652.815C1337.01 714.668 1286.86 764.811 1225.01 764.811L670 764.811H335.34H278.376C217.423 764.811 168.01 715.399 168.01 654.446V626.747C168.01 580.208 130.283 542.48 83.7437 542.48V542.48C37.8692 542.48 0.680664 505.292 0.680664 459.417V382.737V112.659Z",
|
||||
height: 889,
|
||||
height: 765,
|
||||
width: 1340,
|
||||
},
|
||||
"type-4": {
|
||||
@@ -133,6 +152,10 @@ const svgPaths: Record<MaskType, SvgPath> = {
|
||||
},
|
||||
};
|
||||
|
||||
function buildMaskDataUrl(mask: SvgPath): string {
|
||||
return `data:image/svg+xml,%3Csvg width='${mask.width}' height='${mask.height}' viewBox='0 0 ${mask.width} ${mask.height}' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='${mask.path}' fill='%23D9D9D9'/%3E%3C/svg%3E`;
|
||||
}
|
||||
|
||||
const MaskedDiv: React.FC<MaskedDivProps> = ({
|
||||
children,
|
||||
maskType = "type-1",
|
||||
@@ -141,30 +164,30 @@ const MaskedDiv: React.FC<MaskedDivProps> = ({
|
||||
size = 1,
|
||||
}) => {
|
||||
const selectedMask = svgPaths[maskType];
|
||||
|
||||
const svgString = `${selectedMask.width}${selectedMask.height}${selectedMask.width} ${selectedMask.height}${selectedMask.path}`;
|
||||
const maskUrl = buildMaskDataUrl(selectedMask);
|
||||
|
||||
const containerStyle: React.CSSProperties = {
|
||||
aspectRatio: `${selectedMask.width}/${selectedMask.height}`,
|
||||
aspectRatio: `${selectedMask.width} / ${selectedMask.height}`,
|
||||
backgroundColor,
|
||||
maskImage: `url("${svgString}")`,
|
||||
WebkitMaskImage: `url("${svgString}")`,
|
||||
maskImage: `url("${maskUrl}")`,
|
||||
WebkitMaskImage: `url("${maskUrl}")`,
|
||||
maskRepeat: "no-repeat",
|
||||
WebkitMaskRepeat: "no-repeat",
|
||||
maskSize: "contain",
|
||||
WebkitMaskSize: "contain",
|
||||
maskSize: "100% 100%",
|
||||
WebkitMaskSize: "100% 100%",
|
||||
maskPosition: "center",
|
||||
WebkitMaskPosition: "center",
|
||||
width: `${size * 100}%`,
|
||||
maxWidth: "100%",
|
||||
margin: "0 auto",
|
||||
marginInline: "auto",
|
||||
};
|
||||
|
||||
return (
|
||||
<section className={`relative ${className}`} style={containerStyle}>
|
||||
{React.cloneElement(children, {
|
||||
className: `w-full h-full object-cover transition-all duration-300 ${
|
||||
children.props.className || ""
|
||||
}`,
|
||||
})}
|
||||
</section>
|
||||
<div
|
||||
className={cn("relative overflow-hidden", className)}
|
||||
style={containerStyle}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user