@@ -162,6 +162,7 @@ import {
type AvailabilitySlot,
} from '@/api/availability';
import { ApiError } from '@/api/client';
+import ListCardSkeleton from '@/components/ui/ListCardSkeleton.vue';
import AppButton from '@/components/ui/AppButton.vue';
import AppIcon from '@/components/ui/AppIcon.vue';
import TimeRangeList from '@/components/owner/TimeRangeList.vue';
diff --git a/src/components/owner/ServiceClassManager.vue b/src/components/owner/ServiceClassManager.vue
index 6f509f1..4d01cf3 100644
--- a/src/components/owner/ServiceClassManager.vue
+++ b/src/components/owner/ServiceClassManager.vue
@@ -45,7 +45,7 @@
{{ error }}
-
در حال بارگذاری…
+
- {
if (!props.enabled) return 'غیرفعال — هر خدمت یک قیمت ثابت';
- if (loading.value) return 'فعال — در حال بارگذاری…';
+ if (loading.value) return '…';
const count = classes.value.length;
if (count === 0) return 'فعال — هنوز کلاسی تعریف نشده';
const activeCount = classes.value.filter((c) => c.isActive).length;
diff --git a/src/components/ui/AppSkeleton.vue b/src/components/ui/AppSkeleton.vue
new file mode 100644
index 0000000..5aaca9a
--- /dev/null
+++ b/src/components/ui/AppSkeleton.vue
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/src/components/ui/BusinessCardSkeleton.vue b/src/components/ui/BusinessCardSkeleton.vue
new file mode 100644
index 0000000..be637d2
--- /dev/null
+++ b/src/components/ui/BusinessCardSkeleton.vue
@@ -0,0 +1,41 @@
+
+
+
+
+
diff --git a/src/components/ui/DetailPageSkeleton.vue b/src/components/ui/DetailPageSkeleton.vue
new file mode 100644
index 0000000..b9ba2c7
--- /dev/null
+++ b/src/components/ui/DetailPageSkeleton.vue
@@ -0,0 +1,27 @@
+
+
+
+
+
diff --git a/src/components/ui/FormPageSkeleton.vue b/src/components/ui/FormPageSkeleton.vue
new file mode 100644
index 0000000..5af5b9a
--- /dev/null
+++ b/src/components/ui/FormPageSkeleton.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/src/components/ui/InlineCardSkeleton.vue b/src/components/ui/InlineCardSkeleton.vue
new file mode 100644
index 0000000..2f0a659
--- /dev/null
+++ b/src/components/ui/InlineCardSkeleton.vue
@@ -0,0 +1,12 @@
+
+
+
+
+
diff --git a/src/components/ui/ListCardSkeleton.vue b/src/components/ui/ListCardSkeleton.vue
new file mode 100644
index 0000000..97f329c
--- /dev/null
+++ b/src/components/ui/ListCardSkeleton.vue
@@ -0,0 +1,37 @@
+
+
+
+
+
diff --git a/src/components/ui/ServiceGridSkeleton.vue b/src/components/ui/ServiceGridSkeleton.vue
new file mode 100644
index 0000000..4d8aa33
--- /dev/null
+++ b/src/components/ui/ServiceGridSkeleton.vue
@@ -0,0 +1,19 @@
+
+
+
+
+
diff --git a/src/components/ui/SlotGridSkeleton.vue b/src/components/ui/SlotGridSkeleton.vue
new file mode 100644
index 0000000..b8f244e
--- /dev/null
+++ b/src/components/ui/SlotGridSkeleton.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/src/components/ui/StatGridSkeleton.vue b/src/components/ui/StatGridSkeleton.vue
new file mode 100644
index 0000000..0ca5c74
--- /dev/null
+++ b/src/components/ui/StatGridSkeleton.vue
@@ -0,0 +1,15 @@
+
+
+
+
+
diff --git a/src/views/app/AppBookingsView.vue b/src/views/app/AppBookingsView.vue
index 801f841..5803dd0 100644
--- a/src/views/app/AppBookingsView.vue
+++ b/src/views/app/AppBookingsView.vue
@@ -16,7 +16,7 @@
{{ error }}
-
در حال بارگذاری…
+
- در حال بارگذاری…
+
خدمات
- در حال بارگذاری…
+
-
- در حال بارگذاری…
-
+
@@ -33,9 +31,7 @@
@select="onCategorySelect"
/>
-
- در حال بارگذاری…
-
+
-
در حال بارگذاری…
+
-
در حال بارگذاری خدمات…
+
- {
- if (loadingServices.value) return 'در حال بارگذاری…';
+ if (loadingServices.value) return '…';
const count = services.value.length;
if (count === 0) return 'هنوز خدمتی ثبت نشده';
const activeCount = services.value.filter((s) => s.isActive).length;
diff --git a/src/views/app/AppRegisterBusinessView.vue b/src/views/app/AppRegisterBusinessView.vue
index 07f55f8..5456ef9 100644
--- a/src/views/app/AppRegisterBusinessView.vue
+++ b/src/views/app/AppRegisterBusinessView.vue
@@ -12,7 +12,7 @@
{{ error }}
-
در حال بارگذاری…
+