'use client'; import React from 'react'; import { cn } from '../../lib/utils'; import * as LucideIcons from 'lucide-react'; // Supported icon types export type IconName = // Lucide icons (primary) | 'star' | 'check' | 'x' | 'arrow-left' | 'arrow-right' | 'chevron-left' | 'chevron-right' | 'quote' | 'phone' | 'mail' | 'map-pin' | 'clock' | 'calendar' | 'user' | 'users' | 'award' | 'briefcase' | 'building' | 'globe' | 'settings' | 'tool' | 'wrench' | 'shield' | 'lock' | 'key' | 'heart' | 'thumbs-up' | 'message-circle' | 'phone-call' | 'mail-open' | 'map' | 'navigation' | 'home' | 'info' | 'alert-circle' | 'check-circle' | 'x-circle' | 'plus' | 'minus' | 'search' | 'filter' | 'download' | 'upload' | 'share-2' | 'link' | 'external-link' | 'file-text' | 'file' | 'folder' // Font Awesome style aliases (for WP compatibility) | 'fa-star' | 'fa-check' | 'fa-times' | 'fa-arrow-left' | 'fa-arrow-right' | 'fa-quote-left' | 'fa-phone' | 'fa-envelope' | 'fa-map-marker' | 'fa-clock-o' | 'fa-calendar' | 'fa-user' | 'fa-users' | 'fa-trophy' | 'fa-briefcase' | 'fa-building' | 'fa-globe' | 'fa-cog' | 'fa-wrench' | 'fa-shield' | 'fa-lock' | 'fa-key' | 'fa-heart' | 'fa-thumbs-up' | 'fa-comment' | 'fa-phone-square' | 'fa-envelope-open' | 'fa-map' | 'fa-compass' | 'fa-home' | 'fa-info-circle' | 'fa-check-circle' | 'fa-times-circle' | 'fa-plus' | 'fa-minus' | 'fa-search' | 'fa-filter' | 'fa-download' | 'fa-upload' | 'fa-share-alt' | 'fa-link' | 'fa-external-link' | 'fa-file-text' | 'fa-file' | 'fa-folder'; export interface IconProps { name: IconName; size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; className?: string; color?: 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'muted' | 'current'; strokeWidth?: number; onClick?: () => void; ariaLabel?: string; } /** * Icon Component * Universal icon component supporting Lucide icons and Font Awesome aliases * Maps WPBakery vc_icon patterns to modern React icons */ export const Icon: React.FC = ({ name, size = 'md', className = '', color = 'current', strokeWidth = 2, onClick, ariaLabel }) => { // Map size to actual dimensions const sizeMap = { xs: 'w-3 h-3', sm: 'w-4 h-4', md: 'w-5 h-5', lg: 'w-6 h-6', xl: 'w-8 h-8', '2xl': 'w-10 h-10' }; // Map color to Tailwind classes const colorMap = { primary: 'text-primary', secondary: 'text-secondary', success: 'text-green-600', warning: 'text-yellow-600', error: 'text-red-600', muted: 'text-gray-500', current: 'text-current' }; // Normalize icon name (remove fa- prefix and map to Lucide) const normalizeIconName = (iconName: string): string => { // Remove fa- prefix if present const cleanName = iconName.replace(/^fa-/, ''); // Map common Font Awesome names to Lucide const faToLucide: Record = { 'star': 'star', 'check': 'check', 'times': 'x', 'arrow-left': 'arrow-left', 'arrow-right': 'arrow-right', 'quote-left': 'quote', 'phone': 'phone', 'envelope': 'mail', 'map-marker': 'map-pin', 'clock-o': 'clock', 'calendar': 'calendar', 'user': 'user', 'users': 'users', 'trophy': 'award', 'briefcase': 'briefcase', 'building': 'building', 'globe': 'globe', 'cog': 'settings', 'wrench': 'wrench', 'shield': 'shield', 'lock': 'lock', 'key': 'key', 'heart': 'heart', 'thumbs-up': 'thumbs-up', 'comment': 'message-circle', 'phone-square': 'phone', 'envelope-open': 'mail-open', 'map': 'map', 'compass': 'navigation', 'home': 'home', 'info-circle': 'info', 'check-circle': 'check-circle', 'times-circle': 'x-circle', 'plus': 'plus', 'minus': 'minus', 'search': 'search', 'filter': 'filter', 'download': 'download', 'upload': 'upload', 'share-alt': 'share-2', 'link': 'link', 'external-link': 'external-link', 'file-text': 'file-text', 'file': 'file', 'folder': 'folder' }; return faToLucide[cleanName] || cleanName; }; const iconName = normalizeIconName(name); const IconComponent = (LucideIcons as any)[iconName]; if (!IconComponent) { console.warn(`Icon "${name}" (normalized: "${iconName}") not found in Lucide icons`); return ( ? ); } return ( ); }; // Helper component for icon buttons export const IconButton: React.FC = ({ name, size = 'md', className = '', color = 'primary', onClick, label, ariaLabel }) => { return ( ); }; // Helper function to parse WPBakery vc_icon attributes export function parseWpIcon(iconClass: string): IconProps { // Parse classes like "vc_icon fa fa-star" or "vc_icon lucide-star" const parts = iconClass.split(/\s+/); let name: IconName = 'star'; let size: IconProps['size'] = 'md'; // Find icon name const iconPart = parts.find(p => p.includes('fa-') || p.includes('lucide-') || p === 'fa'); if (iconPart) { if (iconPart.includes('fa-')) { name = iconPart.replace('fa-', '') as IconName; } else if (iconPart.includes('lucide-')) { name = iconPart.replace('lucide-', '') as IconName; } } // Find size if (parts.includes('fa-lg') || parts.includes('text-xl')) size = 'lg'; if (parts.includes('fa-2x')) size = 'xl'; if (parts.includes('fa-3x')) size = '2xl'; if (parts.includes('fa-xs')) size = 'xs'; if (parts.includes('fa-sm')) size = 'sm'; return { name, size }; } // Icon wrapper for feature lists export const IconFeature: React.FC<{ icon: IconName; title: string; description?: string; iconPosition?: 'top' | 'left'; className?: string; }> = ({ icon, title, description, iconPosition = 'left', className = '' }) => { const isLeft = iconPosition === 'left'; return (

{title}

{description && (

{description}

)}
); }; export default Icon;