fix(storefront): use shared app-skeleton in category/search loading state
Category and Search pages still hand-rolled their infinite-scroll loading skeleton (.skeleton-card/.skeleton-image/.skeleton-line divs with their own hardcoded-hex shimmer animation) instead of the shared app-skeleton primitive already used by catalog-container and product-details-container. Swapped both to app-skeleton (shape=rect for image/button, shape=text for lines), removed the now-dead per-page shimmer CSS/hex colors. Closes KNOWN-ISSUES.md item 9. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -20,17 +20,17 @@
|
||||
|
||||
@if (loading() && items().length > 0) {
|
||||
@for (i of skeletonSlots; track i) {
|
||||
<div class="item-card skeleton-card">
|
||||
<div class="item-card skeleton-card" aria-hidden="true">
|
||||
<div class="item-link">
|
||||
<div class="item-image skeleton-image"></div>
|
||||
<app-skeleton shape="rect" class="item-image" height="auto" />
|
||||
<div class="item-details">
|
||||
<div class="skeleton-line skeleton-title"></div>
|
||||
<div class="skeleton-line skeleton-rating"></div>
|
||||
<div class="skeleton-line skeleton-price"></div>
|
||||
<div class="skeleton-line skeleton-stock"></div>
|
||||
<app-skeleton shape="text" width="80%" height="16px" />
|
||||
<app-skeleton shape="text" width="50%" height="12px" />
|
||||
<app-skeleton shape="text" width="40%" height="18px" />
|
||||
<app-skeleton shape="text" width="60px" height="6px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="skeleton-btn"></div>
|
||||
<app-skeleton shape="rect" class="skeleton-btn" height="42px" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,59 +310,27 @@
|
||||
padding: 40px 20px;
|
||||
}
|
||||
|
||||
// Skeleton loading cards
|
||||
// Skeleton loading cards (shimmer/animation owned by shared app-skeleton)
|
||||
.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;
|
||||
.item-image {
|
||||
display: block;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.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;
|
||||
.item-details app-skeleton {
|
||||
display: block;
|
||||
margin-bottom: var(--space-sm, 8px);
|
||||
}
|
||||
|
||||
.skeleton-btn {
|
||||
height: 42px;
|
||||
background: linear-gradient(90deg, #5a8a85 25%, #497671 50%, #5a8a85 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
display: block;
|
||||
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 {
|
||||
|
||||
@@ -12,10 +12,11 @@ import { SCROLL_THRESHOLD_PX, SCROLL_DEBOUNCE_MS, ITEMS_PER_PAGE } from '../../c
|
||||
import { ProductFacade } from '../../facades/platform/product.facade';
|
||||
import { ProductCardComponent } from '../../components/product-card/product-card.component';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
import { SkeletonComponent } from '../../shared/ui/skeleton/skeleton.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-category',
|
||||
imports: [RouterLink, LangRoutePipe, TranslatePipe, ProductCardComponent, IconComponent],
|
||||
imports: [RouterLink, LangRoutePipe, TranslatePipe, ProductCardComponent, IconComponent, SkeletonComponent],
|
||||
templateUrl: './category.component.html',
|
||||
styleUrls: ['./category.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
||||
@@ -72,17 +72,17 @@
|
||||
|
||||
@if (loading() && items().length > 0) {
|
||||
@for (i of skeletonSlots; track i) {
|
||||
<div class="item-card skeleton-card">
|
||||
<div class="item-card skeleton-card" aria-hidden="true">
|
||||
<div class="item-link">
|
||||
<div class="item-image skeleton-image"></div>
|
||||
<app-skeleton shape="rect" class="item-image" height="auto" />
|
||||
<div class="item-details">
|
||||
<div class="skeleton-line skeleton-title"></div>
|
||||
<div class="skeleton-line skeleton-rating"></div>
|
||||
<div class="skeleton-line skeleton-price"></div>
|
||||
<div class="skeleton-line skeleton-stock"></div>
|
||||
<app-skeleton shape="text" width="80%" height="16px" />
|
||||
<app-skeleton shape="text" width="50%" height="12px" />
|
||||
<app-skeleton shape="text" width="40%" height="18px" />
|
||||
<app-skeleton shape="text" width="60px" height="6px" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="skeleton-btn"></div>
|
||||
<app-skeleton shape="rect" class="skeleton-btn" height="42px" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,59 +352,27 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Skeleton loading cards
|
||||
// Skeleton loading cards (shimmer/animation owned by shared app-skeleton)
|
||||
.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;
|
||||
.item-image {
|
||||
display: block;
|
||||
aspect-ratio: 1 / 1;
|
||||
}
|
||||
|
||||
.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;
|
||||
.item-details app-skeleton {
|
||||
display: block;
|
||||
margin-bottom: var(--space-sm, 8px);
|
||||
}
|
||||
|
||||
.skeleton-btn {
|
||||
height: 42px;
|
||||
background: linear-gradient(90deg, #5a8a85 25%, #497671 50%, #5a8a85 75%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s infinite;
|
||||
display: block;
|
||||
border-radius: 0 0 13px 13px;
|
||||
margin-top: -1px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% { background-position: 200% 0; }
|
||||
100% { background-position: -200% 0; }
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.search-header h1 {
|
||||
font-size: var(--font-size-3xl, 1.5rem);
|
||||
|
||||
@@ -13,10 +13,11 @@ import { SEARCH_DEBOUNCE_MS, ITEMS_PER_PAGE, SCROLL_THRESHOLD_PX, SCROLL_DEBOUNC
|
||||
import { ProductFacade } from '../../facades/platform/product.facade';
|
||||
import { ProductCardComponent } from '../../components/product-card/product-card.component';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
import { SkeletonComponent } from '../../shared/ui/skeleton/skeleton.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
imports: [FormsModule, TranslatePipe, ProductCardComponent, IconComponent],
|
||||
imports: [FormsModule, TranslatePipe, ProductCardComponent, IconComponent, SkeletonComponent],
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
||||
Reference in New Issue
Block a user