feat(icons): add Lucide icon foundation

Add @lucide/angular dependency and a single shared entry point for
every icon in the app: app-icon (src/app/shared/ui/icon), backed by a
canonical name -> Lucide-icon registry (icon-registry.ts) covering
every concept the RC icon audit needs across storefront, builder, and
backoffice. One name per meaning, one default size/stroke-width, so
every screen renders the same icon the same way.

Package note: lucide-angular (unscoped) is deprecated upstream in
favor of @lucide/angular - installed the maintained package directly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-20 01:49:38 +04:00
parent fd5a436220
commit f3c8a8cc96
4 changed files with 216 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
import {
LucideAlignLeft as AlignLeft,
LucideArrowDown as ArrowDown,
LucideArrowLeft as ArrowLeft,
LucideArrowRight as ArrowRight,
LucideArrowUp as ArrowUp,
LucideBadgeCheck as BadgeCheck,
LucideBarChart3 as BarChart3,
LucideBell as Bell,
LucideBook as Book,
LucideBoxes as Boxes,
LucideBuilding2 as Building2,
LucideCalendar as Calendar,
LucideCheck as Check,
LucideCheckCircle2 as CheckCircle2,
LucideChevronDown as ChevronDown,
LucideChevronLeft as ChevronLeft,
LucideChevronRight as ChevronRight,
LucideChevronUp as ChevronUp,
LucideCircle as Circle,
LucideClock as Clock,
LucideCode2 as Code2,
LucideCompass as Compass,
LucideCopy as Copy,
LucideCreditCard as CreditCard,
LucideDatabase as Database,
LucideDownload as Download,
LucideFilter as Filter,
LucideFlag as Flag,
LucideFolder as Folder,
LucideGlobe as Globe,
LucideHeart as Heart,
LucideHelpCircle as HelpCircle,
LucideHistory as History,
LucideHome as Home,
LucideImage as Image,
LucideImages as Images,
LucideInfo as Info,
LucideLayoutGrid as LayoutGrid,
LucideLineChart as LineChart,
LucideLink as Link,
LucideList as List,
LucideLoader2 as Loader2,
LucideLock as Lock,
LucideLogOut as LogOut,
LucideMegaphone as Megaphone,
LucideMenu as Menu,
LucideMinus as Minus,
LucideMonitor as Monitor,
LucideNetwork as Network,
LucidePackage as Package,
LucidePalette as Palette,
LucidePencil as Pencil,
LucidePlus as Plus,
LucidePlusCircle as PlusCircle,
LucideSave as Save,
LucideScale as Scale,
LucideSearch as Search,
LucideSettings as Settings,
LucideShield as Shield,
LucideShoppingCart as ShoppingCart,
LucideSlidersHorizontal as SlidersHorizontal,
LucideSquare as Square,
LucideStar as Star,
LucideStore as Store,
LucideTable as Table,
LucideTag as Tag,
LucideTags as Tags,
LucideTrash2 as Trash2,
LucideTriangleAlert as TriangleAlert,
LucideUpload as Upload,
LucideUser as User,
LucideUsers as Users,
LucideVideo as Video,
LucideX as X,
LucideXCircle as XCircle
} from '@lucide/angular';
/**
* Canonical name -> Lucide icon map for the whole app (storefront + builder + backoffice).
* One entry per concept so every screen renders the same icon for the same meaning
* (RC UI Sprint - Icon & Visual Language Audit). Extend this list rather than
* importing Lucide icons ad hoc in individual components.
*/
export const APP_ICONS = {
home: Home,
store: Store,
cart: ShoppingCart,
package: Package,
boxes: Boxes,
folder: Folder,
tag: Tag,
tags: Tags,
users: Users,
user: User,
settings: Settings,
chartBar: BarChart3,
chartLine: LineChart,
search: Search,
filter: Filter,
heart: Heart,
scale: Scale,
bell: Bell,
image: Image,
images: Images,
palette: Palette,
monitor: Monitor,
shield: Shield,
lock: Lock,
database: Database,
upload: Upload,
download: Download,
edit: Pencil,
trash: Trash2,
copy: Copy,
plus: Plus,
plusCircle: PlusCircle,
minus: Minus,
check: Check,
checkCircle: CheckCircle2,
x: X,
xCircle: XCircle,
arrowUp: ArrowUp,
arrowDown: ArrowDown,
arrowLeft: ArrowLeft,
arrowRight: ArrowRight,
chevronUp: ChevronUp,
chevronDown: ChevronDown,
chevronLeft: ChevronLeft,
chevronRight: ChevronRight,
info: Info,
help: HelpCircle,
warning: TriangleAlert,
clock: Clock,
calendar: Calendar,
menu: Menu,
alignLeft: AlignLeft,
book: Book,
building: Building2,
code: Code2,
compass: Compass,
creditCard: CreditCard,
flag: Flag,
globe: Globe,
history: History,
link: Link,
list: List,
megaphone: Megaphone,
logOut: LogOut,
network: Network,
slidersHorizontal: SlidersHorizontal,
spinner: Loader2,
star: Star,
stop: Square,
table: Table,
layoutGrid: LayoutGrid,
verified: BadgeCheck,
video: Video,
circle: Circle
} as const;
export type AppIconName = keyof typeof APP_ICONS;

View File

@@ -0,0 +1,39 @@
import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
import { LucideDynamicIcon } from '@lucide/angular';
import { APP_ICONS, type AppIconName } from './icon-registry';
/**
* Single entry point for every icon in the app. Renders a Lucide icon by
* canonical name (see icon-registry.ts) so every screen uses one icon family
* at one consistent size/stroke-width by default.
*
* Decorative by default (aria-hidden). Pass `ariaLabel` only when the icon
* itself carries meaning with no adjacent text (e.g. inside an icon-only
* button) - the label belongs on the interactive element when there is one.
*/
@Component({
selector: 'app-icon',
standalone: true,
imports: [LucideDynamicIcon],
template: `
<svg
[lucideIcon]="iconData()"
[size]="size()"
[strokeWidth]="strokeWidth()"
[title]="ariaLabel()"
></svg>
`,
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'app-icon',
'[style.display]': "'inline-flex'"
}
})
export class IconComponent {
readonly name = input.required<AppIconName>();
readonly size = input<number>(20);
readonly strokeWidth = input<number>(2);
readonly ariaLabel = input<string | null>(null);
protected readonly iconData = computed(() => APP_ICONS[this.name()]);
}