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

ورود، مدلِ ساده: همان فرم وسطِ صفحه، بدونِ پنلِ کناری. همان فرم، اعتبارسنجی و حالت‌های صفحهٔ اصلی.

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

این بلاک از ۱۱ آیتم دیگ استفاده می‌کند: alertbuttoncheckboxcontrol-sizeiconslabellinkpassword-fieldpersianseparatortext-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/separator.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/separator.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/separator.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/separator.json https://docs.digdesign.ir/r/text-field.json

۲. کد صفحه

کد را در app/<route>/page.tsx بگذارید و متن‌ها، داده و هندلرها را با محصول خودتان عوض کنید.

login-simple.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 { Separator } from "@/components/ui/separator"
import { TextField } from "@/components/ui/text-field"
import { isValidEmail, isValidMobile } from "@/lib/persian"

/** نشانِ برند بالای فرم. */
function BrandMark() {
  return (
    <span aria-hidden className="flex size-12 items-center justify-center rounded-xl bg-[var(--dig-violet-700)] text-[var(--dig-white)] [&>svg]:size-6">
      <SparklesIcon />
    </span>
  )
}

/**
 * ورود با چیدمانِ دوستونه: فرم در ستونِ شروع (وسطِ ستون)، پنلِ برند در ستونِ
 * پایان. همان ساختارِ صفحهٔ ثبت‌نام، تا جابه‌جایی بین این دو حسِ یک صفحه بدهد.
 */
/** مدلِ ساده: همان فرم وسطِ صفحه، بدونِ پنلِ کناری؛ برای اپ‌هایی که برند را در خودِ فرم نشان می‌دهند. */
export default function LoginSimpleBlock() {
  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 (
    <main className="flex min-h-svh flex-col items-center bg-background p-4">
      <div className="flex w-full flex-1 flex-col items-center px-4 py-10">
        <ControlSizeProvider size="xl" className="flex w-full max-w-sm flex-1 flex-col justify-center gap-8">
          <header className="flex flex-col items-center gap-4 text-center">
            <BrandMark />
            <div className="flex flex-col gap-2">
              <h1 className="text-2xl font-bold">ورود به حساب</h1>
              <p className="text-sm text-muted-foreground">با ایمیل یا شمارهٔ موبایل وارد شوید.</p>
            </div>
          </header>

          <div className="flex flex-col gap-4">
            <Button variant="outline" fullWidth>
              ورود با رمزِ یک‌بارمصرف
            </Button>
            <div className="flex items-center gap-3 text-xs text-muted-foreground">
              <Separator className="flex-1" />
              یا با رمز عبور
              <Separator className="flex-1" />
            </div>
          </div>

          <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="remember" name="remember" />
                <Label htmlFor="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-center text-sm text-muted-foreground">
            حساب ندارید؟ <Link href="/signup">ثبت‌نام کنید</Link>
          </p>
        </ControlSizeProvider>
        <p className="pt-10 text-xs text-muted-foreground">
          <Link href="#" size="sm">
            قوانین
          </Link>{" "}
          و{" "}
          <Link href="#" size="sm">
            حریم خصوصی
          </Link>
        </p>
      </div>
    </main>
  )
}