اسپینر (Spinner)

نشان‌دهنده بارگذاری برای عملیات‌های ناهمزمان.

نصب (Installation)

1npx @quark-lab/rad-ui add spinner

نمونه‌ها (Examples)

استفاده پایه (Basic Usage)

Spinner برای نمایش حالت بارگذاری استفاده می‌شود.

Loading...
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function BasicExample() {
4  return (
5    <div className="flex items-center justify-center">
6      <Spinner />
7    </div>
8  );
9}
10

اندازه‌ها (Sizes)

چهار اندازه مختلف برای موارد مختلف.

Loading...کوچک
Loading...پیش‌فرض
Loading...بزرگ
Loading...خیلی بزرگ
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function SizesExample() {
4  return (
5    <div className="flex items-end gap-8 justify-center">
6      <div className="flex flex-col items-center gap-2">
7        <Spinner size="sm" />
8        <span className="text-xs text-muted-foreground">کوچک</span>
9      </div>
10      <div className="flex flex-col items-center gap-2">
11        <Spinner size="default" />
12        <span className="text-xs text-muted-foreground">پیش‌فرض</span>
13      </div>
14      <div className="flex flex-col items-center gap-2">
15        <Spinner size="lg" />
16        <span className="text-xs text-muted-foreground">بزرگ</span>
17      </div>
18      <div className="flex flex-col items-center gap-2">
19        <Spinner size="xl" />
20        <span className="text-xs text-muted-foreground">خیلی بزرگ</span>
21      </div>
22    </div>
23  );
24}
25

رنگ‌ها (Colors)

می‌توانید رنگ اسپینر را با className تغییر دهید.

Loading...Primary
Loading...Destructive
Loading...Blue
Loading...Green
Loading...Purple
Loading...Orange
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function ColorsExample() {
4  return (
5    <div className="flex items-center gap-8 justify-center flex-wrap">
6      <div className="flex flex-col items-center gap-2">
7        <Spinner className="text-primary" />
8        <span className="text-xs text-muted-foreground">Primary</span>
9      </div>
10      <div className="flex flex-col items-center gap-2">
11        <Spinner className="text-destructive" />
12        <span className="text-xs text-muted-foreground">Destructive</span>
13      </div>
14      <div className="flex flex-col items-center gap-2">
15        <Spinner className="text-blue-500" />
16        <span className="text-xs text-muted-foreground">Blue</span>
17      </div>
18      <div className="flex flex-col items-center gap-2">
19        <Spinner className="text-green-500" />
20        <span className="text-xs text-muted-foreground">Green</span>
21      </div>
22      <div className="flex flex-col items-center gap-2">
23        <Spinner className="text-purple-500" />
24        <span className="text-xs text-muted-foreground">Purple</span>
25      </div>
26      <div className="flex flex-col items-center gap-2">
27        <Spinner className="text-orange-500" />
28        <span className="text-xs text-muted-foreground">Orange</span>
29      </div>
30    </div>
31  );
32}
33

با دکمه (With Button)

نمایش اسپینر در دکمه‌های در حال بارگذاری.

مشاهده کد
1import { useState } from "react";
2import { Spinner } from "@/components/ui/spinner";
3import { Button } from "@/components/ui/button";
4
5export default function WithButtonsExample() {
6  const [isLoading, setIsLoading] = useState(false);
7
8  const handleClick = () => {
9    setIsLoading(true);
10    setTimeout(() => setIsLoading(false), 2000);
11  };
12
13  return (
14    <div className="flex items-center gap-4 flex-wrap justify-center">
15      <Button disabled>
16        <Spinner size="sm" className="me-2" />
17        در حال بارگذاری...
18      </Button>
19      <Button variant="outline" onClick={handleClick} disabled={isLoading}>
20        {isLoading ? (
21          <>
22            <Spinner size="sm" className="me-2" />
23            لطفاً صبر کنید
24          </>
25        ) : (
26          "کلیک کنید"
27        )}
28      </Button>
29      <Button variant="destructive" disabled>
30        <Spinner size="sm" className="me-2" />
31        در حال حذف...
32      </Button>
33    </div>
34  );
35}
36

با متن (With Text)

ترکیب اسپینر با متن توضیحی.

Loading...در حال بارگذاری...
Loading...در حال پردازش درخواست شما
Loading...

لطفاً صبر کنید

این ممکن است چند لحظه طول بکشد

مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function WithTextExample() {
4  return (
5    <div className="space-y-4 max-w-md mx-auto">
6      <div className="flex items-center gap-3">
7        <Spinner size="sm" />
8        <span className="text-sm">در حال بارگذاری...</span>
9      </div>
10      <div className="flex items-center gap-3">
11        <Spinner size="default" className="text-primary" />
12        <span>در حال پردازش درخواست شما</span>
13      </div>
14      <div className="flex items-center gap-3">
15        <Spinner size="lg" className="text-blue-500" />
16        <div>
17          <p className="font-medium">لطفاً صبر کنید</p>
18          <p className="text-sm text-muted-foreground">
19            این ممکن است چند لحظه طول بکشد
20          </p>
21        </div>
22      </div>
23    </div>
24  );
25}
26

وسط‌چین (Centered)

نمایش اسپینر در وسط صفحه یا کانتینر.

Loading...
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function CenteredExample() {
4  return (
5    <div className="h-40 flex items-center justify-center">
6      <Spinner size="lg" />
7    </div>
8  );
9}
10

مثال‌های کاربردی (Practical Examples)

دکمه بارگذاری (Loading Button)

استفاده از اسپینر در دکمه‌ها.

مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2import { Button } from "@/components/ui/button";
3
4export default function LoadingButtonExample() {
5  return (
6    <div className="flex items-center gap-4 flex-wrap">
7      <Button>
8        <Spinner size="sm" className="me-2" />
9        ارسال فرم
10      </Button>
11      <Button variant="outline">
12        <Spinner size="sm" className="me-2" />
13        ذخیره تغییرات
14      </Button>
15      <Button variant="ghost">
16        <Spinner size="sm" className="me-2" />
17        بارگذاری بیشتر
18      </Button>
19    </div>
20  );
21}
22

بارگذاری صفحه کامل (Full Page Loading)

نمایش وضعیت بارگذاری برای کل صفحه.

Loading...

در حال بارگذاری

لطفاً چند لحظه صبر کنید...

مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function FullPageExample() {
4  return (
5    <div className="h-64 flex flex-col items-center justify-center gap-4">
6      <Spinner size="xl" className="text-primary" />
7      <div className="text-center">
8        <p className="font-medium mb-1">در حال بارگذاری</p>
9        <p className="text-sm text-muted-foreground">
10          لطفاً چند لحظه صبر کنید...
11        </p>
12      </div>
13    </div>
14  );
15}
16

بارگذاری درون‌خطی (Inline Loading)

نمایش وضعیت بارگذاری در کنار متن.

در حال آپلود فایل...Loading...
در حال پردازش تصویر...Loading...
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function InlineExample() {
4  return (
5    <div className="max-w-md space-y-4">
6      <div className="p-4 rounded-lg bg-muted/50">
7        <div className="flex items-center justify-between">
8          <span className="text-sm">در حال آپلود فایل...</span>
9          <Spinner size="sm" />
10        </div>
11        <div className="mt-2 h-2 bg-background rounded-full overflow-hidden">
12          <div className="h-full bg-primary w-2/3 rounded-full" />
13        </div>
14      </div>
15      <div className="p-4 rounded-lg bg-muted/50">
16        <div className="flex items-center justify-between">
17          <span className="text-sm">در حال پردازش تصویر...</span>
18          <Spinner size="sm" className="text-blue-500" />
19        </div>
20      </div>
21    </div>
22  );
23}
24

اورلی بارگذاری کارت (Card Loading Overlay)

نمایش اسپینر روی کارت هنگام به‌روزرسانی.

اطلاعات کاربر

نام: علی محمدی

ایمیل: ali@example.com

تلفن: 09123456789

Loading...در حال به‌روزرسانی...
مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2
3export default function CardOverlayExample() {
4  return (
5    <div className="max-w-sm mx-auto relative">
6      <div className="p-6 rounded-lg border border-border">
7        <h4 className="font-semibold mb-2">اطلاعات کاربر</h4>
8        <div className="space-y-2 text-sm text-muted-foreground">
9          <p>نام: علی محمدی</p>
10          <p>ایمیل: ali@example.com</p>
11          <p>تلفن: 09123456789</p>
12        </div>
13      </div>
14      <div className="absolute inset-0 bg-background/80 backdrop-blur-sm rounded-lg flex items-center justify-center">
15        <div className="flex flex-col items-center gap-2">
16          <Spinner size="lg" />
17          <span className="text-sm font-medium">در حال به‌روزرسانی...</span>
18        </div>
19      </div>
20    </div>
21  );
22}
23

ارسال فرم (Form Submission)

غیرفعال کردن فرم هنگام ارسال.

مشاهده کد
1import { Spinner } from "@/components/ui/spinner";
2import { Button } from "@/components/ui/button";
3
4export default function FormSubmissionExample() {
5  return (
6    <div className="max-w-md mx-auto space-y-4">
7      <div className="space-y-2">
8        <label className="text-sm font-medium">نام</label>
9        <input
10          type="text"
11          className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm"
12          placeholder="نام خود را وارد کنید"
13          disabled
14        />
15      </div>
16      <div className="space-y-2">
17        <label className="text-sm font-medium">ایمیل</label>
18        <input
19          type="email"
20          className="flex h-10 w-full rounded-md border border-border bg-background px-3 py-2 text-sm"
21          placeholder="your@email.com"
22          disabled
23        />
24      </div>
25      <Button className="w-full" disabled>
26        <Spinner size="sm" className="me-2" />
27        در حال ارسال...
28      </Button>
29    </div>
30  );
31}
32

مرجع API (API Reference)

Spinner

پراپ‌های کامپوننت Spinner.

پراپ (Prop)نوع (Type)پیش‌فرض (Default)توضیحات (Description)
size"sm" | "default" | "lg" | "xl""default"اندازه اسپینر
classNamestringundefinedکلاس‌های CSS سفارشی (برای رنگ)
srTextstring"Loading..."متن برای اسکرین ریدرها

دسترسی‌پذیری (Accessibility)

role و aria-label

اسپینر به صورت خودکار role="status" و aria-label دارد

متن اسکرین ریدر

یک sr-only span برای اسکرین ریدرها اضافه شده است

سفارشی‌سازی متن

می‌توانید متن اسکرین ریدر را با prop srText تغییر دهید

بهترین شیوه‌ها (Best Practices)

کی از Spinner استفاده کنیم؟

از Spinner زمانی استفاده کنید که عملیاتی در حال انجام است و کاربر باید منتظر بماند (مثل ارسال فرم، بارگذاری داده، یا پردازش)

متن توضیحی

همیشه یک متن توضیحی همراه اسپینر قرار دهید تا کاربر بداند چه اتفاقی در حال رخ دادن است

اندازه مناسب

از اندازه مناسب برای محیط استفاده کنید: sm برای دکمه‌ها، default برای کارت‌ها، lg/xl برای صفحات کامل

غیرفعال کردن تعامل

هنگام نمایش اسپینر، دکمه‌ها و فرم‌ها را غیرفعال کنید تا از ارسال مجدد جلوگیری شود

زمان‌بندی

برای عملیات‌های سریع (کمتر از 500ms) ممکن است نمایش اسپینر نیاز نباشد. برای عملیات‌های طولانی، پیشرفت را نشان دهید