fix(icons): replace broken Material-icon-ligature text with app-icon in search suggestions
Search suggestions/popular-searches (search-autocomplete.service.ts,
search.facade.ts) set icon values like 'inventory_2', 'category', 'sell',
'auto_awesome', 'trending_up' - Material Symbols ligature names rendered as
raw {{ item.icon }} text in search-bar.component.html. No Material Icons
font is loaded anywhere in this Lucide/app-icon-based app, so these
rendered as literal garbled text ("inventory_2", etc.) instead of icons.
- SearchSuggestion.icon retyped from string to AppIconName (search.model.ts)
- Suggestion icon values mapped to registered app-icon names: product->package,
category->folder, brand->tag, ai->zap, popular/trending->trendingUp (new
registry entry, LucideTrendingUp)
- search-bar.component now renders <app-icon [name]="item.icon" /> instead of
the raw ligature string, and its icon-only clear ("x") button now renders
app-icon name="x" instead of a bare literal "x" character glyph
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,7 +26,9 @@
|
|||||||
<span class="loading-dot" [attr.aria-label]="'search.searching' | translate"></span>
|
<span class="loading-dot" [attr.aria-label]="'search.searching' | translate"></span>
|
||||||
}
|
}
|
||||||
|
|
||||||
<button type="button" class="search-clear-btn" [disabled]="!query" (click)="clearQuery()" [attr.aria-label]="'catalog.clearSearch' | translate">×</button>
|
<button type="button" class="search-clear-btn" [disabled]="!query" (click)="clearQuery()" [attr.aria-label]="'catalog.clearSearch' | translate">
|
||||||
|
<app-icon name="x" [size]="16" />
|
||||||
|
</button>
|
||||||
<button type="submit" [disabled]="loading">{{ 'catalog.searchSubmit' | translate }}</button>
|
<button type="submit" [disabled]="loading">{{ 'catalog.searchSubmit' | translate }}</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@@ -44,7 +46,7 @@
|
|||||||
[attr.aria-selected]="$index === activeSuggestionIndex()"
|
[attr.aria-selected]="$index === activeSuggestionIndex()"
|
||||||
[attr.aria-label]="suggestionLabel(item)"
|
[attr.aria-label]="suggestionLabel(item)"
|
||||||
(click)="selectSuggestion(item)">
|
(click)="selectSuggestion(item)">
|
||||||
<span class="suggestion-icon" aria-hidden="true">{{ item.icon }}</span>
|
<span class="suggestion-icon" aria-hidden="true"><app-icon [name]="item.icon" [size]="16" /></span>
|
||||||
<span class="suggestion-copy">
|
<span class="suggestion-copy">
|
||||||
<span class="suggestion-title">{{ item.title }}</span>
|
<span class="suggestion-title">{{ item.title }}</span>
|
||||||
@if (item.subtitle) {
|
@if (item.subtitle) {
|
||||||
|
|||||||
@@ -59,11 +59,13 @@
|
|||||||
.search-clear-btn {
|
.search-clear-btn {
|
||||||
min-width: 44px;
|
min-width: 44px;
|
||||||
min-height: 44px;
|
min-height: 44px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
border: 1px solid var(--border-color) !important;
|
border: 1px solid var(--border-color) !important;
|
||||||
border-radius: var(--radius-sm);
|
border-radius: var(--radius-sm);
|
||||||
background: var(--bg-primary) !important;
|
background: var(--bg-primary) !important;
|
||||||
color: var(--text-secondary) !important;
|
color: var(--text-secondary) !important;
|
||||||
font-size: var(--font-size-2xl, 1.25rem);
|
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -98,8 +100,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.suggestion-icon {
|
.suggestion-icon {
|
||||||
font-size: var(--font-size-xs, 0.75rem);
|
display: flex;
|
||||||
text-transform: uppercase;
|
align-items: center;
|
||||||
color: var(--text-secondary);
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import { ChangeDetectionStrategy, Component, EventEmitter, HostListener, Input,
|
|||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { SearchSuggestion } from '../../models/search.model';
|
import { SearchSuggestion } from '../../models/search.model';
|
||||||
import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
import { TranslatePipe } from '../../../../i18n/translate.pipe';
|
||||||
|
import { IconComponent } from '../../../../shared/ui/icon/icon.component';
|
||||||
import { TrendingSearchesComponent } from '../trending-searches/trending-searches.component';
|
import { TrendingSearchesComponent } from '../trending-searches/trending-searches.component';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search-bar',
|
selector: 'app-search-bar',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [FormsModule, TranslatePipe, TrendingSearchesComponent],
|
imports: [FormsModule, TranslatePipe, IconComponent, TrendingSearchesComponent],
|
||||||
templateUrl: './search-bar.component.html',
|
templateUrl: './search-bar.component.html',
|
||||||
styleUrls: ['./search-bar.component.scss'],
|
styleUrls: ['./search-bar.component.scss'],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush
|
changeDetection: ChangeDetectionStrategy.OnPush
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ export class SearchFacade {
|
|||||||
type: 'collection',
|
type: 'collection',
|
||||||
title: 'Smartphones',
|
title: 'Smartphones',
|
||||||
text: 'Smartphones',
|
text: 'Smartphones',
|
||||||
icon: 'trending_up',
|
icon: 'trendingUp',
|
||||||
target: { route: '/search', query: { q: 'Smartphones' } }
|
target: { route: '/search', query: { q: 'Smartphones' } }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -67,7 +67,7 @@ export class SearchFacade {
|
|||||||
type: 'collection',
|
type: 'collection',
|
||||||
title: 'Sneakers',
|
title: 'Sneakers',
|
||||||
text: 'Sneakers',
|
text: 'Sneakers',
|
||||||
icon: 'trending_up',
|
icon: 'trendingUp',
|
||||||
target: { route: '/search', query: { q: 'Sneakers' } }
|
target: { route: '/search', query: { q: 'Sneakers' } }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -75,7 +75,7 @@ export class SearchFacade {
|
|||||||
type: 'collection',
|
type: 'collection',
|
||||||
title: 'Headphones',
|
title: 'Headphones',
|
||||||
text: 'Headphones',
|
text: 'Headphones',
|
||||||
icon: 'trending_up',
|
icon: 'trendingUp',
|
||||||
target: { route: '/search', query: { q: 'Headphones' } }
|
target: { route: '/search', query: { q: 'Headphones' } }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ export class SearchFacade {
|
|||||||
type: 'collection',
|
type: 'collection',
|
||||||
title: 'Laptops',
|
title: 'Laptops',
|
||||||
text: 'Laptops',
|
text: 'Laptops',
|
||||||
icon: 'trending_up',
|
icon: 'trendingUp',
|
||||||
target: { route: '/search', query: { q: 'Laptops' } }
|
target: { route: '/search', query: { q: 'Laptops' } }
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Product, ProductSort } from '../../../core/products/models/product-domain.model';
|
import { Product, ProductSort } from '../../../core/products/models/product-domain.model';
|
||||||
|
import { AppIconName } from '../../../shared/ui/icon/icon-registry';
|
||||||
|
|
||||||
export type SearchFilterType =
|
export type SearchFilterType =
|
||||||
| 'checkbox'
|
| 'checkbox'
|
||||||
@@ -33,7 +34,7 @@ export interface SearchSuggestion {
|
|||||||
text: string;
|
text: string;
|
||||||
kind?: 'live' | 'recent' | 'popular';
|
kind?: 'live' | 'recent' | 'popular';
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
icon: string;
|
icon: AppIconName;
|
||||||
target: SearchNavigationTarget;
|
target: SearchNavigationTarget;
|
||||||
score?: number;
|
score?: number;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export class SearchAutocompleteService {
|
|||||||
text: item.name,
|
text: item.name,
|
||||||
kind: 'live' as const,
|
kind: 'live' as const,
|
||||||
subtitle: item.simpleDescription ?? '',
|
subtitle: item.simpleDescription ?? '',
|
||||||
icon: 'inventory_2',
|
icon: 'package',
|
||||||
target: { route: '/product', params: { id: item.itemID } },
|
target: { route: '/product', params: { id: item.itemID } },
|
||||||
score: this.score(item.name, normalized),
|
score: this.score(item.name, normalized),
|
||||||
}))
|
}))
|
||||||
@@ -39,7 +39,7 @@ export class SearchAutocompleteService {
|
|||||||
text: item.title,
|
text: item.title,
|
||||||
kind: 'live' as const,
|
kind: 'live' as const,
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
icon: 'category',
|
icon: 'folder',
|
||||||
target: { route: '/catalog', params: { id: item.id } },
|
target: { route: '/catalog', params: { id: item.id } },
|
||||||
score: this.score(item.title, normalized),
|
score: this.score(item.title, normalized),
|
||||||
}))
|
}))
|
||||||
@@ -57,7 +57,7 @@ export class SearchAutocompleteService {
|
|||||||
text: tag,
|
text: tag,
|
||||||
kind: 'live' as const,
|
kind: 'live' as const,
|
||||||
subtitle: '',
|
subtitle: '',
|
||||||
icon: 'sell',
|
icon: 'tag',
|
||||||
target: { route: '/search', query: { q: tag } },
|
target: { route: '/search', query: { q: tag } },
|
||||||
score: this.score(tag, normalized),
|
score: this.score(tag, normalized),
|
||||||
}))
|
}))
|
||||||
@@ -71,7 +71,7 @@ export class SearchAutocompleteService {
|
|||||||
text: query,
|
text: query,
|
||||||
kind: 'live',
|
kind: 'live',
|
||||||
subtitle: 'search.aiSuggestionHint',
|
subtitle: 'search.aiSuggestionHint',
|
||||||
icon: 'auto_awesome',
|
icon: 'zap',
|
||||||
target: { route: '/search', query: { q: query } },
|
target: { route: '/search', query: { q: query } },
|
||||||
score: 0,
|
score: 0,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ import {
|
|||||||
LucideThumbsDown as ThumbsDown,
|
LucideThumbsDown as ThumbsDown,
|
||||||
LucideThumbsUp as ThumbsUp,
|
LucideThumbsUp as ThumbsUp,
|
||||||
LucideTrash2 as Trash2,
|
LucideTrash2 as Trash2,
|
||||||
|
LucideTrendingUp as TrendingUp,
|
||||||
LucideTriangleAlert as TriangleAlert,
|
LucideTriangleAlert as TriangleAlert,
|
||||||
LucideUpload as Upload,
|
LucideUpload as Upload,
|
||||||
LucideUser as User,
|
LucideUser as User,
|
||||||
@@ -171,7 +172,8 @@ export const APP_ICONS = {
|
|||||||
verified: BadgeCheck,
|
verified: BadgeCheck,
|
||||||
video: Video,
|
video: Video,
|
||||||
circle: Circle,
|
circle: Circle,
|
||||||
zap: Zap
|
zap: Zap,
|
||||||
|
trendingUp: TrendingUp
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export type AppIconName = keyof typeof APP_ICONS;
|
export type AppIconName = keyof typeof APP_ICONS;
|
||||||
|
|||||||
Reference in New Issue
Block a user