fix(storefront): premium UX polish for home, catalog, search
- product-card: normalize hardcoded hex colors to design tokens (--text-primary, --border-color, --primary-color, --bg-tertiary, --bg-secondary); stock bar and stock badge now use semantic --success-color/--warning-color/--error-color instead of near-duplicate literal hex; add-to-cart hover uses --primary-hover and --transition-* tokens; card hover shadow uses --shadow-lg - product-card: add aria-pressed to favorite/compare toggle buttons so their selected state isn't color-only - filters-panel: add aria-pressed to color/size/rating filter chips; add a visible checkmark glyph on selected color swatches plus a focus-style selection ring, so selection isn't conveyed by border color alone - layout-switcher: add aria-pressed to the active layout button - catalog-container: add aria-current to the mobile sort-sheet and grid-sheet option buttons; active sort option gets a checkmark and bold weight instead of color-only highlighting - category-grid: normalize hardcoded border/background/text colors to tokens; align focus ring with the color-mix pattern used elsewhere in catalog - search-results, sorting-control: normalize skeleton/select colors to tokens; sort <select> gets a hover border state - home: convert loading-grid/empty-state spacing to --space-* tokens Build verified green via `npm run build`. Out of scope / skipped: - pages/category and pages/search retain their existing hand-rolled skeleton markup (not app-skeleton) - replacing it is a composition change, not covered by this visual-polish pass - product-card rating-stars color and legacy pages/category, pages/search hex literals left as-is where no exact token match exists, to avoid an unintended visual shift Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,10 +12,10 @@
|
||||
@if (showFavoriteControl() || showCompareControl() || showShareAction || showQuickViewPlaceholder) {
|
||||
<div class="product-actions-overlay">
|
||||
@if (showFavoriteControl()) {
|
||||
<button type="button" class="product-action-btn product-action-favorite" [attr.aria-label]="'catalog.favorite' | translate" [class.active]="isFavorite" (click)="onFavoritePlaceholder($event)">❤</button>
|
||||
<button type="button" class="product-action-btn product-action-favorite" [attr.aria-label]="'catalog.favorite' | translate" [attr.aria-pressed]="isFavorite" [class.active]="isFavorite" (click)="onFavoritePlaceholder($event)">❤</button>
|
||||
}
|
||||
@if (showCompareControl()) {
|
||||
<button type="button" class="product-action-btn" [attr.aria-label]="'catalog.compare' | translate" [class.active]="isCompared" (click)="onComparePlaceholder($event)">⇄</button>
|
||||
<button type="button" class="product-action-btn" [attr.aria-label]="'catalog.compare' | translate" [attr.aria-pressed]="isCompared" [class.active]="isCompared" (click)="onComparePlaceholder($event)">⇄</button>
|
||||
}
|
||||
@if (showShareAction) {
|
||||
<button type="button" class="product-action-btn" [attr.aria-label]="'catalog.share' | translate" (click)="onShare($event)">↗</button>
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
transition: transform var(--transition-normal), box-shadow var(--transition-normal);
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.12);
|
||||
box-shadow: var(--shadow-lg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
min-height: 220px;
|
||||
border: 1px solid #d3dad9;
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: 13px 13px 0 0;
|
||||
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f0f0f0;
|
||||
background: var(--bg-tertiary);
|
||||
|
||||
img {
|
||||
width: 100%;
|
||||
@@ -72,7 +72,7 @@
|
||||
align-items: center;
|
||||
padding: 2px 8px;
|
||||
border-radius: var(--radius-full, 999px);
|
||||
background: rgba(22, 163, 74, 0.9);
|
||||
background: color-mix(in srgb, var(--success-color) 90%, black);
|
||||
color: #fff;
|
||||
font-size: var(--font-size-xs, 0.75rem);
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
@@ -80,7 +80,7 @@
|
||||
}
|
||||
|
||||
.stock-badge.out {
|
||||
background: rgba(239, 68, 68, 0.9);
|
||||
background: color-mix(in srgb, var(--error-color) 90%, black);
|
||||
}
|
||||
|
||||
.product-actions-overlay {
|
||||
@@ -98,7 +98,7 @@
|
||||
border: 1px solid rgba(30, 60, 56, 0.15);
|
||||
border-radius: 50%;
|
||||
background: rgba(255, 255, 255, 0.95);
|
||||
color: #1e3c38;
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-lg, 1rem);
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
display: inline-flex;
|
||||
@@ -110,12 +110,12 @@
|
||||
|
||||
.product-action-btn:hover {
|
||||
transform: translateY(-1px);
|
||||
border-color: #497671;
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.product-action-btn.active {
|
||||
border-color: #497671;
|
||||
color: #497671;
|
||||
border-color: var(--primary-color);
|
||||
color: var(--primary-color);
|
||||
}
|
||||
|
||||
.product-action-btn:focus-visible,
|
||||
@@ -158,7 +158,7 @@
|
||||
min-height: 24px;
|
||||
padding: 3px 8px;
|
||||
border-radius: var(--radius-full, 999px);
|
||||
background: #497671;
|
||||
background: var(--primary-color);
|
||||
color: #fff;
|
||||
font-size: var(--font-size-xs, 0.75rem);
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
@@ -167,12 +167,12 @@
|
||||
|
||||
.product-details {
|
||||
width: 100%;
|
||||
border: 1px solid #d3dad9;
|
||||
border: 1px solid var(--border-color);
|
||||
border-top: none;
|
||||
border-radius: 0 0 13px 13px;
|
||||
padding: 16px;
|
||||
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
|
||||
background: #f5f3f9;
|
||||
background: var(--bg-secondary);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -182,7 +182,7 @@
|
||||
.product-name {
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
font-size: clamp(14px, 1.4vw, 18px);
|
||||
color: #1e3c38;
|
||||
color: var(--text-primary);
|
||||
margin: 0;
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
@@ -196,7 +196,7 @@
|
||||
|
||||
.product-description {
|
||||
margin: 0;
|
||||
color: #697777;
|
||||
color: var(--text-secondary);
|
||||
font-size: var(--font-size-base, 0.875rem);
|
||||
line-height: 1.45;
|
||||
display: -webkit-box;
|
||||
@@ -211,7 +211,7 @@
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: var(--font-size-sm, 0.8125rem);
|
||||
color: #697777;
|
||||
color: var(--text-secondary);
|
||||
|
||||
.rating-stars {
|
||||
color: #b45309;
|
||||
@@ -234,7 +234,7 @@
|
||||
|
||||
.discounted-price,
|
||||
.current-price {
|
||||
color: #1e3c38;
|
||||
color: var(--text-primary);
|
||||
font-size: var(--font-size-xl, 1.125rem);
|
||||
font-weight: 800;
|
||||
}
|
||||
@@ -252,18 +252,18 @@
|
||||
.bar-segment {
|
||||
flex: 1;
|
||||
border-radius: var(--radius-full, 999px);
|
||||
background: #d3dad9;
|
||||
background: var(--border-color);
|
||||
|
||||
&.filled.high {
|
||||
background: #16a34a;
|
||||
background: var(--success-color);
|
||||
}
|
||||
|
||||
&.filled.medium {
|
||||
background: #f59e0b;
|
||||
background: var(--warning-color);
|
||||
}
|
||||
|
||||
&.filled.low {
|
||||
background: #ef4444;
|
||||
background: var(--error-color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,14 +273,14 @@
|
||||
min-height: 42px;
|
||||
border: 0;
|
||||
border-radius: var(--radius-lg, 13px);
|
||||
background: #497671;
|
||||
background: var(--primary-color);
|
||||
color: #fff;
|
||||
font-weight: var(--font-weight-bold, 700);
|
||||
cursor: pointer;
|
||||
transition: background 0.2s ease, transform 0.15s ease;
|
||||
transition: background var(--transition-normal), transform var(--transition-fast);
|
||||
|
||||
&:hover {
|
||||
background: #3d635f;
|
||||
background: var(--primary-hover);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user