diff --git a/src/app/pages/category/category.component.html b/src/app/pages/category/category.component.html
index 9e10629..001c290 100644
--- a/src/app/pages/category/category.component.html
+++ b/src/app/pages/category/category.component.html
@@ -12,7 +12,7 @@
- @if (loading() && items().length > 0) {
-
-
-
{{ 'category.loadingMore' | translate }}
-
- }
+ @if (loading() && items().length > 0) {
+ @for (i of skeletonSlots; track i) {
+
+ }
+ }
+
@if (!hasMore() && items().length > 0) {
diff --git a/src/app/pages/category/category.component.scss b/src/app/pages/category/category.component.scss
index 4ed4a0b..25e5ddb 100644
--- a/src/app/pages/category/category.component.scss
+++ b/src/app/pages/category/category.component.scss
@@ -141,7 +141,7 @@
display: flex;
align-items: center;
justify-content: center;
- background: #f5f5f5;
+ background: #f0f0f0;
img {
width: 100%;
@@ -149,7 +149,7 @@
object-fit: contain;
background: white;
padding: 12px;
- transition: transform 0.3s ease;
+ transition: transform 0.3s ease, opacity 0.3s ease;
}
&:hover img {
@@ -290,11 +290,6 @@
}
}
-.loading-more {
- text-align: center;
- padding: 40px 20px;
-}
-
.spinner {
width: 40px;
height: 40px;
@@ -315,6 +310,59 @@
padding: 40px 20px;
}
+// Skeleton loading cards
+.skeleton-card {
+ pointer-events: none;
+
+ .skeleton-image {
+ background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
+ background-size: 200% 100%;
+ animation: shimmer 1.5s infinite;
+ }
+
+ .skeleton-line {
+ border-radius: 6px;
+ background: linear-gradient(90deg, #e8e8e8 25%, #d8d8d8 50%, #e8e8e8 75%);
+ background-size: 200% 100%;
+ animation: shimmer 1.5s infinite;
+ }
+
+ .skeleton-title {
+ height: 16px;
+ width: 80%;
+ }
+
+ .skeleton-rating {
+ height: 12px;
+ width: 50%;
+ }
+
+ .skeleton-price {
+ height: 18px;
+ width: 40%;
+ margin-top: auto;
+ }
+
+ .skeleton-stock {
+ height: 6px;
+ width: 60px;
+ }
+
+ .skeleton-btn {
+ height: 42px;
+ background: linear-gradient(90deg, #5a8a85 25%, #497671 50%, #5a8a85 75%);
+ background-size: 200% 100%;
+ animation: shimmer 1.5s infinite;
+ border-radius: 0 0 13px 13px;
+ margin-top: -1px;
+ }
+}
+
+@keyframes shimmer {
+ 0% { background-position: 200% 0; }
+ 100% { background-position: -200% 0; }
+}
+
// Responsive
@media (max-width: 1200px) {
.items-grid {
diff --git a/src/app/pages/category/category.component.ts b/src/app/pages/category/category.component.ts
index 8e3dc6d..386dd4d 100644
--- a/src/app/pages/category/category.component.ts
+++ b/src/app/pages/category/category.component.ts
@@ -90,7 +90,7 @@ export class CategoryComponent implements OnInit, OnDestroy {
this.scrollTimeout = setTimeout(() => {
const scrollPosition = window.innerHeight + window.scrollY;
- const bottomPosition = document.documentElement.scrollHeight - 500;
+ const bottomPosition = document.documentElement.scrollHeight - 1200;
if (scrollPosition >= bottomPosition && !this.loading() && this.hasMore() && !this.isLoadingMore) {
this.loadItems();
@@ -104,6 +104,7 @@ export class CategoryComponent implements OnInit, OnDestroy {
this.cartService.addItem(itemID);
}
+ readonly skeletonSlots = Array.from({ length: 8 });
readonly getDiscountedPrice = getDiscountedPrice;
readonly getMainImage = getMainImage;
readonly trackByItemId = trackByItemId;