بلاک‌ها · ورود و ثبت‌نام

ورود با چیدمانِ دوستونه و عکسِ واقعیِ تمام‌قد با جملهٔ برند روی آن؛ فرمِ ایمیل یا موبایل و رمز، خطای ورود، مرا به خاطر بسپار و فراموشی رمز.

۱. نصب کامپوننت‌ها

این بلاک از ۱۰ آیتم دیگ استفاده می‌کند: 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.json
pnpm 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.json
yarn 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.json
bunx --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>
  )
}