diff --git a/apps/admin/src/pages/menu-manager/MenuEditorPage.tsx b/apps/admin/src/pages/menu-manager/MenuEditorPage.tsx index ad72d5b..9cd27fc 100644 --- a/apps/admin/src/pages/menu-manager/MenuEditorPage.tsx +++ b/apps/admin/src/pages/menu-manager/MenuEditorPage.tsx @@ -1,6 +1,25 @@ import { useState, useEffect, useRef } from 'react' import { API_BASE, type Menu } from '@homaroma/types' import { Save, Loader2, Plus, Trash2, GripVertical, Copy, Check, Download, Upload, Star, Pencil } from 'lucide-react' +import { ICON_REGISTRY, type AvailableIcons } from '../../utils/iconRegistry' +import FocalPointPicker from '../../components/page-builder/FocalPointPicker' + +const IconSelect = ({ value, onChange }: { value?: string, onChange: (val: string) => void }) => { + return ( + + ) +} const languages = ['th', 'en', 'ja', 'zh', 'vi', 'ko']; @@ -133,6 +152,15 @@ const FeaturedCardEditorFields = ({ featured, onChange }: any) => { onChange={e => updateFeatured('imageUrl', e.target.value || null)} /> + {featured.imageUrl && ( +
+ updateFeatured('focalPoint', focalPoint)} + /> +
+ )}
0 ? 'ml-6 border-l-cyan-500/30' : ''}`}> -
-
+
+
+ {type} + {nodeLabel.en || nodeLabel.th || nodeLabel.ja || 'Untitled'} +
+ +
+ + {!isCollapsed && ( + <> +
+
@@ -272,6 +314,12 @@ const TreeNodeEditor = ({ node, type, depth, onChange, onRemove, onEditFeatured, placeholder="https://cdn.example.com/image.webp" onChange={e => onChange({ ...node, [imageFieldKey]: e.target.value || null })} /> + {type !== 'root' && ( + onChange({ ...node, icon: val || undefined })} + /> + )}
@@ -338,6 +386,8 @@ const TreeNodeEditor = ({ node, type, depth, onChange, onRemove, onEditFeatured, ))}
)} + + )}
); } diff --git a/apps/admin/src/utils/iconRegistry.ts b/apps/admin/src/utils/iconRegistry.ts new file mode 100644 index 0000000..4ea8ad8 --- /dev/null +++ b/apps/admin/src/utils/iconRegistry.ts @@ -0,0 +1,103 @@ +import { + // Business + Sparkles, Leaf, Wind, Droplets, Flower2, Flame, Sofa, BedDouble, Bath, + Sun, Moon, TreePine, Sprout, Coffee, Waves, Cherry, Citrus, Snowflake, + Palmtree, Crown, Gem, Feather, Smile, Zap, Cloud, Beaker, SprayCan, + Wine, MountainSnow, Vegan, + + // E-commerce + ShoppingBag, ShoppingCart, Package, Truck, CreditCard, Wallet, Tag, Percent, + Gift, Ticket, Store, User, Heart, Clock, MapPin, Settings, LogOut, LogIn, + Bell, Bookmark, Search, Menu, X, ArrowRight, ArrowLeft, ChevronRight, + ChevronDown, Plus, Minus, Trash2, Eye, Filter, SlidersHorizontal, RefreshCw, + Camera, Share2, Award, ShieldCheck, Star, ThumbsUp, HelpCircle, Info, + Phone, Mail, MessageCircle, CheckCircle2, XCircle, AlertCircle, Calendar, Box +} from 'lucide-react'; + +export const ICON_REGISTRY = { + // Business + 'sparkles': Sparkles, + 'leaf': Leaf, + 'wind': Wind, + 'droplets': Droplets, + 'flower': Flower2, + 'flame': Flame, + 'sofa': Sofa, + 'bed': BedDouble, + 'bath': Bath, + 'sun': Sun, + 'moon': Moon, + 'tree-pine': TreePine, + 'sprout': Sprout, + 'coffee': Coffee, + 'waves': Waves, + 'cherry': Cherry, + 'citrus': Citrus, + 'snowflake': Snowflake, + 'palmtree': Palmtree, + 'crown': Crown, + 'gem': Gem, + 'feather': Feather, + 'smile': Smile, + 'zap': Zap, + 'cloud': Cloud, + 'beaker': Beaker, + 'spray-can': SprayCan, + 'wine': Wine, + 'mountain': MountainSnow, + 'vegan': Vegan, + + // E-commerce + 'shopping-bag': ShoppingBag, + 'shopping-cart': ShoppingCart, + 'package': Package, + 'truck': Truck, + 'credit-card': CreditCard, + 'wallet': Wallet, + 'tag': Tag, + 'percent': Percent, + 'gift': Gift, + 'ticket': Ticket, + 'store': Store, + 'user': User, + 'heart': Heart, + 'clock': Clock, + 'map-pin': MapPin, + 'settings': Settings, + 'logout': LogOut, + 'login': LogIn, + 'bell': Bell, + 'bookmark': Bookmark, + 'search': Search, + 'menu': Menu, + 'close': X, + 'arrow-right': ArrowRight, + 'arrow-left': ArrowLeft, + 'chevron-right': ChevronRight, + 'chevron-down': ChevronDown, + 'plus': Plus, + 'minus': Minus, + 'trash': Trash2, + 'eye': Eye, + 'filter': Filter, + 'sliders': SlidersHorizontal, + 'refresh': RefreshCw, + 'camera': Camera, + 'share': Share2, + 'award': Award, + 'shield-check': ShieldCheck, + 'star': Star, + 'thumbs-up': ThumbsUp, + 'help': HelpCircle, + 'info': Info, + 'phone': Phone, + 'mail': Mail, + 'chat': MessageCircle, + 'check-circle': CheckCircle2, + 'x-circle': XCircle, + 'alert': AlertCircle, + 'calendar': Calendar, + 'box': Box, +} as const; + +export type AvailableIcons = keyof typeof ICON_REGISTRY; diff --git a/apps/spa/src/components/DesktopMegaMenu.tsx b/apps/spa/src/components/DesktopMegaMenu.tsx index 7df2b67..dbc982b 100644 --- a/apps/spa/src/components/DesktopMegaMenu.tsx +++ b/apps/spa/src/components/DesktopMegaMenu.tsx @@ -4,17 +4,21 @@ import type { MegaMenuPayload, MenuColumn } from '../store/menuStore'; import { useTranslation } from 'react-i18next'; import { ArrowRight, - Award, - Box, ChevronRight, - Gift, - Leaf, - Package, - ShoppingBag, - Sparkles, Star, - type LucideIcon, + Sparkles, + Box, } from 'lucide-react'; +import { ICON_REGISTRY, type AvailableIcons } from '../utils/iconRegistry'; + +function DynamicIcon({ iconName, defaultIcon: DefaultIcon, className, strokeWidth }: { iconName?: string, defaultIcon: any, className?: string, strokeWidth?: number }) { + const IconComponent = (iconName && ICON_REGISTRY[iconName as AvailableIcons]) + ? ICON_REGISTRY[iconName as AvailableIcons] + : DefaultIcon; + + return ; +} + interface DesktopMegaMenuProps { items: MegaMenuPayload[]; @@ -26,14 +30,7 @@ const getLocalizedText = (textObj: Record | string | undefined, return textObj[lang] || textObj.en || textObj.th || Object.values(textObj)[0] || ''; }; -const MENU_ICONS: LucideIcon[] = [ - ShoppingBag, - Sparkles, - Leaf, - Package, - Gift, - Award, -]; + const MAX_TOP_LEVEL_LINKS = 5; const MAX_INLINE_CHILD_LINKS = 3; @@ -48,16 +45,16 @@ const getMoreLabel = (count: number, lang: string) => { }; // Image block shared between Root and Hover areas -function MenuImage({ src, alt, placeholder }: { src?: string | null; alt: string; placeholder?: string }) { +function MenuImage({ src, alt, placeholder, className, style }: { src?: string | null; alt: string; placeholder?: string; className?: string; style?: React.CSSProperties }) { if (!src) { if (!placeholder) return null; return ( -
+
{placeholder}
); } - return {alt}; + return {alt}; } export function DesktopMegaMenu({ items }: DesktopMegaMenuProps) { @@ -105,6 +102,8 @@ export function DesktopMegaMenu({ items }: DesktopMegaMenuProps) { const showFeatured = featuredConfig?.enabled !== false; const configuredImage = featuredConfig?.imageUrl || null; const featuredImage = hoveredLinkImage ?? configuredImage ?? featuredLink?.imageUrl ?? item.rootImageUrl; + const focalPoint = featuredConfig?.focalPoint; + const objectPosition = focalPoint ? `${focalPoint.x} ${focalPoint.y}` : 'center'; const featuredHeading = getLocalizedText(featuredConfig?.sectionTitle, lang) || 'Featured'; const featuredBadge = getLocalizedText(featuredConfig?.badge, lang) || 'Recommended'; const featuredTitle = getLocalizedText(featuredConfig?.title, lang) @@ -165,15 +164,16 @@ export function DesktopMegaMenu({ items }: DesktopMegaMenuProps) { className={`pr-8 text-left ${idx > 0 ? 'border-l border-pop-black/10 pl-8' : ''}`} >

- {(() => { - const HeadingIcon = MENU_ICONS[idx] ?? Sparkles; - return ; - })()} + {getLocalizedText(col.title, lang)}

    {col.links.slice(0, MAX_TOP_LEVEL_LINKS).map((link, lIdx) => { - const RowIcon = MENU_ICONS[(idx * 3 + lIdx + 1) % MENU_ICONS.length] ?? Box; const hasNestedLinks = !!link.links?.length; const visibleChildLinks = link.links?.slice(0, MAX_INLINE_CHILD_LINKS) ?? []; const hiddenChildCount = Math.max((link.links?.length ?? 0) - MAX_INLINE_CHILD_LINKS, 0); @@ -191,7 +191,12 @@ export function DesktopMegaMenu({ items }: DesktopMegaMenuProps) { className="group flex items-center gap-4 rounded-md px-1 py-2.5 text-left transition-colors hover:bg-pop-black/5" > - + @@ -261,6 +266,8 @@ export function DesktopMegaMenu({ items }: DesktopMegaMenuProps) { src={featuredImage} alt={featuredTitle} placeholder={getLocalizedText(item.label, lang)} + className="transition-transform duration-700 group-hover:scale-105" + style={{ objectPosition }} />
diff --git a/apps/spa/src/store/menuStore.ts b/apps/spa/src/store/menuStore.ts index 95ad752..2404d19 100644 --- a/apps/spa/src/store/menuStore.ts +++ b/apps/spa/src/store/menuStore.ts @@ -6,12 +6,14 @@ export interface MenuLink { url?: string; links?: MenuLink[]; imageUrl?: string | null; // รูปที่แสดงเมื่อ Hover ลิงก์ + icon?: string; // ชื่อ icon จาก registry (lucide) } export interface MenuColumn { title: Record | string; links: MenuLink[]; iconUrl?: string | null; // รูปประจำคอลัมน์ (1:1) + icon?: string; // ชื่อ icon จาก registry (lucide) } export interface MenuFeaturedCard { @@ -22,6 +24,7 @@ export interface MenuFeaturedCard { subtitle?: Record | string; price?: string; imageUrl?: string | null; + focalPoint?: { x: string; y: string }; url?: string; ctaLabel?: Record | string; } diff --git a/apps/spa/src/utils/iconRegistry.ts b/apps/spa/src/utils/iconRegistry.ts new file mode 100644 index 0000000..4ea8ad8 --- /dev/null +++ b/apps/spa/src/utils/iconRegistry.ts @@ -0,0 +1,103 @@ +import { + // Business + Sparkles, Leaf, Wind, Droplets, Flower2, Flame, Sofa, BedDouble, Bath, + Sun, Moon, TreePine, Sprout, Coffee, Waves, Cherry, Citrus, Snowflake, + Palmtree, Crown, Gem, Feather, Smile, Zap, Cloud, Beaker, SprayCan, + Wine, MountainSnow, Vegan, + + // E-commerce + ShoppingBag, ShoppingCart, Package, Truck, CreditCard, Wallet, Tag, Percent, + Gift, Ticket, Store, User, Heart, Clock, MapPin, Settings, LogOut, LogIn, + Bell, Bookmark, Search, Menu, X, ArrowRight, ArrowLeft, ChevronRight, + ChevronDown, Plus, Minus, Trash2, Eye, Filter, SlidersHorizontal, RefreshCw, + Camera, Share2, Award, ShieldCheck, Star, ThumbsUp, HelpCircle, Info, + Phone, Mail, MessageCircle, CheckCircle2, XCircle, AlertCircle, Calendar, Box +} from 'lucide-react'; + +export const ICON_REGISTRY = { + // Business + 'sparkles': Sparkles, + 'leaf': Leaf, + 'wind': Wind, + 'droplets': Droplets, + 'flower': Flower2, + 'flame': Flame, + 'sofa': Sofa, + 'bed': BedDouble, + 'bath': Bath, + 'sun': Sun, + 'moon': Moon, + 'tree-pine': TreePine, + 'sprout': Sprout, + 'coffee': Coffee, + 'waves': Waves, + 'cherry': Cherry, + 'citrus': Citrus, + 'snowflake': Snowflake, + 'palmtree': Palmtree, + 'crown': Crown, + 'gem': Gem, + 'feather': Feather, + 'smile': Smile, + 'zap': Zap, + 'cloud': Cloud, + 'beaker': Beaker, + 'spray-can': SprayCan, + 'wine': Wine, + 'mountain': MountainSnow, + 'vegan': Vegan, + + // E-commerce + 'shopping-bag': ShoppingBag, + 'shopping-cart': ShoppingCart, + 'package': Package, + 'truck': Truck, + 'credit-card': CreditCard, + 'wallet': Wallet, + 'tag': Tag, + 'percent': Percent, + 'gift': Gift, + 'ticket': Ticket, + 'store': Store, + 'user': User, + 'heart': Heart, + 'clock': Clock, + 'map-pin': MapPin, + 'settings': Settings, + 'logout': LogOut, + 'login': LogIn, + 'bell': Bell, + 'bookmark': Bookmark, + 'search': Search, + 'menu': Menu, + 'close': X, + 'arrow-right': ArrowRight, + 'arrow-left': ArrowLeft, + 'chevron-right': ChevronRight, + 'chevron-down': ChevronDown, + 'plus': Plus, + 'minus': Minus, + 'trash': Trash2, + 'eye': Eye, + 'filter': Filter, + 'sliders': SlidersHorizontal, + 'refresh': RefreshCw, + 'camera': Camera, + 'share': Share2, + 'award': Award, + 'shield-check': ShieldCheck, + 'star': Star, + 'thumbs-up': ThumbsUp, + 'help': HelpCircle, + 'info': Info, + 'phone': Phone, + 'mail': Mail, + 'chat': MessageCircle, + 'check-circle': CheckCircle2, + 'x-circle': XCircle, + 'alert': AlertCircle, + 'calendar': Calendar, + 'box': Box, +} as const; + +export type AvailableIcons = keyof typeof ICON_REGISTRY; diff --git a/apps/website/src/components/navigation/DesktopMegaMenu.tsx b/apps/website/src/components/navigation/DesktopMegaMenu.tsx index a3ca0ac..41e2ad6 100644 --- a/apps/website/src/components/navigation/DesktopMegaMenu.tsx +++ b/apps/website/src/components/navigation/DesktopMegaMenu.tsx @@ -5,19 +5,24 @@ import Image from 'next/image' import { useState, useRef } from 'react' import { ArrowRight, - Award, - Box, ChevronRight, - Gift, - Leaf, - Package, - ShoppingBag, - Sparkles, Star, - type LucideIcon, + Sparkles, + Box, } from 'lucide-react' import type { MegaMenuPayload, MenuColumn } from './menuTypes' import { getLocalizedMenuText } from './menuTypes' +import { ICON_REGISTRY, type AvailableIcons } from './iconRegistry' + +function DynamicIcon({ iconName, defaultIcon: DefaultIcon, className, strokeWidth }: { iconName?: string, defaultIcon: any, className?: string, strokeWidth?: number }) { + const IconComponent = (iconName && ICON_REGISTRY[iconName as AvailableIcons]) + ? ICON_REGISTRY[iconName as AvailableIcons] + : DefaultIcon; + + return ; +} + + interface DesktopMegaMenuProps { items: MegaMenuPayload[] @@ -25,14 +30,7 @@ interface DesktopMegaMenuProps { currentPath: string } -const MENU_ICONS: LucideIcon[] = [ - ShoppingBag, - Sparkles, - Leaf, - Package, - Gift, - Award, -] + const MAX_TOP_LEVEL_LINKS = 5 const MAX_INLINE_CHILD_LINKS = 3 @@ -52,11 +50,13 @@ function MenuImage({ alt, placeholder, className = '', + style, }: { src?: string | null alt: string placeholder?: string className?: string + style?: React.CSSProperties }) { const [loaded, setLoaded] = useState(false) @@ -74,6 +74,7 @@ function MenuImage({ fill sizes="(max-width: 1024px) 0px, 224px" className={`object-cover transition-opacity duration-300 ${loaded ? 'opacity-100' : 'opacity-0'} ${className}`} + style={style} onLoad={() => setLoaded(true)} loading="lazy" /> @@ -120,6 +121,8 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro const showFeatured = featuredConfig?.enabled !== false const configuredImage = featuredConfig?.imageUrl || null const featuredImage = hoveredLinkImage ?? configuredImage ?? featuredLink?.imageUrl ?? item.rootImageUrl + const focalPoint = featuredConfig?.focalPoint + const objectPosition = focalPoint ? `${focalPoint.x} ${focalPoint.y}` : 'center' const featuredHeading = getLocalizedMenuText(featuredConfig?.sectionTitle, lang) || 'Featured' const featuredBadge = getLocalizedMenuText(featuredConfig?.badge, lang) || 'Recommended' const featuredTitle = getLocalizedMenuText(featuredConfig?.title, lang) @@ -179,15 +182,16 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro className={`pr-8 ${columnIndex > 0 ? 'border-l border-line-primary/15 pl-8' : ''}`} >

- {(() => { - const HeadingIcon = MENU_ICONS[columnIndex] ?? Sparkles - return - })()} + {getLocalizedMenuText(column.title, lang)}

    {column.links.slice(0, MAX_TOP_LEVEL_LINKS).map((link, linkIndex) => { - const RowIcon = MENU_ICONS[(columnIndex * 3 + linkIndex + 1) % MENU_ICONS.length] ?? Box const hasNestedLinks = !!link.links?.length const visibleChildLinks = link.links?.slice(0, MAX_INLINE_CHILD_LINKS) ?? [] const hiddenChildCount = Math.max((link.links?.length ?? 0) - MAX_INLINE_CHILD_LINKS, 0) @@ -205,7 +209,12 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro className="group flex items-center gap-4 rounded-md px-1 py-2.5 text-left transition-colors hover:bg-surface-muted" > - + @@ -275,6 +284,8 @@ export function DesktopMegaMenu({ items, lang, currentPath }: DesktopMegaMenuPro src={featuredImage} alt={featuredTitle} placeholder={getLocalizedMenuText(item.label, lang)} + className="h-full w-full object-cover transition-transform duration-700 group-hover:scale-105" + style={{ objectPosition }} />
diff --git a/apps/website/src/components/navigation/iconRegistry.ts b/apps/website/src/components/navigation/iconRegistry.ts new file mode 100644 index 0000000..4ea8ad8 --- /dev/null +++ b/apps/website/src/components/navigation/iconRegistry.ts @@ -0,0 +1,103 @@ +import { + // Business + Sparkles, Leaf, Wind, Droplets, Flower2, Flame, Sofa, BedDouble, Bath, + Sun, Moon, TreePine, Sprout, Coffee, Waves, Cherry, Citrus, Snowflake, + Palmtree, Crown, Gem, Feather, Smile, Zap, Cloud, Beaker, SprayCan, + Wine, MountainSnow, Vegan, + + // E-commerce + ShoppingBag, ShoppingCart, Package, Truck, CreditCard, Wallet, Tag, Percent, + Gift, Ticket, Store, User, Heart, Clock, MapPin, Settings, LogOut, LogIn, + Bell, Bookmark, Search, Menu, X, ArrowRight, ArrowLeft, ChevronRight, + ChevronDown, Plus, Minus, Trash2, Eye, Filter, SlidersHorizontal, RefreshCw, + Camera, Share2, Award, ShieldCheck, Star, ThumbsUp, HelpCircle, Info, + Phone, Mail, MessageCircle, CheckCircle2, XCircle, AlertCircle, Calendar, Box +} from 'lucide-react'; + +export const ICON_REGISTRY = { + // Business + 'sparkles': Sparkles, + 'leaf': Leaf, + 'wind': Wind, + 'droplets': Droplets, + 'flower': Flower2, + 'flame': Flame, + 'sofa': Sofa, + 'bed': BedDouble, + 'bath': Bath, + 'sun': Sun, + 'moon': Moon, + 'tree-pine': TreePine, + 'sprout': Sprout, + 'coffee': Coffee, + 'waves': Waves, + 'cherry': Cherry, + 'citrus': Citrus, + 'snowflake': Snowflake, + 'palmtree': Palmtree, + 'crown': Crown, + 'gem': Gem, + 'feather': Feather, + 'smile': Smile, + 'zap': Zap, + 'cloud': Cloud, + 'beaker': Beaker, + 'spray-can': SprayCan, + 'wine': Wine, + 'mountain': MountainSnow, + 'vegan': Vegan, + + // E-commerce + 'shopping-bag': ShoppingBag, + 'shopping-cart': ShoppingCart, + 'package': Package, + 'truck': Truck, + 'credit-card': CreditCard, + 'wallet': Wallet, + 'tag': Tag, + 'percent': Percent, + 'gift': Gift, + 'ticket': Ticket, + 'store': Store, + 'user': User, + 'heart': Heart, + 'clock': Clock, + 'map-pin': MapPin, + 'settings': Settings, + 'logout': LogOut, + 'login': LogIn, + 'bell': Bell, + 'bookmark': Bookmark, + 'search': Search, + 'menu': Menu, + 'close': X, + 'arrow-right': ArrowRight, + 'arrow-left': ArrowLeft, + 'chevron-right': ChevronRight, + 'chevron-down': ChevronDown, + 'plus': Plus, + 'minus': Minus, + 'trash': Trash2, + 'eye': Eye, + 'filter': Filter, + 'sliders': SlidersHorizontal, + 'refresh': RefreshCw, + 'camera': Camera, + 'share': Share2, + 'award': Award, + 'shield-check': ShieldCheck, + 'star': Star, + 'thumbs-up': ThumbsUp, + 'help': HelpCircle, + 'info': Info, + 'phone': Phone, + 'mail': Mail, + 'chat': MessageCircle, + 'check-circle': CheckCircle2, + 'x-circle': XCircle, + 'alert': AlertCircle, + 'calendar': Calendar, + 'box': Box, +} as const; + +export type AvailableIcons = keyof typeof ICON_REGISTRY; diff --git a/apps/website/src/components/navigation/menuTypes.ts b/apps/website/src/components/navigation/menuTypes.ts index 9a547fa..4bda32f 100644 --- a/apps/website/src/components/navigation/menuTypes.ts +++ b/apps/website/src/components/navigation/menuTypes.ts @@ -3,12 +3,14 @@ export interface MenuLink { url?: string links?: MenuLink[] imageUrl?: string | null // รูปที่แสดงเมื่อ Hover ลิงก์ + icon?: string // ชื่อ icon จาก registry (lucide) } export interface MenuColumn { title: Record | string links: MenuLink[] iconUrl?: string | null // รูปประจำคอลัมน์ (1:1) + icon?: string // ชื่อ icon จาก registry (lucide) } export interface MenuFeaturedCard { @@ -19,6 +21,7 @@ export interface MenuFeaturedCard { subtitle?: Record | string price?: string imageUrl?: string | null + focalPoint?: { x: string; y: string } url?: string ctaLabel?: Record | string } diff --git a/homaroma_lucide_icons.md b/homaroma_lucide_icons.md new file mode 100644 index 0000000..b6ee151 --- /dev/null +++ b/homaroma_lucide_icons.md @@ -0,0 +1,224 @@ +# HomAroma: Curated Lucide Icon Registry + +This document contains a curated list of 80 `lucide-react` icons tailored specifically for the **HomAroma** project. It is divided into 30 business-specific icons (Home Fragrance & Wellness) and 50 general E-commerce icons. + +You can use this list directly in your `iconRegistry.ts` file to populate the Admin Dropdown and Frontend components. + +## 🌿 30 Business-Specific Icons (HomAroma / Fragrance / Wellness) +These icons are selected to represent product categories, scent notes, moods, and the core identity of a home fragrance and wellness brand. + +| Icon Name | Suggested Usage / Meaning | +| :--- | :--- | +| `Sparkles` | Signature products, Best sellers, Magic / Premium | +| `Leaf` | Organic, Natural ingredients, Green notes | +| `Wind` | Aroma, Diffusers, Air circulation, Scent throw | +| `Droplets` | Essential oils, Serums, Liquid extracts | +| `Flower2` | Floral scent notes (Rose, Jasmine, etc.) | +| `Flame` | Candles, Warmth, Fireplace | +| `Sofa` | Home decor, Living room ambiance | +| `BedDouble` | Bedroom, Sleep wellness, Pillow mists | +| `Bath` | Bath & Body products, Spa, Relaxation | +| `Sun` | Morning routines, Bright / Uplifting scents | +| `Moon` | Night routines, Calming / Sleep scents | +| `TreePine` | Woody scent notes (Cedar, Sandalwood, Pine) | +| `Sprout` | Plant-based, Vegan, Clean beauty | +| `Coffee` | Gourmand notes (Coffee, Vanilla, Warmth) | +| `Waves` | Ocean breeze, Aquatic scent notes | +| `Cherry` | Fruity / Berry scent notes | +| `Citrus` | Citrus notes (Orange, Lemon, Bergamot) | +| `Snowflake` | Cooling, Mint, Crisp winter notes | +| `Palmtree` | Tropical / Summer collections | +| `Crown` | Luxury / Exclusive collections | +| `Gem` | Rare / Premium ingredients | +| `Feather` | Light, Gentle, Sensitive skin | +| `Smile` | Mood enhancing, Happiness | +| `Zap` | Energizing, Invigorating scents | +| `Cloud` | Airy, Soft, Linen sprays | +| `Beaker` | Formulation, Lab, Science of scent | +| `SprayCan` | Room sprays, Body mists | +| `Wine` | Rich / Boozy notes (Bourbon, Rum) | +| `MountainSnow` | Earthy, Fresh mountain air | +| `Vegan` | Cruelty-free, Vegan certification | + +--- + +## 🛒 50 General E-commerce & UI Icons +These icons are essential for standard E-commerce navigation, user accounts, checkout flows, and UI controls. + +### Shopping & Cart +| Icon Name | Suggested Usage / Meaning | +| :--- | :--- | +| `ShoppingBag` | Cart (Bag style) | +| `ShoppingCart` | Cart (Trolley style) | +| `Package` | Orders, Physical products | +| `Truck` | Shipping, Delivery | +| `CreditCard` | Payment methods | +| `Wallet` | Store credit, Points | +| `Tag` | Sale, Price tags | +| `Percent` | Discounts, Promotions | +| `Gift` | Gift cards, Wrapping service | +| `Ticket` | Vouchers, Coupons | +| `Store` | Physical stores, About the brand | + +### Account & User +| Icon Name | Suggested Usage / Meaning | +| :--- | :--- | +| `User` | My Account, Profile | +| `Heart` | Wishlist, Favorites | +| `Clock` | Order history, Recently viewed | +| `MapPin` | Shipping address, Store locator | +| `Settings` | Account settings | +| `LogOut` | Sign out | +| `LogIn` | Sign in | +| `Bell` | Notifications | +| `Bookmark` | Saved for later | + +### Navigation & Actions +| Icon Name | Suggested Usage / Meaning | +| :--- | :--- | +| `Search` | Search bar | +| `Menu` | Mobile hamburger menu | +| `X` | Close modals / drawers | +| `ArrowRight` | Next step, Call to action | +| `ArrowLeft` | Go back | +| `ChevronRight` | Breadcrumbs, Accordion | +| `ChevronDown` | Dropdowns | +| `Plus` | Add to cart / Expand | +| `Minus` | Decrease quantity / Collapse | +| `Trash2` | Remove item | +| `Eye` | Quick view | +| `Filter` | Filter products | +| `SlidersHorizontal` | Sort & Filter options | +| `RefreshCw` | Returns, Exchanges, Sync | +| `Camera` | Upload photo (Reviews) | +| `Share2` | Share product | + +### Information & Trust +| Icon Name | Suggested Usage / Meaning | +| :--- | :--- | +| `Award` | Quality guarantee, Awards | +| `ShieldCheck` | Secure payment, Warranty | +| `Star` | Reviews, Ratings | +| `ThumbsUp` | Helpful review | +| `HelpCircle` | FAQ, Help center | +| `Info` | Product details, About | +| `Phone` | Customer service (Phone) | +| `Mail` | Newsletter, Email support | +| `MessageCircle` | Live chat | +| `CheckCircle2` | Success states, Validation | +| `XCircle` | Error states | +| `AlertCircle` | Warnings, Important notices | +| `Calendar` | Delivery dates, Events | +| `Box` | Inventory, General item | + +--- + +## 💻 Example Implementation (TypeScript) + +You can copy and paste this into your `iconRegistry.ts` file: + +```typescript +import { + // Business + Sparkles, Leaf, Wind, Droplets, Flower2, Flame, Sofa, BedDouble, Bath, + Sun, Moon, TreePine, Sprout, Coffee, Waves, Cherry, Citrus, Snowflake, + Palmtree, Crown, Gem, Feather, Smile, Zap, Cloud, Beaker, SprayCan, + Wine, MountainSnow, Vegan, + + // E-commerce + ShoppingBag, ShoppingCart, Package, Truck, CreditCard, Wallet, Tag, Percent, + Gift, Ticket, Store, User, Heart, Clock, MapPin, Settings, LogOut, LogIn, + Bell, Bookmark, Search, Menu, X, ArrowRight, ArrowLeft, ChevronRight, + ChevronDown, Plus, Minus, Trash2, Eye, Filter, SlidersHorizontal, RefreshCw, + Camera, Share2, Award, ShieldCheck, Star, ThumbsUp, HelpCircle, Info, + Phone, Mail, MessageCircle, CheckCircle2, XCircle, AlertCircle, Calendar, Box +} from 'lucide-react'; + +export const ICON_REGISTRY = { + // Business + 'sparkles': Sparkles, + 'leaf': Leaf, + 'wind': Wind, + 'droplets': Droplets, + 'flower': Flower2, + 'flame': Flame, + 'sofa': Sofa, + 'bed': BedDouble, + 'bath': Bath, + 'sun': Sun, + 'moon': Moon, + 'tree-pine': TreePine, + 'sprout': Sprout, + 'coffee': Coffee, + 'waves': Waves, + 'cherry': Cherry, + 'citrus': Citrus, + 'snowflake': Snowflake, + 'palmtree': Palmtree, + 'crown': Crown, + 'gem': Gem, + 'feather': Feather, + 'smile': Smile, + 'zap': Zap, + 'cloud': Cloud, + 'beaker': Beaker, + 'spray-can': SprayCan, + 'wine': Wine, + 'mountain': MountainSnow, + 'vegan': Vegan, + + // E-commerce + 'shopping-bag': ShoppingBag, + 'shopping-cart': ShoppingCart, + 'package': Package, + 'truck': Truck, + 'credit-card': CreditCard, + 'wallet': Wallet, + 'tag': Tag, + 'percent': Percent, + 'gift': Gift, + 'ticket': Ticket, + 'store': Store, + 'user': User, + 'heart': Heart, + 'clock': Clock, + 'map-pin': MapPin, + 'settings': Settings, + 'logout': LogOut, + 'login': LogIn, + 'bell': Bell, + 'bookmark': Bookmark, + 'search': Search, + 'menu': Menu, + 'close': X, + 'arrow-right': ArrowRight, + 'arrow-left': ArrowLeft, + 'chevron-right': ChevronRight, + 'chevron-down': ChevronDown, + 'plus': Plus, + 'minus': Minus, + 'trash': Trash2, + 'eye': Eye, + 'filter': Filter, + 'sliders': SlidersHorizontal, + 'refresh': RefreshCw, + 'camera': Camera, + 'share': Share2, + 'award': Award, + 'shield-check': ShieldCheck, + 'star': Star, + 'thumbs-up': ThumbsUp, + 'help': HelpCircle, + 'info': Info, + 'phone': Phone, + 'mail': Mail, + 'chat': MessageCircle, + 'check-circle': CheckCircle2, + 'x-circle': XCircle, + 'alert': AlertCircle, + 'calendar': Calendar, + 'box': Box, +} as const; + +export type AvailableIcons = keyof typeof ICON_REGISTRY; +```