آکادمی بنو/آموزش Bootstrap

Alerts، Toasts و Progress در Bootstrap

بهنام نوبخت · ۱۴۰۵/۷/۱۲

در بسیاری از صفحات وب لازم است نتیجه یک عملیات یا وضعیت خاص را به کاربر اطلاع دهیم. برای مثال بعد از ثبت‌نام باید پیام موفقیت نمایش داده شود، هنگام حذف یک محصول باید هشدار مناسب نشان داده شود، اگر اطلاعات واردشده اشتباه باشد باید پیام خطا نمایش داده شود یا هنگام آپلود یک فایل میزان پیشرفت عملیات به کاربر نشان داده شود. Bootstrap برای این نیازها چند کامپوننت کاربردی در اختیار ما قرار می‌دهد. Alert برای نمایش پیام‌های مهم و قابل مشاهده در صفحه، Toast برای نمایش اعلان‌های کوتاه و موقتی و Progress برای نمایش میزان پیشرفت یک عملیات استفاده می‌شود. در این مقاله ابتدا Alertها را یاد می‌گیریم، سپس با انواع Toast و نحوه کنترل آن‌ها با JavaScript آشنا می‌شویم و در ادامه Progress Bar را بررسی می‌کنیم. در پایان نیز این سه کامپوننت را در یک سناریوی واقعی مانند داشبورد مدیریت و فرم آپلود فایل ترکیب خواهیم کرد.

Alert چیست؟

Alert برای نمایش یک پیام مهم به کاربر استفاده می‌شود.

برای مثال:

<div class="alert alert-primary" role="alert">
    این یک پیام اطلاع‌رسانی است.
</div>

Alert معمولاً در بخشی از صفحه نمایش داده می‌شود و تا زمانی که خودمان آن را حذف نکنیم، باقی می‌ماند.

انواع Alert

Bootstrap چند نوع Alert آماده دارد.

Primary

<div class="alert alert-primary" role="alert">
    اطلاعات جدیدی در دسترس است.
</div>

Secondary

<div class="alert alert-secondary" role="alert">
    این یک پیام عمومی است.
</div>

Success

برای عملیات موفق:

<div class="alert alert-success" role="alert">
    اطلاعات با موفقیت ذخیره شد.
</div>

Danger

برای خطا یا عملیات خطرناک:

<div class="alert alert-danger" role="alert">
    ذخیره اطلاعات با خطا مواجه شد.
</div>

Warning

برای هشدار:

<div class="alert alert-warning" role="alert">
    رمز عبور شما ضعیف است.
</div>

Info

برای اطلاعات:

<div class="alert alert-info" role="alert">
    سیستم در ساعت 12 شب بروزرسانی خواهد شد.
</div>

Light

<div class="alert alert-light" role="alert">
    یک پیام ساده.
</div>

Dark

<div class="alert alert-dark" role="alert">
    یک پیام با ظاهر تیره.
</div>

Alert و مفهوم رنگ‌ها

در یک پروژه واقعی بهتر است رنگ Alert با مفهوم پیام هماهنگ باشد:

Success → عملیات موفق
Danger  → خطا
Warning → هشدار
Info    → اطلاع‌رسانی

اما بهتر است مفهوم پیام فقط از طریق رنگ منتقل نشود و متن مناسب نیز وجود داشته باشد.

Alert با عنوان

می‌توانیم داخل Alert یک Heading داشته باشیم:

<div class="alert alert-success" role="alert">

    <h4 class="alert-heading">
        عملیات موفق بود!
    </h4>

    <p>
        اطلاعات حساب کاربری شما با موفقیت ذخیره شد.
    </p>

</div>

این ساختار برای پیام‌های مهم بسیار مناسب است.

Alert با لینک

می‌توانیم لینک را نیز داخل Alert قرار دهیم:

<div class="alert alert-primary" role="alert">

    برای مشاهده جزئیات
    <a href="#" class="alert-link">
        اینجا کلیک کنید
    </a>.

</div>

کلاس alert-link باعث می‌شود لینک با ظاهر مناسب Alert نمایش داده شود.

Alert با دکمه بستن

اگر بخواهیم کاربر بتواند Alert را ببندد، باید از alert-dismissible استفاده کنیم:

<div
    class="alert alert-warning alert-dismissible fade show"
    role="alert"
>
    این پیام را می‌توانید ببندید.

    <button
        type="button"
        class="btn-close"
        data-bs-dismiss="alert"
        aria-label="بستن"
    ></button>

</div>

در این مثال:

  • alert-dismissible فضای مناسب برای دکمه بستن ایجاد می‌کند.

  • btn-close دکمه بستن است.

  • data-bs-dismiss="alert" باعث می‌شود Alert بسته شود.

  • fade show افکت نمایش و مخفی شدن را فعال می‌کند.

برای این قابلیت باید Bootstrap JavaScript نیز در صفحه بارگذاری شده باشد.

Alert ساده یا Dismissible؟

اگر پیام باید همیشه قابل مشاهده باشد:

<div class="alert alert-info">
    ...
</div>

اگر کاربر باید بتواند پیام را ببندد:

<div class="alert alert-info alert-dismissible fade show">
    ...
</div>

در پروژه‌های واقعی، این انتخاب به اهمیت و طول عمر پیام بستگی دارد.

Alert برای فرم ثبت‌نام

فرض کنیم کاربر یک فرم ثبت‌نام دارد:

<div class="alert alert-success" role="alert">
    ثبت‌نام شما با موفقیت انجام شد.
</div>

یا در صورت خطا:

<div class="alert alert-danger" role="alert">
    امکان ثبت‌نام وجود ندارد. اطلاعات واردشده را بررسی کنید.
</div>

این الگو در صفحات Login و Register بسیار رایج است.

Alert برای پیام‌های Validation

می‌توان چند خطا را داخل یک Alert نمایش داد:

<div class="alert alert-danger" role="alert">

    <h5 class="alert-heading">
        خطاهای فرم
    </h5>

    <ul class="mb-0">

        <li>
            ایمیل وارد نشده است.
        </li>

        <li>
            رمز عبور باید حداقل 8 کاراکتر باشد.
        </li>

        <li>
            رمز عبور و تکرار آن یکسان نیستند.
        </li>

    </ul>

</div>

این روش برای نمایش خطاهای کلی فرم مناسب است.

Alert در سمت سرور

در برنامه‌های واقعی، پیام Alert معمولاً به صورت مستقیم داخل HTML ثابت نوشته نمی‌شود.

مثلاً در یک برنامه ASP.NET Core ممکن است نتیجه عملیات از Server به Client ارسال شود:

Server
   |
   v
Operation
   |
   v
Result
   |
   v
Client
   |
   v
Bootstrap Alert

برای مثال:

{
    "success": true,
    "message": "اطلاعات با موفقیت ذخیره شد."
}

سپس Frontend بر اساس مقدار success، Alert مناسب را ایجاد می‌کند.

Toast چیست؟

Toast یک اعلان کوچک و معمولاً موقتی است که بدون اشغال بخش زیادی از صفحه به کاربر نمایش داده می‌شود.

برای مثال:

+-------------------------+
| Success                 |
| Data saved successfully |
+-------------------------+

Toast برای پیام‌هایی مانند موارد زیر بسیار مناسب است:

  • ذخیره موفق

  • حذف موفق

  • ارسال پیام

  • ورود موفق

  • کپی شدن متن

  • تغییر تنظیمات

  • دریافت اعلان جدید

ساخت Toast

یک Toast ساده:

<div class="toast" role="alert" aria-live="assertive" aria-atomic="true">

    <div class="toast-header">

        <strong class="me-auto">
            سیستم
        </strong>

        <small>
            اکنون
        </small>

        <button
            type="button"
            class="btn-close"
            data-bs-dismiss="toast"
            aria-label="بستن"
        ></button>

    </div>

    <div class="toast-body">
        اطلاعات با موفقیت ذخیره شد.
    </div>

</div>

اما برای اینکه Toast نمایش داده شود، باید آن را با JavaScript فعال کنیم.

Toast با JavaScript

ابتدا Bootstrap Bundle را در صفحه قرار دهید:

<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.8/dist/js/bootstrap.bundle.min.js"></script>

سپس:

<script>
    const toastElement = document.getElementById('saveToast');

    const toast = new bootstrap.Toast(toastElement);

    toast.show();
</script>

HTML:

<div
    id="saveToast"
    class="toast"
    role="alert"
    aria-live="assertive"
    aria-atomic="true"
>

    <div class="toast-header">

        <strong class="me-auto">
            سیستم
        </strong>

        <small>
            اکنون
        </small>

        <button
            type="button"
            class="btn-close"
            data-bs-dismiss="toast"
            aria-label="بستن"
        ></button>

    </div>

    <div class="toast-body">
        اطلاعات با موفقیت ذخیره شد.
    </div>

</div>

Toast Container

معمولاً Toast را مستقیماً در وسط صفحه قرار نمی‌دهیم.

بهتر است یک Container داشته باشیم:

<div class="toast-container position-fixed bottom-0 end-0 p-3">

    <div
        id="saveToast"
        class="toast"
        role="alert"
        aria-live="assertive"
        aria-atomic="true"
    >

        <div class="toast-header">

            <strong class="me-auto">
                سیستم
            </strong>

            <small>
                اکنون
            </small>

            <button
                type="button"
                class="btn-close"
                data-bs-dismiss="toast"
                aria-label="بستن"
            ></button>

        </div>

        <div class="toast-body">
            اطلاعات با موفقیت ذخیره شد.
        </div>

    </div>

</div>

در اینجا:

position-fixed

Toast را نسبت به صفحه ثابت می‌کند.

و:

bottom-0 end-0

آن را در پایین و سمت انتهایی صفحه قرار می‌دهد.

در صفحه RTL، این Utilityها نیز باید با مفهوم منطقی Bootstrap هماهنگ استفاده شوند.

Toast در بالای صفحه

می‌توان Toast را در بالای صفحه قرار داد:

<div class="toast-container position-fixed top-0 end-0 p-3">
    ...
</div>

Toast با دکمه

یک نمونه کاربردی:

<button
    type="button"
    class="btn btn-success"
    id="saveButton"
>
    ذخیره اطلاعات
</button>

<div class="toast-container position-fixed bottom-0 end-0 p-3">

    <div
        id="saveToast"
        class="toast"
        role="alert"
        aria-live="polite"
        aria-atomic="true"
    >

        <div class="toast-header">

            <strong class="me-auto">
                پیام سیستم
            </strong>

            <button
                type="button"
                class="btn-close"
                data-bs-dismiss="toast"
                aria-label="بستن"
            ></button>

        </div>

        <div class="toast-body">
            اطلاعات ذخیره شد.
        </div>

    </div>

</div>

<script>

    const saveButton =
        document.getElementById('saveButton');

    const saveToastElement =
        document.getElementById('saveToast');

    const saveToast =
        new bootstrap.Toast(saveToastElement);

    saveButton.addEventListener('click', function () {

        saveToast.show();

    });

</script>

با کلیک روی دکمه، Toast نمایش داده می‌شود.

Toast با زمان مشخص

می‌توان مدت نمایش Toast را نیز کنترل کرد:

const toast = new bootstrap.Toast(
    toastElement,
    {
        delay: 3000
    }
);

toast.show();

در این مثال Toast تقریباً بعد از 3 ثانیه مخفی می‌شود.

Alert یا Toast؟

انتخاب بین این دو بسیار مهم است.

ویژگی

Alert

Toast

پیام مهم

مناسب

مناسب

پیام موقتی

کمتر مناسب

بسیار مناسب

باقی ماندن در صفحه

بله

معمولاً خیر

نیاز به JavaScript برای نمایش

خیر

معمولاً بله

پیام بعد از ذخیره

مناسب

مناسب

خطاهای مهم فرم

مناسب

کمتر مناسب

اعلان کوتاه

کمتر مناسب

مناسب

به صورت ساده:

Alert برای پیام‌هایی است که باید در جریان محتوای صفحه دیده شوند.

Toast برای اعلان‌های کوتاه و غیرمزاحم بسیار مناسب است.

Progress چیست؟

Progress Bar برای نمایش میزان پیشرفت یک عملیات استفاده می‌شود.

مثلاً:

Upload

[############--------] 60%

در Bootstrap می‌توانیم چنین Progress Barای ایجاد کنیم.

Progress ساده

<div class="progress">

    <div
        class="progress-bar"
        role="progressbar"
        style="width: 50%;"
        aria-valuenow="50"
        aria-valuemin="0"
        aria-valuemax="100"
    >
        50%
    </div>

</div>

در این مثال میزان پیشرفت 50 درصد است.

Progress بدون متن

گاهی فقط خود نوار را می‌خواهیم:

<div class="progress">

    <div
        class="progress-bar"
        role="progressbar"
        style="width: 70%;"
        aria-valuenow="70"
        aria-valuemin="0"
        aria-valuemax="100"
    ></div>

</div>

Progress با رنگ

می‌توانیم رنگ Progress را تغییر دهیم:

<div class="progress">
    <div
        class="progress-bar bg-success"
        style="width: 80%;"
    >
        80%
    </div>
</div>

نمونه خطا:

<div class="progress">
    <div
        class="progress-bar bg-danger"
        style="width: 30%;"
    >
        30%
    </div>
</div>

یا هشدار:

<div class="progress">
    <div
        class="progress-bar bg-warning"
        style="width: 60%;"
    >
        60%
    </div>
</div>

Progress چندمرحله‌ای

Bootstrap امکان قرار دادن چند Progress Bar داخل یک Progress Container را نیز فراهم می‌کند:

<div class="progress">

    <div
        class="progress-bar"
        style="width: 30%;"
    >
        30%
    </div>

    <div
        class="progress-bar bg-success"
        style="width: 40%;"
    >
        40%
    </div>

    <div
        class="progress-bar bg-warning"
        style="width: 30%;"
    >
        30%
    </div>

</div>

مجموع بخش‌ها در این مثال 100 درصد است.

این قابلیت برای نمایش مراحل مختلف یک فرآیند مفید است.

Progress Striped

برای ایجاد ظاهر راه‌راه می‌توانیم از progress-bar-striped استفاده کنیم:

<div class="progress">

    <div
        class="progress-bar progress-bar-striped"
        style="width: 70%;"
    >
        70%
    </div>

</div>

Progress Animated

برای متحرک کردن Stripeها:

<div class="progress">

    <div
        class="progress-bar progress-bar-striped progress-bar-animated"
        style="width: 70%;"
    >
        70%
    </div>

</div>

این حالت برای عملیات در حال انجام می‌تواند مناسب باشد.

Progress در آپلود فایل

فرض کنیم کاربر در حال آپلود یک فایل است:

<div class="mb-2">
    در حال آپلود فایل...
</div>

<div class="progress">

    <div
        id="uploadProgress"
        class="progress-bar"
        role="progressbar"
        style="width: 0%;"
        aria-valuenow="0"
        aria-valuemin="0"
        aria-valuemax="100"
    >
        0%
    </div>

</div>

با JavaScript می‌توان مقدار را تغییر داد.

const progress =
    document.getElementById('uploadProgress');

let value = 0;

const interval = setInterval(function () {

    value += 10;

    progress.style.width = value + '%';

    progress.setAttribute(
        'aria-valuenow',
        value
    );

    progress.textContent =
        value + '%';

    if (value >= 100) {
        clearInterval(interval);
    }

}, 500);

در این مثال برای شبیه‌سازی یک فرآیند از setInterval استفاده کرده‌ایم.

در پروژه واقعی، مقدار Progress باید بر اساس وضعیت واقعی عملیات محاسبه شود.

Progress در مراحل ثبت‌نام

فرض کنید ثبت‌نام کاربر چند مرحله دارد:

Step 1 → Account
Step 2 → Profile
Step 3 → Confirmation

می‌توانیم میزان پیشرفت را نمایش دهیم:

<div class="mb-2">
    مرحله 2 از 3
</div>

<div class="progress">

    <div
        class="progress-bar"
        role="progressbar"
        style="width: 66%;"
        aria-valuenow="66"
        aria-valuemin="0"
        aria-valuemax="100"
    >
        66%
    </div>

</div>

Progress در داشبورد

مثلاً می‌توانیم میزان تکمیل پروفایل را نشان دهیم:

<div class="card">

    <div class="card-body">

        <h5 class="card-title">
            تکمیل پروفایل
        </h5>

        <p>
            پروفایل شما 75 درصد تکمیل شده است.
        </p>

        <div class="progress">

            <div
                class="progress-bar"
                role="progressbar"
                style="width: 75%;"
                aria-valuenow="75"
                aria-valuemin="0"
                aria-valuemax="100"
            >
                75%
            </div>

        </div>

    </div>

</div>

نمونه واقعی: فرم ذخیره اطلاعات

می‌توانیم Alert و Toast را با یک فرم ترکیب کنیم:

<div class="container py-5">

    <div class="row justify-content-center">

        <div class="col-12 col-md-8 col-lg-6">

            <div class="card shadow-sm">

                <div class="card-body">

                    <h1 class="h4 mb-4">
                        اطلاعات کاربری
                    </h1>

                    <div
                        id="errorAlert"
                        class="alert alert-danger d-none"
                        role="alert"
                    >
                        لطفاً نام و ایمیل را وارد کنید.
                    </div>

                    <form id="profileForm">

                        <div class="mb-3">

                            <label
                                for="name"
                                class="form-label"
                            >
                                نام
                            </label>

                            <input
                                type="text"
                                id="name"
                                class="form-control"
                            >

                        </div>

                        <div class="mb-3">

                            <label
                                for="email"
                                class="form-label"
                            >
                                ایمیل
                            </label>

                            <input
                                type="email"
                                id="email"
                                class="form-control"
                            >

                        </div>

                        <button
                            type="submit"
                            class="btn btn-primary"
                        >
                            ذخیره
                        </button>

                    </form>

                </div>

            </div>

        </div>

    </div>

</div>

<div class="toast-container position-fixed bottom-0 end-0 p-3">

    <div
        id="successToast"
        class="toast"
        role="alert"
        aria-live="polite"
        aria-atomic="true"
    >

        <div class="toast-header">

            <strong class="me-auto">
                سیستم
            </strong>

            <button
                type="button"
                class="btn-close"
                data-bs-dismiss="toast"
                aria-label="بستن"
            ></button>

        </div>

        <div class="toast-body">
            اطلاعات با موفقیت ذخیره شد.
        </div>

    </div>

</div>

<script>

    const form =
        document.getElementById('profileForm');

    const errorAlert =
        document.getElementById('errorAlert');

    const successToastElement =
        document.getElementById('successToast');

    const successToast =
        new bootstrap.Toast(successToastElement);

    form.addEventListener('submit', function (event) {

        event.preventDefault();

        const name =
            document.getElementById('name').value.trim();

        const email =
            document.getElementById('email').value.trim();

        if (!name || !email) {

            errorAlert.classList.remove('d-none');

            return;
        }

        errorAlert.classList.add('d-none');

        successToast.show();

    });

</script>

در این مثال:

  • خطای فرم با Alert نمایش داده می‌شود.

  • پیام موفقیت با Toast نمایش داده می‌شود.

  • d-none برای مخفی کردن Alert استفاده شده است.

  • JavaScript رفتار فرم را کنترل می‌کند.

نمونه واقعی: آپلود فایل

یک UI ساده برای آپلود فایل:

<div class="container py-5">

    <div class="card">

        <div class="card-body">

            <h2 class="h5 mb-3">
                آپلود فایل
            </h2>

            <input
                type="file"
                class="form-control mb-3"
            >

            <div class="mb-2">
                میزان پیشرفت
            </div>

            <div class="progress">

                <div
                    id="progressBar"
                    class="progress-bar progress-bar-striped progress-bar-animated"
                    role="progressbar"
                    style="width: 0%;"
                    aria-valuenow="0"
                    aria-valuemin="0"
                    aria-valuemax="100"
                >
                    0%
                </div>

            </div>

        </div>

    </div>

</div>

در پروژه واقعی می‌توان Progress را به API یا Upload Service متصل کرد.

Alert، Toast و Progress در یک معماری Frontend

در یک پروژه واقعی بهتر است مسئولیت هر کامپوننت مشخص باشد:

User Action
     |
     v
Application Logic
     |
     +------> Error -------> Alert
     |
     +------> Success -----> Toast
     |
     +------> Long Process -> Progress

برای مثال هنگام آپلود فایل:

Select File
    |
    v
Upload Started
    |
    v
Progress 0% -> 25% -> 50% -> 75% -> 100%
    |
    v
Upload Completed
    |
    v
Success Toast

این الگو در بسیاری از برنامه‌های واقعی کاربرد دارد.

نکات Accessibility

هنگام استفاده از Alert باید نقش مناسب مشخص شود:

<div
    class="alert alert-danger"
    role="alert"
>
    عملیات ناموفق بود.
</div>

برای Toast نیز بسته به نوع پیام می‌توان از aria-live مناسب استفاده کرد:

<div
    class="toast"
    role="alert"
    aria-live="polite"
    aria-atomic="true"
>
    ...
</div>

برای Progress نیز استفاده از ویژگی‌های زیر مهم است:

role="progressbar"
aria-valuenow="60"
aria-valuemin="0"
aria-valuemax="100"

این اطلاعات به فناوری‌های کمکی کمک می‌کنند وضعیت Progress را بهتر درک کنند.

Alert، Toast و Progress در طراحی Responsive

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

برای Alert معمولاً Bootstrap به صورت پیش‌فرض رفتار مناسبی دارد.

برای Toast باید به محل قرارگیری توجه کنیم.

مثلاً:

<div class="toast-container position-fixed bottom-0 end-0 p-3">

اگر Toast بسیار عریض باشد، ممکن است در موبایل فضای زیادی اشغال کند. بنابراین بهتر است محتوا کوتاه باشد.

برای Progress نیز بهتر است متن داخل آن خیلی طولانی نباشد:

<div class="progress">
    <div class="progress-bar" style="width: 75%;">
        75%
    </div>
</div>

اشتباهات رایج

استفاده از Alert برای همه پیام‌ها

هر پیام کوتاهی نباید Alert باشد.

برای اعلان‌های موقتی، Toast می‌تواند مناسب‌تر باشد.

استفاده از Toast برای خطاهای مهم

اگر کاربر باید حتماً یک خطای مهم را ببیند، پیام موقتی ممکن است انتخاب مناسبی نباشد.

نمایش Progress غیرواقعی

نباید یک Progress مصنوعی ایجاد کنیم که 90 درصد را نشان دهد در حالی که عملیات واقعی هنوز مقدار مشخصی ندارد.

فراموش کردن Accessibility

ویژگی‌های ARIA و Roleها را در کامپوننت‌های اطلاع‌رسانی و Progress جدی بگیرید.

استفاده بیش از حد از رنگ

رنگ باید به درک وضعیت کمک کند، نه اینکه تنها راه تشخیص وضعیت باشد.

تمرین عملی

یک صفحه مدیریت کاربر ایجاد کنید که شامل موارد زیر باشد:

  1. فرم ویرایش کاربر

  2. Alert برای نمایش خطا

  3. Toast برای نمایش ذخیره موفق

  4. Progress برای نمایش میزان تکمیل پروفایل

  5. طراحی Responsive

  6. استفاده از RTL

میزان تکمیل پروفایل را به صورت زیر نمایش دهید:

Profile Completion
[##############------] 70%

تمرین پیشرفته

یک صفحه Upload طراحی کنید که مراحل زیر را داشته باشد:

Select File
    |
    v
Upload
    |
    v
Progress
    |
    v
Completed

در هنگام شروع:

Alert → Upload started

در زمان آپلود:

Progress → 0% ... 100%

پس از موفقیت:

Toast → Upload completed

در صورت خطا:

Alert → Upload failed

همچنین صفحه باید در موبایل، تبلت و دسکتاپ به‌درستی نمایش داده شود.

جمع‌بندی

در این مقاله با سه کامپوننت مهم Bootstrap آشنا شدیم. Alert برای نمایش پیام‌هایی مانند موفقیت، خطا، هشدار و اطلاع‌رسانی در جریان محتوای صفحه استفاده می‌شود و می‌تواند ساده یا قابل بسته شدن باشد. Toast برای نمایش اعلان‌های کوتاه و موقتی بسیار مناسب است و می‌توان آن را با JavaScript ایجاد، نمایش و کنترل کرد. همچنین با Progress Bar یاد گرفتیم چگونه میزان پیشرفت عملیات‌هایی مانند آپلود فایل، تکمیل پروفایل یا مراحل ثبت‌نام را نمایش دهیم. در ادامه این کامپوننت‌ها را با Form، Card، Grid، Flexbox و JavaScript ترکیب کردیم تا به ساختارهایی نزدیک به پروژه‌های واقعی برسیم. در پروژه‌های حرفه‌ای، انتخاب صحیح بین Alert، Toast و Progress اهمیت زیادی دارد؛ زیرا هرکدام برای نوع متفاوتی از اطلاعات و تعامل کاربر طراحی شده‌اند.

۱۰

نظرات

کد در دسترس نیست

هنوز نظری ثبت نشده است.