@pattern-stack/frontend-patterns 0.0.4 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts +19 -0
  2. package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts.map +1 -0
  3. package/dist/atoms/composed/SalesPanel/index.d.ts +2 -0
  4. package/dist/atoms/composed/SalesPanel/index.d.ts.map +1 -0
  5. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts +63 -0
  6. package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts.map +1 -0
  7. package/dist/atoms/composed/index.d.ts +1 -0
  8. package/dist/atoms/composed/index.d.ts.map +1 -1
  9. package/dist/atoms/types/entity-config.d.ts +117 -0
  10. package/dist/atoms/types/entity-config.d.ts.map +1 -0
  11. package/dist/atoms/types/index.d.ts +2 -0
  12. package/dist/atoms/types/index.d.ts.map +1 -1
  13. package/dist/atoms/types/navigation.d.ts +30 -0
  14. package/dist/atoms/types/navigation.d.ts.map +1 -0
  15. package/dist/atoms/ui/ErrorBoundary.d.ts +1 -1
  16. package/dist/atoms/ui/button.d.ts +1 -1
  17. package/dist/atoms/utils/icon-resolver.d.ts +72 -0
  18. package/dist/atoms/utils/icon-resolver.d.ts.map +1 -0
  19. package/dist/atoms/utils/metric-engine.d.ts +30 -0
  20. package/dist/atoms/utils/metric-engine.d.ts.map +1 -0
  21. package/dist/atoms/utils/utils.d.ts +2 -0
  22. package/dist/atoms/utils/utils.d.ts.map +1 -1
  23. package/dist/features/auth/components/ProtectedRoute.d.ts +1 -1
  24. package/dist/frontend-patterns.css +1 -1
  25. package/dist/index.es.js +402 -14
  26. package/dist/index.es.js.map +1 -1
  27. package/dist/index.js +402 -14
  28. package/dist/index.js.map +1 -1
  29. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +16 -0
  30. package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts.map +1 -0
  31. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +2 -0
  32. package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts.map +1 -0
  33. package/dist/molecules/layout/NavigationContext.d.ts +15 -0
  34. package/dist/molecules/layout/NavigationContext.d.ts.map +1 -0
  35. package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
  36. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +2 -0
  37. package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
  38. package/dist/molecules/layout/index.d.ts +3 -0
  39. package/dist/molecules/layout/index.d.ts.map +1 -1
  40. package/dist/templates/factory.d.ts +2 -1
  41. package/dist/templates/factory.d.ts.map +1 -1
  42. package/dist/templates/index.d.ts.map +1 -1
  43. package/package.json +7 -3
  44. package/src/App.tsx +11 -1
  45. package/src/__tests__/atoms/composed/databadge.test.tsx +106 -0
  46. package/src/__tests__/atoms/composed/statcard.test.tsx +133 -0
  47. package/src/__tests__/atoms/utils/icon-resolver.test.tsx +140 -0
  48. package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
  49. package/src/atoms/composed/SalesPanel/index.ts +1 -0
  50. package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
  51. package/src/atoms/composed/index.ts +1 -0
  52. package/src/atoms/types/entity-config.ts +127 -0
  53. package/src/atoms/types/index.ts +3 -1
  54. package/src/atoms/types/navigation.ts +43 -0
  55. package/src/atoms/utils/icon-resolver.tsx +54 -0
  56. package/src/atoms/utils/metric-engine.ts +236 -0
  57. package/src/atoms/utils/utils.ts +4 -2
  58. package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
  59. package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
  60. package/src/molecules/layout/NavigationContext.tsx +63 -0
  61. package/src/molecules/layout/Sidebar.tsx +10 -23
  62. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +32 -10
  63. package/src/molecules/layout/index.ts +4 -1
  64. package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
  65. package/src/organisms/entity/EntityListPanel.tsx +339 -0
  66. package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
  67. package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
  68. package/src/organisms/entity/index.ts +4 -0
  69. package/src/organisms/index.ts +5 -1
  70. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +77 -75
  71. package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
  72. package/src/pages/AdminShowcase/index.tsx +2 -1
  73. package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
  74. package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
  75. package/src/pages/EntityShowcase/index.ts +2 -0
  76. package/src/pages/EntityTemplateExample.tsx +229 -0
  77. package/src/pages/TestEntityTemplate.tsx +40 -0
  78. package/src/pages/index.ts +2 -1
  79. package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
  80. package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
  81. package/src/templates/entity/configs/financial-config.ts +141 -0
  82. package/src/templates/entity/configs/index.ts +1 -0
  83. package/src/templates/entity/index.ts +3 -0
  84. package/src/templates/factory.tsx +14 -7
  85. package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
  86. package/src/templates/index.ts +4 -0
@@ -0,0 +1,116 @@
1
+ import React from 'react';
2
+ import { DataBadge } from '../DataBadge';
3
+ import { Button } from '../../ui/button';
4
+ import {
5
+ Target,
6
+ ExternalLink
7
+ } from 'lucide-react';
8
+
9
+ interface SalesPanelProps {
10
+ sales: Array<{
11
+ id: string;
12
+ customer: string;
13
+ product: string;
14
+ amount: number;
15
+ stage: string;
16
+ salesperson: string;
17
+ region: string;
18
+ closeDate: string;
19
+ dealSize: string;
20
+ }>;
21
+ onSaleClick?: (sale: any) => void;
22
+ onClose?: () => void;
23
+ }
24
+
25
+ const getStageStatus = (stage: string) => {
26
+ switch (stage) {
27
+ case 'Closed Won': return 'success';
28
+ case 'Negotiation': return 'warning';
29
+ case 'Proposal Sent': return 'info';
30
+ case 'Qualified': return 'info';
31
+ case 'Discovery': return 'neutral';
32
+ default: return 'neutral';
33
+ }
34
+ };
35
+
36
+ export const SalesPanel: React.FC<SalesPanelProps> = ({
37
+ sales,
38
+ onSaleClick,
39
+ onClose
40
+ }) => {
41
+ const topDeals = sales.slice(0, 5); // Show only top 5 recent deals
42
+ const totalValue = sales.reduce((sum, sale) => sum + sale.amount, 0);
43
+
44
+ return (
45
+ <div className="fixed right-0 top-16 h-[calc(100vh-4rem)] w-72 bg-background border-l border-border shadow-lg flex flex-col z-30">
46
+ {/* Header */}
47
+ <div className="p-3 border-b border-border">
48
+ <div className="flex items-center justify-between">
49
+ <h3 className="font-medium flex items-center gap-2">
50
+ <Target className="w-4 h-4" />
51
+ Pipeline
52
+ </h3>
53
+ {onClose && (
54
+ <Button variant="ghost" size="sm" onClick={onClose}>
55
+ ×
56
+ </Button>
57
+ )}
58
+ </div>
59
+ </div>
60
+
61
+ {/* Quick Stats */}
62
+ <div className="p-3 border-b border-border">
63
+ <div className="space-y-2">
64
+ <div className="flex justify-between">
65
+ <span className="text-sm text-muted-foreground">Total Value</span>
66
+ <span className="font-semibold text-green-600">${totalValue.toLocaleString()}</span>
67
+ </div>
68
+ <div className="flex justify-between">
69
+ <span className="text-sm text-muted-foreground">Active Deals</span>
70
+ <span className="font-semibold">{sales.length}</span>
71
+ </div>
72
+ </div>
73
+ </div>
74
+
75
+ {/* Recent Deals */}
76
+ <div className="flex-1 overflow-auto p-3">
77
+ <h4 className="text-sm font-medium mb-3">Recent Opportunities</h4>
78
+ <div className="space-y-2">
79
+ {topDeals.map((sale) => (
80
+ <div
81
+ key={sale.id}
82
+ className="p-2 border border-border rounded-md hover:bg-muted/50 cursor-pointer transition-colors"
83
+ onClick={() => onSaleClick?.(sale)}
84
+ >
85
+ <div className="flex justify-between items-start mb-1">
86
+ <div className="flex-1 min-w-0">
87
+ <p className="text-sm font-medium truncate">{sale.customer}</p>
88
+ <p className="text-xs text-muted-foreground truncate">{sale.product}</p>
89
+ </div>
90
+ <div className="text-right ml-2">
91
+ <p className="text-sm font-semibold text-green-600">
92
+ ${sale.amount.toLocaleString()}
93
+ </p>
94
+ </div>
95
+ </div>
96
+ <div className="flex justify-between items-center">
97
+ <DataBadge variant="status" status={getStageStatus(sale.stage)}>
98
+ {sale.stage}
99
+ </DataBadge>
100
+ <span className="text-xs text-muted-foreground">{sale.salesperson}</span>
101
+ </div>
102
+ </div>
103
+ ))}
104
+ </div>
105
+ </div>
106
+
107
+ {/* Footer */}
108
+ <div className="p-3 border-t border-border">
109
+ <Button variant="outline" size="sm" className="w-full">
110
+ <ExternalLink className="w-4 h-4 mr-2" />
111
+ View All Deals
112
+ </Button>
113
+ </div>
114
+ </div>
115
+ );
116
+ };
@@ -0,0 +1 @@
1
+ export { SalesPanel } from './SalesPanel';
@@ -0,0 +1,151 @@
1
+ // Mock sales data for demonstrations
2
+ export const mockSalesData = [
3
+ {
4
+ id: 'SALE-2024-001',
5
+ customer: 'TechCorp Industries',
6
+ product: 'Enterprise License',
7
+ amount: 45000,
8
+ stage: 'Closed Won',
9
+ salesperson: 'Sarah Chen',
10
+ region: 'North America',
11
+ closeDate: '2024-06-08',
12
+ dealSize: 'Large'
13
+ },
14
+ {
15
+ id: 'SALE-2024-002',
16
+ customer: 'StartupXYZ',
17
+ product: 'Professional Plan',
18
+ amount: 12000,
19
+ stage: 'Proposal Sent',
20
+ salesperson: 'Mike Johnson',
21
+ region: 'North America',
22
+ closeDate: '2024-06-15',
23
+ dealSize: 'Medium'
24
+ },
25
+ {
26
+ id: 'SALE-2024-003',
27
+ customer: 'Global Enterprises Ltd',
28
+ product: 'Enterprise Suite',
29
+ amount: 78000,
30
+ stage: 'Negotiation',
31
+ salesperson: 'Lisa Wang',
32
+ region: 'Europe',
33
+ closeDate: '2024-06-20',
34
+ dealSize: 'Large'
35
+ },
36
+ {
37
+ id: 'SALE-2024-004',
38
+ customer: 'Innovation Labs',
39
+ product: 'Starter Package',
40
+ amount: 5000,
41
+ stage: 'Qualified',
42
+ salesperson: 'David Kim',
43
+ region: 'Asia Pacific',
44
+ closeDate: '2024-06-25',
45
+ dealSize: 'Small'
46
+ },
47
+ {
48
+ id: 'SALE-2024-005',
49
+ customer: 'FutureTech Solutions',
50
+ product: 'Custom Integration',
51
+ amount: 95000,
52
+ stage: 'Discovery',
53
+ salesperson: 'Sarah Chen',
54
+ region: 'North America',
55
+ closeDate: '2024-07-01',
56
+ dealSize: 'Large'
57
+ }
58
+ ];
59
+
60
+ // Sales configuration for entity template
61
+ export const salesConfig = {
62
+ entityType: 'performance' as const,
63
+ display: {
64
+ title: 'Sales Performance',
65
+ subtitle: 'Monitor sales metrics, team performance, and revenue trends',
66
+ category: 3 as const
67
+ },
68
+ metrics: [
69
+ {
70
+ key: 'revenue',
71
+ label: 'Total Revenue',
72
+ type: 'currency' as const,
73
+ aggregate: 'sum',
74
+ showTrend: true,
75
+ category: 2
76
+ },
77
+ {
78
+ key: 'deals',
79
+ label: 'Deals Closed',
80
+ type: 'number' as const,
81
+ aggregate: 'count',
82
+ showTrend: true,
83
+ category: 3
84
+ },
85
+ {
86
+ key: 'conversion',
87
+ label: 'Conversion Rate',
88
+ type: 'percentage' as const,
89
+ aggregate: 'average',
90
+ showTrend: true,
91
+ category: 1
92
+ },
93
+ {
94
+ key: 'pipeline',
95
+ label: 'Pipeline Value',
96
+ type: 'currency' as const,
97
+ aggregate: 'sum',
98
+ showTrend: true,
99
+ category: 4
100
+ }
101
+ ],
102
+ categories: [
103
+ { key: 'region', label: 'By Region', type: 'categorical' },
104
+ { key: 'product', label: 'By Product', type: 'categorical' },
105
+ { key: 'stage', label: 'By Stage', type: 'categorical' }
106
+ ],
107
+ trends: {
108
+ periods: ['7d', '30d', '90d', '1y'],
109
+ defaultPeriod: '30d'
110
+ }
111
+ };
112
+
113
+ // Sample sales performance data
114
+ export const salesPerformanceData = [
115
+ {
116
+ id: 'sale-1',
117
+ revenue: 45000,
118
+ deals: 12,
119
+ conversion: 0.24,
120
+ pipeline: 125000,
121
+ region: 'North America',
122
+ product: 'Enterprise',
123
+ stage: 'Closed Won',
124
+ date: '2024-06-01',
125
+ salesperson: 'Sarah Chen'
126
+ },
127
+ {
128
+ id: 'sale-2',
129
+ revenue: 32000,
130
+ deals: 8,
131
+ conversion: 0.18,
132
+ pipeline: 89000,
133
+ region: 'Europe',
134
+ product: 'Professional',
135
+ stage: 'Negotiation',
136
+ date: '2024-06-02',
137
+ salesperson: 'Mike Johnson'
138
+ },
139
+ {
140
+ id: 'sale-3',
141
+ revenue: 67000,
142
+ deals: 15,
143
+ conversion: 0.31,
144
+ pipeline: 156000,
145
+ region: 'Asia Pacific',
146
+ product: 'Enterprise',
147
+ stage: 'Closed Won',
148
+ date: '2024-06-03',
149
+ salesperson: 'Lisa Wang'
150
+ }
151
+ ];
@@ -1,5 +1,6 @@
1
1
  // Business-specific shared components
2
2
  export { DataBadge } from './DataBadge';
3
+ export { SalesPanel } from './SalesPanel';
3
4
  export { StatCard } from './StatCard';
4
5
  export { DetailedCard } from './DetailedCard';
5
6
  export { EmptyState } from './EmptyState';
@@ -0,0 +1,127 @@
1
+ import * as React from 'react';
2
+
3
+ export type EntityType = 'transactional' | 'categorical' | 'temporal';
4
+
5
+ export type MetricType = 'currency' | 'percentage' | 'count' | 'duration' | 'ratio';
6
+
7
+ export type AggregationType = 'sum' | 'avg' | 'count' | 'min' | 'max';
8
+
9
+ export type TemporalCycle = 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly';
10
+
11
+ export type ForecastingAlgorithm = 'linear' | 'seasonal' | 'ml';
12
+
13
+ export type ActionType = 'primary' | 'secondary' | 'danger';
14
+
15
+ export interface FormatConfig {
16
+ decimals?: number;
17
+ prefix?: string;
18
+ suffix?: string;
19
+ thousands?: boolean;
20
+ }
21
+
22
+ export interface MetricConfig {
23
+ key: string;
24
+ label: string;
25
+ type: MetricType;
26
+ format?: FormatConfig;
27
+ trend?: boolean;
28
+ target?: number | ((data: EntityData[]) => number);
29
+ aggregation?: AggregationType;
30
+ icon?: React.ComponentType;
31
+ }
32
+
33
+ export interface TemporalConfig {
34
+ cycles: TemporalCycle[];
35
+ defaultCycle: TemporalCycle;
36
+ enableComparisons: boolean;
37
+ forecasting?: {
38
+ enabled: boolean;
39
+ periods: number;
40
+ algorithm: ForecastingAlgorithm;
41
+ };
42
+ }
43
+
44
+ export interface CategoryConfig {
45
+ hierarchy: string[];
46
+ defaultGroupBy: string;
47
+ enableDrillDown: boolean;
48
+ colorCoding?: boolean;
49
+ }
50
+
51
+ export interface ActionConfig {
52
+ label: string;
53
+ type: ActionType;
54
+ onClick: (context: { selectedItems?: EntityData[]; data?: EntityData[]; config?: EntityTemplateConfig }) => void | Promise<void>;
55
+ icon?: React.ComponentType;
56
+ permissions?: string[];
57
+ validation?: (context: { selectedItems?: EntityData[]; data?: EntityData[]; config?: EntityTemplateConfig }) => boolean;
58
+ }
59
+
60
+ export interface BusinessRulesConfig<T> {
61
+ validation?: (item: T) => string[];
62
+ constraints?: {
63
+ [key: string]: {
64
+ min?: number;
65
+ max?: number;
66
+ required?: boolean;
67
+ pattern?: RegExp;
68
+ };
69
+ };
70
+ workflows?: {
71
+ [status: string]: string[];
72
+ };
73
+ }
74
+
75
+ export interface EntityDisplayConfig {
76
+ title: string;
77
+ description?: string;
78
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
79
+ }
80
+
81
+ export interface EntityTemplateConfig<T = EntityData> {
82
+ entityType: EntityType;
83
+ display: EntityDisplayConfig;
84
+ metrics: MetricConfig[];
85
+ temporal?: TemporalConfig;
86
+ categories?: CategoryConfig;
87
+ businessRules?: BusinessRulesConfig<T>;
88
+ actions?: ActionConfig[];
89
+ }
90
+
91
+ export interface EntityData {
92
+ id: string | number;
93
+ [key: string]: unknown;
94
+ }
95
+
96
+ export interface MetricValue {
97
+ current: number;
98
+ previous?: number;
99
+ trend?: 'up' | 'down' | 'neutral';
100
+ target?: number;
101
+ formattedValue: string;
102
+ }
103
+
104
+ export interface CategoryBreakdown {
105
+ category: string;
106
+ value: number;
107
+ percentage: number;
108
+ color?: string;
109
+ subcategories?: CategoryBreakdown[];
110
+ }
111
+
112
+ export interface TrendDataPoint {
113
+ date: string;
114
+ value: number;
115
+ label?: string;
116
+ }
117
+
118
+ export interface EntityAnalyticsData {
119
+ metrics: Record<string, MetricValue>;
120
+ categories: CategoryBreakdown[];
121
+ trends: Record<string, TrendDataPoint[]>;
122
+ insights?: {
123
+ type: 'positive' | 'negative' | 'neutral';
124
+ message: string;
125
+ value?: number;
126
+ }[];
127
+ }
@@ -1,4 +1,6 @@
1
1
  // Export all type definitions
2
2
  export * from './generated';
3
3
  export * from './loading';
4
- export * from './auth';
4
+ export * from './auth';
5
+ export * from './navigation';
6
+ export * from './entity-config';
@@ -0,0 +1,43 @@
1
+ // Navigation configuration types for createReactApp factory
2
+
3
+ export type IconName =
4
+ | 'Palette' | 'Menu' | 'X' | 'Shield' | 'Users' | 'BarChart3'
5
+ | 'Database' | 'TrendingUp' | 'Layout' | 'Home' | 'Settings'
6
+ | 'Bell' | 'Search' | 'Plus' | 'Edit' | 'Trash2' | 'Eye'
7
+ | 'Download' | 'Upload' | 'Share' | 'Lock' | 'Unlock'
8
+ | 'Mail' | 'Phone' | 'Calendar' | 'Clock' | 'MapPin'
9
+ | 'Star' | 'Heart' | 'Bookmark' | 'Tag' | 'Flag'
10
+ | 'File' | 'Folder' | 'Image' | 'Video' | 'Music'
11
+ | 'ChevronRight' | 'ChevronDown' | 'ChevronLeft' | 'ChevronUp'
12
+ | 'ArrowRight' | 'ArrowLeft' | 'ArrowUp' | 'ArrowDown'
13
+ | 'Check' | 'AlertCircle' | 'Info' | 'HelpCircle'
14
+
15
+ export interface NavigationItem {
16
+ /** Unique identifier for the navigation item */
17
+ value: string
18
+ /** Display label for the navigation item */
19
+ label: string
20
+ /** Path to navigate to when clicked */
21
+ path: string
22
+ /** Icon name from Lucide React icons */
23
+ icon: IconName
24
+ /** Optional category for color theming (1-8) */
25
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
26
+ /** Optional badge text/count to display */
27
+ badge?: string | number
28
+ /** Whether this item is disabled */
29
+ disabled?: boolean
30
+ /** Child navigation items for nested menus */
31
+ children?: NavigationItem[]
32
+ }
33
+
34
+ export interface NavigationConfig {
35
+ /** Main navigation items */
36
+ items: NavigationItem[]
37
+ /** Whether to show the default showcase navigation as fallback */
38
+ showDefaultNavigation?: boolean
39
+ /** Custom logo or title for the sidebar header */
40
+ logo?: string
41
+ /** Whether the sidebar starts expanded */
42
+ defaultExpanded?: boolean
43
+ }
@@ -0,0 +1,54 @@
1
+ import {
2
+ Palette, Menu, X, Shield, Users, BarChart3, Database, TrendingUp, Layout,
3
+ Home, Settings, Bell, Search, Plus, Edit, Trash2, Eye, Download, Upload,
4
+ Share, Lock, Unlock, Mail, Phone, Calendar, Clock, MapPin, Star, Heart,
5
+ Bookmark, Tag, Flag, File, Folder, Image, Video, Music, ChevronRight,
6
+ ChevronDown, ChevronLeft, ChevronUp, ArrowRight, ArrowLeft, ArrowUp,
7
+ ArrowDown, Check, AlertCircle, Info, HelpCircle
8
+ } from 'lucide-react'
9
+ import type { IconName } from '../types'
10
+
11
+ // Map of icon names to Lucide React components
12
+ export const iconMap = {
13
+ Palette, Menu, X, Shield, Users, BarChart3, Database, TrendingUp, Layout,
14
+ Home, Settings, Bell, Search, Plus, Edit, Trash2, Eye, Download, Upload,
15
+ Share, Lock, Unlock, Mail, Phone, Calendar, Clock, MapPin, Star, Heart,
16
+ Bookmark, Tag, Flag, File, Folder, Image, Video, Music, ChevronRight,
17
+ ChevronDown, ChevronLeft, ChevronUp, ArrowRight, ArrowLeft, ArrowUp,
18
+ ArrowDown, Check, AlertCircle, Info, HelpCircle
19
+ }
20
+
21
+ interface IconProps {
22
+ name: IconName
23
+ className?: string
24
+ size?: number
25
+ [key: string]: any // Allow any additional props to be passed through
26
+ }
27
+
28
+ /**
29
+ * Resolves an icon name to the corresponding Lucide React component
30
+ */
31
+ export const Icon = ({ name, className = "w-5 h-5", size, ...props }: IconProps) => {
32
+ const IconComponent = iconMap[name]
33
+
34
+ if (!IconComponent) {
35
+ console.warn(`Icon "${name}" not found. Using default Menu icon.`)
36
+ return <Menu className={className} size={size} {...props} />
37
+ }
38
+
39
+ return <IconComponent className={className} size={size} {...props} />
40
+ }
41
+
42
+ /**
43
+ * Get the icon component directly for custom rendering
44
+ */
45
+ export const getIcon = (name: IconName) => {
46
+ return iconMap[name] || Menu
47
+ }
48
+
49
+ /**
50
+ * Check if an icon name is valid
51
+ */
52
+ export const isValidIcon = (name: string): name is IconName => {
53
+ return name in iconMap
54
+ }