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:
@@ -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 }}
|
||||
}
|
||||
|
||||
@@ -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> </td><td> </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> </td><td> </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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user