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:
sdarbinyan
2026-07-23 23:50:59 +04:00
parent b672cd90d5
commit 2e854954ac
6 changed files with 34 additions and 96 deletions

View File

@@ -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>
}
}

View File

@@ -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 {

View File

@@ -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

View File

@@ -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>
}
}

View File

@@ -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);

View File

@@ -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