لندینگِ نرمافزارِ کلینیک
پیشنمایش تمامصفحهلندینگِ گرم و قهوهای: هیروی تمامعرض روی عکس با ردیفِ کلینیکها، جذب/تبدیل/بازگشت با عکس، پنلِ قهوهای با زبانههایی که عکس را عوض میکنند، موتورِ درآمد با آمار، نوارِ امنیت و فراخوان روی عکس.
۱. نصب کامپوننتها
این بلاک از ۴ آیتم دیگ استفاده میکند: buttoncontrol-sizeiconsreveal
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/reveal.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/reveal.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/reveal.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/reveal.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
landing-clinic.tsx
"use client";
import * as React from "react";
import {
CalendarIcon,
ChatIcon,
CheckCircleIcon,
CreditCardIcon,
FileTextIcon,
PhoneIcon,
PlayIcon,
ShieldCheckIcon,
SparklesIcon,
UsersIcon,
} from "@/components/icons";
import { Button } from "@/components/ui/button";
import { ControlSizeProvider } from "@/components/ui/control-size";
import { Reveal } from "@/components/ui/reveal";
import { cn } from "@/lib/utils";
import { stockImages, type StockImageName } from "@/lib/stock-images";
const BROWN = "bg-[var(--dig-orange-950)]";
const PARTNERS = [
"درمانگاهِ مهر",
"سلامتِ نو",
"کلینیکِ آرین",
"دندانپزشکیِ لبخند",
"فیزیوتراپیِ نیک",
"آزمایشگاهِ پارس",
];
const PILLARS: { title: string; text: string; photo: StockImageName }[] = [
{
title: "جذب",
text: "هر تماس، پیام و فرمِ سایت ۲۴ ساعته جواب میگیرد و به نوبت تبدیل میشود.",
photo: "womanPhoneCall",
},
{
title: "تبدیل",
text: "معرفینامهها خوانده و دستهبندی میشوند و بیمار همان روز نوبت میگیرد.",
photo: "teamReviewingDocs",
},
{
title: "بازگشت",
text: "بیمارهای غایب و نوبتهای لغوشده خودکار پیگیری میشوند.",
photo: "clinicReception",
},
];
const TABS = [
{
id: "inbound",
label: "پذیرشِ تلفنی",
text: "پاسخ به تماسها، رزرو و جابهجاییِ نوبت، پرسشِ بیمه و هدایتِ موارد فوری به پزشک؛ بدونِ صفِ انتظار.",
photo: "callCenter" as StockImageName,
},
{
id: "docs",
label: "مدارک و ارجاع",
text: "نامههای ارجاع، نتایجِ آزمایش و فرمهای بیمه خوانده و به پروندهٔ درست وصل میشوند.",
photo: "teamReviewingDocs" as StockImageName,
},
{
id: "outbound",
label: "پیگیریِ بیماران",
text: "یادآوریِ نوبت، پیگیریِ پس از درمان و دعوتِ بیمارهای غایب، با پیامک و تماس.",
photo: "womanLaptopSofa" as StockImageName,
},
];
const ENGINE = [
{
icon: <CalendarIcon />,
title: "مدیریتِ نوبت",
text: "رزرو، جابهجایی و یادآوری، هماهنگ با تقویمِ پزشکان.",
},
{
icon: <UsersIcon />,
title: "ارجاعها",
text: "هر ارجاع همان روز بررسی و نوبتدهی میشود.",
},
{
icon: <CreditCardIcon />,
title: "صورتحساب و بیمه",
text: "استعلامِ بیمه و پیشفاکتور پیش از مراجعه.",
},
{
icon: <ChatIcon />,
title: "پشتیبانیِ ۲۴ ساعته",
text: "پاسخ به پرسشهای بیمار، حتی ساعتِ سه صبح.",
},
];
/**
* لندینگِ نرمافزارِ پذیرشِ کلینیک، گرم و قهوهای روی کرم: هیروی تمامعرض روی عکسِ واقعی با
* تیترِ بزرگ و دو دکمه و ردیفِ کلینیکها، سه ستونِ جذب/تبدیل/بازگشت با عکس، پنلِ قهوهای با
* زبانههای قابلیت که عکس را عوض میکنند، موتورِ درآمد با آمار و چهار قابلیت، نوارِ امنیت و
* فراخوانِ پایانی روی عکس.
*/
export default function LandingClinicBlock() {
const [tab, setTab] = React.useState(TABS[0].id);
const current = TABS.find((item) => item.id === tab) ?? TABS[0];
return (
<ControlSizeProvider size="xl" asChild>
<main className="flex w-full flex-col bg-[var(--dig-amber-50)] dark:bg-[var(--dig-graphite-950)]">
<section className="relative isolate flex min-h-[38rem] flex-col justify-end overflow-hidden px-4 pt-32 text-[var(--dig-white)] sm:px-6">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img
src={stockImages.womanPhoneCall.src}
alt=""
className="absolute inset-0 -z-20 size-full object-cover object-[20%_25%]"
/>
<span
aria-hidden
className="absolute inset-0 -z-10 bg-[linear-gradient(270deg,color-mix(in_oklab,var(--dig-orange-950)_88%,transparent)_30%,transparent_75%),linear-gradient(0deg,color-mix(in_oklab,var(--dig-orange-950)_80%,transparent),transparent_35%)]"
/>
<div className="mx-auto flex w-full max-w-6xl flex-col items-start gap-5 pb-14">
<h1 className="max-w-lg text-4xl leading-tight font-bold text-balance sm:text-6xl sm:leading-tight">
پذیرشی که خودش میچرخد
</h1>
<p className="max-w-md text-lg leading-8 text-[var(--dig-orange-100)]">
از پاسخِ تلفن تا پیگیریِ ارجاع و بازگرداندنِ بیمار؛ کلینیک بیوقفه
کار میکند و تیم روی درمان تمرکز.
</p>
<div className="flex flex-wrap gap-3">
<Button
radius="full"
className="[--primary-foreground:var(--dig-orange-950)] [--primary:var(--dig-white)]"
>
رزروِ دمو
</Button>
<Button
radius="full"
variant="outline"
className="border-[var(--dig-orange-200)] bg-transparent text-[var(--dig-white)] hover:bg-[var(--dig-orange-900)]"
>
<PlayIcon />
امتحانش کنید
</Button>
</div>
</div>
<ul
aria-label="کلینیکهای همکار"
className="mx-auto flex w-full max-w-6xl flex-wrap justify-center gap-x-10 gap-y-3 border-t border-[color-mix(in_oklab,var(--dig-white)_20%,transparent)] py-6 text-sm font-semibold text-[var(--dig-orange-100)] sm:justify-between"
>
{PARTNERS.map((name) => (
<li key={name}>{name}</li>
))}
</ul>
</section>
<section
aria-labelledby="lcl-scale"
className="mx-auto flex w-full max-w-6xl flex-col gap-10 px-4 py-24 sm:px-6"
>
<div className="flex flex-col items-center gap-3 text-center">
<h2 id="lcl-scale" className="text-3xl font-bold sm:text-4xl">
کلینیک را بزرگ کنید
</h2>
<p className="text-muted-foreground">
کارهای روزمره ساده شود تا وقتتان به چیزهای مهم برسد.
</p>
</div>
<ul className="grid grid-cols-1 gap-px overflow-hidden rounded-xl border border-border bg-border md:grid-cols-3">
{PILLARS.map((item, index) => (
<Reveal asChild key={item.title} delay={index * 100}>
<li className="flex flex-col gap-4 bg-card p-4">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img
src={stockImages[item.photo].src}
alt=""
className="aspect-[4/3] w-full rounded-lg object-cover"
/>
<h3 className="text-lg font-bold">{item.title}</h3>
<p className="text-sm leading-6 text-muted-foreground">
{item.text}
</p>
</li>
</Reveal>
))}
</ul>
</section>
<section aria-labelledby="lcl-platform" className="px-4 sm:px-6">
<div
className={cn(
"mx-auto grid w-full max-w-6xl grid-cols-1 overflow-hidden rounded-xl text-[var(--dig-white)] lg:grid-cols-2",
BROWN,
)}
>
<div className="relative min-h-80">
{TABS.map((item) => (
// eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ
<img
key={item.id}
src={stockImages[item.photo].src}
alt={item.id === tab ? stockImages[item.photo].alt : ""}
aria-hidden={item.id !== tab}
className={cn(
"absolute inset-0 size-full object-cover transition-[opacity] duration-700",
item.id !== tab && "[opacity:0]",
)}
/>
))}
</div>
<div className="flex flex-col justify-center gap-8 p-8 sm:p-12">
<h2
id="lcl-platform"
className="text-3xl leading-snug font-bold sm:text-4xl"
>
یک سامانهٔ یکپارچه برای پذیرش
</h2>
<div
role="tablist"
aria-label="قابلیتها"
className="flex flex-col gap-2"
>
{TABS.map((item) => (
<Button
key={item.id}
role="tab"
variant="link"
aria-selected={item.id === tab}
onClick={() => setTab(item.id)}
className={cn(
"h-auto justify-start p-0 text-xl font-bold no-underline hover:no-underline",
item.id === tab
? "text-[var(--dig-white)]"
: "text-[var(--dig-orange-300)] hover:text-[var(--dig-orange-100)]",
)}
>
{item.label}
</Button>
))}
</div>
<p
aria-live="polite"
className="max-w-md leading-7 text-[var(--dig-orange-100)]"
>
{current.text}
</p>
<Button
radius="full"
className="self-start [--primary-foreground:var(--dig-orange-950)] [--primary:var(--dig-white)]"
>
رزروِ دمو
</Button>
</div>
</div>
</section>
<section
aria-labelledby="lcl-engine"
className="mx-auto grid w-full max-w-6xl grid-cols-1 gap-12 px-4 py-24 sm:px-6 lg:grid-cols-[1fr_1.4fr]"
>
<div className="flex flex-col gap-6">
<h2
id="lcl-engine"
className="text-3xl leading-snug font-bold sm:text-4xl"
>
موتورِ درآمدِ پذیرش
</h2>
<p className="leading-7 text-muted-foreground">
همهٔ کارهای پذیرش، امروز و خودکار.
</p>
<dl className="flex flex-col gap-5">
{[
["٪۷۱", "کاهشِ تماسهای بیپاسخ"],
["٪۹۹", "کاهشِ زمانِ انتظار پشتِ خط"],
["۲×", "تبدیلِ ارجاع به نوبت"],
].map(([value, label]) => (
<div
key={label}
className="flex flex-col gap-0.5 border-b border-border pb-4"
>
<dt className="order-2 text-sm text-muted-foreground">
{label}
</dt>
<dd className="order-1 text-3xl font-bold">{value}</dd>
</div>
))}
</dl>
</div>
<ul className="grid grid-cols-1 gap-x-8 gap-y-10 sm:grid-cols-2">
{ENGINE.map((item) => (
<li key={item.title} className="flex flex-col gap-3">
<span
aria-hidden
className="flex size-12 items-center justify-center rounded-full border border-[var(--dig-orange-200)] bg-card text-[var(--dig-orange-800)] dark:border-[var(--dig-orange-900)] dark:text-[var(--dig-orange-300)] [&>svg]:size-5"
>
{item.icon}
</span>
<h3 className="text-lg font-bold">{item.title}</h3>
<p className="text-sm leading-6 text-muted-foreground">
{item.text}
</p>
</li>
))}
</ul>
</section>
<section className="px-4 pb-24 sm:px-6">
<div className="mx-auto flex w-full max-w-4xl flex-col items-center justify-between gap-6 rounded-xl bg-[var(--dig-cyan-950)] p-8 text-[var(--dig-white)] sm:flex-row">
<div className="flex flex-col gap-2">
<h2 className="text-2xl font-bold">امنیت و انطباق</h2>
<p className="text-sm leading-6 text-[var(--dig-cyan-100)]">
رمزگذاریِ کامل، سرورِ داخلِ کشور و گزارشِ دسترسی برای هر پرونده.
</p>
</div>
<ul className="flex gap-3">
{[
<ShieldCheckIcon key="a" />,
<FileTextIcon key="b" />,
<CheckCircleIcon key="c" />,
].map((icon, index) => (
<li
key={index}
aria-hidden
className="flex size-16 items-center justify-center rounded-full border-2 border-[var(--dig-cyan-700)] text-[var(--dig-cyan-100)] [&>svg]:size-7"
>
{icon}
</li>
))}
</ul>
</div>
</section>
<section className="relative isolate overflow-hidden px-4 py-28 text-[var(--dig-white)] sm:px-6">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img
src={stockImages.womanLaptopSofa.src}
alt=""
className="absolute inset-0 -z-20 size-full object-cover"
/>
<span
aria-hidden
className="absolute inset-0 -z-10 bg-[linear-gradient(270deg,color-mix(in_oklab,var(--dig-orange-950)_85%,transparent),transparent_75%)]"
/>
<div className="mx-auto flex w-full max-w-6xl flex-col items-start gap-6">
<h2 className="max-w-md text-3xl leading-snug font-bold sm:text-5xl sm:leading-tight">
ببینید پذیرشِ کلینیکتان چطور عوض میشود
</h2>
<div className="flex flex-wrap gap-3">
<Button
radius="full"
className="[--primary-foreground:var(--dig-orange-950)] [--primary:var(--dig-white)]"
>
<SparklesIcon />
رزروِ دمو
</Button>
<Button
radius="full"
variant="outline"
className="border-[var(--dig-orange-200)] bg-transparent text-[var(--dig-white)] hover:bg-[var(--dig-orange-900)]"
>
<PhoneIcon />
تماس با فروش
</Button>
</div>
</div>
</section>
</main>
</ControlSizeProvider>
);
}