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:
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user