fix(icons): replace hand-rolled inline SVGs with Lucide (cart, selectors, carousel)
Cart: trash/X/plus/minus/lock icons replaced with app-icon. Removed the standalone EmptyCartIconComponent entirely - it was a duplicate 80px shopping-cart glyph with no unique illustration, only ever used in one place; now app-icon name="cart" inline. Language/region selectors: dropdown chevrons (duplicated 3x with identical path data across two components) unified on chevronDown; region pin, locate (crosshair), and globe icons replaced. New mapPin/locate icons added to the registry. Items carousel: rating star and add-to-cart icons replaced. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +0,0 @@
|
||||
<svg width="80" height="80" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3 4h2l2.5 10.5a2 2 0 0 0 2 1.5H17a2 2 0 0 0 2-1.5L21 7H6" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<circle cx="10" cy="19" r="1.5" stroke="currentColor" stroke-width="2"/>
|
||||
<circle cx="17" cy="19" r="1.5" stroke="currentColor" stroke-width="2"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 411 B |
@@ -1,7 +0,0 @@
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
svg {
|
||||
color: var(--primary-color);
|
||||
}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-empty-cart-icon',
|
||||
templateUrl: './empty-cart-icon.component.html',
|
||||
styleUrls: ['./empty-cart-icon.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
export class EmptyCartIconComponent {}
|
||||
@@ -36,9 +36,7 @@
|
||||
|
||||
@if (product.rating) {
|
||||
<div class="item-rating">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="#497671" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26L12 2Z"/>
|
||||
</svg>
|
||||
<app-icon name="star" [size]="14" />
|
||||
<span class="rating-value">{{ product.rating }}</span>
|
||||
<span class="rating-count">({{ product.callbacks?.length || 0 }})</span>
|
||||
</div>
|
||||
@@ -54,11 +52,7 @@
|
||||
}
|
||||
</div>
|
||||
<button class="cart-icon-btn" (click)="addToCart($event, product)" [title]="'carousel.addToCart' | translate">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M6 2L3 6v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2V6l-3-4z"></path>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<path d="M16 10a4 4 0 0 1-8 0"></path>
|
||||
</svg>
|
||||
<app-icon name="cart" [size]="16" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,11 +11,12 @@ import { LanguageService } from '../../services/language.service';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { ProductFacade } from '../../facades/platform/product.facade';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-items-carousel',
|
||||
templateUrl: './items-carousel.component.html',
|
||||
imports: [DecimalPipe, RouterLink, CarouselModule, ButtonModule, TagModule, LangRoutePipe, TranslatePipe],
|
||||
imports: [DecimalPipe, RouterLink, CarouselModule, ButtonModule, TagModule, LangRoutePipe, TranslatePipe, IconComponent],
|
||||
styleUrls: ['./items-carousel.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
})
|
||||
|
||||
@@ -4,9 +4,7 @@
|
||||
[alt]="languageService.getCurrentLanguage()?.name"
|
||||
class="language-flag">
|
||||
<span class="language-code">{{ languageService.getCurrentLanguage()?.code?.toUpperCase() }}</span>
|
||||
<svg class="dropdown-arrow" [class.rotated]="dropdownOpen" width="12" height="12" viewBox="0 0 12 12" fill="none">
|
||||
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<app-icon name="chevronDown" [size]="14" [class.rotated]="dropdownOpen" class="dropdown-arrow" />
|
||||
</button>
|
||||
|
||||
<div class="language-dropdown" [class.open]="dropdownOpen">
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { Component, HostListener, ElementRef, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { LanguageService, Language, Currency } from '../../services/language.service';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-language-selector',
|
||||
imports: [],
|
||||
imports: [IconComponent],
|
||||
templateUrl: './language-selector.component.html',
|
||||
styleUrls: ['./language-selector.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<div class="region-selector">
|
||||
<button class="region-trigger" (click)="toggleDropdown()" [class.active]="dropdownOpen()">
|
||||
<svg class="pin-icon" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"></path>
|
||||
<circle cx="12" cy="10" r="3"></circle>
|
||||
</svg>
|
||||
<app-icon name="mapPin" [size]="16" class="pin-icon" />
|
||||
<span class="region-name">
|
||||
@if (detecting()) {
|
||||
<span class="detecting">...</span>
|
||||
@@ -13,10 +10,7 @@
|
||||
{{ 'location.allRegions' | translate }}
|
||||
}
|
||||
</span>
|
||||
<svg class="chevron" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"
|
||||
[class.rotated]="dropdownOpen()">
|
||||
<path d="M6 9l6 6 6-6"></path>
|
||||
</svg>
|
||||
<app-icon name="chevronDown" [size]="14" [class.rotated]="dropdownOpen()" class="chevron" />
|
||||
</button>
|
||||
|
||||
@if (dropdownOpen()) {
|
||||
@@ -25,20 +19,14 @@
|
||||
<span>{{ 'location.chooseRegion' | translate }}</span>
|
||||
@if (!detecting()) {
|
||||
<button class="detect-btn" (click)="detectLocation()" title="{{ 'location.detectAuto' | translate }}">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M12 2v4M12 18v4M2 12h4M18 12h4"></path>
|
||||
</svg>
|
||||
<app-icon name="locate" [size]="14" />
|
||||
</button>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="region-list">
|
||||
<button class="region-option" [class.selected]="!region()" (click)="selectGlobal()">
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"></path>
|
||||
</svg>
|
||||
<app-icon name="globe" [size]="14" />
|
||||
<span>{{ 'location.allRegions' | translate }}</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@ import { Component, ChangeDetectionStrategy, inject, signal, HostListener } from
|
||||
import { LocationService } from '../../services/location.service';
|
||||
import { Region } from '../../models/location.model';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-region-selector',
|
||||
imports: [TranslatePipe],
|
||||
imports: [TranslatePipe, IconComponent],
|
||||
templateUrl: './region-selector.component.html',
|
||||
styleUrls: ['./region-selector.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
||||
@@ -3,9 +3,7 @@
|
||||
<h1>{{ 'cart.title' | translate }}</h1>
|
||||
@if (itemCount() > 0) {
|
||||
<button class="clear-cart-btn" (click)="clearCart()">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2"/>
|
||||
</svg>
|
||||
<app-icon name="trash" [size]="16" />
|
||||
{{ 'cart.clear' | translate }}
|
||||
</button>
|
||||
}
|
||||
@@ -14,7 +12,7 @@
|
||||
@if (itemCount() === 0) {
|
||||
<div class="empty-cart">
|
||||
<div class="empty-icon">
|
||||
<app-empty-cart-icon />
|
||||
<app-icon name="cart" [size]="64" />
|
||||
</div>
|
||||
<h2>{{ 'cart.empty' | translate }}</h2>
|
||||
<p>{{ 'cart.emptyDesc' | translate }}</p>
|
||||
@@ -38,9 +36,7 @@
|
||||
<div class="item-header">
|
||||
<a [routerLink]="['/product', item.itemID] | langRoute" class="item-name">{{ itemName(item) }}</a>
|
||||
<button class="remove-btn" (click)="removeItem(item)" [attr.title]="'cart.removeItem' | translate" [attr.aria-label]="'cart.removeItem' | translate">
|
||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M18 6L6 18M6 6l12 12"/>
|
||||
</svg>
|
||||
<app-icon name="x" [size]="18" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -82,15 +78,11 @@
|
||||
|
||||
<div class="quantity-controls">
|
||||
<button class="qty-btn" (click)="decreaseQuantity(item)" [disabled]="item.quantity <= 1" [attr.aria-label]="'cart.decreaseQuantity' | translate">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
||||
<path d="M5 12h14"/>
|
||||
</svg>
|
||||
<app-icon name="minus" [size]="14" />
|
||||
</button>
|
||||
<span class="qty-value">{{ item.quantity }}</span>
|
||||
<button class="qty-btn" (click)="increaseQuantity(item)" [attr.aria-label]="'cart.increaseQuantity' | translate">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
|
||||
<path d="M12 5v14M5 12h14"/>
|
||||
</svg>
|
||||
<app-icon name="plus" [size]="14" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -105,9 +97,7 @@
|
||||
</div>
|
||||
|
||||
<button class="delete-btn-mobile" (click)="removeItem(item)" [attr.aria-label]="'cart.removeItem' | translate">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M3 6h18M19 6v14a2 2 0 01-2 2H7a2 2 0 01-2-2V6m3 0V4a2 2 0 012-2h4a2 2 0 012 2v2" stroke="white" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<app-icon name="trash" [size]="20" />
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
@@ -181,9 +171,7 @@
|
||||
@if (!isAuthenticated()) {
|
||||
<div class="cart-login-gate">
|
||||
<div class="login-gate-icon">
|
||||
<svg width="40" height="40" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
||||
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
|
||||
</svg>
|
||||
<app-icon name="lock" [size]="32" />
|
||||
</div>
|
||||
<p class="login-gate-title">{{ 'cart.loginRequired' | translate }}</p>
|
||||
<p class="login-gate-desc">{{ 'cart.loginRequiredDesc' | translate }}</p>
|
||||
@@ -206,9 +194,7 @@
|
||||
<div class="payment-modal-overlay">
|
||||
<div class="payment-modal">
|
||||
<button class="close-modal-btn" (click)="closePaymentPopup()" [attr.aria-label]="'cart.close' | translate">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<app-icon name="x" [size]="20" />
|
||||
</button>
|
||||
@if (paymentStatus() === 'creating') {
|
||||
<div class="payment-status-screen">
|
||||
@@ -343,9 +329,7 @@
|
||||
<div class="bank-payment-modal-overlay">
|
||||
<div class="bank-payment-modal">
|
||||
<button class="close-modal-btn" (click)="closeBankPaymentPopup()" [attr.aria-label]="'cart.close' | translate">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none">
|
||||
<path d="M6 6L18 18M6 18L18 6" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<app-icon name="x" [size]="20" />
|
||||
</button>
|
||||
<iframe [src]="bankPaymentFrameUrl()" class="bank-payment-frame" title="Bank card payment"></iframe>
|
||||
</div>
|
||||
|
||||
@@ -8,19 +8,19 @@ import { Item, CartItem, DeliveryOption } from '../../models';
|
||||
import { EMPTY, interval, of, Subscription } from 'rxjs';
|
||||
import { catchError, exhaustMap, take, timeout } from 'rxjs/operators';
|
||||
import { DeliverySelectorComponent } from '../../components/delivery-selector/delivery-selector.component';
|
||||
import { EmptyCartIconComponent } from '../../components/empty-cart-icon/empty-cart-icon.component';
|
||||
import { TelegramLoginComponent } from '../../components/telegram-login/telegram-login.component';
|
||||
import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTranslatedField } from '../../utils/item.utils';
|
||||
import { LangRoutePipe } from '../../pipes/lang-route.pipe';
|
||||
import { TranslatePipe } from '../../i18n/translate.pipe';
|
||||
import { TranslateService } from '../../i18n/translate.service';
|
||||
import { PAYMENT_POLL_INTERVAL_MS, PAYMENT_MAX_CHECKS, PAYMENT_TIMEOUT_CLOSE_MS, LINK_COPIED_DURATION_MS } from '../../config/constants';
|
||||
import { IconComponent } from '../../shared/ui/icon/icon.component';
|
||||
|
||||
type PaymentMethod = 'qr' | 'card';
|
||||
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
imports: [DecimalPipe, RouterLink, FormsModule, EmptyCartIconComponent, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe],
|
||||
imports: [DecimalPipe, RouterLink, FormsModule, DeliverySelectorComponent, TelegramLoginComponent, LangRoutePipe, TranslatePipe, IconComponent],
|
||||
templateUrl: './cart.component.html',
|
||||
styleUrls: ['./cart.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
|
||||
@@ -42,8 +42,10 @@ import {
|
||||
LucideLink as Link,
|
||||
LucideList as List,
|
||||
LucideLoader2 as Loader2,
|
||||
LucideLocate as Locate,
|
||||
LucideLock as Lock,
|
||||
LucideLogOut as LogOut,
|
||||
LucideMapPin as MapPin,
|
||||
LucideMegaphone as Megaphone,
|
||||
LucideMenu as Menu,
|
||||
LucideMinus as Minus,
|
||||
@@ -149,6 +151,8 @@ export const APP_ICONS = {
|
||||
history: History,
|
||||
link: Link,
|
||||
list: List,
|
||||
locate: Locate,
|
||||
mapPin: MapPin,
|
||||
megaphone: Megaphone,
|
||||
logOut: LogOut,
|
||||
network: Network,
|
||||
|
||||
Reference in New Issue
Block a user