ورود با عکس
پیشنمایش تمامصفحهورود با چیدمانِ دوستونه و عکسِ واقعیِ تمامقد با جملهٔ برند روی آن؛ فرمِ ایمیل یا موبایل و رمز، خطای ورود، مرا به خاطر بسپار و فراموشی رمز.
۱. نصب کامپوننتها
این بلاک از ۱۰ آیتم دیگ استفاده میکند: alertbuttoncheckboxcontrol-sizeiconslabellinkpassword-fieldpersiantext-field
پکیجمنیجر پیشفرض Node.jsنصب سریع با لینک سخت و دیسک مشترکYarn نسخهٔ ۲ به بالا (Berry)رانتایم و پکیجمنیجر Bun
npx digdesign@latest add https://docs.digdesign.ir/r/alert.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/label.json https://docs.digdesign.ir/r/link.json https://docs.digdesign.ir/r/password-field.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.jsonpnpm dlx digdesign@latest add https://docs.digdesign.ir/r/alert.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/label.json https://docs.digdesign.ir/r/link.json https://docs.digdesign.ir/r/password-field.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.jsonyarn dlx digdesign@latest add https://docs.digdesign.ir/r/alert.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/label.json https://docs.digdesign.ir/r/link.json https://docs.digdesign.ir/r/password-field.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.jsonbunx --bun digdesign@latest add https://docs.digdesign.ir/r/alert.json https://docs.digdesign.ir/r/button.json https://docs.digdesign.ir/r/checkbox.json https://docs.digdesign.ir/r/control-size.json https://docs.digdesign.ir/r/icons.json https://docs.digdesign.ir/r/label.json https://docs.digdesign.ir/r/link.json https://docs.digdesign.ir/r/password-field.json https://docs.digdesign.ir/r/persian.json https://docs.digdesign.ir/r/text-field.json۲. کد صفحه
کد را در app/<route>/page.tsx بگذارید و متنها، داده و هندلرها را با محصول خودتان عوض کنید.
login-image.tsx
"use client"
import * as React from "react"
import { SparklesIcon } from "@/components/icons"
import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"
import { Button } from "@/components/ui/button"
import { Checkbox } from "@/components/ui/checkbox"
import { ControlSizeProvider } from "@/components/ui/control-size"
import { Label } from "@/components/ui/label"
import { Link } from "@/components/ui/link"
import { PasswordField } from "@/components/ui/password-field"
import { TextField } from "@/components/ui/text-field"
import { isValidEmail, isValidMobile } from "@/lib/persian"
import { stockImages } from "@/lib/stock-images"
/**
* ورود با عکسِ تمامقد: فرم در ستونِ شروع، عکسِ واقعی در ستونِ پایان با یک جملهٔ
* برند روی پایینِ عکس. در صفحهٔ باریک عکس به نواری کوتاه بالای فرم تبدیل میشود.
*/
export default function LoginImageBlock() {
const [error, setError] = React.useState(false)
const [signing, setSigning] = React.useState(false)
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
event.preventDefault()
setSigning(true)
setError(false)
// جای درخواستِ واقعی ورود؛ این نمونه همیشه «اطلاعات نادرست» برمیگرداند.
await new Promise((resolve) => setTimeout(resolve, 800))
setSigning(false)
setError(true)
}
return (
<ControlSizeProvider size="xl" asChild>
<main className="grid grid-cols-1 min-h-svh gap-4 bg-background p-4 lg:grid-cols-2">
<div className="flex flex-col px-4 py-10 sm:px-10">
<span className="flex items-center gap-2 font-black">
<span aria-hidden className="flex size-9 items-center justify-center rounded-lg bg-foreground text-background [&>svg]:size-4">
<SparklesIcon />
</span>
حسابیار
</span>
<div className="mx-auto flex w-full max-w-sm flex-1 flex-col justify-center gap-8 py-10">
<header className="flex flex-col gap-2">
<h1 className="text-3xl font-bold">خوش برگشتی</h1>
<p className="text-muted-foreground">برای ادامه وارد حسابت شو.</p>
</header>
<form onSubmit={onSubmit} className="flex flex-col gap-4">
{error && (
<Alert color="destructive">
<AlertTitle>ورود ناموفق بود</AlertTitle>
<AlertDescription>ایمیل، شماره یا رمز عبور درست نیست.</AlertDescription>
</Alert>
)}
<TextField
label="ایمیل یا شمارهٔ موبایل"
name="identifier"
dir="ltr"
autoComplete="username"
required
validate={(value) => (isValidEmail(value) || isValidMobile(value) ? undefined : "یک ایمیل یا شماره موبایلِ معتبر وارد کنید.")}
disabled={signing}
/>
<PasswordField label="رمز عبور" name="password" autoComplete="current-password" required disabled={signing} />
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
<Checkbox id="login-image-remember" name="remember" />
<Label htmlFor="login-image-remember">مرا به خاطر بسپار</Label>
</div>
<Link href="/forgot-password" size="sm">
فراموشی رمز
</Link>
</div>
<Button type="submit" fullWidth loading={signing} className="mt-4">
ورود
</Button>
</form>
<p className="text-sm text-muted-foreground">
حساب ندارید؟ <Link href="/signup">ثبتنام کنید</Link>
</p>
</div>
</div>
{/* عکسِ واقعی با جملهٔ برند روی سایهروشنِ پایین. */}
<aside className="relative order-first min-h-56 overflow-hidden rounded-xl bg-muted lg:order-none">
{/* eslint-disable-next-line @next/next/no-img-element -- عکس از کتابخانهٔ تصویرِ دیگ */}
<img src={stockImages.authWorkspace.src} alt="" className="absolute inset-0 size-full object-cover" />
<div className="absolute inset-x-0 bottom-0 flex flex-col gap-2 bg-linear-to-t from-[var(--dig-graphite-950)] to-transparent p-8 pt-24 text-[var(--dig-white)] sm:p-12 sm:pt-32">
<p className="max-w-md text-2xl leading-relaxed font-bold sm:text-3xl sm:leading-relaxed">حسابوکتاب، آرام و بیدردسر.</p>
<p className="text-sm text-[var(--dig-neutral-300)]">بیش از ۱۲ هزار کسبوکار هر روز با حسابیار کار میکنند.</p>
</div>
</aside>
</main>
</ControlSizeProvider>
)
}