some edit
This commit is contained in:
+34
-29
@@ -220,56 +220,61 @@ const Feature199 = ({ className }: Feature199Props) => {
|
||||
const handleScroll = () => {
|
||||
const container = containerRef.current;
|
||||
if (!container) return;
|
||||
const items = container.getElementsByClassName("feature-item");
|
||||
const containerMiddle = window.innerHeight * 0.6;
|
||||
|
||||
let closestItem: number | null = null;
|
||||
let closestDistance = Infinity;
|
||||
const rect = container.getBoundingClientRect();
|
||||
const listHeight = container.offsetHeight;
|
||||
const viewportHeight = window.innerHeight;
|
||||
const scrollRange = Math.max(listHeight - viewportHeight * 0.45, 1);
|
||||
const passed = Math.min(Math.max(-rect.top + viewportHeight * 0.2, 0), scrollRange);
|
||||
const progress = passed / scrollRange;
|
||||
const steppedIndex = Math.round(progress * (FEATURES.length - 1));
|
||||
const nextIndex = Math.min(Math.max(steppedIndex, 0), FEATURES.length - 1);
|
||||
|
||||
Array.from(items).forEach((item, index) => {
|
||||
const rect = item.getBoundingClientRect();
|
||||
const distance = Math.abs(rect.top + rect.height / 2 - containerMiddle);
|
||||
|
||||
if (distance < closestDistance) {
|
||||
closestDistance = distance;
|
||||
closestItem = index;
|
||||
}
|
||||
});
|
||||
|
||||
if (closestItem !== null) {
|
||||
setActiveFeature(closestItem);
|
||||
}
|
||||
setActiveFeature((prev) => (prev === nextIndex ? prev : nextIndex));
|
||||
};
|
||||
|
||||
window.addEventListener("scroll", handleScroll);
|
||||
handleScroll();
|
||||
window.addEventListener("scroll", handleScroll, { passive: true });
|
||||
return () => window.removeEventListener("scroll", handleScroll);
|
||||
}, [isMobile]);
|
||||
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<h2 className="mb-10 text-xl font-bold text-balance md:text-2xll lg:mb-20 lg:text-2xll">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn("min-w-0 overflow-x-hidden py-16 sm:py-24 lg:py-32", className)}
|
||||
>
|
||||
<div className="container min-w-0">
|
||||
<h2 className="mb-8 text-xl font-bold text-balance sm:mb-10 sm:text-2xl lg:mb-20 lg:text-3xl">
|
||||
هر سرنخ را تا قرارداد دنبال کنید
|
||||
</h2>
|
||||
<div className="relative gap-6 pb-72 md:grid md:grid-cols-5 md:pb-0">
|
||||
<div className="col-span-3 pb-4 text-start" ref={containerRef}>
|
||||
<div className="relative min-w-0 gap-6 pb-64 sm:pb-60 lg:grid lg:grid-cols-5 lg:pb-0">
|
||||
<div
|
||||
className="col-span-3 min-w-0 pb-4 text-start"
|
||||
ref={containerRef}
|
||||
>
|
||||
<Separator />
|
||||
{FEATURES.map((feature, index) => (
|
||||
<React.Fragment key={feature.id}>
|
||||
<div
|
||||
className="feature-item py-3"
|
||||
className="feature-item py-2.5 sm:py-3"
|
||||
onMouseEnter={() => !isMobile && setActiveFeature(index)}
|
||||
>
|
||||
<div className="flex items-center gap-7 md:gap-16 lg:gap-28">
|
||||
<div
|
||||
className={cn(
|
||||
"flex min-w-0 items-center gap-3 rounded-lg px-2 py-2 transition-colors sm:gap-5 sm:px-0 sm:py-0 lg:gap-16 xl:gap-28",
|
||||
activeFeature === index && "bg-muted/40 sm:bg-transparent",
|
||||
)}
|
||||
>
|
||||
<span
|
||||
className={cn(
|
||||
"invisible size-2.5 shrink-0 rounded-full bg-primary md:size-3",
|
||||
"invisible size-2 shrink-0 rounded-full bg-primary sm:size-2.5 lg:size-3",
|
||||
activeFeature === index && "visible",
|
||||
)}
|
||||
/>
|
||||
<p
|
||||
className={cn(
|
||||
"text-[clamp(1.65rem,3vw,2.15rem)] font-bold text-muted-foreground",
|
||||
"min-w-0 wrap-break-word text-base font-bold text-muted-foreground sm:text-lg md:text-xl lg:text-2xl xl:text-3xl",
|
||||
activeFeature === index && "text-primary",
|
||||
)}
|
||||
>
|
||||
@@ -281,11 +286,11 @@ const Feature199 = ({ className }: Feature199Props) => {
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
<div className="sticky bottom-3 start-3 col-span-2 h-72 w-fit border md:top-20 md:h-fit">
|
||||
<div className="fixed inset-x-3 bottom-3 z-20 mx-auto max-w-md border bg-background shadow-md md:sticky md:top-20 md:bottom-auto md:inset-x-auto md:col-span-2 md:mx-0 md:max-w-none md:h-fit md:w-fit md:shadow-none">
|
||||
<img
|
||||
src={FEATURES[activeFeature].image}
|
||||
alt={FEATURES[activeFeature].imageAlt}
|
||||
className="h-72 md:h-auto"
|
||||
className="h-44 w-full object-cover sm:h-52 md:h-72 md:w-auto md:object-fill"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+7
-14
@@ -153,7 +153,6 @@ const Feature216 = ({ className }: Feature216Props) => {
|
||||
const [buttonPosition, setButtonPosition] = useState<number>(0);
|
||||
// Rightmost tab in RTL (`justify-start`) is the first item.
|
||||
const [tabValue, setTabValue] = useState<TabValue>(TAB_ITEMS[0].value);
|
||||
const triggerRefs = useRef<HTMLButtonElement[]>([]);
|
||||
const imageRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const updateBottom = () => {
|
||||
@@ -178,10 +177,6 @@ const Feature216 = ({ className }: Feature216Props) => {
|
||||
};
|
||||
|
||||
const handleTabNavigation = (direction: "next" | "prev") => {
|
||||
triggerRefs.current.forEach((ref) => {
|
||||
ref.classList.add("grayscale-[1]", "opacity-[0.2]");
|
||||
});
|
||||
|
||||
const currentIndex = getCurrentTabIndex();
|
||||
if (currentIndex === -1) return;
|
||||
|
||||
@@ -207,21 +202,19 @@ const Feature216 = ({ className }: Feature216Props) => {
|
||||
<h2 className="mb-10 text-center text-3xl font-light text-balance md:text-xl">
|
||||
شاخصهای کلیدی را یکجا ببینید
|
||||
</h2>
|
||||
<Tabs value={tabValue} onValueChange={onValueChange} className="w-full">
|
||||
<Tabs
|
||||
dir="rtl"
|
||||
value={tabValue}
|
||||
onValueChange={onValueChange}
|
||||
className="w-full"
|
||||
>
|
||||
<TabsList className="hidden !h-auto w-full !justify-start items-end gap-12 bg-transparent pb-10 xl:flex">
|
||||
{TAB_ITEMS.map((trigger, index) => {
|
||||
const Icon = trigger.icon;
|
||||
|
||||
return (
|
||||
<TabsTrigger
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
triggerRefs.current[index] = el;
|
||||
} else {
|
||||
delete triggerRefs.current[index];
|
||||
}
|
||||
}}
|
||||
className="flex !h-auto flex-col items-center gap-5 !border-none !bg-transparent p-0 opacity-[0.2] !shadow-none grayscale-[1] hover:!bg-transparent hover:opacity-[0.5] hover:grayscale-[0] data-[state=active]:!bg-transparent data-[state=active]:opacity-100 data-[state=active]:!shadow-none data-[state=active]:grayscale-0 dark:!bg-transparent dark:data-[state=active]:!bg-transparent"
|
||||
className="flex !h-auto !flex-none shrink-0 flex-col items-center gap-5 !border-none !bg-transparent p-0 opacity-[0.2] !shadow-none grayscale hover:!bg-transparent hover:opacity-50 hover:grayscale-0 data-[state=active]:!bg-transparent data-[state=active]:opacity-100 data-[state=active]:!shadow-none data-[state=active]:grayscale-0 dark:!bg-transparent dark:data-[state=active]:!bg-transparent"
|
||||
key={trigger.id}
|
||||
value={trigger.value}
|
||||
data-index={index}
|
||||
|
||||
+11
-13
@@ -1,6 +1,5 @@
|
||||
import { ArrowRight } from "lucide-react";
|
||||
|
||||
import { AspectRatio } from "@/components/ui/aspect-ratio";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -32,13 +31,13 @@ const Feature220 = ({ className }: Feature220Props) => {
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-20",
|
||||
"flex min-h-full w-full min-w-0 flex-col justify-center bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-12 sm:py-16 lg:py-20",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container flex flex-wrap-reverse gap-12 lg:grid lg:grid-cols-[1fr_1.5fr] lg:gap-[7.5rem]">
|
||||
<div className="flex flex-col justify-between gap-20">
|
||||
<div className="mt-10 flex flex-col gap-5 text-start">
|
||||
<div className="container flex min-w-0 flex-col gap-8 px-4 sm:gap-10 sm:px-6 md:gap-12 lg:grid lg:grid-cols-[1fr_1.5fr] lg:gap-[7.5rem] lg:px-0">
|
||||
<div className="order-2 flex min-w-0 flex-col justify-between gap-10 sm:gap-14 md:gap-16 lg:order-1 lg:gap-20 lg:ps-12">
|
||||
<div className="flex flex-col gap-5 text-start md:mt-8 lg:mt-10">
|
||||
<h2 className="text-xl leading-none font-semibold tracking-tight text-balance md:text-2xll">
|
||||
از خرید تا فروش در یک سیستم
|
||||
</h2>
|
||||
@@ -53,7 +52,7 @@ const Feature220 = ({ className }: Feature220Props) => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="group flex w-full max-w-[30rem] flex-col gap-10 rounded-[.5rem] bg-background p-5 text-start transition-shadow hover:shadow-[0_0_2px_theme('colors.gray.300')]">
|
||||
<div className="group flex w-full max-w-full flex-col gap-10 rounded-[.5rem] bg-background p-5 text-start transition-shadow hover:shadow-[0_0_2px_theme('colors.gray.300')] sm:max-w-[30rem]">
|
||||
<div className="flex w-full flex-col gap-8 sm:flex-row">
|
||||
{STATS.map((item) => (
|
||||
<div className="flex flex-col gap-1" key={item.id}>
|
||||
@@ -67,21 +66,20 @@ const Feature220 = ({ className }: Feature220Props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full max-w-[46.5rem]">
|
||||
<AspectRatio
|
||||
ratio={0.873239437}
|
||||
className="overflow-hidden rounded-2xl"
|
||||
>
|
||||
<div className="order-1 w-full min-w-0 max-w-full pt-6 sm:pt-8 md:pt-8 lg:order-2 lg:max-w-[46.5rem] lg:pe-12 lg:pt-10">
|
||||
<div className="aspect-video max-h-80 overflow-hidden rounded-2xl sm:max-h-96 md:aspect-[4/3] md:max-h-none lg:aspect-[712/815]">
|
||||
<video
|
||||
src="/block-media/shadcnblocks/block/video-8.mp4"
|
||||
src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/video-8.mp4"
|
||||
className="block size-full object-cover object-center"
|
||||
loop
|
||||
autoPlay
|
||||
muted
|
||||
playsInline
|
||||
preload="metadata"
|
||||
controls={false}
|
||||
aria-label="عملیات سازمان را یکپارچه کنید"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
+22
-14
@@ -33,44 +33,52 @@ const Feature220a = ({ className }: Feature220aProps) => {
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-24",
|
||||
"flex min-h-full w-full min-w-0 flex-col justify-center overflow-x-hidden bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-12 sm:py-16 lg:py-24",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container max-w-5xl">
|
||||
<div className="mb-16 text-center">
|
||||
<div className="container min-w-0 max-w-5xl px-4 sm:px-6">
|
||||
<div className="mb-10 min-w-0 text-center sm:mb-16">
|
||||
<Badge variant="secondary" className="mb-6 px-4 py-2">
|
||||
هر تیم داشبورد خودش را داشته باشد
|
||||
</Badge>
|
||||
<h2 className="leading-tighter mb-6 text-2xll font-semibold tracking-tight text-balance lg:text-2xll">
|
||||
<h2 className="leading-tighter mb-6 text-balance text-xl font-semibold tracking-tight sm:text-2xll lg:text-2xll">
|
||||
روندها را زودتر از رقبا ببینید
|
||||
<span className="block text-primary">گزارشهایی که مدیران واقعاً استفاده میکنند</span>
|
||||
<span className="block text-primary">
|
||||
گزارشهایی که مدیران واقعاً استفاده میکنند
|
||||
</span>
|
||||
</h2>
|
||||
<p className="mx-auto mb-8 max-w-3xl text-xl leading-relaxed font-medium text-pretty text-muted-foreground">
|
||||
داشبوردهای تعاملی به تیمها اجازه میدهد سؤال جدید بپرسند بدون اینکه هر بار به تیم داده وابسته باشند.
|
||||
<p className="mx-auto mb-8 max-w-3xl text-base leading-relaxed font-medium text-pretty text-muted-foreground sm:text-xl">
|
||||
داشبوردهای تعاملی به تیمها اجازه میدهد سؤال جدید بپرسند بدون اینکه
|
||||
هر بار به تیم داده وابسته باشند.
|
||||
</p>
|
||||
<Button size="lg" className="gap-2 px-8 py-6 text-lg">
|
||||
<Button
|
||||
size="lg"
|
||||
className="h-auto max-w-full gap-2 px-6 py-4 text-base whitespace-normal sm:px-8 sm:py-6 sm:text-lg"
|
||||
>
|
||||
گزارش سفارشی را بدون SQL بسازید و سریع منتشر کنید.
|
||||
<ArrowRight className="size-4 rtl:rotate-180" />
|
||||
<ArrowRight className="size-4 shrink-0 rtl:rotate-180" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="mb-16">
|
||||
<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-3xl">
|
||||
<div className="mb-10 min-w-0 sm:mb-16">
|
||||
<AspectRatio ratio={16 / 9} className="overflow-hidden rounded-2xl sm:rounded-3xl">
|
||||
<video
|
||||
src="/block-media/shadcnblocks/block/video-8.mp4"
|
||||
src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/video-8.mp4"
|
||||
className="block size-full object-cover object-center"
|
||||
loop
|
||||
autoPlay
|
||||
muted
|
||||
playsInline
|
||||
preload="metadata"
|
||||
controls={false}
|
||||
aria-label="تصمیم استراتژیک را دادهمحور کنید"
|
||||
/>
|
||||
</AspectRatio>
|
||||
</div>
|
||||
|
||||
<div className="rounded-2xl bg-card p-8">
|
||||
<div className="grid grid-cols-1 gap-8 sm:grid-cols-3">
|
||||
<div className="min-w-0 rounded-2xl bg-card p-4 sm:p-8">
|
||||
<div className="grid min-w-0 grid-cols-1 gap-6 sm:grid-cols-3 sm:gap-8">
|
||||
{STATS.map((item) => (
|
||||
<div className="text-center" key={item.id}>
|
||||
<div className="mb-2 text-xl font-bold text-primary">
|
||||
|
||||
@@ -32,11 +32,11 @@ const Feature220b = ({ className }: Feature220bProps) => {
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-20",
|
||||
"flex min-h-full w-full min-w-0 flex-col justify-center overflow-x-hidden bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-12 sm:py-16 lg:py-20",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="container min-w-0 px-4 sm:px-6">
|
||||
<div className="mb-20 flex flex-wrap justify-center gap-12">
|
||||
{STATS.map((item) => (
|
||||
<div key={item.id} className="min-w-48 text-center">
|
||||
@@ -57,11 +57,13 @@ const Feature220b = ({ className }: Feature220bProps) => {
|
||||
className="overflow-hidden rounded-2xl"
|
||||
>
|
||||
<video
|
||||
src="/block-media/shadcnblocks/block/video-8.mp4"
|
||||
src="https://deifkwefumgah.cloudfront.net/shadcnblocks/block/video-8.mp4"
|
||||
className="block size-full object-cover object-center"
|
||||
loop
|
||||
autoPlay
|
||||
muted
|
||||
playsInline
|
||||
preload="metadata"
|
||||
controls={false}
|
||||
aria-label="هر سرنخ را تا قرارداد دنبال کنید"
|
||||
/>
|
||||
@@ -73,7 +75,9 @@ const Feature220b = ({ className }: Feature220bProps) => {
|
||||
فروش تیمتان را یکجا مدیریت کنید
|
||||
</h2>
|
||||
<p className="text-lg leading-[1.4] font-medium text-pretty text-muted-foreground md:text-xl">
|
||||
تمام تعاملات، سرنخها و قراردادها در یک فضای کاری متمرکز جمع میشود. تیم فروش بدون جابجایی بین ابزارها، سریعتر پیشبینی میکند و معاملات بیشتری میبندد.
|
||||
تمام تعاملات، سرنخها و قراردادها در یک فضای کاری متمرکز جمع
|
||||
میشود. تیم فروش بدون جابجایی بین ابزارها، سریعتر پیشبینی میکند
|
||||
و معاملات بیشتری میبندد.
|
||||
</p>
|
||||
<div className="pt-4">
|
||||
<Button size="lg" className="gap-2 px-8 py-6 text-lg">
|
||||
|
||||
+16
-15
@@ -64,41 +64,42 @@ const Feature221 = ({ className }: Feature221Props) => {
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-[length:3.125rem_3.125rem] bg-repeat py-32",
|
||||
"w-full min-w-0 bg-muted bg-[url('/block-media/shadcnblocks/block/patterns/dot-pattern-2.svg')] bg-size-[3.125rem_3.125rem] bg-repeat py-32",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container">
|
||||
<div className="container px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex w-full flex-col items-start justify-between gap-4 pb-16 lg:flex-row lg:items-end">
|
||||
<div className="flex w-full max-w-lg flex-1 flex-col items-start gap-5 text-start">
|
||||
<h2 className="text-[2rem] leading-none font-bold tracking-tight text-balance md:text-[2.75rem] lg:text-2xll">
|
||||
<h2 className="text-[2rem] leading-none font-bold tracking-tight text-balance md:text-[2.75rem]">
|
||||
پیشبینی درآمد را دقیقتر کنید
|
||||
</h2>
|
||||
<p className="w-full max-w-[30rem] text-[1.15rem] leading-normal font-medium text-pretty text-muted-foreground sm:text-xl">
|
||||
با یادآورهای هوشمند و اولویتبندی سرنخ، زمان تیم روی معاملات با احتمال بیشتر صرف میشود و چرخه فروش کوتاهتر میشود.
|
||||
با یادآورهای هوشمند و اولویتبندی سرنخ، زمان تیم روی معاملات با
|
||||
احتمال بیشتر صرف میشود و چرخه فروش کوتاهتر میشود.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Button className="gap-2 rounded-full">
|
||||
چرخه فروش را از سرنخ تا قرارداد در یک مسیر مشخص پیش ببرید. مدیران میتوانند گلوگاهها را ببینند و تیمها با اولویت درست روی معاملات ارزشمند تمرکز کنند.
|
||||
<ArrowRight className="size-4 rtl:rotate-180" />
|
||||
<div className="w-full lg:w-auto lg:shrink-0">
|
||||
<Button className="h-10 w-full gap-2 rounded-full px-4 lg:w-auto">
|
||||
شروع کنید
|
||||
<ArrowRight className="size-4 shrink-0 rtl:rotate-180" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid w-full grid-cols-1 grid-rows-[auto] gap-10 md:grid-cols-2">
|
||||
<div className="grid w-full grid-cols-1 gap-10 md:grid-cols-2">
|
||||
{FEATURES.map((feature) => (
|
||||
<Card
|
||||
key={feature.id}
|
||||
className="flex w-full flex-col justify-between gap-10 rounded-lg border bg-background p-5"
|
||||
className="flex w-full min-w-0 flex-col justify-between gap-10 rounded-lg border bg-background p-5"
|
||||
>
|
||||
<CardHeader className="flex w-full flex-col justify-between gap-4 p-0 lg:flex-row lg:items-center">
|
||||
<CardTitle className="flex w-fit items-center justify-start gap-2.5">
|
||||
<CardHeader className="flex w-full min-w-0 flex-row items-center justify-between gap-4 p-0">
|
||||
<CardTitle className="min-w-0 flex-1">
|
||||
<h3 className="text-[1.75rem] leading-none font-bold tracking-tight text-balance">
|
||||
{feature.title}
|
||||
</h3>
|
||||
</CardTitle>
|
||||
<Badge className="bg-muted">
|
||||
<p className="text-sm text-foreground">الگوهای موفق فروش را در کل سازمان تکرار کنید. داده لحظهای نشان میدهد کدام مرحله بیشترین افت تبدیل را دارد.</p>
|
||||
<Badge className="shrink-0 bg-muted px-2 py-0.5 text-xs text-foreground">
|
||||
ویژگی
|
||||
</Badge>
|
||||
</CardHeader>
|
||||
<CardContent className="p-0 text-start">
|
||||
@@ -106,7 +107,7 @@ const Feature221 = ({ className }: Feature221Props) => {
|
||||
{feature.description}
|
||||
</p>
|
||||
</CardContent>
|
||||
<CardFooter className="flex w-full items-end justify-between gap-5 p-0 lg:flex-row">
|
||||
<CardFooter className="flex w-full items-end justify-between gap-5 border-0 bg-transparent p-0 pb-5">
|
||||
<div className="flex-1">
|
||||
<Button size="sm" className="rounded-full">
|
||||
<a
|
||||
|
||||
@@ -118,7 +118,7 @@ const Card = ({ link, background, title, imageAlt, stats }: CardData) => {
|
||||
href={link}
|
||||
aria-label={title}
|
||||
style={{ backgroundImage: `url(${background})` }}
|
||||
className="before:content-[] relative min-h-auto w-full overflow-hidden rounded-lg bg-black/80 bg-cover bg-center bg-no-repeat p-5 transition-all duration-300 before:absolute before:start-0 before:top-0 before:z-10 before:block before:size-full before:bg-black/50 before:transition-all before:duration-300 hover:before:bg-black/30 sm:aspect-square md:aspect-auto md:min-h-120 md:max-w-120"
|
||||
className="before:content-[] relative min-h-auto w-full overflow-hidden rounded-lg bg-black/80 bg-cover bg-center bg-no-repeat p-5 transition-all duration-300 before:absolute before:start-0 before:top-0 before:z-10 before:block before:size-full before:bg-black/50 before:transition-all before:duration-300 hover:before:bg-black/30 sm:aspect-square md:aspect-auto md:min-h-120"
|
||||
>
|
||||
<span className="sr-only">{imageAlt}</span>
|
||||
<div className="relative z-20 flex size-full flex-col justify-between gap-20 text-start md:gap-16">
|
||||
@@ -150,9 +150,9 @@ interface Feature222Props {
|
||||
|
||||
const Feature222 = ({ className }: Feature222Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="grid gap-5 md:grid-cols-2 lg:grid-cols-3">
|
||||
<section dir="rtl" lang="fa" className={cn("w-full min-w-0 py-32", className)}>
|
||||
<div className="w-full px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid w-full grid-cols-1 gap-5 md:grid-cols-2 lg:grid-cols-3">
|
||||
{LIST.map((item) => (
|
||||
<Card key={item.id} {...item} />
|
||||
))}
|
||||
|
||||
+24
-21
@@ -120,10 +120,14 @@ const Feature224 = ({ className }: Feature224Props) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="flex w-full flex-col items-center justify-center gap-4">
|
||||
<h2 className="mx-auto max-w-87.5 text-center text-xl leading-none font-medium text-balance md:max-w-112.5 md:text-2xll lg:max-w-140 lg:text-2xll">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn("w-full min-w-0 overflow-x-hidden py-12 sm:py-20 lg:py-32", className)}
|
||||
>
|
||||
<div className="container min-w-0 px-4 sm:px-6">
|
||||
<div className="flex w-full min-w-0 flex-col items-center justify-center gap-4">
|
||||
<h2 className="mx-auto max-w-full text-center text-xl leading-none font-medium text-balance md:max-w-112.5 md:text-2xll lg:max-w-140 lg:text-2xll">
|
||||
فرایندها را استاندارد و سریع کنید
|
||||
</h2>
|
||||
</div>
|
||||
@@ -132,27 +136,27 @@ const Feature224 = ({ className }: Feature224Props) => {
|
||||
align: "start",
|
||||
direction: "rtl",
|
||||
}}
|
||||
className="w-full"
|
||||
className="w-full min-w-0 max-w-full"
|
||||
setApi={setApi}
|
||||
>
|
||||
<CarouselContent className="-ms-8 pt-20">
|
||||
<CarouselContent className="pt-12 sm:pt-20">
|
||||
{FEATURES.map((card) => (
|
||||
<CarouselItem
|
||||
key={card.id}
|
||||
className="ps-8 md:basis-1/2 lg:basis-1/3"
|
||||
className="min-w-0 basis-[85%] sm:basis-1/2 lg:basis-1/3"
|
||||
>
|
||||
<div className="p-1">
|
||||
<Card className="border-0 py-0 shadow-none dark:bg-background">
|
||||
<CardContent className="flex flex-col p-0">
|
||||
<div className="min-w-0 p-1">
|
||||
<Card className="min-w-0 border-0 py-0 shadow-none dark:bg-background">
|
||||
<CardContent className="flex min-w-0 flex-col p-0">
|
||||
<div
|
||||
style={{ backgroundImage: `url("${card.background}")` }}
|
||||
className="relative flex aspect-[0.935802469] w-full flex-col items-center justify-between overflow-hidden rounded-2xl bg-cover bg-center bg-no-repeat p-7"
|
||||
className="relative flex aspect-[0.935802469] w-full min-w-0 flex-col items-center justify-between overflow-hidden rounded-2xl bg-cover bg-center bg-no-repeat p-4 sm:p-7"
|
||||
role="img"
|
||||
aria-label={card.imageAlt}
|
||||
>
|
||||
<div className="flex size-full flex-1" />
|
||||
<div className="h-12 w-full">
|
||||
<div className="mx-auto mb-8 flex w-full max-w-60 items-center gap-4 rounded-full bg-primary px-3 py-2.5 shadow-xl dark:bg-background">
|
||||
<div className="h-12 w-full min-w-0">
|
||||
<div className="mx-auto mb-6 flex w-full max-w-full min-w-0 items-center gap-3 rounded-full bg-primary px-3 py-2.5 shadow-xl sm:mb-8 sm:max-w-60 sm:gap-4 dark:bg-background">
|
||||
<div className="shrink-0">
|
||||
<div className="flex -space-x-2 rtl:space-x-reverse">
|
||||
<div className="flex size-7 rounded-full border border-black bg-background dark:bg-primary">
|
||||
@@ -163,14 +167,14 @@ const Feature224 = ({ className }: Feature224Props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-sm font-medium text-white">
|
||||
<div className="min-w-0 text-sm font-medium text-white">
|
||||
{card.label}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex w-full flex-col gap-1 pt-6 text-start">
|
||||
<h3 className="text-xl font-medium text-balance text-foreground">
|
||||
<div className="flex w-full min-w-0 flex-col gap-1 pt-6 text-start">
|
||||
<h3 className="text-lg font-medium text-balance text-foreground sm:text-xl">
|
||||
{card.title}
|
||||
</h3>
|
||||
<p className="text-sm text-pretty text-muted-foreground">
|
||||
@@ -182,12 +186,11 @@ const Feature224 = ({ className }: Feature224Props) => {
|
||||
</div>
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<div className="mt-8 hidden items-center justify-center gap-4 md:flex">
|
||||
<CarouselPrevious className="static size-12 translate-y-0" />
|
||||
<CarouselNext className="static size-12 translate-y-0" />
|
||||
</CarouselContent> <div className="mt-8 hidden items-center justify-center gap-4 md:flex">
|
||||
<CarouselPrevious className="static size-12 translate-y-0 rtl:rotate-180" />
|
||||
<CarouselNext className="static size-12 translate-y-0 rtl:rotate-180" />
|
||||
</div>
|
||||
<div className="mt-6 flex w-full items-center gap-2 md:hidden">
|
||||
<div className="mt-6 flex w-full min-w-0 items-center gap-2 md:hidden">
|
||||
{Array.from({ length: FEATURES.length }).map((_, i) => (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
+12
-7
@@ -114,7 +114,7 @@ const Feature225 = ({ className }: Feature225Props) => {
|
||||
className={cn("w-full bg-background py-12 md:py-24 lg:py-32", className)}
|
||||
>
|
||||
<div className="container px-4 md:px-6">
|
||||
<div className="flex flex-col items-center justify-center space-y-4 text-center">
|
||||
<div className="flex w-full flex-col items-start space-y-4 text-right">
|
||||
<h2 className="text-3xl font-bold tracking-tighter text-balance sm:text-xl md:text-2xll">
|
||||
داده پراکنده را به تصمیم تبدیل کنید
|
||||
</h2>
|
||||
@@ -125,10 +125,11 @@ const Feature225 = ({ className }: Feature225Props) => {
|
||||
|
||||
<div className="mt-16">
|
||||
<Tabs
|
||||
dir="rtl"
|
||||
defaultValue={FEATURES[0].id}
|
||||
value={activeTab}
|
||||
onValueChange={setActiveTab}
|
||||
className="w-full"
|
||||
className="w-full min-w-0"
|
||||
>
|
||||
<div className="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4">
|
||||
{FEATURES.map((feature) => (
|
||||
@@ -141,8 +142,8 @@ const Feature225 = ({ className }: Feature225Props) => {
|
||||
onClick={() => setActiveTab(feature.id)}
|
||||
>
|
||||
<CardContent className="p-6">
|
||||
<div className="flex flex-col items-start space-y-2 text-start">
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="flex w-full flex-col items-start space-y-2 text-right">
|
||||
<div className="flex w-full items-center justify-start gap-2">
|
||||
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-primary/10">
|
||||
{feature.icon}
|
||||
</div>
|
||||
@@ -150,7 +151,7 @@ const Feature225 = ({ className }: Feature225Props) => {
|
||||
{feature.title}
|
||||
</h3>
|
||||
</div>
|
||||
<p className="text-sm text-pretty text-muted-foreground">
|
||||
<p className="w-full text-sm text-pretty text-muted-foreground">
|
||||
{feature.description}
|
||||
</p>
|
||||
</div>
|
||||
@@ -184,8 +185,12 @@ const Feature225 = ({ className }: Feature225Props) => {
|
||||
className="size-full object-cover"
|
||||
/>
|
||||
) : (
|
||||
<div className="flex size-full items-center justify-center bg-muted">
|
||||
<p className="text-muted-foreground">داده فروش، بازاریابی و پشتیبانی در داشبوردهای یکپارچه جمع میشود. مدیران بدون انتظار گزارش دستی، وضعیت واقعی کسبوکار را میبینند.</p>
|
||||
<div className="flex size-full items-center justify-center bg-muted p-6">
|
||||
<p className="text-right text-pretty text-muted-foreground">
|
||||
داده فروش، بازاریابی و پشتیبانی در داشبوردهای یکپارچه جمع
|
||||
میشود. مدیران بدون انتظار گزارش دستی، وضعیت واقعی
|
||||
کسبوکار را میبینند.
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+22
-15
@@ -10,19 +10,26 @@ interface Feature228Props {
|
||||
|
||||
const Feature228 = ({ className }: Feature228Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("bg-muted/50 py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="grid grid-cols-1 items-center gap-10 lg:grid-cols-2 lg:gap-0">
|
||||
<div className="text-start lg:pe-16">
|
||||
<h2 className="mb-5 text-2xll text-balance md:text-2xll md:leading-20">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"w-full min-w-0 overflow-x-hidden bg-muted/50 py-16 md:py-24 lg:py-32",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container px-4 sm:px-6 lg:px-8">
|
||||
<div className="grid w-full min-w-0 grid-cols-1 items-center gap-10 lg:grid-cols-2 lg:gap-12 xl:gap-16">
|
||||
<div className="min-w-0 text-start lg:pe-16">
|
||||
<h2 className="mb-5 text-xl leading-tight font-semibold text-balance md:text-2xll md:leading-20">
|
||||
با هوش مصنوعی سریعتر تصمیم بگیرید
|
||||
<br />
|
||||
کارهای تکراری را به AI بسپارید
|
||||
</h2>
|
||||
<p className="text-lg text-pretty text-muted-foreground">
|
||||
<p className="text-base text-pretty text-muted-foreground md:text-lg">
|
||||
مدلهای هوشمند الگوهای پنهان در داده فروش و پشتیبانی را پیدا میکنند. تیمها با پیشنهادهای عملی، سریعتر اقدام میکنند.
|
||||
</p>
|
||||
<div className="mt-12 grid gap-8 sm:grid-cols-2 sm:gap-10">
|
||||
<div className="mt-8 grid gap-6 sm:mt-12 sm:grid-cols-2 sm:gap-8 md:gap-10">
|
||||
<div>
|
||||
<span className="mb-4 grid size-12 place-items-center rounded-lg bg-muted-foreground/10">
|
||||
<Lightbulb />
|
||||
@@ -81,27 +88,27 @@ const Feature228 = ({ className }: Feature228Props) => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex h-full flex-col gap-6 sm:max-h-[440px] sm:flex-row xl:max-h-[550px]">
|
||||
<div className="flex flex-col gap-6">
|
||||
<div className="flex w-full min-w-0 flex-col gap-6 md:max-h-[440px] md:flex-row xl:max-h-[550px]">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-6">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/placeholder-2.svg"
|
||||
alt="تحلیل با AI"
|
||||
className="aspect-video rounded-2xl border border-border object-cover"
|
||||
className="aspect-video w-full rounded-2xl border border-border object-cover"
|
||||
/>
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/placeholder-3.svg"
|
||||
alt="دستیار هوش مصنوعی"
|
||||
className="ms-auto aspect-video flex-1 rounded-2xl border border-border object-cover sm:aspect-auto sm:w-2/3"
|
||||
className="aspect-video w-full rounded-2xl border border-border object-cover md:ms-auto md:aspect-auto md:w-2/3"
|
||||
/>
|
||||
</div>
|
||||
<div className="min-h-[580px] rounded-4xl border border-border p-2 sm:min-h-0 sm:max-w-56 sm:shrink-0 xl:max-w-72">
|
||||
<div className="mx-auto aspect-[9/16] w-full max-w-72 rounded-4xl border border-border p-2 md:mx-0 md:aspect-auto md:max-w-56 md:shrink-0 xl:max-w-72">
|
||||
<div className="flex h-full flex-col rounded-3xl border border-border bg-background px-1.5 pt-3 pb-1.5">
|
||||
<div className="mx-auto mb-3 h-4 w-16 rounded-full bg-muted-foreground/15 xl:h-5 xl:w-20" />
|
||||
<div className="flex-1">
|
||||
<div className="mx-auto mb-3 h-4 w-16 shrink-0 rounded-full bg-muted-foreground/15 xl:h-5 xl:w-20" />
|
||||
<div className="min-h-0 flex-1">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/placeholder-1.svg"
|
||||
alt="پیشنهادهای هوشمند"
|
||||
className="h-full rounded-2xl object-cover"
|
||||
className="size-full rounded-2xl object-cover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+20
-13
@@ -12,27 +12,34 @@ interface Feature234Props {
|
||||
|
||||
const Feature234 = ({ className }: Feature234Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("bg-background py-32", className)}>
|
||||
<div className="container flex flex-col items-center">
|
||||
<h1 className="font-inter mx-auto max-w-4xl text-center text-[70px] leading-[65px] font-semibold tracking-tighter text-balance lg:text-[85px] lg:leading-[86px]">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"w-full min-w-0 overflow-x-hidden bg-background py-12 sm:py-20 lg:py-32",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container flex min-w-0 flex-col items-center px-4 sm:px-6">
|
||||
<h1 className="font-inter mx-auto max-w-full text-center text-3xl leading-tight font-semibold tracking-tighter text-balance sm:text-5xl md:text-6xl lg:max-w-4xl lg:text-[85px] lg:leading-[86px]">
|
||||
عملیات سازمان را یکپارچه کنید
|
||||
</h1>
|
||||
<CardsContainer />
|
||||
<p className="font-inter mx-auto max-w-xl text-center text-lg font-medium text-pretty text-black">
|
||||
<p className="font-inter mx-auto max-w-xl text-center text-base font-medium text-pretty text-black sm:text-lg">
|
||||
گزارشهای یکپارچه نشان میدهد کدام بخش بیشترین تأثیر را روی سودآوری دارد.
|
||||
</p>
|
||||
<div className="mt-10 flex items-center gap-2">
|
||||
<div className="mt-8 flex w-full max-w-full flex-wrap items-center justify-center gap-2 sm:mt-10">
|
||||
<Button
|
||||
asChild
|
||||
variant="default"
|
||||
className="block h-fit w-fit rounded-full px-6 py-2 text-sm leading-loose"
|
||||
className="block h-auto max-w-full rounded-full px-5 py-2 text-sm leading-loose whitespace-normal"
|
||||
>
|
||||
<a href="#">از خرید تا فروش در یک سیستم</a>
|
||||
</Button>
|
||||
<Button
|
||||
asChild
|
||||
variant="secondary"
|
||||
className="block h-fit w-fit rounded-full px-6 py-2 text-sm leading-loose"
|
||||
className="block h-auto max-w-full rounded-full px-5 py-2 text-sm leading-loose whitespace-normal"
|
||||
>
|
||||
<a href="#">یکپارچگی</a>
|
||||
</Button>
|
||||
@@ -108,20 +115,20 @@ const CardsContainer = () => {
|
||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||
|
||||
return (
|
||||
<div className="my-16 ms-[50px] flex items-center justify-center lg:ms-0">
|
||||
<div className="my-10 flex w-full max-w-full items-center justify-center overflow-hidden sm:my-14 lg:my-16">
|
||||
{CARDS.map((card, index) => {
|
||||
const yOffset = Math.pow(Math.abs(index - 3), 1.2) * 12;
|
||||
const isHovered = hoveredIndex === index;
|
||||
const visibilityClasses =
|
||||
(index === 0 || index === 1 || index === 5 || index === 6
|
||||
? " hidden sm:hidden "
|
||||
? "hidden sm:hidden "
|
||||
: "") +
|
||||
(index === 0 || index === 6 ? "md:hidden " : "md:block ") +
|
||||
"lg:block";
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
className={visibilityClasses}
|
||||
className={cn("shrink-0", visibilityClasses)}
|
||||
key={card.id}
|
||||
onMouseEnter={() => setHoveredIndex(index)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
@@ -134,14 +141,14 @@ const CardsContainer = () => {
|
||||
>
|
||||
<div
|
||||
className={cn(
|
||||
"relative h-[176px] w-[177px] overflow-hidden rounded-3xl border",
|
||||
"relative h-28 w-28 overflow-hidden rounded-2xl border sm:h-36 sm:w-36 sm:rounded-3xl lg:h-[176px] lg:w-[177px]",
|
||||
index !== 0 && "-ms-7 sm:-ms-9 lg:-ms-[50px]",
|
||||
card.isDark
|
||||
? "mb-14 border-[#8b8b8b] bg-black shadow-2xl"
|
||||
? "mb-8 border-[#8b8b8b] bg-black shadow-2xl sm:mb-14"
|
||||
: "border-[#cecece] bg-[#f5f5f5] shadow-lg",
|
||||
)}
|
||||
style={{
|
||||
transform: `rotate(${card.rotate}deg)`,
|
||||
marginInlineStart: index === 0 ? "0px" : "-50px",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
|
||||
+41
-22
@@ -14,44 +14,63 @@ interface Feature236Props {
|
||||
|
||||
const Feature236 = ({ className }: Feature236Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("bg-background py-32", className)}>
|
||||
<div className="container flex flex-col items-center gap-10 md:gap-0">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"w-full min-w-0 overflow-x-hidden bg-background py-12 sm:py-20 lg:py-32",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container flex min-w-0 flex-col items-center gap-8 px-4 sm:gap-10 sm:px-6 md:gap-0">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="flex items-center justify-center gap-5 rounded-full px-5! py-5 text-sm font-medium text-muted-foreground"
|
||||
className="h-auto max-w-full gap-3 rounded-full px-4 py-4 text-sm font-medium whitespace-normal text-muted-foreground sm:gap-5 sm:px-5 sm:py-5"
|
||||
>
|
||||
<Group />
|
||||
تمام تعاملات، سرنخها و قراردادها در یک فضای کاری متمرکز جمع میشود. تیم فروش بدون جابجایی بین ابزارها، سریعتر پیشبینی میکند و معاملات بیشتری میبندد.
|
||||
<ArrowUpRight className="rtl:rotate-180" />
|
||||
<Group className="size-4 shrink-0 sm:size-5" />
|
||||
<span className="text-pretty">
|
||||
تمام تعاملات، سرنخها و قراردادها در یک فضای کاری متمرکز جمع میشود.
|
||||
تیم فروش بدون جابجایی بین ابزارها، سریعتر پیشبینی میکند و معاملات
|
||||
بیشتری میبندد.
|
||||
</span>
|
||||
<ArrowUpRight className="size-4 shrink-0 rtl:rotate-180" />
|
||||
</Button>
|
||||
|
||||
<BracketedBorder>
|
||||
<div className="mb-7 flex items-center justify-center gap-5 tracking-tight">
|
||||
<div className="relative flex items-center justify-center">
|
||||
<div className="mb-5 flex w-full min-w-0 max-w-2xl items-center justify-center gap-3 px-2 tracking-tight sm:mb-7 sm:gap-5 sm:px-4">
|
||||
<div className="relative flex shrink-0 items-center justify-center">
|
||||
<span className="absolute inline-block size-2 rounded-full bg-green-300" />
|
||||
<span className="absolute inline-block size-3 animate-ping rounded-full bg-green-300" />
|
||||
</div>
|
||||
<p>از اولین تماس تا تمدید قرارداد، هر مرحله فروش قابل ردیابی است. گزارشهای لحظهای به مدیران کمک میکند گلوگاهها را قبل از از دست دادن درآمد شناسایی کنند.</p>
|
||||
<p className="min-w-0 text-pretty text-sm text-muted-foreground sm:text-base">
|
||||
از اولین تماس تا تمدید قرارداد، هر مرحله فروش قابل ردیابی است.
|
||||
گزارشهای لحظهای به مدیران کمک میکند گلوگاهها را قبل از از دست
|
||||
دادن درآمد شناسایی کنند.
|
||||
</p>
|
||||
</div>
|
||||
<h1 className="max-w-xl px-4 text-center text-2xll font-semibold tracking-tighter text-balance text-foreground md:text-[90px] md:leading-22">
|
||||
<h1 className="max-w-full px-2 text-center text-3xl font-semibold tracking-tighter text-balance text-foreground sm:px-4 sm:text-4xl md:max-w-3xl md:text-5xl md:leading-tight lg:text-6xl xl:text-7xl">
|
||||
هر سرنخ را تا قرارداد دنبال کنید
|
||||
</h1>
|
||||
</BracketedBorder>
|
||||
<h2 className="text-3xl font-medium tracking-tighter text-foreground">
|
||||
|
||||
<h2 className="max-w-full px-2 text-center text-2xl font-medium tracking-tighter text-balance text-foreground sm:text-3xl">
|
||||
فروش تیمتان را یکجا مدیریت کنید
|
||||
</h2>
|
||||
<p className="max-w-2xl px-10 text-center text-pretty text-muted-foreground sm:mt-5 lg:text-xl">
|
||||
پروفایل یکپارچه مشتری، تاریخچه تماس و وضعیت معامله را همزمان نشان میدهد. تیمها با دید مشترک، هماهنگتر پیش میروند و نرخ تبدیل بالاتر میرود.
|
||||
<p className="max-w-2xl px-2 text-center text-pretty text-muted-foreground sm:mt-5 sm:px-6 lg:text-xl">
|
||||
پروفایل یکپارچه مشتری، تاریخچه تماس و وضعیت معامله را همزمان نشان
|
||||
میدهد. تیمها با دید مشترک، هماهنگتر پیش میروند و نرخ تبدیل بالاتر
|
||||
میرود.
|
||||
</p>
|
||||
<div className="flex flex-col gap-4 sm:mt-8 md:flex-row">
|
||||
<Button className="h-11 w-full rounded-xl sm:w-auto">
|
||||
<div className="flex w-full min-w-0 max-w-2xl flex-col gap-4 sm:mt-8 md:flex-row md:justify-center">
|
||||
<Button className="h-auto min-h-11 w-full rounded-xl px-4 py-2 whitespace-normal sm:w-auto">
|
||||
روابط مشتری را در یک نگاه ببینید
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-11 w-full gap-2 rounded-xl sm:w-auto"
|
||||
className="h-auto min-h-11 w-full gap-2 rounded-xl px-4 py-2 whitespace-normal sm:w-auto"
|
||||
>
|
||||
پایپلاین فروش را شفاف کنید
|
||||
<ArrowRight className="size-4 rtl:rotate-180" />
|
||||
<ArrowRight className="size-4 shrink-0 rtl:rotate-180" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -61,12 +80,12 @@ const Feature236 = ({ className }: Feature236Props) => {
|
||||
|
||||
const BracketedBorder = ({ children }: { children: ReactNode }) => (
|
||||
<motion.div
|
||||
initial={{ width: 0, opacity: 0 }}
|
||||
className="relative flex flex-col items-center justify-center sm:my-10 md:h-[500px] md:overflow-hidden"
|
||||
whileInView={{ width: "65vw", opacity: 1 }}
|
||||
initial={{ opacity: 0, scaleX: 0.85 }}
|
||||
className="relative flex w-full min-w-0 max-w-full flex-col items-center justify-center overflow-hidden sm:my-10 md:min-h-[500px]"
|
||||
whileInView={{ opacity: 1, scaleX: 1 }}
|
||||
viewport={{ once: true }}
|
||||
transition={{
|
||||
width: {
|
||||
scaleX: {
|
||||
type: "spring",
|
||||
stiffness: 50,
|
||||
damping: 20,
|
||||
@@ -86,7 +105,7 @@ const BracketedBorder = ({ children }: { children: ReactNode }) => (
|
||||
<Vector className="absolute start-1 bottom-1" />
|
||||
<Vector className="absolute end-1 bottom-1 -rotate-90" />
|
||||
</div>
|
||||
<div className="flex h-full w-screen flex-col items-center justify-center">
|
||||
<div className="flex w-full min-w-0 max-w-4xl flex-col items-center justify-center px-4 py-8 md:max-w-[65vw] md:py-12">
|
||||
{children}
|
||||
</div>
|
||||
</motion.div>
|
||||
|
||||
+50
-34
@@ -7,45 +7,53 @@ import { cn } from "@/lib/utils";
|
||||
|
||||
const Feature239 = () => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className="bg-background py-32">
|
||||
<div className="relative container flex flex-col items-center px-0! lg:pt-8">
|
||||
<DottedDiv>
|
||||
<div className="grid lg:grid-cols-2">
|
||||
<div className="flex w-full flex-col gap-8 px-10 py-20 text-start md:px-14">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className="w-full min-w-0 overflow-x-hidden bg-background py-12 sm:py-20 lg:py-32"
|
||||
>
|
||||
<div className="relative container flex min-w-0 flex-col items-center px-4 sm:px-6 lg:px-8 lg:pt-8">
|
||||
<DottedDiv className="w-full min-w-0">
|
||||
<div className="grid min-w-0 lg:grid-cols-2">
|
||||
<div className="flex w-full min-w-0 flex-col gap-6 px-2 py-10 text-start sm:gap-8 sm:px-6 sm:py-14 md:px-10 md:py-20 lg:px-14">
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="flex w-fit cursor-pointer items-center gap-4 rounded-full px-6 py-2 transition-all ease-in-out hover:gap-6"
|
||||
className="flex h-auto w-full max-w-full cursor-pointer items-start gap-3 rounded-full px-4 py-3 whitespace-normal transition-all ease-in-out hover:gap-4 sm:w-fit sm:items-center sm:px-6 sm:py-2"
|
||||
>
|
||||
<span className="text-sm font-medium tracking-tight text-muted-foreground">
|
||||
قوانین ساده تعریف کنید تا وظایف تکراری بدون دخالت دست انجام شود. تیم روی تصمیمهای مهم تمرکز میکند و سرعت اجرا بالاتر میرود.
|
||||
<span className="min-w-0 text-sm font-medium tracking-tight text-pretty text-muted-foreground">
|
||||
قوانین ساده تعریف کنید تا وظایف تکراری بدون دخالت دست انجام
|
||||
شود. تیم روی تصمیمهای مهم تمرکز میکند و سرعت اجرا بالاتر
|
||||
میرود.
|
||||
</span>
|
||||
<ChevronRight className="size-4! rtl:rotate-180" />
|
||||
<ChevronRight className="size-4 shrink-0 rtl:rotate-180" />
|
||||
</Badge>
|
||||
<h1 className="text-2xll font-semibold tracking-tighter text-balance md:text-2xll">
|
||||
<h1 className="text-2xl font-semibold tracking-tighter text-balance text-foreground sm:text-3xl md:text-2xll">
|
||||
فرایندها را استاندارد و سریع کنید
|
||||
<br />
|
||||
اتوماسیون را در کل سازمان یکپارچه کنید
|
||||
<br />
|
||||
خطای انسانی را در کارهای روزمره کم کنید
|
||||
</h1>
|
||||
<p className="tracking-tight text-pretty text-muted-foreground md:text-xl">
|
||||
فرایندهای بینتیمی را در یک بوم بصری طراحی کنید. هر مرحله قابل ردیابی است و گلوگاهها قبل از تأخیر جدی مشخص میشوند.
|
||||
<p className="tracking-tight text-pretty text-muted-foreground sm:text-lg md:text-xl">
|
||||
فرایندهای بینتیمی را در یک بوم بصری طراحی کنید. هر مرحله قابل
|
||||
ردیابی است و گلوگاهها قبل از تأخیر جدی مشخص میشوند.
|
||||
</p>
|
||||
<div className="flex w-full gap-2">
|
||||
<Button className="text-md h-12 w-fit rounded-full bg-primary px-10 text-primary-foreground">
|
||||
<div className="flex w-full flex-wrap gap-2">
|
||||
<Button className="text-md h-12 w-fit rounded-full bg-primary px-8 text-primary-foreground sm:px-10">
|
||||
شروع کنید
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
className="text-md h-12 w-12 rounded-full transition-all ease-in-out hover:rotate-45"
|
||||
className="text-md h-12 w-12 shrink-0 rounded-full transition-all ease-in-out hover:rotate-45"
|
||||
>
|
||||
<ArrowUpRight className="rtl:rotate-180" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<DottedDiv className="group size-full place-self-end p-4 lg:w-4/6">
|
||||
<div className="relative size-full bg-muted/50 p-4 transition-all ease-in-out group-hover:bg-muted">
|
||||
<div className="relative size-full overflow-hidden rounded-3xl">
|
||||
|
||||
<DottedDiv className="group min-w-0 place-self-end p-2 sm:p-4 lg:w-4/6">
|
||||
<div className="relative min-h-80 w-full bg-muted/50 p-3 transition-all ease-in-out group-hover:bg-muted sm:min-h-96 sm:p-4">
|
||||
<div className="relative size-full min-h-72 overflow-hidden rounded-2xl sm:min-h-80 sm:rounded-3xl">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/photos/simone-hutsch-5oYbG-sEImY-unsplash.jpg"
|
||||
alt="سازنده گردشکار"
|
||||
@@ -54,32 +62,40 @@ const Feature239 = () => {
|
||||
<div className="absolute inset-0 bg-linear-to-t from-black/70 to-transparent" />
|
||||
</div>
|
||||
|
||||
<div className="absolute top-4 -ms-4 flex size-full flex-col items-center justify-between p-10">
|
||||
<p className="flex w-full items-center text-xl tracking-tighter text-background">
|
||||
با اتصال ابزارهای موجود، داده بین سیستمها خودکار جریان پیدا میکند و نیاز به کپی دستی از بین میرود.
|
||||
<span className="mx-2 h-2.5 w-px bg-background" />
|
||||
قوانین ساده تعریف کنید تا وظایف تکراری بدون دخالت دست انجام شود. تیم روی تصمیمهای مهم تمرکز میکند و سرعت اجرا بالاتر میرود.
|
||||
<div className="absolute inset-0 flex flex-col items-center justify-between p-4 sm:p-6 lg:p-10">
|
||||
<p className="flex w-full min-w-0 flex-col gap-2 text-sm tracking-tighter text-pretty text-background sm:flex-row sm:items-center sm:text-base lg:text-xl">
|
||||
<span className="min-w-0">
|
||||
با اتصال ابزارهای موجود، داده بین سیستمها خودکار جریان
|
||||
پیدا میکند و نیاز به کپی دستی از بین میرود.
|
||||
</span>
|
||||
<span className="hidden h-2.5 w-px shrink-0 bg-background sm:block" />
|
||||
<span className="min-w-0">
|
||||
قوانین ساده تعریف کنید تا وظایف تکراری بدون دخالت دست
|
||||
انجام شود.
|
||||
</span>
|
||||
</p>
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<h2 className="text-center text-2xll font-semibold tracking-tight text-balance text-background">
|
||||
<div className="flex flex-col items-center justify-center px-2">
|
||||
<h2 className="text-center text-xl font-semibold tracking-tight text-balance text-background sm:text-2xl lg:text-2xll">
|
||||
کارهای تکراری را خودکار کنید
|
||||
<br />
|
||||
گردشکار تیم را بدون کد بسازید
|
||||
</h2>
|
||||
<div className="mt-2 h-1 w-6 rounded-full bg-background" />
|
||||
<p className="mt-10 max-w-sm px-2 text-center text-lg leading-5 font-light tracking-tighter text-pretty text-background/80">
|
||||
فرایندهای بینتیمی را در یک بوم بصری طراحی کنید. هر مرحله قابل ردیابی است و گلوگاهها قبل از تأخیر جدی مشخص میشوند.
|
||||
<p className="mt-6 max-w-sm text-center text-sm leading-5 font-light tracking-tighter text-pretty text-background/80 sm:mt-10 sm:text-lg">
|
||||
فرایندهای بینتیمی را در یک بوم بصری طراحی کنید. هر مرحله
|
||||
قابل ردیابی است و گلوگاهها قبل از تأخیر جدی مشخص
|
||||
میشوند.
|
||||
</p>
|
||||
</div>
|
||||
<a
|
||||
href="#"
|
||||
className="group mb-6 flex cursor-pointer flex-col items-center justify-center text-background"
|
||||
className="group mb-2 flex cursor-pointer flex-col items-center justify-center text-background sm:mb-6"
|
||||
>
|
||||
<ChevronUp
|
||||
size={30}
|
||||
className="transition-all ease-in-out group-hover:-translate-y-2"
|
||||
/>
|
||||
<p className="text-xl tracking-tight text-background">
|
||||
<p className="text-base tracking-tight text-background sm:text-xl">
|
||||
مشاهده همه
|
||||
</p>
|
||||
</a>
|
||||
@@ -102,11 +118,11 @@ const DottedDiv = ({
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
}) => (
|
||||
<div className={cn("relative", className)}>
|
||||
<div className="absolute top-4 -start-25 h-px w-[115%] bg-muted" />
|
||||
<div className="absolute bottom-4 -start-25 h-px w-[115%] bg-muted" />
|
||||
<div className="absolute -top-25 start-4 h-[130%] w-px bg-muted" />
|
||||
<div className="absolute -top-25 end-4 h-[130%] w-px bg-muted" />
|
||||
<div className={cn("relative min-w-0 overflow-hidden", className)}>
|
||||
<div className="absolute top-4 start-4 end-4 h-px bg-muted lg:end-auto lg:w-[115%] lg:-start-25" />
|
||||
<div className="absolute bottom-4 start-4 end-4 h-px bg-muted lg:end-auto lg:w-[115%] lg:-start-25" />
|
||||
<div className="absolute start-4 top-4 bottom-4 w-px bg-muted lg:top-auto lg:bottom-auto lg:h-[130%] lg:-top-25" />
|
||||
<div className="absolute end-4 top-4 bottom-4 w-px bg-muted lg:top-auto lg:bottom-auto lg:h-[130%] lg:-top-25" />
|
||||
<div className="absolute start-[12.5px] top-[12.5px] z-10 size-2 rounded-full bg-foreground" />
|
||||
<div className="absolute end-[12.5px] top-[12.5px] z-10 size-2 rounded-full bg-foreground" />
|
||||
<div className="absolute start-[12.5px] bottom-[12.5px] z-10 size-2 rounded-full bg-foreground" />
|
||||
|
||||
@@ -133,9 +133,9 @@ const Feature240 = () => {
|
||||
))}
|
||||
</CarouselContent>
|
||||
|
||||
<div className="mt-5 flex justify-end gap-3">
|
||||
<CarouselPrevious className="static size-12" />
|
||||
<CarouselNext variant="default" className="static size-12" />
|
||||
<div className="mt-5 flex justify-start gap-3">
|
||||
<CarouselPrevious className="static size-12 translate-y-0 rtl:rotate-180" />
|
||||
<CarouselNext variant="default" className="static size-12 translate-y-0 rtl:rotate-180" />
|
||||
</div>
|
||||
</Carousel>
|
||||
</div>
|
||||
|
||||
+5
-26
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { ChevronLeft, ChevronRight, Plus } from "lucide-react";
|
||||
import { ChevronRight, Plus } from "lucide-react";
|
||||
import React from "react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
Carousel,
|
||||
CarouselContent,
|
||||
CarouselItem,
|
||||
CarouselNext,
|
||||
CarouselPrevious,
|
||||
} from "@/components/ui/carousel";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -149,32 +151,9 @@ const Feature242 = ({ className }: Feature242Props) => {
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/*
|
||||
Embla RTL: scrollNext/scrollPrev are index-based, so default
|
||||
ChevronLeft→prev / ChevronRight→next feels reversed visually.
|
||||
Match arrow direction to movement by swapping handlers.
|
||||
*/}
|
||||
<div className="relative z-10 flex gap-2">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="icon"
|
||||
className="size-10 rounded-full"
|
||||
onClick={() => api?.scrollNext()}
|
||||
aria-label="اسلاید بعدی"
|
||||
>
|
||||
<ChevronLeft className="size-4" />
|
||||
</Button>
|
||||
<Button
|
||||
type="button"
|
||||
variant="default"
|
||||
size="icon"
|
||||
className="size-10 rounded-full"
|
||||
onClick={() => api?.scrollPrev()}
|
||||
aria-label="اسلاید قبلی"
|
||||
>
|
||||
<ChevronRight className="size-4" />
|
||||
</Button>
|
||||
<CarouselPrevious className="static size-10 translate-y-0 rtl:rotate-180" />
|
||||
<CarouselNext className="static size-10 translate-y-0 rtl:rotate-180" />
|
||||
</div>
|
||||
</div>
|
||||
</Carousel>
|
||||
|
||||
@@ -93,11 +93,11 @@ const Feature244 = () => {
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<div className="my-3 flex justify-end gap-3 pe-5">
|
||||
<CarouselPrevious className="static m-0 size-12 translate-y-0 p-0" />
|
||||
<div className="my-3 flex justify-start gap-3 ps-4 sm:ps-5">
|
||||
<CarouselPrevious className="static m-0 size-12 translate-y-0 p-0 rtl:rotate-180" />
|
||||
<CarouselNext
|
||||
variant="default"
|
||||
className="static size-12 translate-y-0"
|
||||
className="static size-12 translate-y-0 rtl:rotate-180"
|
||||
/>
|
||||
</div>
|
||||
</Carousel>
|
||||
|
||||
+15
-11
@@ -7,7 +7,7 @@ import { Card, CardContent } from "@/components/ui/card";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const handwrittenTextClasses =
|
||||
"flex gap-3 font-handwriting text-xs tracking-tight md:text-xl";
|
||||
"flex min-w-0 items-center gap-2 font-handwriting text-xs tracking-tight xl:gap-3 xl:text-xl";
|
||||
|
||||
const FEATURES = [
|
||||
{ id: "dark-mode", label: "ترافیک ارگانیک" },
|
||||
@@ -97,9 +97,13 @@ interface Feature245Props {
|
||||
|
||||
const Feature245 = ({ className }: Feature245Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("bg-background", className)}>
|
||||
<div className="relative container flex flex-col items-center overflow-hidden py-32">
|
||||
<div className="mx-auto max-w-3xl text-center">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn("relative w-full min-w-0 overflow-hidden bg-background", className)}
|
||||
>
|
||||
<div className="relative container flex min-w-0 flex-col items-center overflow-hidden py-16 md:py-24 lg:py-32">
|
||||
<div className="mx-auto w-full min-w-0 max-w-3xl px-4 text-center">
|
||||
<h1 className="text-2xll font-semibold tracking-tighter text-balance text-foreground md:text-2xll">
|
||||
رتبه کلمات کلیدی را پیگیری کنید
|
||||
</h1>
|
||||
@@ -107,8 +111,8 @@ const Feature245 = ({ className }: Feature245Props) => {
|
||||
تحلیل فنی، محتوا و رقبا در یک ابزار جمع میشود. تیم محتوا میداند روی کدام صفحه و کلمه باید تمرکز کند.
|
||||
</p>
|
||||
</div>
|
||||
<div className="relative z-10 mx-auto mt-12 min-h-full max-w-3xl md:w-1/2">
|
||||
<div className="absolute -start-52 z-10 hidden h-full flex-col items-end justify-between md:flex lg:-start-62">
|
||||
<div className="relative z-10 mx-auto mt-12 w-full min-w-0 max-w-3xl px-4 lg:w-1/2 lg:px-0">
|
||||
<div className="absolute -start-40 z-10 hidden h-full flex-col items-end justify-between xl:flex xl:-start-52 2xl:-start-62">
|
||||
{[0, 1, 2, 3].map((i) => (
|
||||
<motion.div
|
||||
key={FEATURES[i].id}
|
||||
@@ -129,7 +133,7 @@ const Feature245 = ({ className }: Feature245Props) => {
|
||||
</motion.div>
|
||||
))}
|
||||
</div>
|
||||
<div className="absolute -end-58 z-10 hidden h-full flex-col justify-between md:flex lg:-end-64">
|
||||
<div className="absolute -end-40 z-10 hidden h-full flex-col justify-between xl:flex xl:-end-52 2xl:-end-64">
|
||||
{[4, 5, 6, 7].map((i) => (
|
||||
<motion.div
|
||||
key={FEATURES[i].id}
|
||||
@@ -152,12 +156,12 @@ const Feature245 = ({ className }: Feature245Props) => {
|
||||
</div>
|
||||
|
||||
<motion.div
|
||||
initial={{ opacity: 0, y: 200 }}
|
||||
animate={{ opacity: 100, y: 0 }}
|
||||
initial={{ opacity: 0, y: 40 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ ease: [0.33, 1, 0.68, 1], duration: 0.8 }}
|
||||
className="relative z-0"
|
||||
className="relative z-0 w-full min-w-0"
|
||||
>
|
||||
<Card className="group h-130 w-full rounded-4xl border border-border bg-background p-2 shadow-none lg:p-3">
|
||||
<Card className="group aspect-[4/3] h-auto max-h-80 w-full rounded-4xl border border-border bg-background p-2 shadow-none sm:max-h-96 xl:h-130 xl:max-h-none xl:aspect-auto lg:p-3">
|
||||
<CardContent className="size-full rounded-3xl border-2 border-background bg-muted">
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/placeholder-1.svg"
|
||||
|
||||
+14
-10
@@ -24,10 +24,14 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
const div6Ref = useRef<HTMLDivElement>(null);
|
||||
const div7Ref = useRef<HTMLDivElement>(null);
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<div className="mx-auto flex max-w-5xl flex-wrap items-center justify-center gap-5">
|
||||
<Card className="relative h-96 w-166 rounded-3xl border">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn("relative w-full min-w-0 overflow-hidden py-16 md:py-24 lg:py-32", className)}
|
||||
>
|
||||
<div className="container min-w-0 px-4 sm:px-6">
|
||||
<div className="mx-auto flex w-full min-w-0 max-w-5xl flex-wrap items-center justify-center gap-5">
|
||||
<Card className="relative h-96 w-full min-w-0 overflow-hidden rounded-3xl border md:w-166">
|
||||
<CardHeader className="text-start">
|
||||
<h3 className="text-xl font-semibold tracking-tight text-balance">
|
||||
تریگر رویداد
|
||||
@@ -36,7 +40,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
شرط هوشمند
|
||||
</p>
|
||||
</CardHeader>
|
||||
<CardContent ref={containerRef1} className="relative ms-5">
|
||||
<CardContent ref={containerRef1} className="relative ms-2 overflow-hidden sm:ms-5">
|
||||
<IconCard
|
||||
ref={div1Ref as React.RefObject<HTMLDivElement>}
|
||||
src="/block-media/shadcnblocks/block/logos/google-icon.svg"
|
||||
@@ -47,7 +51,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
ref={div2Ref as React.RefObject<HTMLDivElement>}
|
||||
src="/block-media/shadcnblocks/block/logos/figma-icon.svg"
|
||||
imageAlt="نمای اتوماسیون فرایند"
|
||||
className="translate-x-32 rtl:-translate-x-32"
|
||||
className="translate-x-12 rtl:-translate-x-12 sm:translate-x-20 sm:rtl:-translate-x-20 md:translate-x-32 md:rtl:-translate-x-32"
|
||||
/>
|
||||
<IconCard
|
||||
ref={div3Ref as React.RefObject<HTMLDivElement>}
|
||||
@@ -59,7 +63,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
ref={div5Ref as React.RefObject<HTMLDivElement>}
|
||||
src="/block-media/shadcnblocks/block/block-1.svg"
|
||||
imageAlt="سازنده گردشکار"
|
||||
className="absolute end-12 top-1/2 -translate-y-1/2"
|
||||
className="absolute end-4 top-1/2 -translate-y-1/2 sm:end-8 md:end-12"
|
||||
/>
|
||||
<div
|
||||
ref={div4Ref as React.RefObject<HTMLDivElement>}
|
||||
@@ -94,7 +98,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="h-96 w-full rounded-3xl border md:w-83">
|
||||
<Card className="h-96 w-full min-w-0 overflow-hidden rounded-3xl border md:w-83">
|
||||
<CardHeader className="text-start">
|
||||
<h3 className="text-xl font-semibold tracking-tight text-balance">
|
||||
اعلان خودکار
|
||||
@@ -132,7 +136,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="relative flex h-96 w-full flex-col rounded-3xl border md:w-[330px]">
|
||||
<Card className="relative flex h-96 w-full min-w-0 flex-col overflow-hidden rounded-3xl border md:w-[330px]">
|
||||
<CardContent>
|
||||
<img
|
||||
src="/block-media/shadcnblocks/block/block-1.svg"
|
||||
@@ -149,7 +153,7 @@ const Feature251 = ({ className }: Feature251Props) => {
|
||||
</p>
|
||||
</CardHeader>
|
||||
</Card>
|
||||
<Card className="relative flex h-96 w-166 flex-col overflow-hidden rounded-3xl border">
|
||||
<Card className="relative flex h-96 w-full min-w-0 flex-col overflow-hidden rounded-3xl border md:w-166">
|
||||
<CardHeader className="relative z-10 shrink-0 text-start">
|
||||
<h3 className="text-xl font-semibold tracking-tight text-balance">
|
||||
اتصال ابزار
|
||||
|
||||
+26
-17
@@ -72,12 +72,19 @@ const Feature313 = ({
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("bg-muted py-24", className)}>
|
||||
<div className="container flex flex-col gap-2">
|
||||
<div className="grid grid-cols-1 gap-1 lg:grid-cols-4">
|
||||
<section
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn("relative w-full min-w-0 overflow-hidden bg-muted py-16 md:py-24", className)}
|
||||
>
|
||||
<div className="container flex min-w-0 flex-col gap-2 px-4 sm:px-6">
|
||||
<div className="grid w-full min-w-0 grid-cols-1 gap-1 lg:grid-cols-4">
|
||||
{cards.map((card, index) => (
|
||||
<Card key={card.id} className="border-none p-10 text-start shadow-none">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
<Card
|
||||
key={card.id}
|
||||
className="min-w-0 overflow-hidden border-none p-5 text-start shadow-none sm:p-8 lg:p-10"
|
||||
>
|
||||
<div className="flex min-w-0 items-center justify-between gap-2">
|
||||
<div className="flex gap-1">
|
||||
{cards.map((_, circleIndex) => (
|
||||
<div
|
||||
@@ -90,7 +97,7 @@ const Feature313 = ({
|
||||
{(index + 1).toLocaleString("fa-IR").padStart(2, "۰")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 md:flex-row md:justify-between">
|
||||
<div className="flex min-w-0 flex-col gap-4 md:flex-row md:justify-between">
|
||||
<div className="aspect-square size-12 shrink-0">
|
||||
<img
|
||||
src={card.image}
|
||||
@@ -99,7 +106,7 @@ const Feature313 = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-md leading-tight font-medium text-pretty">
|
||||
<h3 className="text-md leading-tight font-medium text-balance break-words">
|
||||
{card.title}
|
||||
</h3>
|
||||
</div>
|
||||
@@ -111,7 +118,7 @@ const Feature313 = ({
|
||||
<Dialog>
|
||||
<DialogTrigger asChild>
|
||||
<motion.div
|
||||
className="group relative aspect-video min-h-72 cursor-pointer overflow-hidden rounded-lg"
|
||||
className="group relative aspect-video w-full min-w-0 min-h-48 cursor-pointer overflow-hidden rounded-lg sm:min-h-72"
|
||||
whileHover="hover"
|
||||
initial="initial"
|
||||
>
|
||||
@@ -126,10 +133,10 @@ const Feature313 = ({
|
||||
<motion.img
|
||||
src={imageSrc}
|
||||
alt={imageAlt}
|
||||
className="h-full w-full rounded-lg object-cover"
|
||||
className="h-full w-full max-w-full rounded-lg object-cover"
|
||||
variants={{
|
||||
initial: { scale: 1 },
|
||||
hover: { scale: 1.1 },
|
||||
hover: isMobile ? { scale: 1 } : { scale: 1.1 },
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
/>
|
||||
@@ -148,7 +155,7 @@ const Feature313 = ({
|
||||
initial: { x: 0, scale: 1 },
|
||||
hover: {
|
||||
x: isMobile ? 0 : "-75%",
|
||||
scale: 1.2,
|
||||
scale: isMobile ? 1 : 1.2,
|
||||
},
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
@@ -163,18 +170,20 @@ const Feature313 = ({
|
||||
</motion.div>
|
||||
|
||||
<motion.div
|
||||
className="text-center md:text-start"
|
||||
className="min-w-0 text-center md:text-start"
|
||||
variants={{
|
||||
initial: { opacity: 1 },
|
||||
hover: { opacity: 0, transform: "-translate-y-3" },
|
||||
hover: isMobile
|
||||
? { opacity: 1 }
|
||||
: { opacity: 0, transform: "-translate-y-3" },
|
||||
}}
|
||||
transition={{ duration: 0.3, ease: "easeOut" }}
|
||||
>
|
||||
<div className="px-4 py-2">
|
||||
<p className="text-lg font-bold text-secondary">
|
||||
<div className="px-2 py-2 sm:px-4">
|
||||
<p className="text-base font-bold text-balance break-words text-secondary sm:text-lg">
|
||||
{videoCaption}
|
||||
</p>
|
||||
<p className="text-lg font-medium text-muted-foreground">
|
||||
<p className="text-base font-medium text-balance break-words text-muted-foreground sm:text-lg">
|
||||
{videoSecondaryCaption}
|
||||
</p>
|
||||
</div>
|
||||
@@ -183,7 +192,7 @@ const Feature313 = ({
|
||||
</div>
|
||||
</motion.div>
|
||||
</DialogTrigger>
|
||||
<DialogContent className="w-full border-none bg-black p-0 md:max-w-6xl md:p-1">
|
||||
<DialogContent className="w-[calc(100%-2rem)] max-w-[calc(100%-2rem)] border-none bg-black p-0 sm:w-full md:max-w-6xl md:p-1">
|
||||
<DialogTitle className="sr-only">{videoCaption}</DialogTitle>
|
||||
<DialogDescription className="sr-only">
|
||||
{videoSecondaryCaption} {videoCaption}
|
||||
|
||||
+36
-5
@@ -8,7 +8,7 @@ import {
|
||||
useScroll,
|
||||
useTransform,
|
||||
} from "framer-motion";
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { useLayoutEffect, useRef, useState } from "react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
@@ -228,11 +228,31 @@ const Feature322 = ({
|
||||
testimonial = DEFAULT_TESTIMONIAL,
|
||||
}: Feature322Props) => {
|
||||
const scrollRef = useRef<HTMLElement>(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));
|
||||
@@ -246,14 +266,21 @@ const Feature322 = ({
|
||||
dir="rtl"
|
||||
lang="fa"
|
||||
className={cn(
|
||||
"relative h-svh w-full min-w-[20rem] max-w-full overflow-x-clip overflow-y-auto sm:min-w-[36rem] lg:min-w-[64rem]",
|
||||
"relative h-svh max-h-full min-h-[28rem] w-full min-w-[20rem] max-w-full overflow-x-clip overflow-y-auto overscroll-contain sm:min-w-[36rem] lg:min-h-[32rem] lg:min-w-[64rem]",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="container min-w-0 w-full max-w-full">
|
||||
{/* Desktop: sticky stage + scroll spacer */}
|
||||
<div className="relative hidden lg:block">
|
||||
<div className="sticky top-0 flex h-svh w-full min-w-0 flex-col items-center justify-center">
|
||||
<div
|
||||
className="sticky top-0 z-10 flex w-full min-w-0 flex-col items-center justify-center"
|
||||
style={
|
||||
stageHeight > 0
|
||||
? { height: stageHeight }
|
||||
: { minHeight: "28rem" }
|
||||
}
|
||||
>
|
||||
<div className="relative w-full min-w-0 max-w-full">
|
||||
<AnimatePresence mode="wait" initial={false}>
|
||||
{activeFeature ? (
|
||||
@@ -279,8 +306,12 @@ const Feature322 = ({
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ height: `${Math.max(features.length, 1) * 75}vh` }}
|
||||
className="pointer-events-none w-full"
|
||||
style={
|
||||
scrollSpacerHeight
|
||||
? { height: scrollSpacerHeight }
|
||||
: { height: `${scrollSegmentCount * 75}vh` }
|
||||
}
|
||||
className="pointer-events-none w-full shrink-0"
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -70,7 +70,7 @@ const Feature52 = ({ className }: Feature52Props) => {
|
||||
return (
|
||||
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
||||
<div className="container">
|
||||
<Tabs defaultValue="feature-1">
|
||||
<Tabs defaultValue="feature-1" dir="rtl">
|
||||
<TabsList className="flex h-auto w-full flex-wrap items-stretch justify-between gap-2 bg-background p-0 group-data-horizontal/tabs:h-auto">
|
||||
{tabs.map((tab, index) => (
|
||||
<TabsTrigger
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
ArrowRight,
|
||||
ArrowLeft,
|
||||
Blocks,
|
||||
MessagesSquare,
|
||||
MoveRight,
|
||||
@@ -26,7 +26,7 @@ const Hero26 = ({ className }: Hero26Props) => {
|
||||
<Badge className="rounded-full">نسخه جدید</Badge>
|
||||
معرفی Collaboration 2.0
|
||||
<span className="flex size-7 items-center justify-center rounded-full bg-muted">
|
||||
<ArrowRight className="w-4" />
|
||||
<ArrowLeft className="w-4" />
|
||||
</span>
|
||||
</a>
|
||||
<h1 className="mx-auto mt-4 mb-3 max-w-3xl text-xl font-semibold text-balance lg:mb-7 lg:text-2xll">
|
||||
|
||||
+77
-41
@@ -8,21 +8,33 @@ import {
|
||||
Share2,
|
||||
Sparkles,
|
||||
Video,
|
||||
type LucideIcon,
|
||||
} from "lucide-react";
|
||||
|
||||
import { Marquee } from "@/components/ui/marquee";
|
||||
import {
|
||||
Marquee,
|
||||
MarqueeContent,
|
||||
MarqueeFade,
|
||||
MarqueeItem,
|
||||
} from "@/components/kibo-ui/marquee";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const integrations = [
|
||||
const integrations: {
|
||||
name: string;
|
||||
description: string;
|
||||
icon: LucideIcon;
|
||||
}[] = [
|
||||
{
|
||||
name: "ذخیرهسازی",
|
||||
description: "فایلهای ویدیویی خود را بهصورت امن در فضای ذخیرهسازی دلخواه مدیریت کنید.",
|
||||
description:
|
||||
"فایلهای ویدیویی خود را بهصورت امن در فضای ذخیرهسازی دلخواه مدیریت کنید.",
|
||||
icon: Cloud,
|
||||
},
|
||||
{
|
||||
name: "هوش مصنوعی",
|
||||
description: "با کمک هوش مصنوعی، تولید محتوای ویدیویی و تصویری را سرعت دهید.",
|
||||
description:
|
||||
"با کمک هوش مصنوعی، تولید محتوای ویدیویی و تصویری را سرعت دهید.",
|
||||
icon: Sparkles,
|
||||
},
|
||||
{
|
||||
@@ -37,7 +49,8 @@ const integrations = [
|
||||
},
|
||||
{
|
||||
name: "شبکههای اجتماعی",
|
||||
description: "ویدیوهای خود را تنها با چند کلیک در شبکههای اجتماعی منتشر کنید.",
|
||||
description:
|
||||
"ویدیوهای خود را تنها با چند کلیک در شبکههای اجتماعی منتشر کنید.",
|
||||
icon: Share2,
|
||||
},
|
||||
{
|
||||
@@ -47,6 +60,27 @@ const integrations = [
|
||||
},
|
||||
];
|
||||
|
||||
function IntegrationCard({
|
||||
name,
|
||||
description,
|
||||
icon: Icon,
|
||||
}: (typeof integrations)[number]) {
|
||||
return (
|
||||
<div
|
||||
dir="rtl"
|
||||
className="flex h-28 w-72 shrink-0 gap-2 rounded-lg border border-border p-4 text-right dark:bg-muted"
|
||||
>
|
||||
<Icon className="mt-0.5 size-4 shrink-0" />
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
||||
<p className="text-sm font-medium">{name}</p>
|
||||
<p className="line-clamp-3 text-sm text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface Hero40Props {
|
||||
className?: string;
|
||||
}
|
||||
@@ -59,10 +93,11 @@ const Hero40 = ({ className }: Hero40Props) => {
|
||||
<div className="flex flex-col gap-6">
|
||||
<h1 className="text-2xll font-bold">
|
||||
همه ابزارهای موردنیاز خود را یکپارچه کنید
|
||||
</h1>
|
||||
</h1>
|
||||
<p className="text-lg text-muted-foreground">
|
||||
تمام سرویسها و ابزارهای کاری خود را به یکدیگر متصل کنید و فرایند تولید و انتشار محتوا را سادهتر کنید.
|
||||
</p>
|
||||
تمام سرویسها و ابزارهای کاری خود را به یکدیگر متصل کنید و فرایند
|
||||
تولید و انتشار محتوا را سادهتر کنید.
|
||||
</p>
|
||||
<div className="flex gap-4">
|
||||
<Button variant="outline" size="lg">
|
||||
<span>مشاهده دمو</span>
|
||||
@@ -100,41 +135,42 @@ const Hero40 = ({ className }: Hero40Props) => {
|
||||
alt="تصویر نمونه"
|
||||
className="aspect-video w-full rounded-lg border border-border object-cover"
|
||||
/>
|
||||
<div className="relative flex w-full flex-col items-center justify-center overflow-hidden">
|
||||
<Marquee className="[--duration:30s]">
|
||||
{integrations.map((integration) => (
|
||||
<div
|
||||
key={integration.name}
|
||||
className="flex max-w-72 gap-2 rounded-lg border border-border p-4 dark:bg-muted"
|
||||
>
|
||||
<integration.icon className="mt-0.5 size-4 shrink-0" />
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm">{integration.name}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{integration.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<div
|
||||
dir="rtl"
|
||||
className="relative flex w-full flex-col items-center justify-center gap-4 overflow-hidden"
|
||||
>
|
||||
<Marquee className="w-full">
|
||||
<MarqueeContent
|
||||
direction="right"
|
||||
speed={40}
|
||||
loop={0}
|
||||
autoFill
|
||||
pauseOnHover={false}
|
||||
>
|
||||
{integrations.map((integration) => (
|
||||
<MarqueeItem key={`fwd-${integration.name}`}>
|
||||
<IntegrationCard {...integration} />
|
||||
</MarqueeItem>
|
||||
))}
|
||||
</MarqueeContent>
|
||||
</Marquee>
|
||||
<Marquee reverse className="[--duration:30s]">
|
||||
{integrations.map((integration) => (
|
||||
<div
|
||||
key={integration.name}
|
||||
className="flex max-w-72 gap-2 rounded-lg border border-border p-4 dark:bg-muted"
|
||||
>
|
||||
<integration.icon className="mt-0.5 size-4 shrink-0" />
|
||||
<div className="flex flex-col gap-2">
|
||||
<p className="text-sm">{integration.name}</p>
|
||||
<p className="text-sm text-muted-foreground">
|
||||
{integration.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<Marquee className="w-full">
|
||||
<MarqueeContent
|
||||
direction="right"
|
||||
speed={40}
|
||||
loop={0}
|
||||
autoFill
|
||||
pauseOnHover={false}
|
||||
>
|
||||
{integrations.map((integration) => (
|
||||
<MarqueeItem key={`rev-${integration.name}`}>
|
||||
<IntegrationCard {...integration} />
|
||||
</MarqueeItem>
|
||||
))}
|
||||
</MarqueeContent>
|
||||
</Marquee>
|
||||
<div className="pointer-events-none absolute inset-y-0 left-0 w-1/4 bg-gradient-to-r from-background"></div>
|
||||
<div className="pointer-events-none absolute inset-y-0 right-0 w-1/4 bg-gradient-to-l from-background"></div>
|
||||
<MarqueeFade side="left" />
|
||||
<MarqueeFade side="right" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { ArrowLeft } from "lucide-react";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -91,19 +93,20 @@ const Testimonial31 = ({
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="relative mt-8 -mr-[max(3rem,calc((100vw-80rem)/2+3rem))] md:mt-12 lg:mt-20">
|
||||
<div className="relative mt-8 -ml-[max(3rem,calc((100vw-80rem)/2+3rem))] md:mt-12 lg:mt-20">
|
||||
<Carousel
|
||||
opts={{
|
||||
align: "start",
|
||||
loop: true,
|
||||
direction: "rtl",
|
||||
}}
|
||||
className="w-full"
|
||||
>
|
||||
<CarouselContent>
|
||||
<CarouselContent className="-mr-4 ml-0">
|
||||
{testimonials.map((testimonial, index) => (
|
||||
<CarouselItem
|
||||
key={index}
|
||||
className="basis-4/5 sm:basis-3/5 md:basis-2/5 lg:basis-[28%] xl:basis-[28%] 2xl:basis-1/4"
|
||||
className="basis-4/5 pl-0 pr-4 sm:basis-3/5 md:basis-2/5 lg:basis-[28%] xl:basis-[28%] 2xl:basis-1/4"
|
||||
>
|
||||
<Card className="h-full overflow-hidden border-none bg-muted !pt-0">
|
||||
<CardContent className="flex h-full flex-col p-0">
|
||||
@@ -132,9 +135,9 @@ const Testimonial31 = ({
|
||||
</CarouselItem>
|
||||
))}
|
||||
</CarouselContent>
|
||||
<div className="mt-8 flex gap-3">
|
||||
<CarouselPrevious className="static size-14 translate-x-0 translate-y-0 bg-muted transition-colors hover:bg-muted/80 [&>svg]:size-6 lg:[&>svg]:size-8" />
|
||||
<CarouselNext className="static size-14 translate-x-0 translate-y-0 bg-muted transition-colors hover:bg-muted/80 [&>svg]:size-6 lg:[&>svg]:size-8" />
|
||||
<div className="mt-8 flex justify-start gap-3">
|
||||
<CarouselPrevious className="static size-14 translate-x-0 translate-y-0 bg-muted transition-colors hover:bg-muted/80 rtl:rotate-180 [&>svg]:size-6 lg:[&>svg]:size-8" />
|
||||
<CarouselNext className="static size-14 translate-x-0 translate-y-0 bg-muted transition-colors hover:bg-muted/80 rtl:rotate-180 [&>svg]:size-6 lg:[&>svg]:size-8" />
|
||||
</div>
|
||||
</Carousel>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user