fix(icons): replace remaining hand-rolled inline SVGs with Lucide

telegram-login: close X and lock icons (auth-gate icon reused across
telegram-login and cart - same 'log in required' concept, now the
same lock icon in both instead of two different hand-drawn shapes);
retry/refresh icon (QR expired/error states, was duplicated). Added
missing aria-label on the close button (had none).

catalog-empty-state, category, subcategories, item-detail: empty-state
illustrations (package/search/grid), add-to-cart icons, success/error
status icons, and thumbs up/down vote icons replaced. Rating stars
(item-detail, both product rating and per-review rating) now use one
Star icon with a color input and a .dx-star--filled CSS class for the
solid/outline toggle, instead of hand-toggling raw fill/stroke SVG
attributes - fixes the same rating-star pattern being drawn two
different ways (outline-only in the carousel earlier, fill-toggling
here).

Added color input to app-icon (was stroke-only via currentColor
before) and four more icons to the registry: refresh, thumbsUp/Down,
locate/mapPin (added earlier this session).

Also fixed the currency-dropdown chevron in language-selector that a
prior replace_all missed (same markup, different [class.rotated]
binding target).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-20 02:53:52 +04:00
parent 3837ddfb2d
commit e1112bbd50
14 changed files with 46 additions and 75 deletions

View File

@@ -26,9 +26,7 @@
<button class="currency-button" (click)="toggleCurrency()"> <button class="currency-button" (click)="toggleCurrency()">
<span class="currency-symbol">{{ languageService.getCurrentCurrency()?.symbol }}</span> <span class="currency-symbol">{{ languageService.getCurrentCurrency()?.symbol }}</span>
<span class="currency-code">{{ languageService.currentCurrency() }}</span> <span class="currency-code">{{ languageService.currentCurrency() }}</span>
<svg class="dropdown-arrow" [class.rotated]="currencyOpen" width="12" height="12" viewBox="0 0 12 12" fill="none"> <app-icon name="chevronDown" [size]="14" [class.rotated]="currencyOpen" class="dropdown-arrow" />
<path d="M2.5 4.5L6 8L9.5 4.5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button> </button>
<div class="currency-dropdown" [class.open]="currencyOpen"> <div class="currency-dropdown" [class.open]="currencyOpen">

View File

@@ -1,16 +1,12 @@
@if (showDialog()) { @if (showDialog()) {
<div class="login-overlay" (click)="close()"> <div class="login-overlay" (click)="close()">
<div class="login-dialog" (click)="$event.stopPropagation()"> <div class="login-dialog" (click)="$event.stopPropagation()">
<button class="close-btn" (click)="close()"> <button class="close-btn" (click)="close()" [attr.aria-label]="'cart.close' | translate">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <app-icon name="x" [size]="18" />
<path d="M18 6L6 18M6 6l12 12"/>
</svg>
</button> </button>
<div class="login-icon"> <div class="login-icon">
<svg width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"> <app-icon name="lock" [size]="40" />
<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>
</div> </div>
<h2>{{ 'auth.loginRequired' | translate }}</h2> <h2>{{ 'auth.loginRequired' | translate }}</h2>
@@ -55,19 +51,13 @@
} }
@case ('expired') { @case ('expired') {
<div class="qr-container qr-expired" (click)="refreshQr()"> <div class="qr-container qr-expired" (click)="refreshQr()">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <app-icon name="refresh" [size]="28" />
<path d="M1 4v6h6M23 20v-6h-6"/>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/>
</svg>
<span>{{ 'auth.qrExpired' | translate }}</span> <span>{{ 'auth.qrExpired' | translate }}</span>
</div> </div>
} }
@case ('error') { @case ('error') {
<div class="qr-container qr-error" (click)="refreshQr()"> <div class="qr-container qr-error" (click)="refreshQr()">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <app-icon name="refresh" [size]="28" />
<path d="M1 4v6h6M23 20v-6h-6"/>
<path d="M20.49 9A9 9 0 0 0 5.64 5.64L1 10m22 4l-4.64 4.36A9 9 0 0 1 3.51 15"/>
</svg>
<span>{{ 'auth.qrError' | translate }}</span> <span>{{ 'auth.qrError' | translate }}</span>
</div> </div>
} }

View File

@@ -7,6 +7,7 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
import { QrLoginEngine } from '../../shared/qr-login/qr-login.engine'; import { QrLoginEngine } from '../../shared/qr-login/qr-login.engine';
import { QrLoginAdapter, QrLoginStatus } from '../../shared/qr-login/qr-login.model'; import { QrLoginAdapter, QrLoginStatus } from '../../shared/qr-login/qr-login.model';
import { AuthSession } from '../../models/auth.model'; import { AuthSession } from '../../models/auth.model';
import { IconComponent } from '../../shared/ui/icon/icon.component';
/** /**
* The one QR-login dialog, reused as-is for both customer and admin login. * The one QR-login dialog, reused as-is for both customer and admin login.
@@ -18,7 +19,7 @@ import { AuthSession } from '../../models/auth.model';
*/ */
@Component({ @Component({
selector: 'app-telegram-login', selector: 'app-telegram-login',
imports: [TranslatePipe], imports: [TranslatePipe, IconComponent],
templateUrl: './telegram-login.component.html', templateUrl: './telegram-login.component.html',
styleUrls: ['./telegram-login.component.scss'], styleUrls: ['./telegram-login.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -1,17 +1,9 @@
<section class="catalog-empty-state card" [attr.data-variant]="variant"> <section class="catalog-empty-state card" [attr.data-variant]="variant">
<div class="catalog-empty-state__icon" aria-hidden="true"> <div class="catalog-empty-state__icon" aria-hidden="true">
@if (variant === 'category') { @if (variant === 'category') {
<svg viewBox="0 0 64 64" focusable="false"> <app-icon name="package" [size]="40" />
<rect x="8" y="16" width="48" height="34" rx="6"></rect>
<path d="M14 44l10-10 8 7 12-13 6 6"></path>
<circle cx="24" cy="27" r="4"></circle>
</svg>
} @else { } @else {
<svg viewBox="0 0 64 64" focusable="false"> <app-icon name="search" [size]="40" />
<circle cx="28" cy="28" r="16"></circle>
<path d="M18 28h20"></path>
<path d="M52 52L39 39"></path>
</svg>
} }
</div> </div>

View File

@@ -2,11 +2,12 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from
import { Product } from '../../../../../core/products/models/product-domain.model'; import { Product } from '../../../../../core/products/models/product-domain.model';
import { ProductCardComponent } from '../../../../../components/product-card/product-card.component'; import { ProductCardComponent } from '../../../../../components/product-card/product-card.component';
import { TranslatePipe } from '../../../../../i18n/translate.pipe'; import { TranslatePipe } from '../../../../../i18n/translate.pipe';
import { IconComponent } from '../../../../../shared/ui/icon/icon.component';
@Component({ @Component({
selector: 'app-catalog-empty-state', selector: 'app-catalog-empty-state',
standalone: true, standalone: true,
imports: [ProductCardComponent, TranslatePipe], imports: [ProductCardComponent, TranslatePipe, IconComponent],
templateUrl: './catalog-empty-state.component.html', templateUrl: './catalog-empty-state.component.html',
styleUrls: ['./catalog-empty-state.component.scss'], styleUrls: ['./catalog-empty-state.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -45,12 +45,7 @@
@if (items().length === 0 && !loading()) { @if (items().length === 0 && !loading()) {
<div class="no-items"> <div class="no-items">
<div class="no-items-icon"> <div class="no-items-icon">
<svg width="72" height="72" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <app-icon name="package" [size]="48" />
<path d="M20 7H4C3.44772 7 3 7.44772 3 8V19C3 19.5523 3.44772 20 4 20H20C20.5523 20 21 19.5523 21 19V8C21 7.44772 20.5523 7 20 7Z" stroke="#a1b4b5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 7V5C16 4.46957 15.7893 3.96086 15.4142 3.58579C15.0391 3.21071 14.5304 3 14 3H10C9.46957 3 8.96086 3.21071 8.58579 3.58579C8.21071 3.96086 8 4.46957 8 5V7" stroke="#a1b4b5" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12 12V16" stroke="#d3dad9" stroke-width="1.5" stroke-linecap="round"/>
<path d="M10 14H14" stroke="#d3dad9" stroke-width="1.5" stroke-linecap="round"/>
</svg>
</div> </div>
<h3>{{ 'category.emptyTitle' | translate }}</h3> <h3>{{ 'category.emptyTitle' | translate }}</h3>
<p>{{ 'category.emptyDesc' | translate }}</p> <p>{{ 'category.emptyDesc' | translate }}</p>

View File

@@ -11,10 +11,11 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
import { SCROLL_THRESHOLD_PX, SCROLL_DEBOUNCE_MS, ITEMS_PER_PAGE } from '../../config/constants'; import { SCROLL_THRESHOLD_PX, SCROLL_DEBOUNCE_MS, ITEMS_PER_PAGE } from '../../config/constants';
import { ProductFacade } from '../../facades/platform/product.facade'; import { ProductFacade } from '../../facades/platform/product.facade';
import { ProductCardComponent } from '../../components/product-card/product-card.component'; import { ProductCardComponent } from '../../components/product-card/product-card.component';
import { IconComponent } from '../../shared/ui/icon/icon.component';
@Component({ @Component({
selector: 'app-category', selector: 'app-category',
imports: [RouterLink, LangRoutePipe, TranslatePipe, ProductCardComponent], imports: [RouterLink, LangRoutePipe, TranslatePipe, ProductCardComponent, IconComponent],
templateUrl: './category.component.html', templateUrl: './category.component.html',
styleUrls: ['./category.component.scss'], styleUrls: ['./category.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -79,11 +79,7 @@
} }
</div> </div>
<button class="item-cart-btn" (click)="addToCart(item.itemID, $event)"> <button class="item-cart-btn" (click)="addToCart(item.itemID, $event)">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <app-icon name="cart" [size]="16" />
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
</button> </button>
</div> </div>
</a> </a>
@@ -95,12 +91,7 @@
@if (!hasSubcategories() && categoryItems().length === 0) { @if (!hasSubcategories() && categoryItems().length === 0) {
<div class="no-subcats"> <div class="no-subcats">
<div class="no-subcats-icon"> <div class="no-subcats-icon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <app-icon name="layoutGrid" [size]="40" />
<rect x="3" y="3" width="7" height="7" rx="1.5" stroke="#a1b4b5" stroke-width="1.5"/>
<rect x="14" y="3" width="7" height="7" rx="1.5" stroke="#d3dad9" stroke-width="1.5"/>
<rect x="3" y="14" width="7" height="7" rx="1.5" stroke="#d3dad9" stroke-width="1.5"/>
<rect x="14" y="14" width="7" height="7" rx="1.5" stroke="#d3dad9" stroke-width="1.5"/>
</svg>
</div> </div>
<h3>{{ 'subcategories.emptyTitle' | translate }}</h3> <h3>{{ 'subcategories.emptyTitle' | translate }}</h3>
<p>{{ 'subcategories.emptyDesc' | translate }}</p> <p>{{ 'subcategories.emptyDesc' | translate }}</p>

View File

@@ -11,10 +11,11 @@ import { getDiscountedPrice, getMainImage, trackByItemId, getBadgeClass, getTran
import { ProductFacade } from '../../facades/platform/product.facade'; import { ProductFacade } from '../../facades/platform/product.facade';
import { CategoryFacade } from '../../facades/platform/category.facade'; import { CategoryFacade } from '../../facades/platform/category.facade';
import { Category } from '../../core/categories/models/category-domain.model'; import { Category } from '../../core/categories/models/category-domain.model';
import { IconComponent } from '../../shared/ui/icon/icon.component';
@Component({ @Component({
selector: 'app-subcategories', selector: 'app-subcategories',
imports: [DecimalPipe, RouterLink, LangRoutePipe, TranslatePipe], imports: [DecimalPipe, RouterLink, LangRoutePipe, TranslatePipe, IconComponent],
templateUrl: './subcategories.component.html', templateUrl: './subcategories.component.html',
styleUrls: ['./subcategories.component.scss'], styleUrls: ['./subcategories.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -42,11 +42,7 @@
} }
} @else { } @else {
<div class="dx-no-image"> <div class="dx-no-image">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="#a1b4b5" stroke-width="1.5"> <app-icon name="image" [size]="48" />
<rect x="3" y="3" width="18" height="18" rx="2"></rect>
<circle cx="8.5" cy="8.5" r="1.5"></circle>
<path d="M21 15l-5-5L5 21"></path>
</svg>
<span>{{ 'itemDetail.noImage' | translate }}</span> <span>{{ 'itemDetail.noImage' | translate }}</span>
</div> </div>
} }
@@ -76,9 +72,7 @@
<div class="dx-rating"> <div class="dx-rating">
<div class="dx-stars"> <div class="dx-stars">
@for (star of [1, 2, 3, 4, 5]; track star) { @for (star of [1, 2, 3, 4, 5]; track star) {
<svg width="18" height="18" viewBox="0 0 24 24" [attr.fill]="star <= item()!.rating ? '#497671' : 'none'" [attr.stroke]="star <= item()!.rating ? '#497671' : '#a1b4b5'" stroke-width="2"> <app-icon name="star" [size]="18" [class.dx-star--filled]="star <= item()!.rating" [color]="star <= item()!.rating ? '#497671' : '#a1b4b5'" />
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
} }
</div> </div>
<span class="dx-rating-value">{{ item()!.rating }}</span> <span class="dx-rating-value">{{ item()!.rating }}</span>
@@ -104,7 +98,7 @@
{{ getStockLabel() }} {{ getStockLabel() }}
</span> </span>
@if (effectiveRemaining() != null) { @if (effectiveRemaining() != null) {
<span class="dx-stock-qty">({{ effectiveRemaining() }} øò.)</span> <span class="dx-stock-qty">({{ effectiveRemaining() }} <EFBFBD><EFBFBD>.)</span>
} }
</div> </div>
@@ -177,11 +171,7 @@
} }
<button class="dx-add-cart" (click)="addToCart()"> <button class="dx-add-cart" (click)="addToCart()">
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <app-icon name="cart" [size]="20" />
<circle cx="9" cy="21" r="1"></circle>
<circle cx="20" cy="21" r="1"></circle>
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"></path>
</svg>
{{ 'itemDetail.addToCart' | translate }} {{ 'itemDetail.addToCart' | translate }}
</button> </button>
@@ -260,14 +250,14 @@
@if (reviewSubmitStatus() === 'success') { @if (reviewSubmitStatus() === 'success') {
<div class="dx-status success"> <div class="dx-status success">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M20 6L9 17l-5-5"/></svg> <app-icon name="check" [size]="16" />
{{ 'itemDetail.reviewSuccess' | translate }} {{ 'itemDetail.reviewSuccess' | translate }}
</div> </div>
} }
@if (reviewSubmitStatus() === 'error') { @if (reviewSubmitStatus() === 'error') {
<div class="dx-status error"> <div class="dx-status error">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18 6L6 18M6 6l12 12"/></svg> <app-icon name="x" [size]="16" />
{{ 'itemDetail.reviewError' | translate }} {{ 'itemDetail.reviewError' | translate }}
</div> </div>
} }
@@ -287,9 +277,7 @@
@if (callback.rating) { @if (callback.rating) {
<div class="dx-review-stars"> <div class="dx-review-stars">
@for (star of [1, 2, 3, 4, 5]; track star) { @for (star of [1, 2, 3, 4, 5]; track star) {
<svg width="14" height="14" viewBox="0 0 24 24" [attr.fill]="star <= callback.rating ? '#497671' : 'none'" [attr.stroke]="star <= callback.rating ? '#497671' : '#d3dad9'" stroke-width="2"> <app-icon name="star" [size]="14" [class.dx-star--filled]="star <= callback.rating" [color]="star <= callback.rating ? '#497671' : '#d3dad9'" />
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/>
</svg>
} }
</div> </div>
} }
@@ -313,20 +301,20 @@
@for (question of item()!.questions!; track $index) { @for (question of item()!.questions!; track $index) {
<div class="dx-qa-card"> <div class="dx-qa-card">
<div class="dx-question"> <div class="dx-question">
<span class="dx-qa-label q">Â</span> <span class="dx-qa-label q"><EFBFBD></span>
<span>{{ question.question }}</span> <span>{{ question.question }}</span>
</div> </div>
<div class="dx-answer"> <div class="dx-answer">
<span class="dx-qa-label a">Î</span> <span class="dx-qa-label a"><EFBFBD></span>
<span>{{ question.answer }}</span> <span>{{ question.answer }}</span>
</div> </div>
<div class="dx-qa-votes"> <div class="dx-qa-votes">
<button class="dx-vote up"> <button class="dx-vote up">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 9V5a3 3 0 0 0-3-3l-4 9v11h11.28a2 2 0 0 0 2-1.7l1.38-9a2 2 0 0 0-2-2.3H14z"/><path d="M7 22H4a2 2 0 0 1-2-2v-7a2 2 0 0 1 2-2h3"/></svg> <app-icon name="thumbsUp" [size]="14" />
{{ question.upvotes }} {{ question.upvotes }}
</button> </button>
<button class="dx-vote down"> <button class="dx-vote down">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 15v4a3 3 0 0 0 3 3l4-9V2H5.72a2 2 0 0 0-2 1.7l-1.38 9a2 2 0 0 0 2 2.3H10z"/><path d="M17 2h2.67A2.31 2.31 0 0 1 22 4v7a2.31 2.31 0 0 1-2.33 2H17"/></svg> <app-icon name="thumbsDown" [size]="14" />
{{ question.downvotes }} {{ question.downvotes }}
</button> </button>
</div> </div>

View File

@@ -204,6 +204,10 @@ $dx-card-bg: #f5f3f9;
gap: 3px; gap: 3px;
} }
.dx-star--filled svg path {
fill: currentColor;
}
.dx-rating-value { .dx-rating-value {
font-weight: 700; font-weight: 700;
font-size: 1rem; font-size: 1rem;
@@ -310,7 +314,7 @@ $dx-card-bg: #f5f3f9;
} }
} }
// Variant chips (colour/size) shared between platform and alt // Variant chips (colour/size) <EFBFBD> shared between platform and alt
.dx-variants, .alt-variants { .dx-variants, .alt-variants {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@@ -812,7 +816,7 @@ $dx-card-bg: #f5f3f9;
// ========== platform RESPONSIVE ========== // ========== platform RESPONSIVE ==========
// Large desktop constrain gallery height // Large desktop <EFBFBD> constrain gallery height
@media (min-width: 1201px) { @media (min-width: 1201px) {
.dx-main-photo { .dx-main-photo {
max-height: 560px; max-height: 560px;

View File

@@ -14,10 +14,11 @@ import { TranslatePipe } from '../../i18n/translate.pipe';
import { TranslateService } from '../../i18n/translate.service'; import { TranslateService } from '../../i18n/translate.service';
import { ProductFacade } from '../../facades/platform/product.facade'; import { ProductFacade } from '../../facades/platform/product.facade';
import { ProductCardComponent } from '../../components/product-card/product-card.component'; import { ProductCardComponent } from '../../components/product-card/product-card.component';
import { IconComponent } from '../../shared/ui/icon/icon.component';
@Component({ @Component({
selector: 'app-item-detail', selector: 'app-item-detail',
imports: [DecimalPipe, RouterLink, FormsModule, LangRoutePipe, TranslatePipe, ProductCardComponent], imports: [DecimalPipe, RouterLink, FormsModule, LangRoutePipe, TranslatePipe, ProductCardComponent, IconComponent],
templateUrl: './item-detail.component.html', templateUrl: './item-detail.component.html',
styleUrls: ['./item-detail.component.scss'], styleUrls: ['./item-detail.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -56,6 +56,7 @@ import {
LucidePencil as Pencil, LucidePencil as Pencil,
LucidePlus as Plus, LucidePlus as Plus,
LucidePlusCircle as PlusCircle, LucidePlusCircle as PlusCircle,
LucideRefreshCw as RefreshCw,
LucideSave as Save, LucideSave as Save,
LucideScale as Scale, LucideScale as Scale,
LucideSearch as Search, LucideSearch as Search,
@@ -69,6 +70,8 @@ import {
LucideTable as Table, LucideTable as Table,
LucideTag as Tag, LucideTag as Tag,
LucideTags as Tags, LucideTags as Tags,
LucideThumbsDown as ThumbsDown,
LucideThumbsUp as ThumbsUp,
LucideTrash2 as Trash2, LucideTrash2 as Trash2,
LucideTriangleAlert as TriangleAlert, LucideTriangleAlert as TriangleAlert,
LucideUpload as Upload, LucideUpload as Upload,
@@ -121,6 +124,7 @@ export const APP_ICONS = {
plus: Plus, plus: Plus,
plusCircle: PlusCircle, plusCircle: PlusCircle,
minus: Minus, minus: Minus,
refresh: RefreshCw,
check: Check, check: Check,
checkCircle: CheckCircle2, checkCircle: CheckCircle2,
x: X, x: X,
@@ -162,6 +166,8 @@ export const APP_ICONS = {
stop: Square, stop: Square,
table: Table, table: Table,
layoutGrid: LayoutGrid, layoutGrid: LayoutGrid,
thumbsUp: ThumbsUp,
thumbsDown: ThumbsDown,
verified: BadgeCheck, verified: BadgeCheck,
video: Video, video: Video,
circle: Circle, circle: Circle,

View File

@@ -19,6 +19,7 @@ import { APP_ICONS, type AppIconName } from './icon-registry';
<svg <svg
[lucideIcon]="iconData()" [lucideIcon]="iconData()"
[size]="size()" [size]="size()"
[color]="color()"
[strokeWidth]="strokeWidth()" [strokeWidth]="strokeWidth()"
[title]="ariaLabel()" [title]="ariaLabel()"
></svg> ></svg>
@@ -32,6 +33,7 @@ import { APP_ICONS, type AppIconName } from './icon-registry';
export class IconComponent { export class IconComponent {
readonly name = input.required<AppIconName>(); readonly name = input.required<AppIconName>();
readonly size = input<number>(20); readonly size = input<number>(20);
readonly color = input<string>('currentColor');
readonly strokeWidth = input<number>(2); readonly strokeWidth = input<number>(2);
readonly ariaLabel = input<string | null>(null); readonly ariaLabel = input<string | null>(null);