@gsk_poc/untitled-ui-base 0.1.1

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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +44 -0
  3. package/components/application/app-navigation/base-components/featured-cards.demo.tsx +86 -0
  4. package/components/application/app-navigation/base-components/featured-cards.story.tsx +49 -0
  5. package/components/application/app-navigation/header-navigation.demo.tsx +59 -0
  6. package/components/application/app-navigation/header-navigation.story.tsx +23 -0
  7. package/components/application/app-navigation/sidebar-navigation.demo.tsx +409 -0
  8. package/components/application/app-navigation/sidebar-navigation.story.tsx +47 -0
  9. package/components/application/carousel/carousel.demo.tsx +107 -0
  10. package/components/application/carousel/carousel.story.tsx +21 -0
  11. package/components/application/charts/activity-gauges.demo.tsx +251 -0
  12. package/components/application/charts/activity-gauges.story.tsx +27 -0
  13. package/components/application/charts/bar-charts.demo.tsx +506 -0
  14. package/components/application/charts/bar-charts.story.tsx +36 -0
  15. package/components/application/charts/line-charts.demo.tsx +604 -0
  16. package/components/application/charts/line-charts.story.tsx +43 -0
  17. package/components/application/charts/pie-charts.demo.tsx +193 -0
  18. package/components/application/charts/pie-charts.story.tsx +30 -0
  19. package/components/application/charts/progress-circles.demo.tsx +110 -0
  20. package/components/application/charts/progress-circles.story.tsx +33 -0
  21. package/components/application/charts/radar-charts.demo.tsx +203 -0
  22. package/components/application/charts/radar-charts.story.tsx +18 -0
  23. package/components/application/date-picker/date-picker.demo.tsx +217 -0
  24. package/components/application/date-picker/date-picker.story.tsx +44 -0
  25. package/components/application/file-upload/file-upload.demo.tsx +292 -0
  26. package/components/application/file-upload/file-upload.story.tsx +70 -0
  27. package/components/application/loading-indicator/loading-indicator.demo.tsx +73 -0
  28. package/components/application/loading-indicator/loading-indicator.story.tsx +22 -0
  29. package/components/application/pagination/pagination.demo.tsx +104 -0
  30. package/components/application/pagination/pagination.story.tsx +54 -0
  31. package/components/application/table/table.demo.tsx +1038 -0
  32. package/components/application/table/table.story.tsx +119 -0
  33. package/components/application/tabs/tabs.demo.tsx +322 -0
  34. package/components/application/tabs/tabs.story.tsx +43 -0
  35. package/components/base/avatar/avatar.demo.tsx +865 -0
  36. package/components/base/avatar/avatar.story.tsx +27 -0
  37. package/components/base/badges/badge-groups.demo.tsx +357 -0
  38. package/components/base/badges/badge-groups.story.tsx +25 -0
  39. package/components/base/badges/badges.demo.tsx +497 -0
  40. package/components/base/badges/badges.story.tsx +83 -0
  41. package/components/base/button-group/button-group.demo.tsx +131 -0
  42. package/components/base/button-group/button-group.story.tsx +16 -0
  43. package/components/base/buttons/app-store-buttons.demo.tsx +129 -0
  44. package/components/base/buttons/app-store-buttons.story.tsx +13 -0
  45. package/components/base/buttons/buttons.demo.tsx +1022 -0
  46. package/components/base/buttons/buttons.story.tsx +42 -0
  47. package/components/base/buttons/social-buttons.demo.tsx +432 -0
  48. package/components/base/buttons/social-buttons.story.tsx +20 -0
  49. package/components/base/checkbox/checkbox.demo.tsx +62 -0
  50. package/components/base/checkbox/checkbox.story.tsx +18 -0
  51. package/components/base/dropdown/dropdown.demo.tsx +137 -0
  52. package/components/base/dropdown/dropdown.story.tsx +22 -0
  53. package/components/base/input/inputs.demo.tsx +758 -0
  54. package/components/base/input/inputs.story.tsx +52 -0
  55. package/components/base/pin-input/pin-input.demo.tsx +126 -0
  56. package/components/base/pin-input/pin-input.story.tsx +22 -0
  57. package/components/base/progress-indicators/progress-indicators.demo.tsx +54 -0
  58. package/components/base/progress-indicators/progress-indicators.story.tsx +57 -0
  59. package/components/base/radio-buttons/radio-buttons.demo.tsx +77 -0
  60. package/components/base/radio-buttons/radio-buttons.story.tsx +19 -0
  61. package/components/base/select/select.demo.tsx +936 -0
  62. package/components/base/select/select.story.tsx +43 -0
  63. package/components/base/slider/slider.demo.tsx +19 -0
  64. package/components/base/slider/slider.story.tsx +26 -0
  65. package/components/base/tags/tags.demo.tsx +341 -0
  66. package/components/base/tags/tags.story.tsx +28 -0
  67. package/components/base/textarea/textarea.demo.tsx +25 -0
  68. package/components/base/textarea/textarea.story.tsx +15 -0
  69. package/components/base/toggle/toggle.demo.tsx +76 -0
  70. package/components/base/toggle/toggle.story.tsx +23 -0
  71. package/components/base/tooltip/tooltip.demo.tsx +125 -0
  72. package/components/base/tooltip/tooltip.story.tsx +21 -0
  73. package/components/foundations/featured-icon/featured-icon.demo.tsx +160 -0
  74. package/components/foundations/featured-icon/featured-icon.story.tsx +25 -0
  75. package/components/shared-assets/credit-card/credit-card.demo.tsx +106 -0
  76. package/components/shared-assets/credit-card/credit-card.story.tsx +41 -0
  77. package/dist/index.d.mts +1417 -0
  78. package/dist/index.d.ts +1417 -0
  79. package/dist/index.js +10435 -0
  80. package/dist/index.js.map +1 -0
  81. package/dist/index.mjs +10345 -0
  82. package/dist/index.mjs.map +1 -0
  83. package/package.json +126 -0
  84. package/styles/globals.css +65 -0
  85. package/styles/theme.css +430 -0
  86. package/styles/tokens-mapped.css +233 -0
  87. package/styles/tokens.css +807 -0
  88. package/styles/typography.css +430 -0
  89. package/tokens/design-tokens.dtcg.json +3515 -0
@@ -0,0 +1,1038 @@
1
+ "use client";
2
+
3
+ import { useMemo, useState } from "react";
4
+ import { FileIcon } from "@untitledui/file-icons";
5
+ import { AlertCircle, Check, Edit01, FilterLines, Plus, ReverseLeft, SearchLg, Trash01, UploadCloud02, X } from "@untitledui/icons";
6
+ import type { SortDescriptor } from "react-aria-components";
7
+ import { EmptyState } from "@/components/application/empty-state/empty-state";
8
+ import { PaginationCardMinimal, PaginationPageMinimalCenter } from "@/components/application/pagination/pagination";
9
+ import customers from "@/components/application/table/customers.json";
10
+ import invoices from "@/components/application/table/invoices.json";
11
+ import { Table, TableCard, TableRowActionsDropdown } from "@/components/application/table/table";
12
+ import teamMembers from "@/components/application/table/team-members.json";
13
+ import uploadedFiles from "@/components/application/table/uploaded-files.json";
14
+ import { Avatar } from "@/components/base/avatar/avatar";
15
+ import type { BadgeTypes } from "@/components/base/badges/badge-types";
16
+ import { Badge, type BadgeColor, BadgeWithDot, BadgeWithIcon } from "@/components/base/badges/badges";
17
+ import { ButtonGroup, ButtonGroupItem } from "@/components/base/button-group/button-group";
18
+ import { Button } from "@/components/base/buttons/button";
19
+ import { ButtonUtility } from "@/components/base/buttons/button-utility";
20
+ import { Input } from "@/components/base/input/input";
21
+ import { ProgressBar } from "@/components/base/progress-indicators/progress-indicators";
22
+
23
+ export const Table01DividerLine = () => {
24
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
25
+ column: "status",
26
+ direction: "ascending",
27
+ });
28
+
29
+ const sortedItems = useMemo(() => {
30
+ return teamMembers.items.sort((a, b) => {
31
+ const first = a[sortDescriptor.column as keyof typeof a];
32
+ const second = b[sortDescriptor.column as keyof typeof b];
33
+
34
+ // Compare numbers or booleans
35
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
36
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
37
+ }
38
+
39
+ // Compare strings
40
+ if (typeof first === "string" && typeof second === "string") {
41
+ let cmp = first.localeCompare(second);
42
+ if (sortDescriptor.direction === "descending") {
43
+ cmp *= -1;
44
+ }
45
+ return cmp;
46
+ }
47
+
48
+ return 0;
49
+ });
50
+ }, [sortDescriptor]);
51
+
52
+ return (
53
+ <TableCard.Root>
54
+ <TableCard.Header
55
+ title="Team members"
56
+ badge="100 users"
57
+ contentTrailing={
58
+ <div className="absolute top-5 right-4 md:right-6">
59
+ <TableRowActionsDropdown />
60
+ </div>
61
+ }
62
+ />
63
+ <Table aria-label="Team members" selectionMode="multiple" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
64
+ <Table.Header>
65
+ <Table.Head id="name" label="Name" isRowHeader allowsSorting className="w-full max-w-1/4" />
66
+ <Table.Head id="status" label="Status" allowsSorting />
67
+ <Table.Head id="role" label="Role" allowsSorting tooltip="This is a tooltip" />
68
+ <Table.Head id="email" label="Email address" allowsSorting className="md:hidden xl:table-cell" />
69
+ <Table.Head id="teams" label="Teams" />
70
+ <Table.Head id="actions" />
71
+ </Table.Header>
72
+
73
+ <Table.Body items={sortedItems}>
74
+ {(item) => (
75
+ <Table.Row id={item.username}>
76
+ <Table.Cell>
77
+ <div className="flex items-center gap-3">
78
+ <Avatar src={item.avatarUrl} alt={item.name} size="md" />
79
+ <div className="whitespace-nowrap">
80
+ <p className="text-sm font-medium text-primary">{item.name}</p>
81
+ <p className="text-sm text-tertiary">{item.username}</p>
82
+ </div>
83
+ </div>
84
+ </Table.Cell>
85
+ <Table.Cell>
86
+ <BadgeWithDot size="sm" color={item.status === "active" ? "success" : "gray"} type="modern">
87
+ {item.status === "active" ? "Active" : "Inactive"}
88
+ </BadgeWithDot>
89
+ </Table.Cell>
90
+ <Table.Cell className="whitespace-nowrap">{item.role}</Table.Cell>
91
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.email}</Table.Cell>
92
+ <Table.Cell>
93
+ <div className="flex gap-1">
94
+ {item.teams.slice(0, 3).map((team) => (
95
+ <Badge key={team.name} color={team.color as BadgeColor<BadgeTypes>} size="sm">
96
+ {team.name}
97
+ </Badge>
98
+ ))}
99
+
100
+ {item.teams.length > 3 && (
101
+ <Badge color="gray" size="sm">
102
+ +{item.teams.length - 3}
103
+ </Badge>
104
+ )}
105
+ </div>
106
+ </Table.Cell>
107
+ <Table.Cell className="px-4">
108
+ <div className="flex justify-end gap-0.5">
109
+ <ButtonUtility size="xs" color="tertiary" tooltip="Delete" icon={Trash01} />
110
+ <ButtonUtility size="xs" color="tertiary" tooltip="Edit" icon={Edit01} />
111
+ </div>
112
+ </Table.Cell>
113
+ </Table.Row>
114
+ )}
115
+ </Table.Body>
116
+ </Table>
117
+
118
+ <PaginationPageMinimalCenter page={1} total={10} className="px-4 py-3 md:px-6 md:pt-3 md:pb-4" />
119
+ </TableCard.Root>
120
+ );
121
+ };
122
+
123
+ export const Table01AlternatingFills = () => {
124
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
125
+ column: "status",
126
+ direction: "ascending",
127
+ });
128
+
129
+ const sortedItems = useMemo(() => {
130
+ return teamMembers.items.sort((a, b) => {
131
+ const first = a[sortDescriptor.column as keyof typeof a];
132
+ const second = b[sortDescriptor.column as keyof typeof b];
133
+
134
+ // Compare numbers or booleans
135
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
136
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
137
+ }
138
+
139
+ // Compare strings
140
+ if (typeof first === "string" && typeof second === "string") {
141
+ let cmp = first.localeCompare(second);
142
+ if (sortDescriptor.direction === "descending") {
143
+ cmp *= -1;
144
+ }
145
+ return cmp;
146
+ }
147
+
148
+ return 0;
149
+ });
150
+ }, [sortDescriptor]);
151
+
152
+ return (
153
+ <TableCard.Root>
154
+ <TableCard.Header
155
+ title="Team members"
156
+ badge="100 users"
157
+ contentTrailing={
158
+ <div className="absolute top-5 right-4 md:right-6">
159
+ <TableRowActionsDropdown />
160
+ </div>
161
+ }
162
+ />
163
+ <Table aria-label="Team members" selectionMode="multiple" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
164
+ <Table.Header className="bg-primary">
165
+ <Table.Head id="name" label="Name" isRowHeader allowsSorting className="w-full max-w-1/4" />
166
+ <Table.Head id="status" label="Status" allowsSorting />
167
+ <Table.Head id="role" label="Role" allowsSorting tooltip="This is a tooltip" />
168
+ <Table.Head id="email" label="Email address" allowsSorting className="md:hidden xl:table-cell" />
169
+ <Table.Head id="teams" label="Teams" />
170
+ <Table.Head id="actions" />
171
+ </Table.Header>
172
+ <Table.Body items={sortedItems}>
173
+ {(item) => (
174
+ <Table.Row id={item.username} className="odd:bg-secondary_subtle">
175
+ <Table.Cell>
176
+ <div className="flex items-center gap-3">
177
+ <Avatar src={item.avatarUrl} alt={item.name} size="md" />
178
+ <div className="whitespace-nowrap">
179
+ <p className="text-sm font-medium text-primary">{item.name}</p>
180
+ <p className="text-sm text-tertiary">{item.username}</p>
181
+ </div>
182
+ </div>
183
+ </Table.Cell>
184
+ <Table.Cell>
185
+ <BadgeWithDot size="sm" color={item.status === "active" ? "success" : "gray"} type="modern">
186
+ {item.status === "active" ? "Active" : "Inactive"}
187
+ </BadgeWithDot>
188
+ </Table.Cell>
189
+ <Table.Cell className="whitespace-nowrap">{item.role}</Table.Cell>
190
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.email}</Table.Cell>
191
+ <Table.Cell>
192
+ <div className="flex gap-1">
193
+ {item.teams.slice(0, 3).map((team) => (
194
+ <Badge key={team.name} color={team.color as BadgeColor<BadgeTypes>} size="sm">
195
+ {team.name}
196
+ </Badge>
197
+ ))}
198
+
199
+ {item.teams.length > 3 && (
200
+ <Badge color="gray" size="sm">
201
+ +{item.teams.length - 3}
202
+ </Badge>
203
+ )}
204
+ </div>
205
+ </Table.Cell>
206
+ <Table.Cell className="px-4">
207
+ <div className="flex justify-end gap-0.5">
208
+ <ButtonUtility size="xs" color="tertiary" tooltip="Delete" icon={Trash01} />
209
+ <ButtonUtility size="xs" color="tertiary" tooltip="Edit" icon={Edit01} />
210
+ </div>
211
+ </Table.Cell>
212
+ </Table.Row>
213
+ )}
214
+ </Table.Body>
215
+ </Table>
216
+
217
+ <PaginationPageMinimalCenter page={1} total={10} className="px-4 py-3 md:px-6 md:pt-3 md:pb-4" />
218
+ </TableCard.Root>
219
+ );
220
+ };
221
+
222
+ export const Table01DividerLineSm = () => {
223
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
224
+ column: "status",
225
+ direction: "ascending",
226
+ });
227
+
228
+ const sortedItems = useMemo(() => {
229
+ return teamMembers.items.sort((a, b) => {
230
+ const first = a[sortDescriptor.column as keyof typeof a];
231
+ const second = b[sortDescriptor.column as keyof typeof b];
232
+
233
+ // Compare numbers or booleans
234
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
235
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
236
+ }
237
+
238
+ // Compare strings
239
+ if (typeof first === "string" && typeof second === "string") {
240
+ let cmp = first.localeCompare(second);
241
+ if (sortDescriptor.direction === "descending") {
242
+ cmp *= -1;
243
+ }
244
+ return cmp;
245
+ }
246
+
247
+ return 0;
248
+ });
249
+ }, [sortDescriptor]);
250
+
251
+ return (
252
+ <TableCard.Root size="sm">
253
+ <TableCard.Header
254
+ title="Team members"
255
+ badge="100 users"
256
+ contentTrailing={
257
+ <div className="absolute top-5 right-4 md:right-6">
258
+ <TableRowActionsDropdown />
259
+ </div>
260
+ }
261
+ />
262
+ <Table aria-label="Team members" selectionMode="multiple" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
263
+ <Table.Header>
264
+ <Table.Head id="name" label="Name" isRowHeader allowsSorting className="w-full max-w-1/4" />
265
+ <Table.Head id="status" label="Status" allowsSorting />
266
+ <Table.Head id="role" label="Role" allowsSorting tooltip="This is a tooltip" />
267
+ <Table.Head id="email" label="Email address" allowsSorting className="md:hidden xl:table-cell" />
268
+ <Table.Head id="teams" label="Teams" />
269
+ <Table.Head id="actions" />
270
+ </Table.Header>
271
+
272
+ <Table.Body items={sortedItems}>
273
+ {(item) => (
274
+ <Table.Row id={item.username}>
275
+ <Table.Cell>
276
+ <div className="flex items-center gap-2">
277
+ <Avatar src={item.avatarUrl} alt={item.name} size="sm" />
278
+ <p className="text-sm font-medium whitespace-nowrap text-primary">{item.name}</p>
279
+ </div>
280
+ </Table.Cell>
281
+ <Table.Cell>
282
+ <BadgeWithDot size="sm" color={item.status === "active" ? "success" : "gray"} type="modern">
283
+ {item.status === "active" ? "Active" : "Inactive"}
284
+ </BadgeWithDot>
285
+ </Table.Cell>
286
+ <Table.Cell className="whitespace-nowrap">{item.role}</Table.Cell>
287
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.email}</Table.Cell>
288
+ <Table.Cell>
289
+ <div className="flex gap-1">
290
+ {item.teams.slice(0, 3).map((team) => (
291
+ <Badge key={team.name} color={team.color as BadgeColor<BadgeTypes>} size="sm">
292
+ {team.name}
293
+ </Badge>
294
+ ))}
295
+
296
+ {item.teams.length > 3 && (
297
+ <Badge color="gray" size="sm">
298
+ +{item.teams.length - 3}
299
+ </Badge>
300
+ )}
301
+ </div>
302
+ </Table.Cell>
303
+ <Table.Cell className="px-3">
304
+ <div className="flex justify-end gap-0.5">
305
+ <ButtonUtility size="xs" color="tertiary" tooltip="Delete" icon={Trash01} />
306
+ <ButtonUtility size="xs" color="tertiary" tooltip="Edit" icon={Edit01} />
307
+ </div>
308
+ </Table.Cell>
309
+ </Table.Row>
310
+ )}
311
+ </Table.Body>
312
+ </Table>
313
+
314
+ <PaginationCardMinimal align="right" page={1} total={10} className="px-4 py-3 md:px-5 md:pt-3 md:pb-4" />
315
+ </TableCard.Root>
316
+ );
317
+ };
318
+
319
+ export const Table02DividerLine = () => {
320
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
321
+ column: "status",
322
+ direction: "ascending",
323
+ });
324
+
325
+ const sortedItems = useMemo(() => {
326
+ return customers.items.sort((a, b) => {
327
+ const first = a[sortDescriptor.column as keyof typeof a];
328
+ const second = b[sortDescriptor.column as keyof typeof b];
329
+
330
+ // Compare numbers or booleans
331
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
332
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
333
+ }
334
+
335
+ // Compare strings
336
+ if (typeof first === "string" && typeof second === "string") {
337
+ let cmp = first.localeCompare(second);
338
+ if (sortDescriptor.direction === "descending") {
339
+ cmp *= -1;
340
+ }
341
+ return cmp;
342
+ }
343
+
344
+ return 0;
345
+ });
346
+ }, [sortDescriptor]);
347
+
348
+ return (
349
+ <TableCard.Root>
350
+ <TableCard.Header
351
+ title="Customers"
352
+ description="These companies have purchased in the last 12 months."
353
+ contentTrailing={
354
+ <div className="absolute top-5 right-4 md:right-6">
355
+ <TableRowActionsDropdown />
356
+ </div>
357
+ }
358
+ />
359
+
360
+ <Table aria-label="Team members" selectionMode="none" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
361
+ <Table.Header>
362
+ <Table.Head id="name" label="Company" isRowHeader allowsSorting />
363
+ <Table.Head id="status" label="Status" allowsSorting />
364
+ <Table.Head id="aboutTitle" label="About" allowsSorting />
365
+ <Table.Head id="users" label="Users" className="md:hidden xl:table-cell" />
366
+ <Table.Head id="licenseUse" label="License use" allowsSorting className="min-w-55" />
367
+ <Table.Head id="actions" />
368
+ </Table.Header>
369
+ <Table.Body items={sortedItems}>
370
+ {(item) => (
371
+ <Table.Row id={item.name}>
372
+ <Table.Cell>
373
+ <div className="flex items-center gap-3">
374
+ <Avatar src={item.logoUrl} alt={item.name} size="md" />
375
+ <div className="whitespace-nowrap">
376
+ <p className="text-sm font-medium text-primary">{item.name}</p>
377
+ <p className="text-sm text-tertiary">{item.website}</p>
378
+ </div>
379
+ </div>
380
+ </Table.Cell>
381
+ <Table.Cell>
382
+ <BadgeWithDot size="sm" color={item.status === "Customer" ? "success" : "gray"}>
383
+ {item.status}
384
+ </BadgeWithDot>
385
+ </Table.Cell>
386
+ <Table.Cell className="whitespace-nowrap">
387
+ <p className="text-sm font-medium text-primary">{item.aboutTitle}</p>
388
+ <p className="text-sm text-tertiary">{item.aboutDescription}</p>
389
+ </Table.Cell>
390
+ <Table.Cell className="pr-0 md:hidden xl:table-cell">
391
+ <div className="flex -space-x-1">
392
+ <Avatar
393
+ className="ring-[1.5px] ring-bg-primary"
394
+ size="xs"
395
+ src="https://www.untitledui.com/images/avatars/olivia-rhye?fm=webp&q=80"
396
+ alt="Olivia Rhye"
397
+ />
398
+ <Avatar
399
+ className="ring-[1.5px] ring-bg-primary"
400
+ size="xs"
401
+ src="https://www.untitledui.com/images/avatars/phoenix-baker?fm=webp&q=80"
402
+ alt="Phoenix Baker"
403
+ />
404
+ <Avatar
405
+ className="ring-[1.5px] ring-bg-primary"
406
+ size="xs"
407
+ src="https://www.untitledui.com/images/avatars/lana-steiner?fm=webp&q=80"
408
+ alt="Lana Steiner"
409
+ />
410
+ <Avatar
411
+ className="ring-[1.5px] ring-bg-primary"
412
+ size="xs"
413
+ src="https://www.untitledui.com/images/avatars/demi-wilkinson?fm=webp&q=80"
414
+ alt="Demi Wilkinson"
415
+ />
416
+ <Avatar
417
+ className="ring-[1.5px] ring-bg-primary"
418
+ size="xs"
419
+ src="https://www.untitledui.com/images/avatars/candice-wu?fm=webp&q=80"
420
+ alt="Candice Wu"
421
+ />
422
+ <Avatar
423
+ size="xs"
424
+ className="ring-[1.5px] ring-bg-primary"
425
+ placeholder={<span className="text-xs font-semibold text-quaternary">+5</span>}
426
+ />
427
+ </div>
428
+ </Table.Cell>
429
+ <Table.Cell>
430
+ <ProgressBar labelPosition="right" value={item.licenseUse} />
431
+ </Table.Cell>
432
+ <Table.Cell className="px-4">
433
+ <div className="flex items-center justify-end">
434
+ <TableRowActionsDropdown />
435
+ </div>
436
+ </Table.Cell>
437
+ </Table.Row>
438
+ )}
439
+ </Table.Body>
440
+ </Table>
441
+ </TableCard.Root>
442
+ );
443
+ };
444
+
445
+ export const Table02AlternatingFills = () => {
446
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
447
+ column: "status",
448
+ direction: "ascending",
449
+ });
450
+
451
+ const sortedItems = useMemo(() => {
452
+ return customers.items.sort((a, b) => {
453
+ const first = a[sortDescriptor.column as keyof typeof a];
454
+ const second = b[sortDescriptor.column as keyof typeof b];
455
+
456
+ // Compare numbers or booleans
457
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
458
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
459
+ }
460
+
461
+ // Compare strings
462
+ if (typeof first === "string" && typeof second === "string") {
463
+ let cmp = first.localeCompare(second);
464
+ if (sortDescriptor.direction === "descending") {
465
+ cmp *= -1;
466
+ }
467
+ return cmp;
468
+ }
469
+
470
+ return 0;
471
+ });
472
+ }, [sortDescriptor]);
473
+
474
+ return (
475
+ <TableCard.Root>
476
+ <TableCard.Header
477
+ title="Customers"
478
+ description="These companies have purchased in the last 12 months."
479
+ contentTrailing={
480
+ <div className="absolute top-5 right-4 md:right-6">
481
+ <TableRowActionsDropdown />
482
+ </div>
483
+ }
484
+ />
485
+ <Table aria-label="Team members" selectionMode="none" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
486
+ <Table.Header className="bg-primary">
487
+ <Table.Head id="name" label="Company" isRowHeader allowsSorting />
488
+ <Table.Head id="status" label="Status" allowsSorting />
489
+ <Table.Head id="aboutTitle" label="About" allowsSorting />
490
+ <Table.Head id="users" label="Users" className="md:hidden xl:table-cell" />
491
+ <Table.Head id="licenseUse" label="License use" allowsSorting className="min-w-55" />
492
+ <Table.Head id="actions" />
493
+ </Table.Header>
494
+ <Table.Body items={sortedItems}>
495
+ {(item) => (
496
+ <Table.Row id={item.name} className="odd:bg-secondary_subtle">
497
+ <Table.Cell>
498
+ <div className="flex items-center gap-3">
499
+ <Avatar src={item.logoUrl} alt={item.name} size="md" />
500
+ <div className="whitespace-nowrap">
501
+ <p className="text-sm font-medium text-primary">{item.name}</p>
502
+ <p className="text-sm text-tertiary">{item.website}</p>
503
+ </div>
504
+ </div>
505
+ </Table.Cell>
506
+ <Table.Cell>
507
+ <BadgeWithDot size="sm" color={item.status === "Customer" ? "success" : "gray"} type="modern">
508
+ {item.status}
509
+ </BadgeWithDot>
510
+ </Table.Cell>
511
+ <Table.Cell className="whitespace-nowrap">
512
+ <p className="text-sm font-medium text-primary">{item.aboutTitle}</p>
513
+ <p className="text-sm text-tertiary">{item.aboutDescription}</p>
514
+ </Table.Cell>
515
+ <Table.Cell className="pr-0 md:hidden xl:table-cell">
516
+ <div className="flex -space-x-1">
517
+ <Avatar
518
+ className="ring-[1.5px] ring-bg-primary"
519
+ size="xs"
520
+ src="https://www.untitledui.com/images/avatars/olivia-rhye?fm=webp&q=80&w=100"
521
+ alt="Olivia Rhye"
522
+ />
523
+ <Avatar
524
+ className="ring-[1.5px] ring-bg-primary"
525
+ size="xs"
526
+ src="https://www.untitledui.com/images/avatars/phoenix-baker?fm=webp&q=80&w=100"
527
+ alt="Phoenix Baker"
528
+ />
529
+ <Avatar
530
+ className="ring-[1.5px] ring-bg-primary"
531
+ size="xs"
532
+ src="https://www.untitledui.com/images/avatars/lana-steiner?fm=webp&q=80&w=100"
533
+ alt="Lana Steiner"
534
+ />
535
+ <Avatar
536
+ className="ring-[1.5px] ring-bg-primary"
537
+ size="xs"
538
+ src="https://www.untitledui.com/images/avatars/demi-wilkinson?fm=webp&q=80&w=100"
539
+ alt="Demi Wilkinson"
540
+ />
541
+ <Avatar
542
+ className="ring-[1.5px] ring-bg-primary"
543
+ size="xs"
544
+ src="https://www.untitledui.com/images/avatars/candice-wu?fm=webp&q=80&w=100"
545
+ alt="Candice Wu"
546
+ />
547
+ <Avatar
548
+ size="xs"
549
+ className="ring-[1.5px] ring-bg-primary"
550
+ placeholder={<span className="text-xs font-semibold text-quaternary">+5</span>}
551
+ />
552
+ </div>
553
+ </Table.Cell>
554
+ <Table.Cell>
555
+ <ProgressBar labelPosition="right" value={item.licenseUse} />
556
+ </Table.Cell>
557
+ <Table.Cell className="px-4">
558
+ <div className="flex items-center justify-end">
559
+ <TableRowActionsDropdown />
560
+ </div>
561
+ </Table.Cell>
562
+ </Table.Row>
563
+ )}
564
+ </Table.Body>
565
+ </Table>
566
+ </TableCard.Root>
567
+ );
568
+ };
569
+
570
+ export const Table03DividerLine = () => {
571
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
572
+ column: "invoice",
573
+ direction: "ascending",
574
+ });
575
+
576
+ const sortedItems = useMemo(() => {
577
+ return invoices.items.sort((a, b) => {
578
+ const first = a[sortDescriptor.column as keyof typeof a];
579
+ const second = b[sortDescriptor.column as keyof typeof b];
580
+
581
+ // Compare numbers or booleans
582
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
583
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
584
+ }
585
+
586
+ // Compare strings
587
+ if (typeof first === "string" && typeof second === "string") {
588
+ let cmp = first.localeCompare(second);
589
+ if (sortDescriptor.direction === "descending") {
590
+ cmp *= -1;
591
+ }
592
+ return cmp;
593
+ }
594
+
595
+ return 0;
596
+ });
597
+ }, [sortDescriptor]);
598
+
599
+ const getInitials = (name: string) => {
600
+ return name
601
+ .split(" ")
602
+ .map((n) => n[0])
603
+ .join("");
604
+ };
605
+
606
+ return (
607
+ <TableCard.Root>
608
+ <Table aria-label="Team members" selectionMode="multiple" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
609
+ <Table.Header>
610
+ <Table.Head id="id" label="Invoice" isRowHeader allowsSorting />
611
+ <Table.Head id="date" label="Date" allowsSorting />
612
+ <Table.Head id="status" label="Status" allowsSorting />
613
+ <Table.Head id="customer" label="Customer" />
614
+ <Table.Head id="purchase" label="Purchase" className="md:hidden xl:table-cell" />
615
+ <Table.Head id="actions" />
616
+ </Table.Header>
617
+ <Table.Body items={sortedItems}>
618
+ {(item) => (
619
+ <Table.Row id={item.id}>
620
+ <Table.Cell className="font-medium text-primary">#{item.id}</Table.Cell>
621
+ <Table.Cell className="whitespace-nowrap">
622
+ {new Date(item.date).toLocaleString(undefined, { year: "numeric", month: "short", day: "numeric" })}
623
+ </Table.Cell>
624
+ <Table.Cell>
625
+ {item.status === "paid" ? (
626
+ <BadgeWithIcon size="sm" color="success" iconLeading={Check} className="capitalize">
627
+ {item.status}
628
+ </BadgeWithIcon>
629
+ ) : item.status === "refunded" ? (
630
+ <BadgeWithIcon size="sm" color="gray" iconLeading={ReverseLeft} className="capitalize">
631
+ {item.status}
632
+ </BadgeWithIcon>
633
+ ) : (
634
+ <BadgeWithIcon size="sm" color="error" iconLeading={X} className="capitalize">
635
+ {item.status}
636
+ </BadgeWithIcon>
637
+ )}
638
+ </Table.Cell>
639
+ <Table.Cell>
640
+ <div className="flex items-center gap-3">
641
+ <Avatar initials={getInitials(item.customer.name)} src={item.customer.avatarUrl} alt={item.customer.name} size="md" />
642
+ <div className="whitespace-nowrap">
643
+ <p className="text-sm font-medium text-primary">{item.customer.name}</p>
644
+ <p className="text-sm text-tertiary">{item.customer.email}</p>
645
+ </div>
646
+ </div>
647
+ </Table.Cell>
648
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.purchase}</Table.Cell>
649
+ <Table.Cell>
650
+ <div className="flex items-center justify-end gap-3">
651
+ <Button size="sm" color="link-gray">
652
+ Delete
653
+ </Button>
654
+ <Button size="sm" color="link-color">
655
+ Edit
656
+ </Button>
657
+ </div>
658
+ </Table.Cell>
659
+ </Table.Row>
660
+ )}
661
+ </Table.Body>
662
+ </Table>
663
+ <PaginationPageMinimalCenter page={1} total={10} className="px-4 py-3 md:px-6 md:pt-3 md:pb-4" />
664
+ </TableCard.Root>
665
+ );
666
+ };
667
+
668
+ export const Table03AlternatingFills = () => {
669
+ const [sortDescriptor, setSortDescriptor] = useState<SortDescriptor>({
670
+ column: "invoice",
671
+ direction: "ascending",
672
+ });
673
+
674
+ const sortedItems = useMemo(() => {
675
+ return invoices.items.sort((a, b) => {
676
+ const first = a[sortDescriptor.column as keyof typeof a];
677
+ const second = b[sortDescriptor.column as keyof typeof b];
678
+
679
+ // Compare numbers or booleans
680
+ if ((typeof first === "number" && typeof second === "number") || (typeof first === "boolean" && typeof second === "boolean")) {
681
+ return sortDescriptor.direction === "descending" ? second - first : first - second;
682
+ }
683
+
684
+ // Compare strings
685
+ if (typeof first === "string" && typeof second === "string") {
686
+ let cmp = first.localeCompare(second);
687
+ if (sortDescriptor.direction === "descending") {
688
+ cmp *= -1;
689
+ }
690
+ return cmp;
691
+ }
692
+
693
+ return 0;
694
+ });
695
+ }, [sortDescriptor]);
696
+
697
+ const getInitials = (name: string) => {
698
+ return name
699
+ .split(" ")
700
+ .map((n) => n[0])
701
+ .join("");
702
+ };
703
+
704
+ return (
705
+ <TableCard.Root>
706
+ <Table aria-label="Team members" selectionMode="multiple" sortDescriptor={sortDescriptor} onSortChange={setSortDescriptor}>
707
+ <Table.Header className="bg-primary">
708
+ <Table.Head id="id" label="Invoice" isRowHeader allowsSorting />
709
+ <Table.Head id="date" label="Date" allowsSorting />
710
+ <Table.Head id="status" label="Status" allowsSorting />
711
+ <Table.Head id="customer" label="Customer" />
712
+ <Table.Head id="purchase" label="Purchase" className="md:hidden xl:table-cell" />
713
+ <Table.Head id="actions" />
714
+ </Table.Header>
715
+ <Table.Body items={sortedItems}>
716
+ {(item) => (
717
+ <Table.Row id={item.id} className="odd:bg-secondary_subtle">
718
+ <Table.Cell className="font-medium text-primary">#{item.id}</Table.Cell>
719
+ <Table.Cell className="whitespace-nowrap">{item.date}</Table.Cell>
720
+ <Table.Cell>
721
+ {item.status === "paid" ? (
722
+ <BadgeWithIcon size="sm" color="success" iconLeading={Check} className="capitalize">
723
+ {item.status}
724
+ </BadgeWithIcon>
725
+ ) : item.status === "refunded" ? (
726
+ <BadgeWithIcon size="sm" color="gray" iconLeading={ReverseLeft} className="capitalize">
727
+ {item.status}
728
+ </BadgeWithIcon>
729
+ ) : (
730
+ <BadgeWithIcon size="sm" color="error" iconLeading={X} className="capitalize">
731
+ {item.status}
732
+ </BadgeWithIcon>
733
+ )}
734
+ </Table.Cell>
735
+ <Table.Cell>
736
+ <div className="flex items-center gap-3">
737
+ <Avatar initials={getInitials(item.customer.name)} src={item.customer.avatarUrl} alt={item.customer.name} size="md" />
738
+ <div className="whitespace-nowrap">
739
+ <p className="text-sm font-medium text-primary">{item.customer.name}</p>
740
+ <p className="text-sm text-tertiary">{item.customer.email}</p>
741
+ </div>
742
+ </div>
743
+ </Table.Cell>
744
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.purchase}</Table.Cell>
745
+ <Table.Cell>
746
+ <div className="flex items-center justify-end gap-3">
747
+ <Button size="sm" color="link-gray">
748
+ Delete
749
+ </Button>
750
+ <Button size="sm" color="link-color">
751
+ Edit
752
+ </Button>
753
+ </div>
754
+ </Table.Cell>
755
+ </Table.Row>
756
+ )}
757
+ </Table.Body>
758
+ </Table>
759
+ <PaginationPageMinimalCenter page={1} total={10} className="px-4 py-3 md:px-6 md:pt-3 md:pb-4" />
760
+ </TableCard.Root>
761
+ );
762
+ };
763
+
764
+ export const Table04DividerLine = () => {
765
+ return (
766
+ <TableCard.Root>
767
+ <TableCard.Header
768
+ title="Files uploaded"
769
+ className="pb-5"
770
+ contentTrailing={
771
+ <div className="flex items-center gap-3">
772
+ <Button size="md" color="secondary">
773
+ Download all
774
+ </Button>
775
+ <Button size="md" iconLeading={UploadCloud02}>
776
+ Upload
777
+ </Button>
778
+ </div>
779
+ }
780
+ />
781
+ <Table aria-label="Team members" selectionMode="multiple">
782
+ <Table.Header>
783
+ <Table.Head id="name" label="File name" isRowHeader />
784
+ <Table.Head id="size" label="File size" />
785
+ <Table.Head id="uploadedAt" label="Date uploaded" />
786
+ <Table.Head id="updatedAt" label="Last updated" className="md:hidden xl:table-cell" />
787
+ <Table.Head id="uploadedBy" label="Uploaded by" />
788
+ <Table.Head id="actions" />
789
+ </Table.Header>
790
+ <Table.Body items={uploadedFiles.items}>
791
+ {(item) => (
792
+ <Table.Row id={item.name}>
793
+ <Table.Cell>
794
+ <div className="flex items-center gap-3">
795
+ <FileIcon type={item.name.split(".")[1]} theme="light" className="size-10 dark:hidden" />
796
+ <FileIcon type={item.name.split(".")[1]} theme="dark" className="size-10 not-dark:hidden" />
797
+
798
+ <div className="whitespace-nowrap">
799
+ <p className="text-sm font-medium text-primary">{item.name}</p>
800
+ <p className="text-sm text-tertiary">{item.size}</p>
801
+ </div>
802
+ </div>
803
+ </Table.Cell>
804
+ <Table.Cell className="whitespace-nowrap">{item.size}</Table.Cell>
805
+ <Table.Cell className="whitespace-nowrap">{item.uploadedAt}</Table.Cell>
806
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.updatedAt}</Table.Cell>
807
+ <Table.Cell className="whitespace-nowrap">{item.uploadedBy}</Table.Cell>
808
+ <Table.Cell className="px-4">
809
+ <div className="flex items-center justify-end">
810
+ <TableRowActionsDropdown />
811
+ </div>
812
+ </Table.Cell>
813
+ </Table.Row>
814
+ )}
815
+ </Table.Body>
816
+ </Table>
817
+ </TableCard.Root>
818
+ );
819
+ };
820
+
821
+ export const Table04AlternatingFills = () => {
822
+ return (
823
+ <TableCard.Root>
824
+ <TableCard.Header
825
+ title="Files uploaded"
826
+ badge="10/20 seats"
827
+ contentTrailing={
828
+ <div className="flex items-center gap-3">
829
+ <Button size="md" color="secondary">
830
+ Download all
831
+ </Button>
832
+ <Button size="md" iconLeading={UploadCloud02}>
833
+ Upload
834
+ </Button>
835
+ </div>
836
+ }
837
+ />
838
+ <Table aria-label="Team members" selectionMode="multiple">
839
+ <Table.Header className="bg-primary">
840
+ <Table.Head id="name" label="File name" isRowHeader />
841
+ <Table.Head id="size" label="File size" />
842
+ <Table.Head id="uploadedAt" label="Date uploaded" />
843
+ <Table.Head id="updatedAt" label="Last updated" className="md:hidden xl:table-cell" />
844
+ <Table.Head id="uploadedBy" label="Uploaded by" />
845
+ <Table.Head id="actions" />
846
+ </Table.Header>
847
+ <Table.Body items={uploadedFiles.items}>
848
+ {(item) => (
849
+ <Table.Row id={item.name} className="odd:bg-secondary_subtle">
850
+ <Table.Cell>
851
+ <div className="flex items-center gap-3">
852
+ <FileIcon type={item.name.split(".")[1]} theme="light" className="size-10 dark:hidden" />
853
+ <FileIcon type={item.name.split(".")[1]} theme="dark" className="size-10 not-dark:hidden" />
854
+
855
+ <div className="whitespace-nowrap">
856
+ <p className="text-sm font-medium text-primary">{item.name}</p>
857
+ <p className="text-sm text-tertiary">{item.size}</p>
858
+ </div>
859
+ </div>
860
+ </Table.Cell>
861
+ <Table.Cell className="whitespace-nowrap">{item.size}</Table.Cell>
862
+ <Table.Cell className="whitespace-nowrap">{item.uploadedAt}</Table.Cell>
863
+ <Table.Cell className="whitespace-nowrap md:hidden xl:table-cell">{item.updatedAt}</Table.Cell>
864
+ <Table.Cell className="whitespace-nowrap">{item.uploadedBy}</Table.Cell>
865
+ <Table.Cell className="px-4">
866
+ <div className="flex items-center justify-end">
867
+ <TableRowActionsDropdown />
868
+ </div>
869
+ </Table.Cell>
870
+ </Table.Row>
871
+ )}
872
+ </Table.Body>
873
+ </Table>
874
+ </TableCard.Root>
875
+ );
876
+ };
877
+
878
+ export const TableNoVendorsFound = () => {
879
+ return (
880
+ <TableCard.Root>
881
+ <TableCard.Header
882
+ title="Vendor movements"
883
+ badge="240 vendors"
884
+ description="Keep track of vendor and their security ratings."
885
+ contentTrailing={
886
+ <>
887
+ <div className="flex gap-3 md:pr-9">
888
+ <Button color="secondary" size="md" iconLeading={UploadCloud02}>
889
+ Import
890
+ </Button>
891
+ <Button size="md" iconLeading={Plus}>
892
+ Add vendor
893
+ </Button>
894
+ </div>
895
+ <div className="absolute top-5 right-4 md:right-6">
896
+ <TableRowActionsDropdown />
897
+ </div>
898
+ </>
899
+ }
900
+ />
901
+
902
+ <div className="flex justify-between gap-4 border-b border-secondary px-4 py-3 md:px-6">
903
+ <ButtonGroup defaultSelectedKeys={["all"]}>
904
+ <ButtonGroupItem id="all">View all</ButtonGroupItem>
905
+ <ButtonGroupItem id="monitored">Monitored</ButtonGroupItem>
906
+ <ButtonGroupItem id="unmonitored">Unmonitored</ButtonGroupItem>
907
+ </ButtonGroup>
908
+
909
+ <div className="hidden gap-3 md:flex">
910
+ <Input icon={SearchLg} aria-label="Search" placeholder="Search" className="w-70" />
911
+ <Button size="md" color="secondary" iconLeading={FilterLines}>
912
+ Filters
913
+ </Button>
914
+ </div>
915
+ </div>
916
+
917
+ <div className="flex items-center justify-center overflow-hidden px-8 pt-10 pb-12">
918
+ <EmptyState size="sm">
919
+ <EmptyState.Header pattern="circle">
920
+ <EmptyState.FeaturedIcon color="gray" theme="modern-neue" />
921
+ </EmptyState.Header>
922
+
923
+ <EmptyState.Content>
924
+ <EmptyState.Title>No vendors found</EmptyState.Title>
925
+ <EmptyState.Description>
926
+ Your search “Stripe” did not match any vendors. Please try again or create add a new vendor.
927
+ </EmptyState.Description>
928
+ </EmptyState.Content>
929
+
930
+ <EmptyState.Footer>
931
+ <Button size="md" color="secondary">
932
+ Clear search
933
+ </Button>
934
+ <Button size="md" iconLeading={Plus}>
935
+ New project
936
+ </Button>
937
+ </EmptyState.Footer>
938
+ </EmptyState>
939
+ </div>
940
+
941
+ <div className="flex items-center justify-between border-t border-secondary px-6 pt-3 pb-4">
942
+ <span className="text-sm">Page 1 of 10</span>
943
+ <div className="flex gap-3">
944
+ <Button color="secondary">Previous</Button>
945
+ <Button color="secondary">Next</Button>
946
+ </div>
947
+ </div>
948
+ </TableCard.Root>
949
+ );
950
+ };
951
+
952
+ export const TableStartByUploadingFile = () => {
953
+ return (
954
+ <TableCard.Root>
955
+ <TableCard.Header
956
+ title="Files uploaded"
957
+ contentTrailing={
958
+ <div className="flex items-center">
959
+ <Button size="md" iconLeading={UploadCloud02}>
960
+ Upload
961
+ </Button>
962
+ </div>
963
+ }
964
+ />
965
+
966
+ <div className="flex items-center justify-center overflow-hidden px-8 pt-10 pb-12">
967
+ <EmptyState size="sm">
968
+ <EmptyState.Header pattern="grid">
969
+ <EmptyState.Illustration type="cloud">
970
+ <UploadCloud02 />
971
+ </EmptyState.Illustration>
972
+ </EmptyState.Header>
973
+
974
+ <EmptyState.Content>
975
+ <EmptyState.Title>Start by uploading a file</EmptyState.Title>
976
+ <EmptyState.Description>
977
+ Any assets used in projects will live here. <br />
978
+ Start creating by uploading your files.
979
+ </EmptyState.Description>
980
+ </EmptyState.Content>
981
+
982
+ <EmptyState.Footer>
983
+ <Button size="md" iconLeading={Plus}>
984
+ New project
985
+ </Button>
986
+ </EmptyState.Footer>
987
+ </EmptyState>
988
+ </div>
989
+ </TableCard.Root>
990
+ );
991
+ };
992
+
993
+ export const TableSomethingWentWrong = () => {
994
+ return (
995
+ <TableCard.Root>
996
+ <TableCard.Header
997
+ title="Team members"
998
+ badge="100 users"
999
+ contentTrailing={
1000
+ <div className="absolute top-5 right-4 md:right-6">
1001
+ <TableRowActionsDropdown />
1002
+ </div>
1003
+ }
1004
+ />
1005
+
1006
+ <div className="flex items-center justify-center overflow-hidden px-8 pt-10 pb-12">
1007
+ <EmptyState size="sm">
1008
+ <EmptyState.Header pattern="circle">
1009
+ <EmptyState.FeaturedIcon color="error" theme="light" icon={AlertCircle} />
1010
+ </EmptyState.Header>
1011
+
1012
+ <EmptyState.Content>
1013
+ <EmptyState.Title>Something went wrong...</EmptyState.Title>
1014
+ <EmptyState.Description>
1015
+ We had some trouble loading this page. Please refresh the page or{" "}
1016
+ <a
1017
+ href="#"
1018
+ className="rounded-xs underline underline-offset-2 outline-focus-ring focus-visible:outline-2 focus-visible:outline-offset-2"
1019
+ >
1020
+ get in touch
1021
+ </a>{" "}
1022
+ for support.
1023
+ </EmptyState.Description>
1024
+ </EmptyState.Content>
1025
+
1026
+ <EmptyState.Footer>
1027
+ <Button size="md" color="secondary">
1028
+ Clear search
1029
+ </Button>
1030
+ <Button size="md" iconLeading={Plus}>
1031
+ New project
1032
+ </Button>
1033
+ </EmptyState.Footer>
1034
+ </EmptyState>
1035
+ </div>
1036
+ </TableCard.Root>
1037
+ );
1038
+ };