@turtleclub/ui 0.7.0-beta.33 → 0.7.0-beta.35

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 (135) hide show
  1. package/dist/index.cjs +10331 -110
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.js +7227 -48026
  4. package/dist/index.js.map +1 -1
  5. package/package.json +17 -11
  6. package/.prettierrc.json +0 -4
  7. package/.turbo/turbo-build.log +0 -182
  8. package/CHANGELOG.md +0 -801
  9. package/components.json +0 -21
  10. package/src/components/charts/QUICK_REFERENCE.md +0 -323
  11. package/src/components/charts/README.md +0 -658
  12. package/src/components/charts/RECHARTS_FEATURES.md +0 -458
  13. package/src/components/charts/area-chart.tsx +0 -248
  14. package/src/components/charts/bar-chart.tsx +0 -362
  15. package/src/components/charts/index.ts +0 -4
  16. package/src/components/charts/pie-chart.tsx +0 -277
  17. package/src/components/charts/radial-chart.tsx +0 -312
  18. package/src/components/features/api-status/index.tsx +0 -23
  19. package/src/components/features/data-table/data-table.tsx +0 -538
  20. package/src/components/features/data-table/expand-toggle.tsx +0 -17
  21. package/src/components/features/data-table/fuzzy-filter.tsx +0 -34
  22. package/src/components/features/data-table/index.ts +0 -3
  23. package/src/components/features/data-table/item-info.tsx +0 -19
  24. package/src/components/features/data-table/skeleton.tsx +0 -23
  25. package/src/components/features/data-table/sort-dropdown.tsx +0 -118
  26. package/src/components/features/data-table/sortable-header.tsx +0 -37
  27. package/src/components/features/index.ts +0 -6
  28. package/src/components/features/page-heading.tsx +0 -27
  29. package/src/components/features/search-bar.tsx +0 -55
  30. package/src/components/features/segmented-navigation.tsx +0 -18
  31. package/src/components/features/sidebar-layout.tsx +0 -279
  32. package/src/components/features/turtle-tooltip.tsx +0 -67
  33. package/src/components/icons/arrow.tsx +0 -23
  34. package/src/components/icons/beta.tsx +0 -95
  35. package/src/components/icons/dot.tsx +0 -102
  36. package/src/components/icons/index.ts +0 -7
  37. package/src/components/icons/issue.tsx +0 -106
  38. package/src/components/icons/turtle.tsx +0 -156
  39. package/src/components/icons/update.tsx +0 -113
  40. package/src/components/icons/warning.tsx +0 -95
  41. package/src/components/molecules/index.ts +0 -9
  42. package/src/components/molecules/opportunity/index.ts +0 -10
  43. package/src/components/molecules/opportunity/opportunity-apr.tsx +0 -129
  44. package/src/components/molecules/opportunity/opportunity-disclaimer.tsx +0 -46
  45. package/src/components/molecules/opportunity/opportunity-rate-estimator.tsx +0 -62
  46. package/src/components/molecules/opportunity/opportunity-section.tsx +0 -113
  47. package/src/components/molecules/opportunity/opportunity-selector.tsx +0 -30
  48. package/src/components/molecules/opportunity/opportunity-type.tsx +0 -16
  49. package/src/components/molecules/route-details.tsx +0 -112
  50. package/src/components/molecules/slippage-selector.tsx +0 -200
  51. package/src/components/molecules/swap-details.tsx +0 -55
  52. package/src/components/molecules/swap-input.tsx +0 -186
  53. package/src/components/molecules/tabs.tsx +0 -79
  54. package/src/components/molecules/token-selector.tsx +0 -180
  55. package/src/components/molecules/tx-status.tsx +0 -312
  56. package/src/components/molecules/widget/asset-list/asset-filters.tsx +0 -113
  57. package/src/components/molecules/widget/asset-list/asset-list.tsx +0 -178
  58. package/src/components/molecules/widget/asset-list/asset-row.tsx +0 -45
  59. package/src/components/molecules/widget/asset-list/hooks/index.ts +0 -2
  60. package/src/components/molecules/widget/asset-list/hooks/use-asset-filtering.ts +0 -44
  61. package/src/components/molecules/widget/asset-list/hooks/use-asset-grouping.ts +0 -87
  62. package/src/components/molecules/widget/asset-list/index.ts +0 -3
  63. package/src/components/molecules/widget/base-selector.tsx +0 -121
  64. package/src/components/molecules/widget/campaign-item.tsx +0 -82
  65. package/src/components/molecules/widget/deal-item.tsx +0 -92
  66. package/src/components/molecules/widget/index.ts +0 -36
  67. package/src/components/molecules/widget/opportunity-item.tsx +0 -105
  68. package/src/components/molecules/widget/widget-item-stats.tsx +0 -50
  69. package/src/components/molecules/widget/widget-item.tsx +0 -139
  70. package/src/components/molecules/widget/widget-list-items.tsx +0 -86
  71. package/src/components/ui/alert-dialog.tsx +0 -163
  72. package/src/components/ui/animated-background/animated-background.tsx +0 -182
  73. package/src/components/ui/animated-background/index.ts +0 -1
  74. package/src/components/ui/avatar.tsx +0 -73
  75. package/src/components/ui/badge.tsx +0 -59
  76. package/src/components/ui/banner.tsx +0 -84
  77. package/src/components/ui/button.tsx +0 -100
  78. package/src/components/ui/card.tsx +0 -119
  79. package/src/components/ui/chart.tsx +0 -346
  80. package/src/components/ui/checkbox.tsx +0 -32
  81. package/src/components/ui/chip.tsx +0 -52
  82. package/src/components/ui/collapsible.tsx +0 -34
  83. package/src/components/ui/combobox.tsx +0 -730
  84. package/src/components/ui/command.tsx +0 -184
  85. package/src/components/ui/dialog.tsx +0 -129
  86. package/src/components/ui/dropdown.tsx +0 -316
  87. package/src/components/ui/field.tsx +0 -244
  88. package/src/components/ui/heading.tsx +0 -74
  89. package/src/components/ui/hover-card.tsx +0 -139
  90. package/src/components/ui/icon-animation.tsx +0 -82
  91. package/src/components/ui/icon-list.tsx +0 -168
  92. package/src/components/ui/index.ts +0 -48
  93. package/src/components/ui/info-card.tsx +0 -110
  94. package/src/components/ui/input-group.tsx +0 -170
  95. package/src/components/ui/input.tsx +0 -72
  96. package/src/components/ui/label-with-icon.tsx +0 -122
  97. package/src/components/ui/label.tsx +0 -24
  98. package/src/components/ui/multi-select.tsx +0 -1090
  99. package/src/components/ui/navigation-bar.tsx +0 -153
  100. package/src/components/ui/navigation-menu.tsx +0 -188
  101. package/src/components/ui/opportunity-details-v1.tsx +0 -104
  102. package/src/components/ui/pagination.tsx +0 -127
  103. package/src/components/ui/popover.tsx +0 -48
  104. package/src/components/ui/scroll-area.tsx +0 -64
  105. package/src/components/ui/segment-control.tsx +0 -146
  106. package/src/components/ui/select.tsx +0 -199
  107. package/src/components/ui/separator.tsx +0 -26
  108. package/src/components/ui/sheet.tsx +0 -139
  109. package/src/components/ui/sidebar.tsx +0 -728
  110. package/src/components/ui/skeleton.tsx +0 -14
  111. package/src/components/ui/slider.tsx +0 -58
  112. package/src/components/ui/sonner.tsx +0 -24
  113. package/src/components/ui/switch.tsx +0 -29
  114. package/src/components/ui/table-shadcn.tsx +0 -110
  115. package/src/components/ui/table.tsx +0 -117
  116. package/src/components/ui/textarea.tsx +0 -22
  117. package/src/components/ui/toggle-group.tsx +0 -71
  118. package/src/components/ui/toggle.tsx +0 -47
  119. package/src/components/ui/tooltip.tsx +0 -66
  120. package/src/hooks/index.ts +0 -1
  121. package/src/hooks/useIsMobile.ts +0 -77
  122. package/src/index.ts +0 -16
  123. package/src/lib/utils.ts +0 -6
  124. package/src/styles/globals.css +0 -181
  125. package/src/styles/themes/index.css +0 -9
  126. package/src/styles/themes/semantic.css +0 -117
  127. package/src/styles/tokens/colors.css +0 -124
  128. package/src/styles/tokens/index.css +0 -15
  129. package/src/styles/tokens/radius.css +0 -18
  130. package/src/styles/tokens/spacing.css +0 -58
  131. package/src/styles/tokens/typography.css +0 -87
  132. package/src/tokens/index.ts +0 -108
  133. package/tsconfig.json +0 -20
  134. package/vite.config.js +0 -49
  135. /package/{src/images/enso.png → dist/enso-22FJ4GNK.png} +0 -0
@@ -1,538 +0,0 @@
1
- "use client";
2
-
3
- import React, { Fragment, useMemo, useState } from "react";
4
-
5
- import {
6
- ColumnDef,
7
- ExpandedState,
8
- flexRender,
9
- getCoreRowModel,
10
- getExpandedRowModel,
11
- getFilteredRowModel,
12
- getPaginationRowModel,
13
- getSortedRowModel,
14
- PaginationState,
15
- Row,
16
- RowSelectionState,
17
- SortingState,
18
- useReactTable,
19
- } from "@tanstack/react-table";
20
- import {
21
- Card,
22
- CardContent,
23
- CardHeader,
24
- CardTitle,
25
- ScrollArea,
26
- ShadTableCell,
27
- Table,
28
- TableBody,
29
- TableHead,
30
- TableHeader,
31
- TableRow,
32
- Input,
33
- Combobox,
34
- } from "../../ui";
35
- import SortableHeader from "./sortable-header";
36
- import { SearchBar } from "../search-bar";
37
- import { fuzzyFilter } from "./fuzzy-filter";
38
- import { cn } from "@/lib/utils";
39
- import { ItemInfo } from "./item-info";
40
- import { GridSkeleton, RowsSkeleton } from "./skeleton";
41
- import { SortDropdown } from "./sort-dropdown";
42
- import {
43
- Pagination,
44
- PaginationContent,
45
- PaginationEllipsis,
46
- PaginationItem,
47
- PaginationLink,
48
- PaginationNext,
49
- PaginationPrevious,
50
- } from "../../ui/pagination";
51
- import { useIsMobile } from "@/hooks";
52
-
53
- const getScrollAreaHeight = (size: string | "full" | undefined) => {
54
- if (!size) return "auto";
55
- if (size === "full") return "100%";
56
- return size;
57
- };
58
-
59
- type DataTableProps<TData, TValue> = {
60
- columns: ColumnDef<TData, TValue>[];
61
- data: TData[];
62
- // Loading state
63
- isLoading?: boolean;
64
- // Slot for control appart from the ones baked in
65
- slot?: React.ReactNode;
66
- // Enabling baked in features
67
- enableSearch?: boolean;
68
- enableExpand?: boolean;
69
- enablePagination?: boolean;
70
- enableSorting?: boolean;
71
- // enableSelection?: boolean;
72
- renderSubComponent?: (props: { row: Row<TData> }) => React.ReactElement;
73
-
74
- // Initial setup to match data coming in if server side manipulated
75
- initialSorting?: SortingState;
76
- onRowClick?: (row: TData) => void;
77
- initialColumnVisibility?: Record<keyof TData, boolean>;
78
-
79
- // Server-side control options
80
- manualFiltering?: boolean;
81
- manualSorting?: boolean;
82
- manualPagination?: boolean;
83
-
84
- pageCount?: number; // Total page count from server (required when manualPagination is true)
85
- rowCount?: number; // Total row count from server (optional, for display purposes)
86
-
87
- // Controlled state (for server-side control)
88
- sorting?: SortingState;
89
- onSortingChange?: (sorting: SortingState) => void;
90
- globalFilter?: string;
91
- onGlobalFilterChange?: (filter: string) => void;
92
- pagination?: PaginationState;
93
- onPaginationChange?: (pagination: PaginationState) => void;
94
-
95
- // Exclusive card view configuration
96
- grid?: {
97
- displayAsGrid: boolean;
98
- className?: string;
99
- headerSlot: keyof TData | string;
100
- rightSlot?: keyof TData | string;
101
- excludeColumns?: (keyof TData | string)[];
102
- headerTextSize?: string;
103
- rightSlotTextSize?: string;
104
- };
105
- // ScrollArea size configuration
106
- size?: string | "full";
107
- emptyState?: React.ReactNode;
108
- className?: string;
109
- slotClassName?: string;
110
- };
111
-
112
- export function DataTable<TData, TValue>({
113
- columns,
114
- data,
115
- isLoading,
116
- slot,
117
- enableExpand,
118
- enableSearch,
119
- enablePagination,
120
- enableSorting,
121
- renderSubComponent,
122
- initialSorting = [],
123
- initialColumnVisibility,
124
- size = undefined,
125
- grid,
126
- emptyState,
127
- className,
128
- slotClassName,
129
- onRowClick,
130
- // Server-side props
131
- manualFiltering = false,
132
- manualSorting = false,
133
- manualPagination = false,
134
- pageCount,
135
- rowCount,
136
- sorting: controlledSorting,
137
- onSortingChange: onControlledSortingChange,
138
- globalFilter: controlledGlobalFilter,
139
- onGlobalFilterChange: onControlledGlobalFilterChange,
140
- pagination: controlledPagination,
141
- onPaginationChange: onControlledPaginationChange,
142
- }: DataTableProps<TData, TValue>) {
143
- const [columnVisibility, setColumnVisibility] = React.useState(initialColumnVisibility ?? {});
144
- const [rowSelection, setRowSelection] = React.useState<RowSelectionState>({});
145
- const [expanded, setExpanded] = React.useState<ExpandedState>({});
146
-
147
- // Internal state (used when not controlled from outside)
148
- const [internalGlobalFilter, setInternalGlobalFilter] = React.useState<string>("");
149
- const [internalSorting, setInternalSorting] = React.useState<SortingState>(initialSorting);
150
- const [internalPagination, setInternalPagination] = React.useState<PaginationState>({
151
- pageIndex: 0,
152
- pageSize: 10,
153
- });
154
-
155
- // Store the default page size for reset purposes
156
- const defaultPageSize = React.useMemo(
157
- () => controlledPagination?.pageSize ?? internalPagination.pageSize,
158
- [controlledPagination?.pageSize]
159
- );
160
-
161
- // Use controlled state if provided, otherwise use internal state
162
- const globalFilter = controlledGlobalFilter ?? internalGlobalFilter;
163
- const sorting = controlledSorting ?? internalSorting;
164
- const pagination = controlledPagination ?? internalPagination;
165
-
166
- const setGlobalFilter = (value: string) => {
167
- if (onControlledGlobalFilterChange) {
168
- onControlledGlobalFilterChange(value);
169
- } else {
170
- setInternalGlobalFilter(value);
171
- }
172
- };
173
-
174
- const setSorting = (updaterOrValue: SortingState | ((old: SortingState) => SortingState)) => {
175
- const newSorting =
176
- typeof updaterOrValue === "function" ? updaterOrValue(sorting) : updaterOrValue;
177
-
178
- if (onControlledSortingChange) {
179
- onControlledSortingChange(newSorting);
180
- } else {
181
- setInternalSorting(newSorting);
182
- }
183
- };
184
-
185
- const setPagination = (
186
- updaterOrValue: PaginationState | ((old: PaginationState) => PaginationState)
187
- ) => {
188
- const newPagination =
189
- typeof updaterOrValue === "function" ? updaterOrValue(pagination) : updaterOrValue;
190
-
191
- if (onControlledPaginationChange) {
192
- onControlledPaginationChange(newPagination);
193
- } else {
194
- setInternalPagination(newPagination);
195
- }
196
- };
197
-
198
- const { isMobile } = useIsMobile();
199
-
200
- const table = useReactTable({
201
- data,
202
- columns,
203
- filterFns: {
204
- fuzzy: fuzzyFilter,
205
- },
206
- state: {
207
- expanded,
208
- rowSelection,
209
- sorting,
210
- globalFilter,
211
- columnVisibility,
212
- pagination,
213
- },
214
- onColumnVisibilityChange: setColumnVisibility,
215
- onRowSelectionChange: setRowSelection,
216
- onSortingChange: setSorting,
217
- // onColumnFiltersChange: setColumnFilters,
218
- onGlobalFilterChange: setGlobalFilter,
219
- onPaginationChange: setPagination,
220
- onExpandedChange: setExpanded,
221
- globalFilterFn: "fuzzy" as any,
222
- getRowCanExpand: enableExpand ? () => true : undefined,
223
-
224
- // Server-side control
225
- manualFiltering: manualFiltering,
226
- manualSorting,
227
- manualPagination,
228
- pageCount: manualPagination ? pageCount : undefined,
229
- rowCount: manualPagination ? rowCount : undefined,
230
-
231
- // Core row model is always needed
232
- getCoreRowModel: getCoreRowModel(),
233
- // When manualFiltering: server does the filtering; don't filter current page by globalFilter (so search works across all data).
234
- // When !manualFiltering: use client-side filtered row model.
235
- getFilteredRowModel: manualFiltering
236
- ? (table) => () => table.getCoreRowModel()
237
- : getFilteredRowModel(),
238
- getSortedRowModel: !manualSorting ? getSortedRowModel() : undefined,
239
- getPaginationRowModel:
240
- enablePagination && !manualPagination ? getPaginationRowModel() : undefined,
241
- getExpandedRowModel: getExpandedRowModel(),
242
-
243
- // debugTable: true,
244
- // debugHeaders: true,
245
- // debugColumns: false,
246
- });
247
-
248
- const headers = useMemo(
249
- () =>
250
- table
251
- .getHeaderGroups()
252
- .map((headerGroup) => headerGroup.headers)
253
- .flat(),
254
- [table]
255
- );
256
-
257
- return (
258
- <div className="space-y-3">
259
- {slot || enableSearch || (enableSorting && grid?.displayAsGrid) ? (
260
- <div className={cn("flex items-start gap-1", slotClassName)}>
261
- {slot}
262
- <span className="grow" />
263
- {enableSorting && grid?.displayAsGrid && (
264
- <SortDropdown
265
- headers={headers}
266
- currentSort={sorting.length > 0 ? sorting[0] : null}
267
- onSortChange={(columnId, desc) => {
268
- setSorting([{ id: columnId, desc }]);
269
- }}
270
- onClearSort={() => setSorting([])}
271
- />
272
- )}
273
- {enableSearch && (
274
- <SearchBar
275
- id="search-bar"
276
- value={globalFilter ?? ""}
277
- onChange={(value) => setGlobalFilter(String(value))}
278
- placeholder="Search..."
279
- />
280
- )}
281
- </div>
282
- ) : undefined}
283
- <ScrollArea style={{ height: getScrollAreaHeight(size) }} className={className}>
284
- {table.getRowModel().rows?.length || isLoading ? (
285
- grid?.displayAsGrid ? (
286
- isLoading ? (
287
- <GridSkeleton
288
- className={cn(
289
- "grid gap-1 pr-1.5",
290
- "grid-cols-1 md:grid-cols-2 xl:grid-cols-3",
291
- grid.className
292
- )}
293
- />
294
- ) : (
295
- <div
296
- className={cn(
297
- "grid gap-1 pr-1.5",
298
- "grid-cols-1 md:grid-cols-2 xl:grid-cols-3",
299
- grid.className
300
- )}
301
- >
302
- {table.getRowModel().rows.map((row) => (
303
- <div onClick={() => onRowClick?.(row.original)} key={row.id}>
304
- <Card
305
- className={cn(
306
- "max-w-none",
307
- onRowClick ? "hover:bg-neutral-alpha-5 cursor-pointer" : ""
308
- )}
309
- data-state={row.getIsSelected() && "selected"}
310
- variant="border"
311
- >
312
- <CardHeader className="flex items-center gap-2">
313
- {/* Slot for header, pick the colum you display here */}
314
- <CardTitle className={cn("line-clamp-1 grow", grid.headerTextSize || "text-base")}>
315
- {row
316
- .getVisibleCells()
317
- .filter((cell) => cell.column.id === grid.headerSlot)
318
- ?.map((cell) => (
319
- <Fragment key={cell.id}>
320
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
321
- </Fragment>
322
- ))}
323
- </CardTitle>
324
- {/* Slot for extra right section, pick the colum you display here */}
325
- {row
326
- .getVisibleCells()
327
- .filter((cell) => cell.column.id === grid?.rightSlot)
328
- ?.map((cell) => (
329
- <div key={cell.id} className={cn(grid.rightSlotTextSize || "text-lg")}>
330
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
331
- </div>
332
- ))}
333
- </CardHeader>
334
- <CardContent className="flex flex-wrap justify-between">
335
- {row
336
- .getVisibleCells()
337
- .filter(
338
- (cell) =>
339
- cell.column.id !== grid.headerSlot &&
340
- cell.column.id !== grid.rightSlot &&
341
- !grid.excludeColumns?.includes(cell.column.id)
342
- )
343
- .map((cell) => {
344
- return (
345
- <ItemInfo
346
- key={cell.id}
347
- title={flexRender(
348
- cell.column.columnDef.header,
349
- headers
350
- .find((header) => header.id === cell.column.id)
351
- ?.getContext()
352
- )}
353
- value={flexRender(cell.column.columnDef.cell, cell.getContext())}
354
- className="justify-between gap-3 *:text-xs"
355
- />
356
- );
357
- })}
358
- </CardContent>
359
- {row.getIsExpanded() && renderSubComponent({ row })}
360
- </Card>
361
- </div>
362
- ))}
363
- </div>
364
- )
365
- ) : (
366
- <Table>
367
- <TableHeader>
368
- <TableRow>
369
- {headers.map((header) => {
370
- return (
371
- <TableHead
372
- key={header.id}
373
- style={{
374
- width: header.column.columnDef.size,
375
- minWidth: header.column.columnDef.minSize,
376
- maxWidth: header.column.columnDef.maxSize,
377
- }}
378
- className={(header.column.columnDef.meta as any)?.className}
379
- >
380
- <SortableHeader header={header} />
381
- </TableHead>
382
- );
383
- })}
384
- </TableRow>
385
- </TableHeader>
386
- <TableBody>
387
- {isLoading ? (
388
- <RowsSkeleton headers={headers.map((header) => header.id)} />
389
- ) : (
390
- table.getRowModel().rows.map((row) => (
391
- <Fragment key={row.id}>
392
- <TableRow
393
- onClick={() => onRowClick?.(row.original)}
394
- data-state={row.getIsSelected() && "selected"}
395
- className={onRowClick ? "hover:bg-neutral-alpha-5 cursor-pointer" : ""}
396
- >
397
- {row.getVisibleCells().map((cell) => (
398
- <ShadTableCell key={cell.id}>
399
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
400
- </ShadTableCell>
401
- ))}
402
- </TableRow>
403
- {row.getIsExpanded() && (
404
- <tr>
405
- {/* 2nd row is a custom 1 cell row */}
406
- <td colSpan={row.getVisibleCells().length}>
407
- {renderSubComponent({ row })}
408
- </td>
409
- </tr>
410
- )}
411
- </Fragment>
412
- ))
413
- )}
414
- </TableBody>
415
- </Table>
416
- )
417
- ) : (
418
- (emptyState ?? (
419
- <div className="bg-neutral-alpha-2 m-12 flex h-48 items-center justify-center rounded-lg shadow">
420
- No results available.
421
- </div>
422
- ))
423
- )}
424
- </ScrollArea>
425
- {enablePagination && (
426
- <div className={cn(isMobile ? "flex flex-col gap-2" : "flex justify-between gap-1")}>
427
- <Combobox
428
- options={[10, 20, 30, 40, 50, 100].map((size) => ({
429
- label: `Show ${size.toString()} rows per page`,
430
- value: size,
431
- }))}
432
- defaultValue={table.getState().pagination.pageSize}
433
- onValueChange={(value) => {
434
- // If value is cleared/null/0, reset to default page size
435
- const newPageSize = value || defaultPageSize;
436
- table.setPageSize(newPageSize);
437
- }}
438
- autoSize
439
- className="h-9"
440
- searchable={false}
441
- closeOnSelect
442
- placeholder="Rows shown per page"
443
- />
444
-
445
- <Pagination>
446
- <PaginationContent>
447
- <PaginationItem>
448
- <PaginationPrevious
449
- onClick={() => table.previousPage()}
450
- className={
451
- !table.getCanPreviousPage()
452
- ? "pointer-events-none opacity-50"
453
- : "cursor-pointer"
454
- }
455
- />
456
- </PaginationItem>
457
- {Array.from({ length: table.getPageCount() }, (_, i) => i).map((pageIndex) => {
458
- const currentPage = table.getState().pagination.pageIndex;
459
- const totalPages = table.getPageCount();
460
-
461
- // Show first page, last page, current page, and pages around current
462
- const showPage =
463
- pageIndex === 0 ||
464
- pageIndex === totalPages - 1 ||
465
- (pageIndex >= currentPage - 1 && pageIndex <= currentPage + 1);
466
-
467
- // Show ellipsis before current range (but not right after first page)
468
- const showEllipsisBefore = pageIndex === currentPage - 2 && currentPage > 2;
469
-
470
- // Show ellipsis after current range (but not right before last page)
471
- const showEllipsisAfter =
472
- pageIndex === currentPage + 2 && currentPage < totalPages - 3;
473
-
474
- if (showEllipsisBefore || showEllipsisAfter) {
475
- return (
476
- <PaginationItem key={pageIndex}>
477
- <PaginationEllipsis />
478
- </PaginationItem>
479
- );
480
- }
481
-
482
- if (!showPage) return null;
483
-
484
- return (
485
- <PaginationItem key={pageIndex}>
486
- <PaginationLink
487
- onClick={() => table.setPageIndex(pageIndex)}
488
- isActive={currentPage === pageIndex}
489
- className="cursor-pointer"
490
- >
491
- {pageIndex + 1}
492
- </PaginationLink>
493
- </PaginationItem>
494
- );
495
- })}
496
- <PaginationItem>
497
- <PaginationNext
498
- onClick={() => table.nextPage()}
499
- className={
500
- !table.getCanNextPage() ? "pointer-events-none opacity-50" : "cursor-pointer"
501
- }
502
- />
503
- </PaginationItem>
504
- </PaginationContent>
505
- </Pagination>
506
-
507
- <div className="mx-4 flex items-center gap-1">
508
- <span className="text-muted-foreground truncate text-xs">Go to page:</span>
509
- <Input
510
- min={1}
511
- max={table.getPageCount()}
512
- pattern="[0-9]*"
513
- defaultValue={table.getState().pagination.pageIndex + 1}
514
- onBlurCapture={(e) => {
515
- const page = e.target.value ? Number(e.target.value) - 1 : 0;
516
- if (page >= 0 && page < table.getPageCount()) {
517
- table.setPageIndex(page);
518
- }
519
- }}
520
- onKeyDown={(e) => {
521
- if (e.key === "Enter") {
522
- const page = e.currentTarget.value ? Number(e.currentTarget.value) - 1 : 0;
523
- if (page >= 0 && page < table.getPageCount()) {
524
- table.setPageIndex(page);
525
- }
526
- }
527
- }}
528
- className="h-9! w-12"
529
- />
530
- <span className="text-muted-foreground truncate text-xs">
531
- of {table.getPageCount()}
532
- </span>
533
- </div>
534
- </div>
535
- )}
536
- </div>
537
- );
538
- }
@@ -1,17 +0,0 @@
1
- import { Row } from "@tanstack/react-table";
2
- import { ChevronDown, ChevronRight } from "lucide-react";
3
-
4
- export function ExpandToggle({ row }: { row: Row<any> }) {
5
- return row.getCanExpand() ? (
6
- <button
7
- onClick={row.getToggleExpandedHandler()}
8
- className="flex cursor-pointer items-center justify-center"
9
- >
10
- {row.getIsExpanded() ? (
11
- <ChevronDown className="text-foreground size-3.5" />
12
- ) : (
13
- <ChevronRight className="text-muted-foreground size-3.5" />
14
- )}
15
- </button>
16
- ) : undefined;
17
- }
@@ -1,34 +0,0 @@
1
- import { FilterFn, SortingFn, sortingFns } from "@tanstack/react-table";
2
- import { rankItem, compareItems } from "@tanstack/match-sorter-utils";
3
-
4
- // Define a custom fuzzy filter function that will apply ranking info to rows (using match-sorter utils)
5
- export const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
6
- // Rank the item
7
- const itemRank = rankItem(row.getValue(columnId), value);
8
-
9
- // Store the itemRank info
10
- addMeta({
11
- itemRank,
12
- });
13
-
14
- // Return if the item should be filtered in/out
15
- return itemRank.passed;
16
- };
17
-
18
- // Define a custom fuzzy sort function that will sort by rank if the row has ranking information
19
- export const fuzzySort: SortingFn<any> = (rowA, rowB, columnId) => {
20
- let dir = 0;
21
-
22
- // Only sort by rank if the column has ranking information
23
- if (rowA.columnFiltersMeta[columnId]) {
24
- dir = compareItems(
25
- // @ts-expect-error not in module
26
- rowA.columnFiltersMeta[columnId]?.itemRank,
27
- // @ts-expect-error not in module
28
- rowB.columnFiltersMeta[columnId]?.itemRank,
29
- );
30
- }
31
-
32
- // Provide an alphanumeric fallback for when the item ranks are equal
33
- return dir === 0 ? sortingFns.alphanumeric(rowA, rowB, columnId) : dir;
34
- };
@@ -1,3 +0,0 @@
1
- export * from "./data-table";
2
- export * from "./expand-toggle";
3
- export * from "./sort-dropdown";
@@ -1,19 +0,0 @@
1
- import { cn } from "@/lib/utils";
2
- import React from "react";
3
-
4
- export function ItemInfo({
5
- title,
6
- value,
7
- className,
8
- }: {
9
- title: React.ReactNode;
10
- value: React.ReactNode;
11
- className?: string;
12
- }) {
13
- return (
14
- <div className={cn("flex flex-col items-start gap-1", className)}>
15
- <div className="text-muted-foreground text-xs">{title}</div>
16
- <div className="text-sm">{value}</div>
17
- </div>
18
- );
19
- }
@@ -1,23 +0,0 @@
1
- import { Card, ShadTableCell, TableRow } from "@/components/ui";
2
-
3
- export function RowsSkeleton({ headers }: { headers: string[] }) {
4
- return [...Array(12).keys()].map((i) => (
5
- <TableRow key={i}>
6
- {headers.map((e) => (
7
- <ShadTableCell key={e} className="h-12 animate-pulse">
8
- <div />
9
- </ShadTableCell>
10
- ))}
11
- </TableRow>
12
- ));
13
- }
14
-
15
- export function GridSkeleton({ className }: { className?: string }) {
16
- return (
17
- <div className={className}>
18
- {[...Array(12).keys()].map((i) => (
19
- <Card key={i} className="h-40 animate-pulse" variant="border" />
20
- ))}
21
- </div>
22
- );
23
- }