@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,319 @@
1
+ import React from 'react';
2
+ import { cn } from '../atoms/utils/utils';
3
+ import { SectionHeader } from '../molecules/layout/SectionHeader';
4
+ import { DataTable, type Column } from '../atoms/composed/DataTable';
5
+ import { SearchInput, type SearchResult } from '../molecules/forms/SearchInput';
6
+ import { Pagination } from '../molecules/navigation/Pagination';
7
+ import { Card } from '../atoms/ui/card';
8
+ import { Button } from '../atoms/ui/button';
9
+ import { Plus, Download, Filter } from 'lucide-react';
10
+
11
+ export interface DataTemplateProps {
12
+ /** Page title */
13
+ title: string;
14
+ /** Page description */
15
+ description?: string;
16
+ /** Search functionality */
17
+ searchConfig?: {
18
+ placeholder?: string;
19
+ value?: string;
20
+ onChange?: (value: string) => void;
21
+ results?: SearchResult[];
22
+ };
23
+ /** Filter functionality */
24
+ filterConfig?: {
25
+ onFilter?: () => void;
26
+ filterCount?: number;
27
+ };
28
+ /** Data table configuration */
29
+ tableConfig: {
30
+ data: Record<string, unknown>[];
31
+ columns: Column<Record<string, unknown>>[];
32
+ loading?: boolean;
33
+ onRowClick?: (item: Record<string, unknown>) => void;
34
+ };
35
+ /** Pagination configuration */
36
+ paginationConfig?: {
37
+ currentPage: number;
38
+ totalPages: number;
39
+ onPageChange: (page: number) => void;
40
+ };
41
+ /** Action buttons */
42
+ actions?: {
43
+ primary?: {
44
+ label: string;
45
+ onClick: () => void;
46
+ icon?: React.ReactNode;
47
+ };
48
+ secondary?: Array<{
49
+ label: string;
50
+ onClick: () => void;
51
+ icon?: React.ReactNode;
52
+ }>;
53
+ };
54
+ /** Additional CSS classes */
55
+ className?: string;
56
+ /** Category-based styling */
57
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
58
+ /** Empty state content */
59
+ emptyState?: React.ReactNode;
60
+ }
61
+
62
+ export const DataTemplate: React.FC<DataTemplateProps> = ({
63
+ title,
64
+ description,
65
+ searchConfig,
66
+ filterConfig,
67
+ tableConfig,
68
+ paginationConfig,
69
+ actions,
70
+ className,
71
+ category = 1,
72
+ emptyState
73
+ }) => {
74
+ const hasData = tableConfig.data && tableConfig.data.length > 0;
75
+ const showControls = searchConfig || filterConfig || actions;
76
+
77
+ return (
78
+ <div className={cn('flex flex-col min-h-0 flex-1', className)}>
79
+ {/* Header Section */}
80
+ <div className="flex-shrink-0 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
81
+ <div className="container mx-auto px-6 py-6">
82
+ <div className="flex items-start justify-between">
83
+ <div className="flex-1 min-w-0">
84
+ <SectionHeader
85
+ title={title}
86
+ description={description}
87
+ size="lg"
88
+ className="text-left"
89
+ />
90
+ </div>
91
+
92
+ {actions?.primary && (
93
+ <div className="ml-6 flex-shrink-0">
94
+ <Button
95
+ onClick={actions.primary.onClick}
96
+ className={cn(
97
+ `bg-category-${category} hover:bg-category-${category}/90`,
98
+ 'text-white'
99
+ )}
100
+ >
101
+ {actions.primary.icon || <Plus className="w-4 h-4 mr-2" />}
102
+ {actions.primary.label}
103
+ </Button>
104
+ </div>
105
+ )}
106
+ </div>
107
+ </div>
108
+ </div>
109
+
110
+ {/* Controls Section */}
111
+ {showControls && (
112
+ <div className="flex-shrink-0 border-b border-border bg-muted/30">
113
+ <div className="container mx-auto px-6 py-4">
114
+ <div className="flex items-center gap-4">
115
+ {/* Search */}
116
+ {searchConfig && (
117
+ <div className="flex-1 max-w-md">
118
+ <SearchInput
119
+ placeholder={searchConfig.placeholder}
120
+ value={searchConfig.value}
121
+ onChange={searchConfig.onChange}
122
+ results={searchConfig.results}
123
+ category={category}
124
+ />
125
+ </div>
126
+ )}
127
+
128
+ <div className="flex items-center gap-2">
129
+ {/* Filter Button */}
130
+ {filterConfig && (
131
+ <Button
132
+ variant="outline"
133
+ onClick={filterConfig.onFilter}
134
+ className="relative"
135
+ >
136
+ <Filter className="w-4 h-4 mr-2" />
137
+ Filters
138
+ {filterConfig.filterCount && filterConfig.filterCount > 0 && (
139
+ <span className={cn(
140
+ 'absolute -top-2 -right-2 w-5 h-5 rounded-full text-xs font-bold',
141
+ 'flex items-center justify-center text-white',
142
+ `bg-category-${category}`
143
+ )}>
144
+ {filterConfig.filterCount}
145
+ </span>
146
+ )}
147
+ </Button>
148
+ )}
149
+
150
+ {/* Secondary Actions */}
151
+ {actions?.secondary?.map((action, index) => (
152
+ <Button
153
+ key={index}
154
+ variant="outline"
155
+ onClick={action.onClick}
156
+ >
157
+ {action.icon || <Download className="w-4 h-4 mr-2" />}
158
+ {action.label}
159
+ </Button>
160
+ ))}
161
+ </div>
162
+ </div>
163
+ </div>
164
+ </div>
165
+ )}
166
+
167
+ {/* Main Content */}
168
+ <div className="flex-1 min-h-0 overflow-auto">
169
+ <div className="container mx-auto px-6 py-6">
170
+ {hasData ? (
171
+ <div className="space-y-6">
172
+ {/* Data Table */}
173
+ <Card category={category}>
174
+ <DataTable
175
+ data={tableConfig.data}
176
+ columns={tableConfig.columns}
177
+ isLoading={tableConfig.loading}
178
+ onRowClick={tableConfig.onRowClick}
179
+ hover={true}
180
+ />
181
+ </Card>
182
+
183
+ {/* Pagination */}
184
+ {paginationConfig && paginationConfig.totalPages > 1 && (
185
+ <div className="flex justify-center">
186
+ <Pagination
187
+ currentPage={paginationConfig.currentPage}
188
+ totalPages={paginationConfig.totalPages}
189
+ onPageChange={paginationConfig.onPageChange}
190
+ category={category}
191
+ />
192
+ </div>
193
+ )}
194
+ </div>
195
+ ) : (
196
+ <div className="flex items-center justify-center min-h-96">
197
+ {emptyState || (
198
+ <div className="text-center space-y-4">
199
+ <div className="text-muted-foreground text-lg">
200
+ No data available
201
+ </div>
202
+ <p className="text-sm text-muted-foreground max-w-md">
203
+ {actions?.primary ? (
204
+ <>Get started by creating your first {title.toLowerCase()}.</>
205
+ ) : (
206
+ <>There's no data to display at the moment.</>
207
+ )}
208
+ </p>
209
+ {actions?.primary && (
210
+ <Button
211
+ onClick={actions.primary.onClick}
212
+ className={cn(
213
+ `bg-category-${category} hover:bg-category-${category}/90`,
214
+ 'text-white'
215
+ )}
216
+ >
217
+ {actions.primary.icon || <Plus className="w-4 h-4 mr-2" />}
218
+ {actions.primary.label}
219
+ </Button>
220
+ )}
221
+ </div>
222
+ )}
223
+ </div>
224
+ )}
225
+ </div>
226
+ </div>
227
+ </div>
228
+ );
229
+ };
230
+
231
+ /**
232
+ * Data Detail Template
233
+ * Template for displaying detailed information about a single data item
234
+ */
235
+ export interface DataDetailTemplateProps {
236
+ /** Page title */
237
+ title: string;
238
+ /** Page subtitle */
239
+ subtitle?: string;
240
+ /** Back navigation */
241
+ onBack?: () => void;
242
+ /** Detail content */
243
+ children: React.ReactNode;
244
+ /** Action buttons */
245
+ actions?: React.ReactNode;
246
+ /** Additional CSS classes */
247
+ className?: string;
248
+ /** Category-based styling */
249
+ category?: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8;
250
+ /** Sidebar content */
251
+ sidebar?: React.ReactNode;
252
+ }
253
+
254
+ export const DataDetailTemplate: React.FC<DataDetailTemplateProps> = ({
255
+ title,
256
+ subtitle,
257
+ onBack,
258
+ children,
259
+ actions,
260
+ className,
261
+ sidebar
262
+ }) => {
263
+ return (
264
+ <div className={cn('flex flex-col min-h-0 flex-1', className)}>
265
+ {/* Header */}
266
+ <div className="flex-shrink-0 border-b border-border bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
267
+ <div className="container mx-auto px-6 py-6">
268
+ <div className="flex items-start justify-between">
269
+ <div className="flex-1 min-w-0">
270
+ {onBack && (
271
+ <Button
272
+ variant="ghost"
273
+ onClick={onBack}
274
+ className="mb-4 -ml-3"
275
+ >
276
+ ← Back
277
+ </Button>
278
+ )}
279
+ <SectionHeader
280
+ title={title}
281
+ subtitle={subtitle}
282
+ size="lg"
283
+ className="text-left"
284
+ />
285
+ </div>
286
+
287
+ {actions && (
288
+ <div className="ml-6 flex-shrink-0">
289
+ {actions}
290
+ </div>
291
+ )}
292
+ </div>
293
+ </div>
294
+ </div>
295
+
296
+ {/* Content */}
297
+ <div className="flex-1 min-h-0 overflow-auto">
298
+ <div className="container mx-auto px-6 py-6">
299
+ <div className={cn(
300
+ 'grid gap-6',
301
+ sidebar ? 'grid-cols-1 lg:grid-cols-3' : 'grid-cols-1'
302
+ )}>
303
+ {/* Main Content */}
304
+ <div className={sidebar ? 'lg:col-span-2' : 'col-span-1'}>
305
+ {children}
306
+ </div>
307
+
308
+ {/* Sidebar */}
309
+ {sidebar && (
310
+ <div className="lg:col-span-1">
311
+ {sidebar}
312
+ </div>
313
+ )}
314
+ </div>
315
+ </div>
316
+ </div>
317
+ </div>
318
+ );
319
+ };