@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.
- package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts +19 -0
- package/dist/atoms/composed/SalesPanel/SalesPanel.d.ts.map +1 -0
- package/dist/atoms/composed/SalesPanel/index.d.ts +2 -0
- package/dist/atoms/composed/SalesPanel/index.d.ts.map +1 -0
- package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts +63 -0
- package/dist/atoms/composed/SalesPanel/mockSalesData.d.ts.map +1 -0
- package/dist/atoms/composed/index.d.ts +1 -0
- package/dist/atoms/composed/index.d.ts.map +1 -1
- package/dist/atoms/types/entity-config.d.ts +117 -0
- package/dist/atoms/types/entity-config.d.ts.map +1 -0
- package/dist/atoms/types/index.d.ts +2 -0
- package/dist/atoms/types/index.d.ts.map +1 -1
- package/dist/atoms/types/navigation.d.ts +30 -0
- package/dist/atoms/types/navigation.d.ts.map +1 -0
- package/dist/atoms/ui/ErrorBoundary.d.ts +1 -1
- package/dist/atoms/ui/button.d.ts +1 -1
- package/dist/atoms/utils/icon-resolver.d.ts +72 -0
- package/dist/atoms/utils/icon-resolver.d.ts.map +1 -0
- package/dist/atoms/utils/metric-engine.d.ts +30 -0
- package/dist/atoms/utils/metric-engine.d.ts.map +1 -0
- package/dist/atoms/utils/utils.d.ts +2 -0
- package/dist/atoms/utils/utils.d.ts.map +1 -1
- package/dist/features/auth/components/ProtectedRoute.d.ts +1 -1
- package/dist/frontend-patterns.css +1 -1
- package/dist/index.es.js +402 -14
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +402 -14
- package/dist/index.js.map +1 -1
- package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts +16 -0
- package/dist/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.d.ts.map +1 -0
- package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts +2 -0
- package/dist/molecules/layout/DashboardWithSidePanel/index.d.ts.map +1 -0
- package/dist/molecules/layout/NavigationContext.d.ts +15 -0
- package/dist/molecules/layout/NavigationContext.d.ts.map +1 -0
- package/dist/molecules/layout/Sidebar.d.ts.map +1 -1
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts +2 -0
- package/dist/molecules/layout/SidebarButton/SidebarButton.d.ts.map +1 -1
- package/dist/molecules/layout/index.d.ts +3 -0
- package/dist/molecules/layout/index.d.ts.map +1 -1
- package/dist/templates/factory.d.ts +2 -1
- package/dist/templates/factory.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/package.json +7 -3
- package/src/App.tsx +11 -1
- package/src/__tests__/atoms/composed/databadge.test.tsx +106 -0
- package/src/__tests__/atoms/composed/statcard.test.tsx +133 -0
- package/src/__tests__/atoms/utils/icon-resolver.test.tsx +140 -0
- package/src/atoms/composed/SalesPanel/SalesPanel.tsx +116 -0
- package/src/atoms/composed/SalesPanel/index.ts +1 -0
- package/src/atoms/composed/SalesPanel/mockSalesData.ts +151 -0
- package/src/atoms/composed/index.ts +1 -0
- package/src/atoms/types/entity-config.ts +127 -0
- package/src/atoms/types/index.ts +3 -1
- package/src/atoms/types/navigation.ts +43 -0
- package/src/atoms/utils/icon-resolver.tsx +54 -0
- package/src/atoms/utils/metric-engine.ts +236 -0
- package/src/atoms/utils/utils.ts +4 -2
- package/src/molecules/layout/DashboardWithSidePanel/DashboardWithSidePanel.tsx +42 -0
- package/src/molecules/layout/DashboardWithSidePanel/index.ts +1 -0
- package/src/molecules/layout/NavigationContext.tsx +63 -0
- package/src/molecules/layout/Sidebar.tsx +10 -23
- package/src/molecules/layout/SidebarButton/SidebarButton.tsx +32 -10
- package/src/molecules/layout/index.ts +4 -1
- package/src/organisms/entity/CategoryBreakdownPanel.tsx +427 -0
- package/src/organisms/entity/EntityListPanel.tsx +339 -0
- package/src/organisms/entity/MetricsOverviewPanel.tsx +236 -0
- package/src/organisms/entity/TrendAnalysisPanel.tsx +337 -0
- package/src/organisms/entity/index.ts +4 -0
- package/src/organisms/index.ts +5 -1
- package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +77 -75
- package/src/pages/AdminShowcase/SalesPerformanceDashboard.tsx +158 -0
- package/src/pages/AdminShowcase/index.tsx +2 -1
- package/src/pages/EntityShowcase/EntityManagementShowcase.tsx +137 -0
- package/src/pages/EntityShowcase/EntityPerformanceShowcase.tsx +117 -0
- package/src/pages/EntityShowcase/index.ts +2 -0
- package/src/pages/EntityTemplateExample.tsx +229 -0
- package/src/pages/TestEntityTemplate.tsx +40 -0
- package/src/pages/index.ts +2 -1
- package/src/templates/entity/EntityManagementTemplate.tsx +430 -0
- package/src/templates/entity/EntityPerformanceDashboardTemplate.tsx +277 -0
- package/src/templates/entity/configs/financial-config.ts +141 -0
- package/src/templates/entity/configs/index.ts +1 -0
- package/src/templates/entity/index.ts +3 -0
- package/src/templates/factory.tsx +14 -7
- package/src/templates/financial/FinancialDashboardTemplate.tsx +326 -0
- 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
|
+
];
|
|
@@ -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
|
+
}
|
package/src/atoms/types/index.ts
CHANGED
|
@@ -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
|
+
}
|