fix(icons): migrate Marketplace Builder to Lucide

Replace every PrimeIcons pi-* usage across the builder: overview page
(back link, next-step arrow, section cards, readiness checklist,
quick links), sidebar nav (group/section status dots), main layout
(back/home/menu/help icons), brand + homepage overview panels
(checklist ok/pending dots, contrast warning), footer/homepage/widgets
section editors (drag handles, move up/down, duplicate, remove), and
the HTML editor toolbar (list/link/image/table/divider/code/embed).

Notable correctness fix: PrimeIcons reused pi-bars for both the
hamburger menu toggle AND every drag handle - two different meanings
sharing one icon (exactly the kind of icon collision the audit calls
out). Added a dedicated 'grip' icon (GripVertical) for drag handles so
menu and drag-to-reorder are visually distinct.

Added a global .spin utility (icon-registry has no built-in spinner
animation) for the one loading-spinner icon in the builder overview
checklist.

All icon-bearing fields (BuilderGroup.icon, BlockCatalogEntry.icon,
WIDGET_ICONS, STATUS_ICON, HtmlEditorToolbarCommand.icon, etc.) are
now typed AppIconName instead of string.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-20 02:31:06 +04:00
parent 330f24c8d7
commit 043192accf
21 changed files with 125 additions and 95 deletions

View File

@@ -14,7 +14,7 @@
(click)="runCommand(item)"
>
@if (item.icon) {
<span class="pi {{ item.icon }}" aria-hidden="true"></span>
<app-icon [name]="item.icon" [size]="16" />
} @else {
{{ item.label }}
}

View File

@@ -3,14 +3,16 @@ import { TranslateService } from '../../../../i18n/translate.service';
import { TranslatePipe } from '../../../../i18n/translate.pipe';
import { validateHtml } from '../../schema/validators/primitives';
import { CodeEditorComponent } from '../../../../shared/ui/code-editor/code-editor.component';
import { IconComponent } from '../../../../shared/ui/icon/icon.component';
import { AppIconName } from '../../../../shared/ui/icon/icon-registry';
export interface HtmlEditorToolbarCommand {
id: string;
label: string;
command: string;
value?: string;
/** PrimeIcons class (e.g. 'pi-list'); when set the icon renders instead of the label. */
icon?: string;
/** Lucide icon name (see icon-registry.ts); when set the icon renders instead of the label. */
icon?: AppIconName;
/** i18n key for the tooltip/aria-label. */
titleKey?: string;
}
@@ -21,14 +23,14 @@ export const HTML_EDITOR_TOOLBAR: HtmlEditorToolbarCommand[] = [
{ id: 'underline', label: 'U', command: 'underline', titleKey: 'builder.htmlToolUnderline' },
{ id: 'h2', label: 'H2', command: 'formatBlock', value: 'H2', titleKey: 'builder.htmlToolHeading' },
{ id: 'h3', label: 'H3', command: 'formatBlock', value: 'H3', titleKey: 'builder.htmlToolSubheading' },
{ id: 'ul', label: '', icon: 'pi-list', command: 'insertUnorderedList', titleKey: 'builder.htmlToolBulletList' },
{ id: 'ul', label: '', icon: 'list', command: 'insertUnorderedList', titleKey: 'builder.htmlToolBulletList' },
{ id: 'ol', label: '1.', command: 'insertOrderedList', titleKey: 'builder.htmlToolNumberedList' },
{ id: 'link', label: '', icon: 'pi-link', command: 'createLink', titleKey: 'builder.htmlToolLink' },
{ id: 'image', label: '', icon: 'pi-image', command: 'insertImage', titleKey: 'builder.htmlToolImage' },
{ id: 'table', label: '', icon: 'pi-table', command: 'insertHTML', value: '<table><tr><td>&nbsp;</td><td>&nbsp;</td></tr></table>', titleKey: 'builder.htmlToolTable' },
{ id: 'hr', label: '', icon: 'pi-minus', command: 'insertHorizontalRule', titleKey: 'builder.htmlToolDivider' },
{ id: 'codeblock', label: '', icon: 'pi-code', command: 'formatBlock', value: 'PRE', titleKey: 'builder.htmlToolCodeBlock' },
{ id: 'embed', label: '', icon: 'pi-video', command: 'insertEmbed', titleKey: 'builder.htmlToolEmbed' },
{ id: 'link', label: '', icon: 'link', command: 'createLink', titleKey: 'builder.htmlToolLink' },
{ id: 'image', label: '', icon: 'image', command: 'insertImage', titleKey: 'builder.htmlToolImage' },
{ id: 'table', label: '', icon: 'table', command: 'insertHTML', value: '<table><tr><td>&nbsp;</td><td>&nbsp;</td></tr></table>', titleKey: 'builder.htmlToolTable' },
{ id: 'hr', label: '', icon: 'minus', command: 'insertHorizontalRule', titleKey: 'builder.htmlToolDivider' },
{ id: 'codeblock', label: '', icon: 'code', command: 'formatBlock', value: 'PRE', titleKey: 'builder.htmlToolCodeBlock' },
{ id: 'embed', label: '', icon: 'video', command: 'insertEmbed', titleKey: 'builder.htmlToolEmbed' },
];
/** Visual grouping for the toolbar: text style | headings | lists | insert | advanced. */
@@ -43,7 +45,7 @@ export const HTML_EDITOR_TOOLBAR_GROUPS: string[][] = [
@Component({
selector: 'app-marketplace-html-editor',
standalone: true,
imports: [TranslatePipe, CodeEditorComponent],
imports: [TranslatePipe, CodeEditorComponent, IconComponent],
templateUrl: './marketplace-html-editor.component.html',
styleUrls: ['./marketplace-html-editor.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush

View File

@@ -2,9 +2,9 @@
@for (item of groups(); track item.group.id) {
<div class="editor-nav-group">
<div class="editor-nav-group__header">
<span class="pi {{ item.group.icon }} editor-nav-group__icon" aria-hidden="true"></span>
<app-icon [name]="item.group.icon" [size]="18" class="editor-nav-group__icon" />
<span class="editor-nav-group__label">{{ item.group.labelKey | translate }}</span>
<span class="pi {{ item.statusIcon }} editor-nav-group__status editor-nav-group__status--{{ item.status }}" [attr.aria-label]="item.statusLabelKey | translate"></span>
<app-icon [name]="item.statusIcon" [size]="14" [ariaLabel]="item.statusLabelKey | translate" class="editor-nav-group__status editor-nav-group__status--{{ item.status }}" />
</div>
<ul class="editor-nav-group__list">
@for (section of item.sections; track section.id) {
@@ -16,7 +16,7 @@
class="editor-nav-link"
(click)="onLinkClick()"
>
<span class="pi {{ section.statusIcon }} editor-nav-link__status editor-nav-link__status--{{ section.status }}" [attr.aria-label]="section.statusLabelKey | translate"></span>
<app-icon [name]="section.statusIcon" [size]="14" [ariaLabel]="section.statusLabelKey | translate" class="editor-nav-link__status editor-nav-link__status--{{ section.status }}" />
<span class="editor-nav-link__label">{{ section.labelKey | translate }}</span>
@if (section.issueCount > 0) {
<span class="editor-nav-badge" [attr.aria-label]="section.issueCount + ' ' + ('builder.title' | translate)">{{ section.issueCount }}</span>

View File

@@ -5,12 +5,14 @@ import { LangRoutePipe } from '../../../pipes/lang-route.pipe';
import { ProjectEditorSectionId, BuilderSectionStatus } from '../models/project-editor.model';
import { ProjectEditorFacade } from '../facade/project-editor.facade';
import { BUILDER_GROUPS, BuilderGroup } from '../builder/builder-groups.model';
import { IconComponent } from '../../../shared/ui/icon/icon.component';
import { AppIconName } from '../../../shared/ui/icon/icon-registry';
const STATUS_ICON: Record<BuilderSectionStatus, string> = {
complete: 'pi-check-circle',
'in-progress': 'pi-circle-fill',
'not-started': 'pi-circle',
unknown: 'pi-question-circle',
const STATUS_ICON: Record<BuilderSectionStatus, AppIconName> = {
complete: 'checkCircle',
'in-progress': 'circle',
'not-started': 'circle',
unknown: 'help',
};
const STATUS_LABEL_KEY: Record<BuilderSectionStatus, string> = {
@@ -24,7 +26,7 @@ interface NavSectionItem {
id: ProjectEditorSectionId;
labelKey: string;
status: BuilderSectionStatus;
statusIcon: string;
statusIcon: AppIconName;
statusLabelKey: string;
modified: boolean;
issueCount: number;
@@ -33,7 +35,7 @@ interface NavSectionItem {
interface NavGroupItem {
group: BuilderGroup;
status: BuilderSectionStatus;
statusIcon: string;
statusIcon: AppIconName;
statusLabelKey: string;
sections: NavSectionItem[];
}
@@ -56,7 +58,7 @@ const SECTION_LABEL_KEYS: Record<ProjectEditorSectionId, string> = {
@Component({
selector: 'app-project-editor-nav',
standalone: true,
imports: [TranslatePipe, RouterLink, RouterLinkActive, LangRoutePipe],
imports: [TranslatePipe, RouterLink, RouterLinkActive, LangRoutePipe, IconComponent],
templateUrl: './project-editor-nav.component.html',
styleUrls: ['./project-editor-nav.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,