504 lines
17 KiB
TypeScript
504 lines
17 KiB
TypeScript
"use client";
|
|
|
|
import { AnimatePresence, motion } from "framer-motion";
|
|
import { ArrowLeft, ArrowRight, MousePointer2 } from "lucide-react";
|
|
import React, { useState } from "react";
|
|
|
|
import { Button } from "@/components/ui/button";
|
|
import { Input } from "@/components/ui/input";
|
|
import { Label } from "@/components/ui/label";
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select";
|
|
import { Textarea } from "@/components/ui/textarea";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
interface Avatar {
|
|
image: string;
|
|
avatarClassName: string;
|
|
cursorClassName: string;
|
|
className?: string;
|
|
delay?: number;
|
|
}
|
|
|
|
const BookADemo2Avatar = ({
|
|
image,
|
|
avatarClassName,
|
|
cursorClassName,
|
|
className,
|
|
delay,
|
|
}: Avatar) => {
|
|
return (
|
|
<div className={cn("relative", className)}>
|
|
<motion.div
|
|
animate={{
|
|
x: [0, 10, 10, 0, 0],
|
|
y: [0, 0, -10, -10, 0],
|
|
}}
|
|
transition={{
|
|
duration: 10,
|
|
ease: "linear",
|
|
repeat: Infinity,
|
|
repeatType: "loop",
|
|
delay: delay ?? 0,
|
|
}}
|
|
className={cn(
|
|
"relative size-10 rounded-full border-2 p-[1px]",
|
|
avatarClassName,
|
|
)}
|
|
>
|
|
<MousePointer2
|
|
className={cn(
|
|
"absolute start-full bottom-full shrink-0 translate-x-2/5 translate-y-2/5 !delay-0",
|
|
cursorClassName,
|
|
)}
|
|
size={18}
|
|
/>
|
|
<img
|
|
src={image}
|
|
alt="آواتار"
|
|
className="size-full rounded-full object-cover"
|
|
/>
|
|
</motion.div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface Description {
|
|
text: string;
|
|
hyperlink: string;
|
|
url: string;
|
|
}
|
|
|
|
interface Header {
|
|
heading: string;
|
|
description: Description;
|
|
avatars: Avatar[];
|
|
}
|
|
|
|
const BookADemo2Header = ({ heading, description, avatars }: Header) => {
|
|
return (
|
|
<div className="relative flex w-full max-w-2xl flex-col items-center gap-4 text-center">
|
|
<h3 className="text-xl font-semibold sm:text-2xll md:text-2xll">
|
|
{heading}
|
|
</h3>
|
|
|
|
<p className="font-medium text-muted-foreground sm:text-lg md:text-xl">
|
|
<span>{description.text.split(description.hyperlink)[0]}</span>
|
|
<span className="text-foreground">
|
|
<a href={description.url} className="underline">
|
|
{description.hyperlink}
|
|
</a>
|
|
</span>
|
|
<span>{description.text.split(description.hyperlink)[1]}</span>
|
|
</p>
|
|
|
|
<div className="pointer-events-none absolute inset-0 hidden lg:block">
|
|
<BookADemo2Avatar
|
|
className="absolute bottom-full start-full"
|
|
{...avatars[0]}
|
|
/>
|
|
<BookADemo2Avatar
|
|
className="absolute top-full end-full"
|
|
delay={1}
|
|
{...avatars[1]}
|
|
/>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface FormGroupProps {
|
|
children: React.ReactNode;
|
|
className?: string;
|
|
}
|
|
|
|
const FormGroup = ({ children, className }: FormGroupProps) => {
|
|
return <div className={cn("flex flex-col gap-2", className)}>{children}</div>;
|
|
};
|
|
|
|
const BookADemo2ContactForm = () => {
|
|
return (
|
|
<div className="border-b p-8 lg:border-e lg:border-b-0">
|
|
<form className="grid grid-cols-2 gap-x-3 gap-y-6">
|
|
<FormGroup className="col-span-2 sm:col-span-1">
|
|
<Label>نام</Label>
|
|
<Input type="text" placeholder="علی" />
|
|
</FormGroup>
|
|
<FormGroup className="col-span-2 sm:col-span-1">
|
|
<Label>نام خانوادگی</Label>
|
|
<Input type="text" placeholder="محمدی" />
|
|
</FormGroup>
|
|
<FormGroup className="col-span-2">
|
|
<Label>ایمیل کاری</Label>
|
|
<Input
|
|
type="email"
|
|
placeholder="example@company.com"
|
|
dir="rtl"
|
|
className="text-start"
|
|
/>
|
|
</FormGroup>
|
|
<FormGroup className="col-span-2 sm:col-span-1">
|
|
<Label>تعداد اعضای تیم</Label>
|
|
<Select>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="۱–۱۰ نفر" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="1-10">۱–۱۰ نفر</SelectItem>
|
|
<SelectItem value="11-50">۱۱–۵۰ نفر</SelectItem>
|
|
<SelectItem value="51-100">۵۱–۱۰۰ نفر</SelectItem>
|
|
<SelectItem value="101-500">۱۱–۵۰۰ نفر</SelectItem>
|
|
<SelectItem value="501-1000">۵۱–۱۰۰۰ نفر</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</FormGroup>
|
|
<FormGroup className="col-span-2 sm:col-span-1">
|
|
<Label>سمت شغلی</Label>
|
|
<Select>
|
|
<SelectTrigger className="w-full">
|
|
<SelectValue placeholder="سمت شغلی خود را انتخاب کنید" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="CEO">مدیرعامل</SelectItem>
|
|
<SelectItem value="CTO">مدیر فناوری</SelectItem>
|
|
<SelectItem value="CFO">مدیر مالی</SelectItem>
|
|
<SelectItem value="Other">سایر</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</FormGroup>
|
|
<FormGroup className="col-span-2">
|
|
<Label>توضیحات</Label>
|
|
<Textarea
|
|
placeholder="درباره پروژه، چالشها، نیازها و انتظارات خود از این جلسه دمو توضیح دهید."
|
|
className="min-h-32"
|
|
/>
|
|
</FormGroup>
|
|
<Button type="submit" className="col-span-2 gap-2" size="lg">
|
|
ثبت درخواست
|
|
<ArrowRight className="rtl:rotate-180" />
|
|
</Button>
|
|
</form>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface Author {
|
|
name: string;
|
|
designation: string;
|
|
profilePicture: string;
|
|
}
|
|
|
|
interface Quote {
|
|
fullQuote: string;
|
|
highlightedWords: string[];
|
|
}
|
|
|
|
interface Testimonial {
|
|
companyLogo: string;
|
|
quote: Quote;
|
|
author: Author;
|
|
}
|
|
|
|
interface TestimonialsProps {
|
|
testimonials: Testimonial[];
|
|
}
|
|
|
|
const BookADemo2Testimonials = ({ testimonials }: TestimonialsProps) => {
|
|
const [activeTestimonial, setActiveTestimonial] = useState(0);
|
|
|
|
return (
|
|
<div className="relative flex h-full p-8">
|
|
<div className="absolute top-8 end-8 flex items-center gap-2">
|
|
<Button
|
|
size="sm"
|
|
aria-label="نظر قبلی"
|
|
onClick={() =>
|
|
setActiveTestimonial(
|
|
(activeTestimonial + testimonials.length - 1) %
|
|
testimonials.length,
|
|
)
|
|
}
|
|
>
|
|
<ArrowLeft className="rtl:rotate-180" />
|
|
</Button>
|
|
<Button
|
|
size="sm"
|
|
aria-label="نظر بعدی"
|
|
onClick={() =>
|
|
setActiveTestimonial((activeTestimonial + 1) % testimonials.length)
|
|
}
|
|
>
|
|
<ArrowRight className="rtl:rotate-180" />
|
|
</Button>
|
|
</div>
|
|
|
|
<AnimatePresence mode="wait">
|
|
{testimonials.map((testimonial, index) => {
|
|
if (index !== activeTestimonial) return null;
|
|
|
|
return (
|
|
<motion.div
|
|
initial={{
|
|
opacity: 0,
|
|
}}
|
|
animate={{
|
|
opacity: 1,
|
|
}}
|
|
exit={{
|
|
opacity: 0,
|
|
}}
|
|
transition={{
|
|
duration: 0.3,
|
|
ease: "easeInOut",
|
|
}}
|
|
key={`testimonial-${index}`}
|
|
className="flex h-full flex-col justify-between gap-12"
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<img
|
|
src={testimonial.companyLogo}
|
|
alt={`لوگوی شرکت ${testimonial.author.name}`}
|
|
className="h-6 w-auto object-contain md:h-8 dark:invert"
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-6">
|
|
<blockquote className="leading-snug text-muted-foreground sm:text-lg lg:max-w-md">
|
|
"
|
|
{testimonial.quote.fullQuote
|
|
.split(" ")
|
|
.map((word, wordIndex) => {
|
|
const isHighlighted =
|
|
testimonial.quote.highlightedWords.some((highlighted) =>
|
|
word
|
|
.toLowerCase()
|
|
.includes(highlighted.toLowerCase()),
|
|
);
|
|
return (
|
|
<span
|
|
key={wordIndex}
|
|
className={
|
|
isHighlighted ? "font-medium text-foreground" : ""
|
|
}
|
|
>
|
|
{word}{" "}
|
|
</span>
|
|
);
|
|
})}
|
|
"
|
|
</blockquote>
|
|
|
|
<div className="flex items-center gap-3">
|
|
<img
|
|
src={testimonial.author.profilePicture}
|
|
alt={testimonial.author.name}
|
|
className="size-9 rounded-full object-cover"
|
|
/>
|
|
<div>
|
|
<div className="text-sm font-medium">
|
|
{testimonial.author.name}
|
|
</div>
|
|
<div className="text-sm text-muted-foreground">
|
|
{testimonial.author.designation}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</motion.div>
|
|
);
|
|
})}
|
|
</AnimatePresence>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface Footer {
|
|
heading: string;
|
|
logos: string[];
|
|
}
|
|
|
|
const BookADemo2Footer = ({ heading, logos }: Footer) => {
|
|
return (
|
|
<div className="flex w-full max-w-6xl flex-col items-center gap-14 text-center">
|
|
<h3 className="text-sm font-medium text-muted-foreground">{heading}</h3>
|
|
<div className="flex w-full flex-wrap items-center justify-center gap-10 md:grid md:grid-cols-5">
|
|
{logos.map((logo, index) => {
|
|
return (
|
|
<img
|
|
key={`bookademo2-footer-logo-${index}`}
|
|
src={logo}
|
|
alt={`لوگوی شرکت ${index + 1}`}
|
|
className={cn(
|
|
"h-6 place-self-center object-contain md:h-8 dark:invert",
|
|
index > 5 && "hidden md:block",
|
|
)}
|
|
/>
|
|
);
|
|
})}
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|
|
|
|
interface BookADemo2Props {
|
|
className?: string;
|
|
header: Header;
|
|
testimonials: Testimonial[];
|
|
footer: Footer;
|
|
}
|
|
|
|
const BookADemo2 = ({
|
|
header = {
|
|
heading: "درخواست دمو",
|
|
description: {
|
|
text: "برای آشنایی با قابلیتهای پلتفرم، مشاهده سناریوهای واقعی و دریافت مشاوره تخصصی، درخواست دمو ثبت کنید. کارشناسان ما در کوتاهترین زمان با شما تماس خواهند گرفت.",
|
|
hyperlink: "با تیم ما در تماس باشید",
|
|
url: "https://ShadcnBlocks",
|
|
},
|
|
avatars: [
|
|
{
|
|
image:
|
|
"/block-media/shadcnblocks/block/portraits/christian-buehner-DItYlc26zVI-unsplash 1.jpg",
|
|
avatarClassName: "border-orange-500",
|
|
cursorClassName: "text-orange-500 fill-orange-500",
|
|
},
|
|
{
|
|
image:
|
|
"/block-media/shadcnblocks/block/portraits/christian-buehner-DItYlc26zVI-unsplash 1.jpg",
|
|
avatarClassName: "border-blue-500",
|
|
cursorClassName: "text-blue-500 fill-blue-500",
|
|
},
|
|
],
|
|
},
|
|
testimonials = [
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-1.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"این پلتفرم گردش کار توسعه ما را متحول کرده است. افزایش بهرهوری فوقالعاده بوده است.",
|
|
highlightedWords: ["متحول", "بهرهوری", "فوقالعاده"],
|
|
},
|
|
author: {
|
|
name: "علی رضایی",
|
|
designation: "توسعهدهنده ارشد",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/alexander-hipp-iEEBWgY_6lA-unsplash.jpg",
|
|
},
|
|
},
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-2.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"یکپارچهسازی بیدردسر بود و تیم ما در چند دقیقه آماده شد. برای استارتاپ ما یک تغییردهنده بازی بود.",
|
|
highlightedWords: ["بیدردسر", "دقیقه", "تغییردهنده"],
|
|
},
|
|
author: {
|
|
name: "محمد حسینی",
|
|
designation: "مدیر فناوری",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/christian-buehner-DItYlc26zVI-unsplash 1.jpg",
|
|
},
|
|
},
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-3.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"از زمان استفاده از این راهحل، زمان توسعه را ۴۰٪ کاهش دادهایم. بهشدت توصیه میکنم.",
|
|
highlightedWords: ["کاهش", "۴۰٪", "توصیه"],
|
|
},
|
|
author: {
|
|
name: "سارا احمدی",
|
|
designation: "مدیر مهندسی",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/good-faces-xmSWVeGEnJw-unsplash.jpg",
|
|
},
|
|
},
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-4.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"تجربه توسعهدهنده فوقالعاده است. پذیرش توسط تیم آنی بود و منحنی یادگیری بسیار کوتاه.",
|
|
highlightedWords: ["فوقالعاده", "آنی", "کوتاه"],
|
|
},
|
|
author: {
|
|
name: "داوود کریمی",
|
|
designation: "توسعهدهنده ارشد",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/joseph-gonzalez-iFgRcqHznqg-unsplash.jpg",
|
|
},
|
|
},
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-5.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"از زمان مهاجرت به این پلتفرم، فرکانس استقرار را ۶۰٪ بهبود دادهایم. واقعاً تحولآفرین است.",
|
|
highlightedWords: ["۶۰٪", "بهبود", "تحولآفرین"],
|
|
},
|
|
author: {
|
|
name: "مریم محمدی",
|
|
designation: "مهندس DevOps",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/good-faces-xmSWVeGEnJw-unsplash.jpg",
|
|
},
|
|
},
|
|
{
|
|
companyLogo:
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-6.svg",
|
|
quote: {
|
|
fullQuote:
|
|
"قابلیتهای همکاری نحوه کار تیم دورکار ما را متحول کرده است. انگار کل تیم در یک اتاق حضور دارند.",
|
|
highlightedWords: ["همکاری", "متحول", "اتاق"],
|
|
},
|
|
author: {
|
|
name: "امیر نوری",
|
|
designation: "مدیر محصول",
|
|
profilePicture:
|
|
"/block-media/shadcnblocks/block/portraits/nima-motaghian-nejad-_omdf_EgRUo-unsplash.jpg",
|
|
},
|
|
},
|
|
],
|
|
footer = {
|
|
heading: "انتخاب تیمهای توسعه نرمافزار در سراسر جهان",
|
|
logos: [
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-1.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-2.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-3.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-4.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-5.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-6.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-7.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-8.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-9.svg",
|
|
"/block-media/shadcnblocks/block/logos/company/fictional-company-logo-10.svg",
|
|
],
|
|
},
|
|
className,
|
|
}: BookADemo2Props) => {
|
|
return (
|
|
<section dir="rtl" lang="fa" className={cn("py-32", className)}>
|
|
<div className="container">
|
|
<div className="flex flex-col items-center gap-12 lg:gap-24">
|
|
<BookADemo2Header {...header} />
|
|
<div className="grid max-w-6xl grid-cols-1 rounded-lg border lg:grid-cols-2">
|
|
<BookADemo2ContactForm />
|
|
<BookADemo2Testimonials testimonials={testimonials} />
|
|
</div>
|
|
<BookADemo2Footer {...footer} />
|
|
</div>
|
|
</div>
|
|
</section>
|
|
);
|
|
};
|
|
|
|
export { BookADemo2 };
|