@pattern-stack/frontend-patterns 0.0.3 → 0.0.4

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 (154) hide show
  1. package/dist/index.es.js +1 -1
  2. package/dist/index.js +1 -0
  3. package/package.json +5 -3
  4. package/src/App.css +42 -0
  5. package/src/App.tsx +54 -0
  6. package/src/__tests__/README.md +221 -0
  7. package/src/__tests__/atoms/hooks/simple-hooks.test.ts +44 -0
  8. package/src/__tests__/atoms/ui/button.test.tsx +68 -0
  9. package/src/__tests__/atoms/utils/simple.test.ts +18 -0
  10. package/src/__tests__/atoms/utils/utils.test.ts +77 -0
  11. package/src/__tests__/features/auth/simple-auth.test.tsx +40 -0
  12. package/src/__tests__/molecules/layout/simple-layout.test.tsx +81 -0
  13. package/src/__tests__/organisms/showcase/simple-showcase.test.tsx +167 -0
  14. package/src/__tests__/setup.ts +51 -0
  15. package/src/__tests__/utils.tsx +123 -0
  16. package/src/atoms/composed/Accordion/Accordion.tsx +271 -0
  17. package/src/atoms/composed/Accordion/index.ts +1 -0
  18. package/src/atoms/composed/Alert/Alert.tsx +132 -0
  19. package/src/atoms/composed/Alert/index.ts +1 -0
  20. package/src/atoms/composed/Breadcrumb/Breadcrumb.tsx +83 -0
  21. package/src/atoms/composed/Breadcrumb/index.ts +1 -0
  22. package/src/atoms/composed/Chart/Chart.tsx +425 -0
  23. package/src/atoms/composed/Chart/index.ts +2 -0
  24. package/src/atoms/composed/ColorSwatch/ColorSwatch.tsx +72 -0
  25. package/src/atoms/composed/ColorSwatch/index.ts +1 -0
  26. package/src/atoms/composed/DarkModeToggle.tsx +66 -0
  27. package/src/atoms/composed/DataBadge/DataBadge.tsx +81 -0
  28. package/src/atoms/composed/DataBadge/index.ts +1 -0
  29. package/src/atoms/composed/DataTable/DataTable.tsx +394 -0
  30. package/src/atoms/composed/DataTable/TableCellWithTooltip.tsx +41 -0
  31. package/src/atoms/composed/DataTable/index.ts +2 -0
  32. package/src/atoms/composed/DateTimePicker/DateTimePicker.tsx +611 -0
  33. package/src/atoms/composed/DateTimePicker/index.ts +2 -0
  34. package/src/atoms/composed/DetailedCard/DetailedCard.tsx +181 -0
  35. package/src/atoms/composed/DetailedCard/index.ts +2 -0
  36. package/src/atoms/composed/EmptyState/EmptyState.tsx +90 -0
  37. package/src/atoms/composed/EmptyState/index.ts +1 -0
  38. package/src/atoms/composed/FileUpload/FileUpload.tsx +477 -0
  39. package/src/atoms/composed/FileUpload/index.ts +2 -0
  40. package/src/atoms/composed/FormField/FormField.tsx +92 -0
  41. package/src/atoms/composed/FormField/index.ts +1 -0
  42. package/src/atoms/composed/GlobalSearch/GlobalSearch.tsx +37 -0
  43. package/src/atoms/composed/GlobalSearch/index.ts +1 -0
  44. package/src/atoms/composed/IconBadge/IconBadge.tsx +95 -0
  45. package/src/atoms/composed/IconBadge/index.ts +2 -0
  46. package/src/atoms/composed/Modal/Modal.tsx +223 -0
  47. package/src/atoms/composed/Modal/index.ts +2 -0
  48. package/src/atoms/composed/PaletteSwitcher.tsx +386 -0
  49. package/src/atoms/composed/ProgressBar/ProgressBar.tsx +116 -0
  50. package/src/atoms/composed/ProgressBar/index.ts +1 -0
  51. package/src/atoms/composed/StatCard/StatCard.tsx +219 -0
  52. package/src/atoms/composed/StatCard/index.ts +1 -0
  53. package/src/atoms/composed/StyleGuide.tsx +717 -0
  54. package/src/atoms/composed/Toast/Toast.tsx +219 -0
  55. package/src/atoms/composed/Toast/index.ts +1 -0
  56. package/src/atoms/composed/Tooltip/Tooltip.tsx +213 -0
  57. package/src/atoms/composed/Tooltip/index.ts +1 -0
  58. package/src/atoms/composed/UserAvatar/UserAvatar.tsx +139 -0
  59. package/src/atoms/composed/UserAvatar/index.ts +1 -0
  60. package/src/atoms/composed/UserMenu/UserMenu.tsx +16 -0
  61. package/src/atoms/composed/UserMenu/index.ts +1 -0
  62. package/src/atoms/composed/index.ts +29 -0
  63. package/src/atoms/hooks/useApi.ts +80 -0
  64. package/src/atoms/hooks/useHealth.ts +17 -0
  65. package/src/atoms/index.ts +13 -0
  66. package/src/atoms/services/api/client.ts +134 -0
  67. package/src/atoms/services/auth-service.ts +248 -0
  68. package/src/atoms/services/health.ts +15 -0
  69. package/src/atoms/services/index.ts +3 -0
  70. package/src/atoms/shared/config/constants.ts +17 -0
  71. package/src/atoms/shared/config/dashboard-sizes.ts +111 -0
  72. package/src/atoms/shared/config/environment.ts +10 -0
  73. package/src/atoms/shared/index.ts +4 -0
  74. package/src/atoms/shared/styles/color-palettes.css +566 -0
  75. package/src/atoms/types/auth.ts +62 -0
  76. package/src/atoms/types/generated.ts +1469 -0
  77. package/src/atoms/types/index.ts +4 -0
  78. package/src/atoms/types/loading.ts +28 -0
  79. package/src/atoms/ui/Badge.tsx +30 -0
  80. package/src/atoms/ui/ErrorBoundary.tsx +59 -0
  81. package/src/atoms/ui/Select.tsx +53 -0
  82. package/src/atoms/ui/Switch.tsx +42 -0
  83. package/src/atoms/ui/Tabs.tsx +118 -0
  84. package/src/atoms/ui/avatar.tsx +48 -0
  85. package/src/atoms/ui/button.tsx +70 -0
  86. package/src/atoms/ui/card.tsx +76 -0
  87. package/src/atoms/ui/dropdown-menu.tsx +199 -0
  88. package/src/atoms/ui/index.ts +39 -0
  89. package/src/atoms/ui/input.tsx +23 -0
  90. package/src/atoms/ui/label.tsx +23 -0
  91. package/src/atoms/ui/skeleton.tsx +13 -0
  92. package/src/atoms/ui/spinner.tsx +49 -0
  93. package/src/atoms/ui/table.tsx +116 -0
  94. package/src/atoms/utils/animations.ts +135 -0
  95. package/src/atoms/utils/tooltip-helpers.ts +140 -0
  96. package/src/atoms/utils/utils.ts +9 -0
  97. package/src/features/auth/components/LoginForm.tsx +168 -0
  98. package/src/features/auth/components/LogoutButton.tsx +19 -0
  99. package/src/features/auth/components/ProtectedRoute.tsx +60 -0
  100. package/src/features/auth/components/index.ts +4 -0
  101. package/src/features/auth/hooks/index.ts +2 -0
  102. package/src/features/auth/hooks/useAuth.tsx +205 -0
  103. package/src/features/auth/hooks/usePermissions.ts +35 -0
  104. package/src/features/auth/index.ts +2 -0
  105. package/src/features/index.ts +2 -0
  106. package/src/index.css +704 -0
  107. package/src/index.ts +13 -0
  108. package/src/main.tsx +48 -0
  109. package/src/molecules/.gitkeep +0 -0
  110. package/src/molecules/forms/FormGroup.tsx +75 -0
  111. package/src/molecules/forms/SearchInput.tsx +259 -0
  112. package/src/molecules/forms/index.ts +4 -0
  113. package/src/molecules/index.ts +4 -0
  114. package/src/molecules/layout/AppHeader/AppHeader.tsx +42 -0
  115. package/src/molecules/layout/AppHeader/index.ts +1 -0
  116. package/src/molecules/layout/AppLayout.tsx +29 -0
  117. package/src/molecules/layout/PageTemplate.tsx +87 -0
  118. package/src/molecules/layout/SectionHeader/SectionHeader.tsx +87 -0
  119. package/src/molecules/layout/SectionHeader/index.ts +1 -0
  120. package/src/molecules/layout/ShowcaseSection.tsx +57 -0
  121. package/src/molecules/layout/Sidebar.tsx +144 -0
  122. package/src/molecules/layout/SidebarButton/SidebarButton.tsx +99 -0
  123. package/src/molecules/layout/SidebarButton/index.ts +1 -0
  124. package/src/molecules/layout/SidebarContext.tsx +31 -0
  125. package/src/molecules/layout/index.ts +7 -0
  126. package/src/molecules/navigation/NavMenu.tsx +188 -0
  127. package/src/molecules/navigation/Pagination.tsx +172 -0
  128. package/src/molecules/navigation/index.ts +4 -0
  129. package/src/organisms/index.ts +5 -0
  130. package/src/organisms/showcase/ComponentShowcasePage.tsx +2496 -0
  131. package/src/organisms/showcase/index.ts +1 -0
  132. package/src/pages/AdminShowcase/AdminCRUDShowcase.tsx +242 -0
  133. package/src/pages/AdminShowcase/AdminDashboardShowcase.tsx +171 -0
  134. package/src/pages/AdminShowcase/AdminDetailShowcase.tsx +385 -0
  135. package/src/pages/AdminShowcase/index.tsx +3 -0
  136. package/src/pages/ComponentShowcase/BadgesShowcase.tsx +188 -0
  137. package/src/pages/ComponentShowcase/CardsShowcase.tsx +392 -0
  138. package/src/pages/ComponentShowcase/PalettesShowcase.tsx +207 -0
  139. package/src/pages/ComponentShowcase/StatesShowcase.tsx +485 -0
  140. package/src/pages/ComponentShowcase/TablesShowcase.tsx +134 -0
  141. package/src/pages/ComponentShowcase/TypographyShowcase.tsx +255 -0
  142. package/src/pages/ComponentShowcase/index.tsx +188 -0
  143. package/src/pages/index.ts +2 -0
  144. package/src/templates/AuthTemplate.tsx +216 -0
  145. package/src/templates/ComponentShowcaseTemplate.tsx +173 -0
  146. package/src/templates/DashboardTemplate.tsx +232 -0
  147. package/src/templates/DataTemplate.tsx +319 -0
  148. package/src/templates/admin/AdminCRUDTemplate.tsx +630 -0
  149. package/src/templates/admin/AdminDashboardTemplate.tsx +351 -0
  150. package/src/templates/admin/AdminDetailTemplate.tsx +563 -0
  151. package/src/templates/admin/index.ts +29 -0
  152. package/src/templates/factory.tsx +169 -0
  153. package/src/templates/index.ts +37 -0
  154. package/src/vite-env.d.ts +1 -0
@@ -0,0 +1,351 @@
1
+ import React from 'react';
2
+ import { cn } from '../../atoms/utils/utils';
3
+ import { StatCard } from '../../atoms/composed/StatCard';
4
+ import { Chart } from '../../atoms/composed/Chart';
5
+ import { Card } from '../../atoms/ui/card';
6
+ import { DashboardGrid } from '../DashboardTemplate';
7
+ import { DataBadge } from '../../atoms/composed/DataBadge';
8
+ import { IconBadge } from '../../atoms/composed/IconBadge';
9
+ import { Button } from '../../atoms/ui/button';
10
+ import { getContainerHeightClass } from '../../atoms/shared/config/dashboard-sizes';
11
+ import { Activity, AlertTriangle, TrendingUp, Users, Settings, RefreshCw } from 'lucide-react';
12
+
13
+ export interface MetricCard {
14
+ /** Metric title */
15
+ title: string;
16
+ /** Main value to display */
17
+ value: string | number;
18
+ /** Change percentage */
19
+ change?: number;
20
+ /** Change period description */
21
+ changePeriod?: string;
22
+ /** Metric category for styling */
23
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
24
+ /** Custom icon */
25
+ icon?: React.ReactNode;
26
+ /** Click handler */
27
+ onClick?: () => void;
28
+ }
29
+
30
+ export interface ChartConfig {
31
+ /** Chart title */
32
+ title: string;
33
+ /** Chart type */
34
+ type: 'line' | 'bar' | 'pie' | 'area';
35
+ /** Chart data */
36
+ data: Array<{ label: string; value: number; category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 }>;
37
+ /** Chart configuration */
38
+ config?: Record<string, unknown>;
39
+ /** Chart category for styling */
40
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
41
+ }
42
+
43
+ export interface ActivityItem {
44
+ /** Activity ID */
45
+ id: string;
46
+ /** Activity type */
47
+ type: 'user' | 'system' | 'security' | 'content' | 'error';
48
+ /** Activity message */
49
+ message: string;
50
+ /** Activity timestamp */
51
+ timestamp: Date;
52
+ /** User who performed the activity */
53
+ user?: string;
54
+ /** Additional metadata */
55
+ metadata?: Record<string, unknown>;
56
+ }
57
+
58
+ export interface AlertItem {
59
+ /** Alert ID */
60
+ id: string;
61
+ /** Alert severity */
62
+ severity: 'low' | 'medium' | 'high' | 'critical';
63
+ /** Alert title */
64
+ title: string;
65
+ /** Alert description */
66
+ description: string;
67
+ /** Alert timestamp */
68
+ timestamp: Date;
69
+ /** Whether alert is resolved */
70
+ resolved?: boolean;
71
+ /** Action to resolve alert */
72
+ onResolve?: () => void;
73
+ }
74
+
75
+ export interface AdminDashboardTemplateProps {
76
+ /** Dashboard title */
77
+ title?: string;
78
+ /** Dashboard description */
79
+ description?: string;
80
+ /** Key metrics to display */
81
+ metrics: MetricCard[];
82
+ /** Charts configuration */
83
+ charts?: ChartConfig[];
84
+ /** Recent activities */
85
+ activities?: ActivityItem[];
86
+ /** System alerts */
87
+ alerts?: AlertItem[];
88
+ /** Additional actions in header */
89
+ actions?: React.ReactNode;
90
+ /** Additional CSS classes */
91
+ className?: string;
92
+ /** Whether data is loading */
93
+ isLoading?: boolean;
94
+ /** Refresh handler */
95
+ onRefresh?: () => void;
96
+ /** Last updated timestamp */
97
+ lastUpdated?: Date;
98
+ }
99
+
100
+ export const AdminDashboardTemplate: React.FC<AdminDashboardTemplateProps> = ({
101
+ title = "Admin Dashboard",
102
+ description = "System overview and key metrics",
103
+ metrics,
104
+ charts = [],
105
+ activities = [],
106
+ alerts = [],
107
+ actions,
108
+ className,
109
+ isLoading = false,
110
+ onRefresh,
111
+ lastUpdated
112
+ }) => {
113
+ const unreadAlerts = alerts.filter(alert => !alert.resolved);
114
+ const criticalAlerts = unreadAlerts.filter(alert => alert.severity === 'critical');
115
+
116
+ const getActivityIcon = (type: ActivityItem['type']) => {
117
+ switch (type) {
118
+ case 'user': return <Users className="w-4 h-4" />;
119
+ case 'system': return <Settings className="w-4 h-4" />;
120
+ case 'security': return <AlertTriangle className="w-4 h-4" />;
121
+ case 'content': return <Activity className="w-4 h-4" />;
122
+ case 'error': return <AlertTriangle className="w-4 h-4" />;
123
+ default: return <Activity className="w-4 h-4" />;
124
+ }
125
+ };
126
+
127
+ const getActivityColor = (type: ActivityItem['type']) => {
128
+ switch (type) {
129
+ case 'user': return 'text-category-1';
130
+ case 'system': return 'text-category-2';
131
+ case 'security': return 'text-category-3';
132
+ case 'content': return 'text-category-5';
133
+ case 'error': return 'text-category-8';
134
+ default: return 'text-muted-foreground';
135
+ }
136
+ };
137
+
138
+ const getAlertSeverityCategory = (severity: AlertItem['severity']): 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 => {
139
+ switch (severity) {
140
+ case 'low': return 6;
141
+ case 'medium': return 7;
142
+ case 'high': return 3;
143
+ case 'critical': return 8;
144
+ default: return 2;
145
+ }
146
+ };
147
+
148
+ return (
149
+ <div className={cn('flex flex-col min-h-0 flex-1', className)}>
150
+ {/* Header Section */}
151
+ <div className="bg-gradient-to-br from-muted/50 via-muted/30 to-background border-b border-border/50">
152
+ <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-12">
153
+ <div className="flex items-start justify-between">
154
+ <div className="flex items-center space-x-4">
155
+ <IconBadge
156
+ variant="category"
157
+ category={1}
158
+ size="lg"
159
+ icon={<Activity className="w-5 h-5" />}
160
+ tooltip="Dashboard Activity Overview"
161
+ />
162
+ <div>
163
+ <h1 className="text-4xl font-bold text-foreground">{title}</h1>
164
+ <p className="text-lg text-muted-foreground mt-2">{description}</p>
165
+ </div>
166
+ </div>
167
+
168
+ <div className="ml-6 flex-shrink-0">
169
+ {/* Action buttons */}
170
+ <div className="flex items-center gap-2 mb-2">
171
+ {onRefresh && (
172
+ <Button
173
+ variant="outline"
174
+ onClick={onRefresh}
175
+ disabled={isLoading}
176
+ tooltip={isLoading ? "Refreshing..." : "Refresh data"}
177
+ >
178
+ <RefreshCw className={cn("w-4 h-4 mr-2", isLoading && "animate-spin")} />
179
+ Refresh
180
+ </Button>
181
+ )}
182
+ {actions}
183
+ </div>
184
+
185
+ {/* Status indicators positioned under buttons */}
186
+ <div className="flex items-center gap-4 justify-end">
187
+ {criticalAlerts.length > 0 && (
188
+ <DataBadge
189
+ variant="status"
190
+ status="error"
191
+ size="sm"
192
+ >
193
+ <AlertTriangle className="w-3 h-3 mr-1" />
194
+ {criticalAlerts.length} Critical Alert{criticalAlerts.length !== 1 ? 's' : ''}
195
+ </DataBadge>
196
+ )}
197
+
198
+ {lastUpdated && (
199
+ <span className="text-sm text-muted-foreground">
200
+ Last updated: {lastUpdated.toLocaleTimeString()}
201
+ </span>
202
+ )}
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ {/* Main Content */}
210
+ <div className="flex-1 min-h-0 overflow-auto">
211
+ <div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 py-8 space-y-8">
212
+
213
+ {/* Key Metrics Grid */}
214
+ <DashboardGrid columns={4} gap="md">
215
+ {metrics.map((metric, index) => (
216
+ <StatCard
217
+ key={index}
218
+ title={metric.title}
219
+ value={metric.value}
220
+ trend={metric.change ? { value: metric.change, label: metric.changePeriod } : undefined}
221
+ category={metric.category || 1}
222
+ icon={metric.icon || <TrendingUp className="w-5 h-5" />}
223
+ onClick={metric.onClick}
224
+ className="cursor-pointer transition-shadow"
225
+ />
226
+ ))}
227
+ </DashboardGrid>
228
+
229
+ {/* Charts and Activities Row */}
230
+ <div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
231
+
232
+ {/* Charts Section */}
233
+ <div className="lg:col-span-2 space-y-6">
234
+ {charts.map((chart, index) => (
235
+ <Card key={index} className="p-6 overflow-hidden">
236
+ <div className="mb-4">
237
+ <h3 className="text-lg font-semibold text-foreground">
238
+ {chart.title}
239
+ </h3>
240
+ </div>
241
+ <div className={getContainerHeightClass('container-small-chart')}>
242
+ <Chart
243
+ title={chart.title}
244
+ type={chart.type}
245
+ data={chart.data}
246
+ category={chart.category}
247
+ height="small"
248
+ variant="minimal"
249
+ noWrapper={true}
250
+ />
251
+ </div>
252
+ </Card>
253
+ ))}
254
+ </div>
255
+
256
+ {/* Right Sidebar */}
257
+ <div className="space-y-6">
258
+
259
+ {/* System Alerts */}
260
+ {unreadAlerts.length > 0 && (
261
+ <Card className="p-4">
262
+ <div className="mb-4">
263
+ <h3 className="text-lg font-semibold text-foreground flex items-center">
264
+ <AlertTriangle className="w-5 h-5 mr-2 text-category-8" />
265
+ System Alerts
266
+ </h3>
267
+ </div>
268
+ <div className="space-y-3">
269
+ {unreadAlerts.slice(0, 5).map((alert) => (
270
+ <div
271
+ key={alert.id}
272
+ className="flex items-start space-x-3 p-3 rounded-md border border-border"
273
+ >
274
+ <DataBadge
275
+ variant="category"
276
+ category={getAlertSeverityCategory(alert.severity)}
277
+ size="sm"
278
+ className="mt-0.5"
279
+ >
280
+ {alert.severity}
281
+ </DataBadge>
282
+ <div className="flex-1 min-w-0">
283
+ <p className="text-sm font-medium text-foreground">
284
+ {alert.title}
285
+ </p>
286
+ <p className="text-xs text-muted-foreground mt-1">
287
+ {alert.description}
288
+ </p>
289
+ <p className="text-xs text-muted-foreground mt-1">
290
+ {alert.timestamp.toLocaleString()}
291
+ </p>
292
+ {alert.onResolve && (
293
+ <Button
294
+ size="sm"
295
+ variant="outline"
296
+ className="mt-2"
297
+ onClick={alert.onResolve}
298
+ >
299
+ Resolve
300
+ </Button>
301
+ )}
302
+ </div>
303
+ </div>
304
+ ))}
305
+ </div>
306
+ </Card>
307
+ )}
308
+
309
+ {/* Recent Activity */}
310
+ <Card className="p-4">
311
+ <div className="mb-4">
312
+ <h3 className="text-lg font-semibold text-foreground flex items-center">
313
+ <Activity className="w-5 h-5 mr-2 text-category-2" />
314
+ Recent Activity
315
+ </h3>
316
+ </div>
317
+ <div className="space-y-3">
318
+ {activities.slice(0, 8).map((activity) => (
319
+ <div key={activity.id} className="flex items-start space-x-3">
320
+ <div className={cn(
321
+ "mt-1 flex-shrink-0",
322
+ getActivityColor(activity.type)
323
+ )}>
324
+ {getActivityIcon(activity.type)}
325
+ </div>
326
+ <div className="flex-1 min-w-0">
327
+ <p className="text-sm text-foreground">
328
+ {activity.message}
329
+ </p>
330
+ <div className="flex items-center gap-2 mt-1">
331
+ {activity.user && (
332
+ <span className="text-xs text-muted-foreground">
333
+ by {activity.user}
334
+ </span>
335
+ )}
336
+ <span className="text-xs text-muted-foreground">
337
+ {activity.timestamp.toLocaleString()}
338
+ </span>
339
+ </div>
340
+ </div>
341
+ </div>
342
+ ))}
343
+ </div>
344
+ </Card>
345
+ </div>
346
+ </div>
347
+ </div>
348
+ </div>
349
+ </div>
350
+ );
351
+ };