@mostrom/app-shell 0.1.0

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 (142) hide show
  1. package/.claude/ralph-loop.local.md +9 -0
  2. package/README.md +172 -0
  3. package/bin/init.js +269 -0
  4. package/bun.lock +401 -0
  5. package/components.json +28 -0
  6. package/package.json +74 -0
  7. package/scripts/publish-npm.sh +202 -0
  8. package/src/AppShell.tsx +847 -0
  9. package/src/components/PageHeader.tsx +160 -0
  10. package/src/components/data-table/README.md +447 -0
  11. package/src/components/data-table/data-table-preferences.tsx +184 -0
  12. package/src/components/data-table/data-table-toolbar.tsx +118 -0
  13. package/src/components/data-table/data-table.tsx +37 -0
  14. package/src/components/data-table/index.ts +32 -0
  15. package/src/components/global-header/AllServicesButton.tsx +127 -0
  16. package/src/components/global-header/CategoriesButton.tsx +120 -0
  17. package/src/components/global-header/GlobalHeader.tsx +59 -0
  18. package/src/components/global-header/GlobalHeaderSearch.tsx +57 -0
  19. package/src/components/global-header/HeaderUtilities.tsx +243 -0
  20. package/src/components/global-header/ServicesMenu.tsx +246 -0
  21. package/src/components/layout/AppBreadcrumb.tsx +70 -0
  22. package/src/components/layout/AppFlashbar.tsx +95 -0
  23. package/src/components/layout/AppLayout.tsx +271 -0
  24. package/src/components/layout/AppNavigation.tsx +313 -0
  25. package/src/components/layout/AppSidebar.tsx +229 -0
  26. package/src/components/patterns/index.ts +14 -0
  27. package/src/components/patterns/p-alert-5.tsx +19 -0
  28. package/src/components/patterns/p-autocomplete-5.tsx +89 -0
  29. package/src/components/patterns/p-breadcrumb-1.tsx +28 -0
  30. package/src/components/patterns/p-button-42.tsx +37 -0
  31. package/src/components/patterns/p-button-51.tsx +14 -0
  32. package/src/components/patterns/p-button-6.tsx +5 -0
  33. package/src/components/patterns/p-calendar-1.tsx +18 -0
  34. package/src/components/patterns/p-card-1.tsx +33 -0
  35. package/src/components/patterns/p-card-2.tsx +26 -0
  36. package/src/components/patterns/p-card-5.tsx +31 -0
  37. package/src/components/patterns/p-collapsible-7.tsx +121 -0
  38. package/src/components/patterns/p-command-6.tsx +113 -0
  39. package/src/components/patterns/p-dialog-1.tsx +56 -0
  40. package/src/components/patterns/p-dropdown-menu-1.tsx +38 -0
  41. package/src/components/patterns/p-dropdown-menu-11.tsx +122 -0
  42. package/src/components/patterns/p-dropdown-menu-14.tsx +165 -0
  43. package/src/components/patterns/p-dropdown-menu-9.tsx +108 -0
  44. package/src/components/patterns/p-empty-2.tsx +34 -0
  45. package/src/components/patterns/p-file-upload-1.tsx +72 -0
  46. package/src/components/patterns/p-filters-1.tsx +666 -0
  47. package/src/components/patterns/p-frame-2.tsx +26 -0
  48. package/src/components/patterns/p-tabs-2.tsx +129 -0
  49. package/src/components/reui/alert.tsx +92 -0
  50. package/src/components/reui/autocomplete.tsx +343 -0
  51. package/src/components/reui/badge.tsx +87 -0
  52. package/src/components/reui/data-grid/data-grid-column-filter.tsx +165 -0
  53. package/src/components/reui/data-grid/data-grid-column-header.tsx +339 -0
  54. package/src/components/reui/data-grid/data-grid-column-visibility.tsx +55 -0
  55. package/src/components/reui/data-grid/data-grid-pagination.tsx +224 -0
  56. package/src/components/reui/data-grid/data-grid-table-dnd-rows.tsx +260 -0
  57. package/src/components/reui/data-grid/data-grid-table-dnd.tsx +253 -0
  58. package/src/components/reui/data-grid/data-grid-table.tsx +639 -0
  59. package/src/components/reui/data-grid/data-grid.tsx +209 -0
  60. package/src/components/reui/date-selector.tsx +1330 -0
  61. package/src/components/reui/filters.tsx +1869 -0
  62. package/src/components/reui/frame.tsx +134 -0
  63. package/src/components/reui/index.ts +17 -0
  64. package/src/components/reui/timeline.tsx +219 -0
  65. package/src/components/search/Autocomplete.tsx +183 -0
  66. package/src/components/search/AutocompleteClient.tsx +293 -0
  67. package/src/components/search/GlobalSearch.tsx +187 -0
  68. package/src/components/section-drawer/deal-drawer-content.tsx +891 -0
  69. package/src/components/section-drawer/index.ts +19 -0
  70. package/src/components/section-drawer/section-drawer.css +665 -0
  71. package/src/components/section-drawer/section-drawer.tsx +467 -0
  72. package/src/components/sectioned-list-board/README.md +78 -0
  73. package/src/components/sectioned-list-board/board-card-content.tsx +340 -0
  74. package/src/components/sectioned-list-board/date-range-filter.tsx +249 -0
  75. package/src/components/sectioned-list-board/index.ts +19 -0
  76. package/src/components/sectioned-list-board/sectioned-list-board.css +564 -0
  77. package/src/components/sectioned-list-board/sectioned-list-board.tsx +731 -0
  78. package/src/components/sectioned-list-board/sortable-card.tsx +314 -0
  79. package/src/components/sectioned-list-board/sortable-section.tsx +319 -0
  80. package/src/components/sectioned-list-board/types.ts +216 -0
  81. package/src/components/sectioned-list-table/README.md +80 -0
  82. package/src/components/sectioned-list-table/index.ts +14 -0
  83. package/src/components/sectioned-list-table/sectioned-list-table.css +534 -0
  84. package/src/components/sectioned-list-table/sectioned-list-table.tsx +740 -0
  85. package/src/components/sectioned-list-table/sortable-column-header.tsx +120 -0
  86. package/src/components/sectioned-list-table/sortable-row.tsx +420 -0
  87. package/src/components/sectioned-list-table/sortable-section.tsx +251 -0
  88. package/src/components/sectioned-list-table/table-cell-content.tsx +129 -0
  89. package/src/components/sectioned-list-table/types.ts +120 -0
  90. package/src/components/sectioned-list-table/use-column-preferences.ts +103 -0
  91. package/src/components/ui/actions-dropdown.tsx +109 -0
  92. package/src/components/ui/assignee-selector.tsx +209 -0
  93. package/src/components/ui/avatar.tsx +107 -0
  94. package/src/components/ui/breadcrumb.tsx +109 -0
  95. package/src/components/ui/button-group.tsx +83 -0
  96. package/src/components/ui/button.tsx +64 -0
  97. package/src/components/ui/calendar.tsx +220 -0
  98. package/src/components/ui/card.tsx +92 -0
  99. package/src/components/ui/chart.tsx +376 -0
  100. package/src/components/ui/checkbox.tsx +30 -0
  101. package/src/components/ui/collapsible.tsx +33 -0
  102. package/src/components/ui/command.tsx +182 -0
  103. package/src/components/ui/context-menu.tsx +250 -0
  104. package/src/components/ui/create-button-group.tsx +128 -0
  105. package/src/components/ui/dialog.tsx +156 -0
  106. package/src/components/ui/drawer.tsx +133 -0
  107. package/src/components/ui/dropdown-menu.tsx +255 -0
  108. package/src/components/ui/empty.tsx +104 -0
  109. package/src/components/ui/field.tsx +248 -0
  110. package/src/components/ui/form.tsx +165 -0
  111. package/src/components/ui/index.ts +37 -0
  112. package/src/components/ui/input-group.tsx +168 -0
  113. package/src/components/ui/input.tsx +21 -0
  114. package/src/components/ui/kbd.tsx +28 -0
  115. package/src/components/ui/label.tsx +22 -0
  116. package/src/components/ui/navigation-menu.tsx +168 -0
  117. package/src/components/ui/page-header.tsx +80 -0
  118. package/src/components/ui/popover.tsx +87 -0
  119. package/src/components/ui/scroll-area.tsx +56 -0
  120. package/src/components/ui/select.tsx +190 -0
  121. package/src/components/ui/separator.tsx +26 -0
  122. package/src/components/ui/sheet.tsx +141 -0
  123. package/src/components/ui/sidebar.tsx +726 -0
  124. package/src/components/ui/skeleton.tsx +13 -0
  125. package/src/components/ui/sonner.tsx +38 -0
  126. package/src/components/ui/switch.tsx +33 -0
  127. package/src/components/ui/tabs.tsx +91 -0
  128. package/src/components/ui/textarea.tsx +18 -0
  129. package/src/components/ui/toggle-group.tsx +83 -0
  130. package/src/components/ui/toggle.tsx +45 -0
  131. package/src/components/ui/tooltip.tsx +57 -0
  132. package/src/hooks/use-copy-to-clipboard.ts +37 -0
  133. package/src/hooks/use-file-upload.ts +415 -0
  134. package/src/hooks/use-mobile.ts +19 -0
  135. package/src/index.ts +95 -0
  136. package/src/lib/utils.ts +6 -0
  137. package/src/styles.css +1859 -0
  138. package/src/urls.ts +83 -0
  139. package/src/vite.d.ts +22 -0
  140. package/src/vite.js +241 -0
  141. package/tsconfig.base.json +18 -0
  142. package/tsconfig.json +24 -0
@@ -0,0 +1,666 @@
1
+ import { useCallback, useState } from "react"
2
+ import {
3
+ createFilter,
4
+ Filters,
5
+ type Filter,
6
+ type FilterFieldConfig,
7
+ } from "@/components/reui/filters"
8
+
9
+ import { cn } from "@/lib/utils"
10
+ import {
11
+ Avatar,
12
+ AvatarFallback,
13
+ AvatarImage,
14
+ } from "@/components/ui/avatar"
15
+ import { Button } from "@/components/ui/button"
16
+ import { MailIcon, TypeIcon, GlobeIcon, PhoneIcon, BellIcon, ClockIcon, CircleAlertIcon, CircleCheckIcon, BanIcon, UserRoundCheckIcon, UserRoundXIcon, UsersIcon, StarIcon, BuildingIcon, ListFilterIcon, FunnelXIcon } from "lucide-react"
17
+
18
+ // Priority icon component
19
+ const PriorityIcon = ({ priority }: { priority: string }) => {
20
+ const colors = {
21
+ low: "bg-green-500",
22
+ medium: "bg-yellow-500",
23
+ high: "bg-violet-500",
24
+ urgent: "bg-orange-500",
25
+ critical: "bg-red-500",
26
+ }
27
+ return (
28
+ <div
29
+ className={cn(
30
+ "size-2.25 shrink-0 rounded-full",
31
+ colors[priority as keyof typeof colors]
32
+ )}
33
+ />
34
+ )
35
+ }
36
+
37
+ const countryFlags = [
38
+ { code: "AF", name: "Afghanistan" },
39
+ { code: "AL", name: "Albania" },
40
+ { code: "DZ", name: "Algeria" },
41
+ { code: "AS", name: "American Samoa" },
42
+ { code: "AD", name: "Andorra" },
43
+ { code: "AO", name: "Angola" },
44
+ { code: "AI", name: "Anguilla" },
45
+ { code: "AG", name: "Antigua and Barbuda" },
46
+ { code: "AR", name: "Argentina" },
47
+ { code: "AM", name: "Armenia" },
48
+ { code: "AU", name: "Australia" },
49
+ { code: "AT", name: "Austria" },
50
+ { code: "AZ", name: "Azerbaijan" },
51
+ { code: "BS", name: "Bahamas" },
52
+ { code: "BH", name: "Bahrain" },
53
+ { code: "BD", name: "Bangladesh" },
54
+ { code: "BB", name: "Barbados" },
55
+ { code: "BY", name: "Belarus" },
56
+ { code: "BE", name: "Belgium" },
57
+ { code: "BZ", name: "Belize" },
58
+ { code: "BJ", name: "Benin" },
59
+ { code: "BM", name: "Bermuda" },
60
+ { code: "BT", name: "Bhutan" },
61
+ { code: "BO", name: "Bolivia" },
62
+ { code: "BA", name: "Bosnia and Herzegovina" },
63
+ { code: "BW", name: "Botswana" },
64
+ { code: "BR", name: "Brazil" },
65
+ { code: "IO", name: "British Indian Ocean Territory" },
66
+ { code: "BN", name: "Brunei Darussalam" },
67
+ { code: "BG", name: "Bulgaria" },
68
+ { code: "BF", name: "Burkina Faso" },
69
+ { code: "BI", name: "Burundi" },
70
+ { code: "KH", name: "Cambodia" },
71
+ { code: "CM", name: "Cameroon" },
72
+ { code: "CA", name: "Canada" },
73
+ { code: "CV", name: "Cape Verde" },
74
+ { code: "KY", name: "Cayman Islands" },
75
+ { code: "CF", name: "Central African Republic" },
76
+ { code: "TD", name: "Chad" },
77
+ { code: "CL", name: "Chile" },
78
+ { code: "CN", name: "China" },
79
+ { code: "CO", name: "Colombia" },
80
+ { code: "KM", name: "Comoros" },
81
+ { code: "CG", name: "Congo" },
82
+ { code: "CR", name: "Costa Rica" },
83
+ { code: "CI", name: "Cote D'Ivoire" },
84
+ { code: "HR", name: "Croatia" },
85
+ { code: "CU", name: "Cuba" },
86
+ { code: "CY", name: "Cyprus" },
87
+ { code: "CZ", name: "Czech Republic" },
88
+ { code: "DK", name: "Denmark" },
89
+ { code: "DJ", name: "Djibouti" },
90
+ { code: "DM", name: "Dominica" },
91
+ { code: "DO", name: "Dominican Republic" },
92
+ { code: "EC", name: "Ecuador" },
93
+ { code: "EG", name: "Egypt" },
94
+ { code: "SV", name: "El Salvador" },
95
+ { code: "GQ", name: "Equatorial Guinea" },
96
+ { code: "ER", name: "Eritrea" },
97
+ { code: "EE", name: "Estonia" },
98
+ { code: "SZ", name: "Eswatini" },
99
+ { code: "ET", name: "Ethiopia" },
100
+ { code: "FI", name: "Finland" },
101
+ { code: "FR", name: "France" },
102
+ { code: "GA", name: "Gabon" },
103
+ { code: "GM", name: "Gambia" },
104
+ { code: "GE", name: "Georgia" },
105
+ { code: "DE", name: "Germany" },
106
+ { code: "GH", name: "Ghana" },
107
+ { code: "GR", name: "Greece" },
108
+ { code: "GD", name: "Grenada" },
109
+ { code: "GT", name: "Guatemala" },
110
+ { code: "GN", name: "Guinea" },
111
+ { code: "GW", name: "Guinea-Bissau" },
112
+ { code: "GY", name: "Guyana" },
113
+ { code: "HT", name: "Haiti" },
114
+ { code: "HN", name: "Honduras" },
115
+ { code: "HK", name: "Hong Kong" },
116
+ { code: "HU", name: "Hungary" },
117
+ { code: "IS", name: "Iceland" },
118
+ { code: "IN", name: "India" },
119
+ { code: "ID", name: "Indonesia" },
120
+ { code: "IR", name: "Iran" },
121
+ { code: "IQ", name: "Iraq" },
122
+ { code: "IE", name: "Ireland" },
123
+ { code: "IL", name: "Israel" },
124
+ { code: "IT", name: "Italy" },
125
+ { code: "JM", name: "Jamaica" },
126
+ { code: "JP", name: "Japan" },
127
+ { code: "JO", name: "Jordan" },
128
+ { code: "KZ", name: "Kazakhstan" },
129
+ { code: "KE", name: "Kenya" },
130
+ { code: "KR", name: "South Korea" },
131
+ { code: "KW", name: "Kuwait" },
132
+ { code: "KG", name: "Kyrgyzstan" },
133
+ { code: "LA", name: "Laos" },
134
+ { code: "LV", name: "Latvia" },
135
+ { code: "LB", name: "Lebanon" },
136
+ { code: "LS", name: "Lesotho" },
137
+ { code: "LR", name: "Liberia" },
138
+ { code: "LY", name: "Libya" },
139
+ { code: "LT", name: "Lithuania" },
140
+ { code: "LU", name: "Luxembourg" },
141
+ { code: "MO", name: "Macao" },
142
+ { code: "MG", name: "Madagascar" },
143
+ { code: "MW", name: "Malawi" },
144
+ { code: "MY", name: "Malaysia" },
145
+ { code: "MV", name: "Maldives" },
146
+ { code: "ML", name: "Mali" },
147
+ { code: "MT", name: "Malta" },
148
+ { code: "MH", name: "Marshall Islands" },
149
+ { code: "MR", name: "Mauritania" },
150
+ { code: "MU", name: "Mauritius" },
151
+ { code: "MX", name: "Mexico" },
152
+ { code: "FM", name: "Micronesia" },
153
+ { code: "MD", name: "Moldova" },
154
+ { code: "MC", name: "Monaco" },
155
+ { code: "MN", name: "Mongolia" },
156
+ { code: "ME", name: "Montenegro" },
157
+ { code: "MA", name: "Morocco" },
158
+ { code: "MZ", name: "Mozambique" },
159
+ { code: "MM", name: "Myanmar" },
160
+ { code: "NA", name: "Namibia" },
161
+ { code: "NP", name: "Nepal" },
162
+ { code: "NL", name: "Netherlands" },
163
+ { code: "NZ", name: "New Zealand" },
164
+ { code: "NI", name: "Nicaragua" },
165
+ { code: "NG", name: "Nigeria" },
166
+ { code: "NO", name: "Norway" },
167
+ { code: "OM", name: "Oman" },
168
+ { code: "PK", name: "Pakistan" },
169
+ { code: "PA", name: "Panama" },
170
+ { code: "PG", name: "Papua New Guinea" },
171
+ { code: "PY", name: "Paraguay" },
172
+ { code: "PE", name: "Peru" },
173
+ { code: "PH", name: "Philippines" },
174
+ { code: "PL", name: "Poland" },
175
+ { code: "PT", name: "Portugal" },
176
+ { code: "QA", name: "Qatar" },
177
+ { code: "RO", name: "Romania" },
178
+ { code: "RU", name: "Russia" },
179
+ { code: "RW", name: "Rwanda" },
180
+ { code: "WS", name: "Samoa" },
181
+ { code: "SM", name: "San Marino" },
182
+ { code: "SA", name: "Saudi Arabia" },
183
+ { code: "SN", name: "Senegal" },
184
+ { code: "RS", name: "Serbia" },
185
+ { code: "SG", name: "Singapore" },
186
+ { code: "SK", name: "Slovakia" },
187
+ { code: "SI", name: "Slovenia" },
188
+ { code: "ZA", name: "South Africa" },
189
+ { code: "ES", name: "Spain" },
190
+ { code: "LK", name: "Sri Lanka" },
191
+ { code: "SE", name: "Sweden" },
192
+ { code: "CH", name: "Switzerland" },
193
+ { code: "SY", name: "Syria" },
194
+ { code: "TW", name: "Taiwan" },
195
+ { code: "TJ", name: "Tajikistan" },
196
+ { code: "TZ", name: "Tanzania" },
197
+ { code: "TH", name: "Thailand" },
198
+ { code: "TR", name: "Turkey" },
199
+ { code: "UG", name: "Uganda" },
200
+ { code: "UA", name: "Ukraine" },
201
+ { code: "AE", name: "United Arab Emirates" },
202
+ { code: "GB", name: "United Kingdom" },
203
+ { code: "US", name: "United States" },
204
+ { code: "UY", name: "Uruguay" },
205
+ { code: "UZ", name: "Uzbekistan" },
206
+ { code: "VN", name: "Vietnam" },
207
+ { code: "ZM", name: "Zambia" },
208
+ { code: "ZW", name: "Zimbabwe" },
209
+ ]
210
+
211
+ export function Pattern() {
212
+ // Example: All Possible Filter Field Types with Grouping
213
+ const fields: FilterFieldConfig[] = [
214
+ {
215
+ group: "Basic",
216
+ fields: [
217
+ {
218
+ key: "text",
219
+ label: "Text",
220
+ type: "text",
221
+ icon: (
222
+ <MailIcon
223
+ />
224
+ ),
225
+ placeholder: "Search text...",
226
+ },
227
+ {
228
+ key: "email",
229
+ label: "Email",
230
+ type: "text",
231
+ icon: (
232
+ <TypeIcon
233
+ />
234
+ ),
235
+ placeholder: "user@example.com",
236
+ },
237
+ {
238
+ key: "website",
239
+ label: "Website",
240
+ icon: (
241
+ <GlobeIcon
242
+ />
243
+ ),
244
+ type: "text",
245
+ placeholder: "https://example.com",
246
+ },
247
+ {
248
+ key: "phone",
249
+ label: "Phone",
250
+ icon: (
251
+ <PhoneIcon
252
+ />
253
+ ),
254
+ type: "text",
255
+ placeholder: "+1 (123) 456-7890",
256
+ },
257
+ ],
258
+ },
259
+ {
260
+ group: "Select",
261
+ fields: [
262
+ {
263
+ key: "status",
264
+ label: "Status",
265
+ icon: (
266
+ <BellIcon
267
+ />
268
+ ),
269
+ type: "select",
270
+ searchable: false,
271
+ className: "w-[200px]",
272
+ options: [
273
+ {
274
+ value: "todo",
275
+ label: "To Do",
276
+ icon: (
277
+ <ClockIcon className="stroke-violet-500" />
278
+ ),
279
+ },
280
+ {
281
+ value: "in-progress",
282
+ label: "In Progress",
283
+ icon: (
284
+ <CircleAlertIcon className="stroke-yellow-500" />
285
+ ),
286
+ },
287
+ {
288
+ value: "done",
289
+ label: "Done",
290
+ icon: (
291
+ <CircleCheckIcon className="stroke-green-500" />
292
+ ),
293
+ },
294
+ {
295
+ value: "cancelled",
296
+ label: "Cancelled",
297
+ icon: (
298
+ <BanIcon className="stroke-destructive" />
299
+ ),
300
+ },
301
+ ],
302
+ },
303
+ {
304
+ key: "priority",
305
+ label: "Priority",
306
+ icon: (
307
+ <BanIcon
308
+ />
309
+ ),
310
+ type: "multiselect",
311
+ className: "w-[180px]",
312
+ options: [
313
+ {
314
+ value: "low",
315
+ label: "Low",
316
+ icon: <PriorityIcon priority="low" />,
317
+ },
318
+ {
319
+ value: "medium",
320
+ label: "Medium",
321
+ icon: <PriorityIcon priority="medium" />,
322
+ },
323
+ {
324
+ value: "high",
325
+ label: "High",
326
+ icon: <PriorityIcon priority="high" />,
327
+ },
328
+ {
329
+ value: "urgent",
330
+ label: "Urgent",
331
+ icon: <PriorityIcon priority="urgent" />,
332
+ },
333
+ {
334
+ value: "critical",
335
+ label: "Critical",
336
+ icon: <PriorityIcon priority="critical" />,
337
+ },
338
+ ],
339
+ },
340
+ {
341
+ key: "assignee",
342
+ label: "Assignee",
343
+ icon: (
344
+ <UserRoundCheckIcon
345
+ />
346
+ ),
347
+ type: "multiselect",
348
+ maxSelections: 5,
349
+ options: [
350
+ {
351
+ value: "john",
352
+ label: "John Doe",
353
+ icon: (
354
+ <Avatar className="size-5 border">
355
+ <AvatarImage
356
+ src="https://randomuser.me/api/portraits/men/1.jpg"
357
+ alt="John Doe"
358
+ />
359
+ <AvatarFallback>JD</AvatarFallback>
360
+ </Avatar>
361
+ ),
362
+ },
363
+ {
364
+ value: "jane",
365
+ label: "Jane Smith",
366
+ icon: (
367
+ <Avatar className="size-5">
368
+ <AvatarImage
369
+ src="https://randomuser.me/api/portraits/women/2.jpg"
370
+ alt="Jane Smith"
371
+ />
372
+ <AvatarFallback>JS</AvatarFallback>
373
+ </Avatar>
374
+ ),
375
+ },
376
+ {
377
+ value: "bob",
378
+ label: "Bob Johnson",
379
+ icon: (
380
+ <Avatar className="size-5">
381
+ <AvatarImage
382
+ src="https://randomuser.me/api/portraits/men/3.jpg"
383
+ alt="Bob Johnson"
384
+ />
385
+ <AvatarFallback>BJ</AvatarFallback>
386
+ </Avatar>
387
+ ),
388
+ },
389
+ {
390
+ value: "alice",
391
+ label: "Alice Brown",
392
+ icon: (
393
+ <Avatar className="size-5">
394
+ <AvatarImage
395
+ src="https://randomuser.me/api/portraits/women/4.jpg"
396
+ alt="Alice Brown"
397
+ />
398
+ <AvatarFallback>AB</AvatarFallback>
399
+ </Avatar>
400
+ ),
401
+ },
402
+ {
403
+ value: "nick",
404
+ label: "Nick Bold",
405
+ icon: (
406
+ <Avatar className="size-5">
407
+ <AvatarImage
408
+ src="https://randomuser.me/api/portraits/men/4.jpg"
409
+ alt="Nick Bold"
410
+ />
411
+ <AvatarFallback>NB</AvatarFallback>
412
+ </Avatar>
413
+ ),
414
+ },
415
+ {
416
+ value: "sarah",
417
+ label: "Sarah Wilson",
418
+ icon: (
419
+ <Avatar className="size-5">
420
+ <AvatarImage
421
+ src="https://randomuser.me/api/portraits/women/5.jpg"
422
+ alt="Sarah Wilson"
423
+ />
424
+ <AvatarFallback>SW</AvatarFallback>
425
+ </Avatar>
426
+ ),
427
+ },
428
+ {
429
+ value: "michael",
430
+ label: "Michael Scott",
431
+ icon: (
432
+ <Avatar className="size-5">
433
+ <AvatarImage
434
+ src="https://randomuser.me/api/portraits/men/6.jpg"
435
+ alt="Michael Scott"
436
+ />
437
+ <AvatarFallback>MS</AvatarFallback>
438
+ </Avatar>
439
+ ),
440
+ },
441
+ {
442
+ value: "emily",
443
+ label: "Emily Blunt",
444
+ icon: (
445
+ <Avatar className="size-5">
446
+ <AvatarImage
447
+ src="https://randomuser.me/api/portraits/women/7.jpg"
448
+ alt="Emily Blunt"
449
+ />
450
+ <AvatarFallback>EB</AvatarFallback>
451
+ </Avatar>
452
+ ),
453
+ },
454
+ {
455
+ value: "david",
456
+ label: "David Gandy",
457
+ icon: (
458
+ <Avatar className="size-5">
459
+ <AvatarImage
460
+ src="https://randomuser.me/api/portraits/men/8.jpg"
461
+ alt="David Gandy"
462
+ />
463
+ <AvatarFallback>DG</AvatarFallback>
464
+ </Avatar>
465
+ ),
466
+ },
467
+ {
468
+ value: "laura",
469
+ label: "Laura Palmer",
470
+ icon: (
471
+ <Avatar className="size-5">
472
+ <AvatarImage
473
+ src="https://randomuser.me/api/portraits/women/9.jpg"
474
+ alt="Laura Palmer"
475
+ />
476
+ <AvatarFallback>LP</AvatarFallback>
477
+ </Avatar>
478
+ ),
479
+ },
480
+ {
481
+ value: "kevin",
482
+ label: "Kevin Hart",
483
+ icon: (
484
+ <Avatar className="size-5">
485
+ <AvatarImage
486
+ src="https://randomuser.me/api/portraits/men/10.jpg"
487
+ alt="Kevin Hart"
488
+ />
489
+ <AvatarFallback>KH</AvatarFallback>
490
+ </Avatar>
491
+ ),
492
+ },
493
+ {
494
+ value: "anna",
495
+ label: "Anna Kendrick",
496
+ icon: (
497
+ <Avatar className="size-5">
498
+ <AvatarImage
499
+ src="https://randomuser.me/api/portraits/women/11.jpg"
500
+ alt="Anna Kendrick"
501
+ />
502
+ <AvatarFallback>AK</AvatarFallback>
503
+ </Avatar>
504
+ ),
505
+ },
506
+ {
507
+ value: "tom",
508
+ label: "Tom Cruise",
509
+ icon: (
510
+ <Avatar className="size-5">
511
+ <AvatarImage
512
+ src="https://randomuser.me/api/portraits/men/12.jpg"
513
+ alt="Tom Cruise"
514
+ />
515
+ <AvatarFallback>TC</AvatarFallback>
516
+ </Avatar>
517
+ ),
518
+ },
519
+ {
520
+ value: "lisa",
521
+ label: "Lisa Kudrow",
522
+ icon: (
523
+ <Avatar className="size-5">
524
+ <AvatarImage
525
+ src="https://randomuser.me/api/portraits/women/13.jpg"
526
+ alt="Lisa Kudrow"
527
+ />
528
+ <AvatarFallback>LK</AvatarFallback>
529
+ </Avatar>
530
+ ),
531
+ },
532
+ {
533
+ value: "james",
534
+ label: "James Bond",
535
+ icon: (
536
+ <Avatar className="size-5">
537
+ <AvatarImage
538
+ src="https://randomuser.me/api/portraits/men/14.jpg"
539
+ alt="James Bond"
540
+ />
541
+ <AvatarFallback>JB</AvatarFallback>
542
+ </Avatar>
543
+ ),
544
+ },
545
+ {
546
+ value: "unassigned",
547
+ label: "Unassigned",
548
+ icon: (
549
+ <Avatar className="size-5">
550
+ <AvatarFallback>
551
+ <UserRoundXIcon
552
+ />
553
+ </AvatarFallback>
554
+ </Avatar>
555
+ ),
556
+ },
557
+ ],
558
+ },
559
+ {
560
+ key: "userType",
561
+ label: "User Type",
562
+ icon: (
563
+ <UsersIcon
564
+ />
565
+ ),
566
+ type: "select",
567
+ searchable: false,
568
+ className: "w-[200px]",
569
+ options: [
570
+ {
571
+ value: "premium",
572
+ label: "Premium",
573
+ icon: (
574
+ <StarIcon className="size-3 text-yellow-500" />
575
+ ),
576
+ },
577
+ {
578
+ value: "standard",
579
+ label: "Standard",
580
+ icon: (
581
+ <BuildingIcon className="size-3 text-blue-500" />
582
+ ),
583
+ },
584
+ {
585
+ value: "trial",
586
+ label: "Trial",
587
+ icon: (
588
+ <ClockIcon className="size-3 text-gray-500" />
589
+ ),
590
+ },
591
+ ],
592
+ },
593
+ {
594
+ key: "country",
595
+ label: "Country",
596
+ icon: (
597
+ <GlobeIcon
598
+ />
599
+ ),
600
+ type: "select",
601
+ searchable: true,
602
+ className: "w-[220px]",
603
+ options: countryFlags.map((country) => ({
604
+ value: country.code,
605
+ label: country.name,
606
+ icon: (
607
+ <img
608
+ src={`https://flagcdn.com/${country.code.toLowerCase()}.svg`}
609
+ alt={country.code}
610
+ className="size-4 rounded-full object-cover"
611
+ />
612
+ ),
613
+ })),
614
+ },
615
+ ],
616
+ },
617
+ ]
618
+
619
+ const [filters, setFilters] = useState<Filter[]>([
620
+ createFilter("priority", "is_any_of", ["low", "medium", "critical"]),
621
+ ])
622
+
623
+ const handleFiltersChange = useCallback((filters: Filter[]) => {
624
+ setFilters(filters)
625
+ }, [])
626
+
627
+ return (
628
+ <div className="flex grow content-start items-start gap-2.5 self-start">
629
+ <div className="grow space-y-5">
630
+ {/* Filters Section */}
631
+ <div className="flex items-start gap-2.5">
632
+ <div className="flex-1">
633
+ <Filters
634
+ filters={filters}
635
+ fields={fields}
636
+ onChange={handleFiltersChange}
637
+ shortcutKey="f"
638
+ shortcutLabel="F"
639
+ enableShortcut={true}
640
+ trigger={
641
+ <Button variant="outline">
642
+ <ListFilterIcon
643
+ />
644
+ Add Filter
645
+ </Button>
646
+ }
647
+ />
648
+ </div>
649
+
650
+ {filters.length > 0 && (
651
+ <Button variant="outline" onClick={() => setFilters([])}>
652
+ <FunnelXIcon
653
+ />
654
+ Clear
655
+ </Button>
656
+ )}
657
+ </div>
658
+
659
+ {/* Debug Block */}
660
+ <pre className="bg-muted dark:bg-muted/60 mt-2 max-h-[400px] w-full max-w-[500px] overflow-auto overflow-x-auto rounded-md border p-3 text-xs">
661
+ {JSON.stringify(filters, null, 2)}
662
+ </pre>
663
+ </div>
664
+ </div>
665
+ )
666
+ }
@@ -0,0 +1,26 @@
1
+ import {
2
+ Frame,
3
+ FrameDescription,
4
+ FrameHeader,
5
+ FramePanel,
6
+ FrameTitle,
7
+ } from "@/components/reui/frame"
8
+
9
+ export function Pattern() {
10
+ return (
11
+ <Frame className="w-full">
12
+ <FrameHeader>
13
+ <FrameTitle>Section header</FrameTitle>
14
+ <FrameDescription>Description for the section</FrameDescription>
15
+ </FrameHeader>
16
+ <FramePanel>
17
+ <h2 className="text-sm font-semibold">Separated panel</h2>
18
+ <p className="text-muted-foreground text-sm">Section description</p>
19
+ </FramePanel>
20
+ <FramePanel>
21
+ <h2 className="text-sm font-semibold">Separated panel</h2>
22
+ <p className="text-muted-foreground text-sm">Section description</p>
23
+ </FramePanel>
24
+ </Frame>
25
+ )
26
+ }