@pago-sh/ui 1.0.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.
- package/.turbo/turbo-build.log +195 -0
- package/CHANGELOG.md +47 -0
- package/README.md +22 -0
- package/components.json +17 -0
- package/dist/chunk-2RCGDEGJ.mjs +1 -0
- package/dist/chunk-3GDNSYGJ.mjs +1 -0
- package/dist/chunk-4TCUGB6E.mjs +1 -0
- package/dist/chunk-6XCXQA5L.mjs +1 -0
- package/dist/chunk-BBYR3CIF.mjs +1 -0
- package/dist/chunk-CFBUY7KY.mjs +1 -0
- package/dist/chunk-CHG2VB73.mjs +1 -0
- package/dist/chunk-GCVBVZU7.mjs +1 -0
- package/dist/chunk-HRGUR4R2.mjs +1 -0
- package/dist/chunk-IVU4SSCD.mjs +1 -0
- package/dist/chunk-N6WI5TGM.mjs +1 -0
- package/dist/chunk-OTKGECM3.mjs +1 -0
- package/dist/chunk-SRZFZUN4.mjs +1 -0
- package/dist/chunk-VPECET7P.mjs +1 -0
- package/dist/chunk-WQPSZXQS.mjs +1 -0
- package/dist/chunk-YXNT3UEO.mjs +1 -0
- package/dist/components/atoms/Accordion.d.mts +20 -0
- package/dist/components/atoms/Accordion.d.ts +20 -0
- package/dist/components/atoms/Accordion.js +1 -0
- package/dist/components/atoms/Accordion.mjs +1 -0
- package/dist/components/atoms/Card.d.mts +18 -0
- package/dist/components/atoms/Card.d.ts +18 -0
- package/dist/components/atoms/Card.js +1 -0
- package/dist/components/atoms/Card.mjs +1 -0
- package/dist/components/atoms/Combobox.d.mts +24 -0
- package/dist/components/atoms/Combobox.d.ts +24 -0
- package/dist/components/atoms/Combobox.js +1 -0
- package/dist/components/atoms/Combobox.mjs +1 -0
- package/dist/components/atoms/CopyToClipboardInput.d.mts +12 -0
- package/dist/components/atoms/CopyToClipboardInput.d.ts +12 -0
- package/dist/components/atoms/CopyToClipboardInput.js +1 -0
- package/dist/components/atoms/CopyToClipboardInput.mjs +1 -0
- package/dist/components/atoms/CountryPicker.d.mts +16 -0
- package/dist/components/atoms/CountryPicker.d.ts +16 -0
- package/dist/components/atoms/CountryPicker.js +1 -0
- package/dist/components/atoms/CountryPicker.mjs +1 -0
- package/dist/components/atoms/CountryStatePicker.d.mts +18 -0
- package/dist/components/atoms/CountryStatePicker.d.ts +18 -0
- package/dist/components/atoms/CountryStatePicker.js +1 -0
- package/dist/components/atoms/CountryStatePicker.mjs +1 -0
- package/dist/components/atoms/DateTimePicker.d.mts +10 -0
- package/dist/components/atoms/DateTimePicker.d.ts +10 -0
- package/dist/components/atoms/DateTimePicker.js +1 -0
- package/dist/components/atoms/DateTimePicker.mjs +1 -0
- package/dist/components/atoms/DropdownMenu.d.mts +22 -0
- package/dist/components/atoms/DropdownMenu.d.ts +22 -0
- package/dist/components/atoms/DropdownMenu.js +1 -0
- package/dist/components/atoms/DropdownMenu.mjs +1 -0
- package/dist/components/atoms/FormattedDateTime.d.mts +10 -0
- package/dist/components/atoms/FormattedDateTime.d.ts +10 -0
- package/dist/components/atoms/FormattedDateTime.js +1 -0
- package/dist/components/atoms/FormattedDateTime.mjs +1 -0
- package/dist/components/atoms/FormattedInterval.d.mts +9 -0
- package/dist/components/atoms/FormattedInterval.d.ts +9 -0
- package/dist/components/atoms/FormattedInterval.js +1 -0
- package/dist/components/atoms/FormattedInterval.mjs +1 -0
- package/dist/components/atoms/InputOTP.d.mts +4 -0
- package/dist/components/atoms/InputOTP.d.ts +4 -0
- package/dist/components/atoms/InputOTP.js +1 -0
- package/dist/components/atoms/InputOTP.mjs +1 -0
- package/dist/components/atoms/MoneyInput.d.mts +21 -0
- package/dist/components/atoms/MoneyInput.d.ts +21 -0
- package/dist/components/atoms/MoneyInput.js +1 -0
- package/dist/components/atoms/MoneyInput.mjs +1 -0
- package/dist/components/atoms/Paginator.d.mts +21 -0
- package/dist/components/atoms/Paginator.d.ts +21 -0
- package/dist/components/atoms/Paginator.js +1 -0
- package/dist/components/atoms/Paginator.mjs +1 -0
- package/dist/components/atoms/PagoTimeAgo.d.mts +8 -0
- package/dist/components/atoms/PagoTimeAgo.d.ts +8 -0
- package/dist/components/atoms/PagoTimeAgo.js +1 -0
- package/dist/components/atoms/PagoTimeAgo.mjs +1 -0
- package/dist/components/atoms/PercentageInput.d.mts +19 -0
- package/dist/components/atoms/PercentageInput.d.ts +19 -0
- package/dist/components/atoms/PercentageInput.js +1 -0
- package/dist/components/atoms/PercentageInput.mjs +1 -0
- package/dist/components/atoms/ShadowBox.d.mts +14 -0
- package/dist/components/atoms/ShadowBox.d.ts +14 -0
- package/dist/components/atoms/ShadowBox.js +1 -0
- package/dist/components/atoms/ShadowBox.mjs +1 -0
- package/dist/components/atoms/ShadowBoxOnMd.d.mts +6 -0
- package/dist/components/atoms/ShadowBoxOnMd.d.ts +6 -0
- package/dist/components/atoms/ShadowBoxOnMd.js +1 -0
- package/dist/components/atoms/ShadowBoxOnMd.mjs +1 -0
- package/dist/components/atoms/Sidebar.d.mts +11 -0
- package/dist/components/atoms/Sidebar.d.ts +11 -0
- package/dist/components/atoms/Sidebar.js +1 -0
- package/dist/components/atoms/Sidebar.mjs +1 -0
- package/dist/components/molecules/Banner.d.mts +11 -0
- package/dist/components/molecules/Banner.d.ts +11 -0
- package/dist/components/molecules/Banner.js +1 -0
- package/dist/components/molecules/Banner.mjs +1 -0
- package/dist/components/ui/accordion.d.mts +19 -0
- package/dist/components/ui/accordion.d.ts +19 -0
- package/dist/components/ui/accordion.js +1 -0
- package/dist/components/ui/accordion.mjs +1 -0
- package/dist/components/ui/alert-dialog.d.mts +41 -0
- package/dist/components/ui/alert-dialog.d.ts +41 -0
- package/dist/components/ui/alert-dialog.js +1 -0
- package/dist/components/ui/alert-dialog.mjs +1 -0
- package/dist/components/ui/calendar.d.mts +12 -0
- package/dist/components/ui/calendar.d.ts +12 -0
- package/dist/components/ui/calendar.js +1 -0
- package/dist/components/ui/calendar.mjs +1 -0
- package/dist/components/ui/card.d.mts +23 -0
- package/dist/components/ui/card.d.ts +23 -0
- package/dist/components/ui/card.js +1 -0
- package/dist/components/ui/card.mjs +1 -0
- package/dist/components/ui/chart.d.mts +55 -0
- package/dist/components/ui/chart.d.ts +55 -0
- package/dist/components/ui/chart.js +7 -0
- package/dist/components/ui/chart.mjs +7 -0
- package/dist/components/ui/checkbox.d.mts +2 -0
- package/dist/components/ui/checkbox.d.ts +2 -0
- package/dist/components/ui/checkbox.js +1 -0
- package/dist/components/ui/checkbox.mjs +1 -0
- package/dist/components/ui/command.d.mts +36 -0
- package/dist/components/ui/command.d.ts +36 -0
- package/dist/components/ui/command.js +1 -0
- package/dist/components/ui/command.mjs +1 -0
- package/dist/components/ui/dialog.d.mts +34 -0
- package/dist/components/ui/dialog.d.ts +34 -0
- package/dist/components/ui/dialog.js +1 -0
- package/dist/components/ui/dialog.mjs +1 -0
- package/dist/components/ui/dropdown-menu.d.mts +23 -0
- package/dist/components/ui/dropdown-menu.d.ts +23 -0
- package/dist/components/ui/dropdown-menu.js +1 -0
- package/dist/components/ui/dropdown-menu.mjs +1 -0
- package/dist/components/ui/form.d.mts +43 -0
- package/dist/components/ui/form.d.ts +43 -0
- package/dist/components/ui/form.js +1 -0
- package/dist/components/ui/form.mjs +1 -0
- package/dist/components/ui/input-otp.d.mts +21 -0
- package/dist/components/ui/input-otp.d.ts +21 -0
- package/dist/components/ui/input-otp.js +1 -0
- package/dist/components/ui/input-otp.mjs +1 -0
- package/dist/components/ui/label.d.mts +9 -0
- package/dist/components/ui/label.d.ts +9 -0
- package/dist/components/ui/label.js +1 -0
- package/dist/components/ui/label.mjs +1 -0
- package/dist/components/ui/popover.d.mts +12 -0
- package/dist/components/ui/popover.d.ts +12 -0
- package/dist/components/ui/popover.js +1 -0
- package/dist/components/ui/popover.mjs +1 -0
- package/dist/components/ui/radio-group.d.mts +14 -0
- package/dist/components/ui/radio-group.d.ts +14 -0
- package/dist/components/ui/radio-group.js +1 -0
- package/dist/components/ui/radio-group.mjs +1 -0
- package/dist/components/ui/separator.d.mts +10 -0
- package/dist/components/ui/separator.d.ts +10 -0
- package/dist/components/ui/separator.js +1 -0
- package/dist/components/ui/separator.mjs +1 -0
- package/dist/components/ui/sheet.d.mts +43 -0
- package/dist/components/ui/sheet.d.ts +43 -0
- package/dist/components/ui/sheet.js +1 -0
- package/dist/components/ui/sheet.mjs +1 -0
- package/dist/components/ui/sidebar.d.mts +149 -0
- package/dist/components/ui/sidebar.d.ts +149 -0
- package/dist/components/ui/sidebar.js +1 -0
- package/dist/components/ui/sidebar.mjs +1 -0
- package/dist/components/ui/tooltip.d.mts +1 -0
- package/dist/components/ui/tooltip.d.ts +1 -0
- package/dist/components/ui/tooltip.js +1 -0
- package/dist/components/ui/tooltip.mjs +1 -0
- package/dist/hooks/theming.d.mts +76 -0
- package/dist/hooks/theming.d.ts +76 -0
- package/dist/hooks/theming.js +1 -0
- package/dist/hooks/theming.mjs +1 -0
- package/dist/hooks/use-mobile.d.mts +3 -0
- package/dist/hooks/use-mobile.d.ts +3 -0
- package/dist/hooks/use-mobile.js +1 -0
- package/dist/hooks/use-mobile.mjs +1 -0
- package/dist/lib/meterUnit.d.mts +34 -0
- package/dist/lib/meterUnit.d.ts +34 -0
- package/dist/lib/meterUnit.js +1 -0
- package/dist/lib/meterUnit.mjs +1 -0
- package/dist/lib/utils.d.mts +5 -0
- package/dist/lib/utils.d.ts +5 -0
- package/dist/lib/utils.js +1 -0
- package/dist/lib/utils.mjs +1 -0
- package/eslint.config.mjs +18 -0
- package/package.json +74 -0
- package/src/components/atoms/Accordion.tsx +56 -0
- package/src/components/atoms/Card.tsx +52 -0
- package/src/components/atoms/Combobox.tsx +166 -0
- package/src/components/atoms/CopyToClipboardInput.tsx +72 -0
- package/src/components/atoms/CountryPicker.tsx +81 -0
- package/src/components/atoms/CountryStatePicker.tsx +155 -0
- package/src/components/atoms/DateTimePicker.tsx +69 -0
- package/src/components/atoms/DropdownMenu.tsx +68 -0
- package/src/components/atoms/FormattedDateTime.tsx +58 -0
- package/src/components/atoms/FormattedInterval.tsx +81 -0
- package/src/components/atoms/InputOTP.tsx +7 -0
- package/src/components/atoms/MoneyInput.tsx +297 -0
- package/src/components/atoms/Paginator.tsx +227 -0
- package/src/components/atoms/PagoTimeAgo.tsx +19 -0
- package/src/components/atoms/PercentageInput.tsx +97 -0
- package/src/components/atoms/ShadowBox.tsx +26 -0
- package/src/components/atoms/ShadowBoxOnMd.tsx +20 -0
- package/src/components/atoms/Sidebar.tsx +1 -0
- package/src/components/molecules/Banner.tsx +42 -0
- package/src/components/ui/accordion.tsx +63 -0
- package/src/components/ui/alert-dialog.tsx +147 -0
- package/src/components/ui/calendar.tsx +81 -0
- package/src/components/ui/card.tsx +47 -0
- package/src/components/ui/chart.tsx +372 -0
- package/src/components/ui/checkbox.tsx +3 -0
- package/src/components/ui/command.tsx +133 -0
- package/src/components/ui/dialog.tsx +127 -0
- package/src/components/ui/dropdown-menu.tsx +74 -0
- package/src/components/ui/form.tsx +180 -0
- package/src/components/ui/input-otp.tsx +68 -0
- package/src/components/ui/label.tsx +25 -0
- package/src/components/ui/popover.tsx +34 -0
- package/src/components/ui/radio-group.tsx +46 -0
- package/src/components/ui/separator.tsx +29 -0
- package/src/components/ui/sheet.tsx +149 -0
- package/src/components/ui/sidebar.tsx +742 -0
- package/src/components/ui/tooltip.tsx +8 -0
- package/src/hooks/theming.ts +87 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/meterUnit.ts +52 -0
- package/src/lib/utils.ts +6 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +11 -0
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { ChevronLeft, ChevronRight } from 'lucide-react'
|
|
4
|
+
import { useMemo } from 'react'
|
|
5
|
+
import { twMerge } from 'tailwind-merge'
|
|
6
|
+
import { Button } from '@pago-sh/orbit'
|
|
7
|
+
|
|
8
|
+
interface PaginatorProps {
|
|
9
|
+
totalCount: number
|
|
10
|
+
pageSize: number
|
|
11
|
+
currentPage: number
|
|
12
|
+
siblingCount?: number
|
|
13
|
+
onPageChange: (page: number) => void
|
|
14
|
+
className?: string
|
|
15
|
+
currentURL: URLSearchParams
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const Paginator = ({
|
|
19
|
+
totalCount,
|
|
20
|
+
pageSize,
|
|
21
|
+
currentPage,
|
|
22
|
+
siblingCount = 1,
|
|
23
|
+
onPageChange,
|
|
24
|
+
className,
|
|
25
|
+
currentURL,
|
|
26
|
+
}: PaginatorProps) => {
|
|
27
|
+
const paginationRange = usePagination({
|
|
28
|
+
totalCount,
|
|
29
|
+
currentPage,
|
|
30
|
+
pageSize,
|
|
31
|
+
siblingCount,
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const buildUrlForPage = (page: number): URLSearchParams => {
|
|
35
|
+
const url = new URLSearchParams(currentURL)
|
|
36
|
+
url.set('page', page.toString())
|
|
37
|
+
return url
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// If there are less than 2 times in pagination range we shall not render the component
|
|
41
|
+
if (currentPage === 0 || (paginationRange?.length ?? 0) < 2) {
|
|
42
|
+
return null
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const maybeLastPage = paginationRange?.[paginationRange.length - 1]
|
|
46
|
+
const lastPage = typeof maybeLastPage === 'number' ? maybeLastPage : 1
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<div
|
|
50
|
+
className={twMerge(
|
|
51
|
+
'flex flex-row items-center justify-center gap-x-2',
|
|
52
|
+
className,
|
|
53
|
+
)}
|
|
54
|
+
>
|
|
55
|
+
<a
|
|
56
|
+
// Navigation both with and without JS
|
|
57
|
+
href={`?${buildUrlForPage(currentPage > 1 ? currentPage - 1 : 1)}`}
|
|
58
|
+
onClick={(e) => {
|
|
59
|
+
e.stopPropagation()
|
|
60
|
+
e.preventDefault()
|
|
61
|
+
if (currentPage > 1) {
|
|
62
|
+
onPageChange(currentPage - 1)
|
|
63
|
+
}
|
|
64
|
+
}}
|
|
65
|
+
className={twMerge(currentPage === 1 ? 'cursor-default' : '')}
|
|
66
|
+
>
|
|
67
|
+
<Button
|
|
68
|
+
variant="secondary"
|
|
69
|
+
size="sm"
|
|
70
|
+
asChild
|
|
71
|
+
disabled={currentPage === 1}
|
|
72
|
+
className={twMerge(
|
|
73
|
+
currentPage === 1 ? 'cursor-default opacity-50' : '',
|
|
74
|
+
)}
|
|
75
|
+
>
|
|
76
|
+
<ChevronLeft fontSize="small" />
|
|
77
|
+
</Button>
|
|
78
|
+
</a>
|
|
79
|
+
{paginationRange?.map((pageNumber, idx) => {
|
|
80
|
+
// If the pageItem is a DOT, render the DOTS unicode character
|
|
81
|
+
if (typeof pageNumber !== 'number') {
|
|
82
|
+
return (
|
|
83
|
+
<div className="dark:text-pago-400 text-gray-400" key={idx}>
|
|
84
|
+
…
|
|
85
|
+
</div>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Render page pills
|
|
90
|
+
return (
|
|
91
|
+
<a
|
|
92
|
+
href={`?${buildUrlForPage(pageNumber)}`}
|
|
93
|
+
key={idx}
|
|
94
|
+
onClick={(e) => {
|
|
95
|
+
e.stopPropagation()
|
|
96
|
+
e.preventDefault()
|
|
97
|
+
if (pageNumber !== currentPage) onPageChange(pageNumber)
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
<Button
|
|
101
|
+
asChild
|
|
102
|
+
variant={pageNumber === currentPage ? 'default' : 'secondary'}
|
|
103
|
+
size="sm"
|
|
104
|
+
>
|
|
105
|
+
{pageNumber}
|
|
106
|
+
</Button>
|
|
107
|
+
</a>
|
|
108
|
+
)
|
|
109
|
+
})}
|
|
110
|
+
|
|
111
|
+
<a
|
|
112
|
+
href={`?${buildUrlForPage(lastPage)}`}
|
|
113
|
+
onClick={(e) => {
|
|
114
|
+
e.stopPropagation()
|
|
115
|
+
e.preventDefault()
|
|
116
|
+
if (currentPage < lastPage) {
|
|
117
|
+
onPageChange(currentPage + 1)
|
|
118
|
+
}
|
|
119
|
+
}}
|
|
120
|
+
className={twMerge(currentPage >= lastPage ? 'cursor-default' : '')}
|
|
121
|
+
>
|
|
122
|
+
<Button
|
|
123
|
+
variant="secondary"
|
|
124
|
+
asChild
|
|
125
|
+
size="sm"
|
|
126
|
+
disabled={currentPage >= lastPage}
|
|
127
|
+
className={twMerge(
|
|
128
|
+
currentPage >= lastPage ? 'cursor-default opacity-50' : '',
|
|
129
|
+
)}
|
|
130
|
+
>
|
|
131
|
+
<ChevronRight fontSize="small" />
|
|
132
|
+
</Button>
|
|
133
|
+
</a>
|
|
134
|
+
</div>
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export default Paginator
|
|
139
|
+
|
|
140
|
+
const range = (start: number, end: number) => {
|
|
141
|
+
const length = end - start + 1
|
|
142
|
+
/*
|
|
143
|
+
Create an array of certain length and set the elements within it from
|
|
144
|
+
start value to end value.
|
|
145
|
+
*/
|
|
146
|
+
return Array.from({ length }, (_, idx) => idx + start)
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const DOTS = Symbol('DOTS')
|
|
150
|
+
|
|
151
|
+
export const usePagination = ({
|
|
152
|
+
totalCount,
|
|
153
|
+
pageSize,
|
|
154
|
+
siblingCount = 1,
|
|
155
|
+
currentPage,
|
|
156
|
+
}: {
|
|
157
|
+
totalCount: number
|
|
158
|
+
pageSize: number
|
|
159
|
+
siblingCount?: number
|
|
160
|
+
currentPage: number
|
|
161
|
+
}) => {
|
|
162
|
+
const paginationRange = useMemo(() => {
|
|
163
|
+
const totalPageCount = Math.ceil(totalCount / pageSize)
|
|
164
|
+
|
|
165
|
+
// Pages count is determined as siblingCount + firstPage + lastPage + currentPage + 2*DOTS
|
|
166
|
+
const totalPageNumbers = siblingCount + 5
|
|
167
|
+
|
|
168
|
+
/*
|
|
169
|
+
Case 1:
|
|
170
|
+
If the number of pages is less than the page numbers we want to show in our
|
|
171
|
+
paginationComponent, we return the range [1..totalPageCount]
|
|
172
|
+
*/
|
|
173
|
+
if (totalPageNumbers >= totalPageCount) {
|
|
174
|
+
return range(1, totalPageCount)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/*
|
|
178
|
+
Calculate left and right sibling index and make sure they are within range 1 and totalPageCount
|
|
179
|
+
*/
|
|
180
|
+
const leftSiblingIndex = Math.max(currentPage - siblingCount, 1)
|
|
181
|
+
const rightSiblingIndex = Math.min(
|
|
182
|
+
currentPage + siblingCount,
|
|
183
|
+
totalPageCount,
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
/*
|
|
187
|
+
We do not show dots just when there is just one page number to be inserted between the extremes of sibling and the page limits i.e 1 and totalPageCount. Hence we are using leftSiblingIndex > 2 and rightSiblingIndex < totalPageCount - 2
|
|
188
|
+
*/
|
|
189
|
+
const shouldShowLeftDots = leftSiblingIndex > 2
|
|
190
|
+
const shouldShowRightDots = rightSiblingIndex < totalPageCount - 2
|
|
191
|
+
|
|
192
|
+
const firstPageIndex = 1
|
|
193
|
+
const lastPageIndex = totalPageCount
|
|
194
|
+
|
|
195
|
+
/*
|
|
196
|
+
Case 2: No left dots to show, but rights dots to be shown
|
|
197
|
+
*/
|
|
198
|
+
if (!shouldShowLeftDots && shouldShowRightDots) {
|
|
199
|
+
const leftItemCount = 3 + 2 * siblingCount
|
|
200
|
+
const leftRange = range(1, leftItemCount)
|
|
201
|
+
|
|
202
|
+
return [...leftRange, DOTS, totalPageCount]
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/*
|
|
206
|
+
Case 3: No right dots to show, but left dots to be shown
|
|
207
|
+
*/
|
|
208
|
+
if (shouldShowLeftDots && !shouldShowRightDots) {
|
|
209
|
+
const rightItemCount = 3 + 2 * siblingCount
|
|
210
|
+
const rightRange = range(
|
|
211
|
+
totalPageCount - rightItemCount + 1,
|
|
212
|
+
totalPageCount,
|
|
213
|
+
)
|
|
214
|
+
return [firstPageIndex, DOTS, ...rightRange]
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/*
|
|
218
|
+
Case 4: Both left and right dots to be shown
|
|
219
|
+
*/
|
|
220
|
+
if (shouldShowLeftDots && shouldShowRightDots) {
|
|
221
|
+
const middleRange = range(leftSiblingIndex, rightSiblingIndex)
|
|
222
|
+
return [firstPageIndex, DOTS, ...middleRange, DOTS, lastPageIndex]
|
|
223
|
+
}
|
|
224
|
+
}, [totalCount, pageSize, siblingCount, currentPage])
|
|
225
|
+
|
|
226
|
+
return paginationRange
|
|
227
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import TimeAgo from 'react-timeago'
|
|
2
|
+
|
|
3
|
+
const PagoTimeAgo = (props: { date: Date; suffix?: string }) => {
|
|
4
|
+
return (
|
|
5
|
+
<TimeAgo
|
|
6
|
+
date={props.date}
|
|
7
|
+
formatter={(value: number, unit: string, suffix: string) => {
|
|
8
|
+
if (unit === 'second') {
|
|
9
|
+
return 'just now'
|
|
10
|
+
}
|
|
11
|
+
return `${value} ${unit}${value !== 1 ? 's' : ''} ${
|
|
12
|
+
props.suffix ?? suffix
|
|
13
|
+
}`
|
|
14
|
+
}}
|
|
15
|
+
/>
|
|
16
|
+
)
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export default PagoTimeAgo
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { Percent } from 'lucide-react'
|
|
2
|
+
import {
|
|
3
|
+
ChangeEvent,
|
|
4
|
+
FocusEvent,
|
|
5
|
+
InputEvent,
|
|
6
|
+
useCallback,
|
|
7
|
+
useState,
|
|
8
|
+
} from 'react'
|
|
9
|
+
import { twMerge } from 'tailwind-merge'
|
|
10
|
+
import { Input } from '@pago-sh/orbit'
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
name: string
|
|
14
|
+
placeholder: number
|
|
15
|
+
id?: string
|
|
16
|
+
onChange?: (value: number) => void
|
|
17
|
+
onBlur?: (e: ChangeEvent<HTMLInputElement>) => void
|
|
18
|
+
onFocus?: (e: FocusEvent<HTMLInputElement>) => void
|
|
19
|
+
value?: number
|
|
20
|
+
className?: string
|
|
21
|
+
disabled?: boolean
|
|
22
|
+
preSlot?: React.ReactNode
|
|
23
|
+
postSlot?: React.ReactNode
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const getPercentageBasisPoints = (value: string): number => {
|
|
27
|
+
let newAmount = Number.parseFloat(value)
|
|
28
|
+
if (isNaN(newAmount)) {
|
|
29
|
+
newAmount = 0
|
|
30
|
+
}
|
|
31
|
+
return Math.round(newAmount * 100)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const PercentageInput = (props: Props) => {
|
|
35
|
+
const {
|
|
36
|
+
id,
|
|
37
|
+
name,
|
|
38
|
+
value,
|
|
39
|
+
placeholder,
|
|
40
|
+
preSlot,
|
|
41
|
+
postSlot,
|
|
42
|
+
onChange: _onChange,
|
|
43
|
+
onBlur,
|
|
44
|
+
onFocus,
|
|
45
|
+
disabled,
|
|
46
|
+
} = props
|
|
47
|
+
const [internalValue, setInternalValue] = useState<string | undefined>(
|
|
48
|
+
value ? (value / 100).toFixed(2) : undefined,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const onChange = useCallback(
|
|
52
|
+
(e: ChangeEvent<HTMLInputElement>) => {
|
|
53
|
+
if (_onChange) {
|
|
54
|
+
_onChange(getPercentageBasisPoints(e.target.value))
|
|
55
|
+
}
|
|
56
|
+
setInternalValue(e.target.value)
|
|
57
|
+
},
|
|
58
|
+
[_onChange],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
const onInput = (e: InputEvent<HTMLInputElement>) => {
|
|
62
|
+
const value = e.currentTarget.value
|
|
63
|
+
const regex = /^\d+([.,]\d{0,2})?$/
|
|
64
|
+
if (!regex.test(value)) {
|
|
65
|
+
e.currentTarget.value = Number.parseFloat(value).toFixed(2)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<Input
|
|
71
|
+
type="number"
|
|
72
|
+
step={0.01}
|
|
73
|
+
min={0.01}
|
|
74
|
+
max={100}
|
|
75
|
+
id={id}
|
|
76
|
+
name={name}
|
|
77
|
+
className={twMerge(
|
|
78
|
+
'dark:placeholder:text-pago-500 block w-full px-4 text-base placeholder:text-gray-400',
|
|
79
|
+
props.className ?? '',
|
|
80
|
+
)}
|
|
81
|
+
value={internalValue}
|
|
82
|
+
onChange={onChange}
|
|
83
|
+
onInput={onInput}
|
|
84
|
+
placeholder={placeholder ? `${placeholder / 100}` : undefined}
|
|
85
|
+
postSlot={postSlot ? postSlot : <Percent className="h-4 w-4" />}
|
|
86
|
+
preSlot={preSlot}
|
|
87
|
+
onBlur={onBlur}
|
|
88
|
+
onFocus={onFocus}
|
|
89
|
+
onWheel={(e) => {
|
|
90
|
+
;(e.target as HTMLInputElement).blur()
|
|
91
|
+
}}
|
|
92
|
+
disabled={disabled}
|
|
93
|
+
/>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export default PercentageInput
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react'
|
|
2
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
|
+
import ShadowBoxOnMd from './ShadowBoxOnMd'
|
|
4
|
+
|
|
5
|
+
const ShadowBox = ({
|
|
6
|
+
ref,
|
|
7
|
+
...props
|
|
8
|
+
}: PropsWithChildren<{ className?: string }> & {
|
|
9
|
+
ref?: React.RefObject<HTMLDivElement>
|
|
10
|
+
}) => (
|
|
11
|
+
<div
|
|
12
|
+
ref={ref}
|
|
13
|
+
className={twMerge(
|
|
14
|
+
'dark:bg-pago-900 dark:border-pago-700 w-full rounded-xl border border-transparent bg-gray-50 p-8 lg:rounded-4xl',
|
|
15
|
+
props.className,
|
|
16
|
+
)}
|
|
17
|
+
>
|
|
18
|
+
{props.children}
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
ShadowBox.displayName = 'ShadowBox'
|
|
23
|
+
|
|
24
|
+
export default ShadowBox
|
|
25
|
+
|
|
26
|
+
export { ShadowBoxOnMd }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { DetailedHTMLProps } from 'react'
|
|
2
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
|
+
|
|
4
|
+
const ShadowBoxOnMd = ({
|
|
5
|
+
className,
|
|
6
|
+
children,
|
|
7
|
+
...props
|
|
8
|
+
}: DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>) => (
|
|
9
|
+
<div
|
|
10
|
+
className={twMerge(
|
|
11
|
+
'md:dark:bg-pago-900 dark:border-pago-700 w-full md:rounded-xl md:border md:border-transparent md:bg-gray-50 md:p-8 lg:rounded-4xl',
|
|
12
|
+
className,
|
|
13
|
+
)}
|
|
14
|
+
{...props}
|
|
15
|
+
>
|
|
16
|
+
{children}
|
|
17
|
+
</div>
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
export default ShadowBoxOnMd
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@/components/ui/sidebar'
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { twMerge } from 'tailwind-merge'
|
|
3
|
+
|
|
4
|
+
type Color = 'default' | 'muted' | 'red' | 'green' | 'blue'
|
|
5
|
+
|
|
6
|
+
const Banner = ({
|
|
7
|
+
children,
|
|
8
|
+
right,
|
|
9
|
+
color,
|
|
10
|
+
}: {
|
|
11
|
+
children: React.ReactNode
|
|
12
|
+
right?: React.ReactNode
|
|
13
|
+
color: Color
|
|
14
|
+
}) => {
|
|
15
|
+
return (
|
|
16
|
+
<div
|
|
17
|
+
className={twMerge(
|
|
18
|
+
'flex items-center justify-between gap-2 rounded-lg px-3 py-2 text-sm',
|
|
19
|
+
color === 'default'
|
|
20
|
+
? 'dark:bg-pago-800 dark:ring-pago-700 bg-white ring-1 ring-gray-100'
|
|
21
|
+
: '',
|
|
22
|
+
color === 'muted'
|
|
23
|
+
? 'dark:bg-pago-800 dark:border-pago-700 border bg-gray-100 text-gray-500'
|
|
24
|
+
: '',
|
|
25
|
+
color === 'red'
|
|
26
|
+
? 'border bg-red-100 text-red-600 dark:border-red-900 dark:bg-red-950/50 dark:text-red-600'
|
|
27
|
+
: '',
|
|
28
|
+
color === 'green'
|
|
29
|
+
? 'border bg-green-100 text-green-600 dark:border-green-800 dark:bg-green-900 dark:text-green-200'
|
|
30
|
+
: '',
|
|
31
|
+
color === 'blue'
|
|
32
|
+
? 'border border-blue-100 bg-blue-50 text-blue-500 dark:border-blue-700 dark:bg-blue-900 dark:text-blue-300'
|
|
33
|
+
: '',
|
|
34
|
+
)}
|
|
35
|
+
>
|
|
36
|
+
<div className="flex flex-1 items-center gap-2">{children}</div>
|
|
37
|
+
{right && <div>{right}</div>}
|
|
38
|
+
</div>
|
|
39
|
+
)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default Banner
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as AccordionPrimitive from '@radix-ui/react-accordion'
|
|
4
|
+
import { ChevronDown } from 'lucide-react'
|
|
5
|
+
import * as React from 'react'
|
|
6
|
+
|
|
7
|
+
import { cn } from '@/lib/utils'
|
|
8
|
+
|
|
9
|
+
const Accordion = AccordionPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AccordionItem = ({
|
|
12
|
+
ref,
|
|
13
|
+
className,
|
|
14
|
+
...props
|
|
15
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Item>) => (
|
|
16
|
+
<AccordionPrimitive.Item
|
|
17
|
+
ref={ref}
|
|
18
|
+
className={cn('border-b', className)}
|
|
19
|
+
{...props}
|
|
20
|
+
/>
|
|
21
|
+
)
|
|
22
|
+
AccordionItem.displayName = 'AccordionItem'
|
|
23
|
+
|
|
24
|
+
const AccordionTrigger = ({
|
|
25
|
+
ref,
|
|
26
|
+
className,
|
|
27
|
+
children,
|
|
28
|
+
...props
|
|
29
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Trigger>) => (
|
|
30
|
+
<AccordionPrimitive.Header className="flex">
|
|
31
|
+
<AccordionPrimitive.Trigger
|
|
32
|
+
ref={ref}
|
|
33
|
+
className={cn(
|
|
34
|
+
'flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180',
|
|
35
|
+
className,
|
|
36
|
+
)}
|
|
37
|
+
{...props}
|
|
38
|
+
>
|
|
39
|
+
{children}
|
|
40
|
+
<ChevronDown className="h-4 w-4 shrink-0 transition-transform duration-200" />
|
|
41
|
+
</AccordionPrimitive.Trigger>
|
|
42
|
+
</AccordionPrimitive.Header>
|
|
43
|
+
)
|
|
44
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
|
45
|
+
|
|
46
|
+
const AccordionContent = ({
|
|
47
|
+
ref,
|
|
48
|
+
className,
|
|
49
|
+
children,
|
|
50
|
+
...props
|
|
51
|
+
}: React.ComponentProps<typeof AccordionPrimitive.Content>) => (
|
|
52
|
+
<AccordionPrimitive.Content
|
|
53
|
+
ref={ref}
|
|
54
|
+
className="data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down overflow-hidden text-sm transition-all"
|
|
55
|
+
{...props}
|
|
56
|
+
>
|
|
57
|
+
<div className={cn('pt-0 pb-4', className)}>{children}</div>
|
|
58
|
+
</AccordionPrimitive.Content>
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
|
62
|
+
|
|
63
|
+
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger }
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
|
|
6
|
+
import { buttonVariants } from '@pago-sh/orbit/ui/button'
|
|
7
|
+
import { cn } from '@/lib/utils'
|
|
8
|
+
|
|
9
|
+
const AlertDialog = AlertDialogPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AlertDialogTrigger = AlertDialogPrimitive.Trigger
|
|
12
|
+
|
|
13
|
+
const AlertDialogPortal = AlertDialogPrimitive.Portal
|
|
14
|
+
|
|
15
|
+
const AlertDialogOverlay = ({
|
|
16
|
+
ref,
|
|
17
|
+
className,
|
|
18
|
+
...props
|
|
19
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Overlay>) => (
|
|
20
|
+
<AlertDialogPrimitive.Overlay
|
|
21
|
+
className={cn(
|
|
22
|
+
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
|
23
|
+
className,
|
|
24
|
+
)}
|
|
25
|
+
{...props}
|
|
26
|
+
ref={ref}
|
|
27
|
+
/>
|
|
28
|
+
)
|
|
29
|
+
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName
|
|
30
|
+
|
|
31
|
+
const AlertDialogContent = ({
|
|
32
|
+
ref,
|
|
33
|
+
className,
|
|
34
|
+
...props
|
|
35
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Content>) => (
|
|
36
|
+
<AlertDialogPortal>
|
|
37
|
+
<AlertDialogOverlay />
|
|
38
|
+
<AlertDialogPrimitive.Content
|
|
39
|
+
ref={ref}
|
|
40
|
+
className={cn(
|
|
41
|
+
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
|
|
42
|
+
className,
|
|
43
|
+
)}
|
|
44
|
+
{...props}
|
|
45
|
+
/>
|
|
46
|
+
</AlertDialogPortal>
|
|
47
|
+
)
|
|
48
|
+
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName
|
|
49
|
+
|
|
50
|
+
const AlertDialogHeader = ({
|
|
51
|
+
className,
|
|
52
|
+
...props
|
|
53
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
54
|
+
<div
|
|
55
|
+
className={cn(
|
|
56
|
+
'flex flex-col space-y-2 text-center sm:text-left',
|
|
57
|
+
className,
|
|
58
|
+
)}
|
|
59
|
+
{...props}
|
|
60
|
+
/>
|
|
61
|
+
)
|
|
62
|
+
AlertDialogHeader.displayName = 'AlertDialogHeader'
|
|
63
|
+
|
|
64
|
+
const AlertDialogFooter = ({
|
|
65
|
+
className,
|
|
66
|
+
...props
|
|
67
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
68
|
+
<div
|
|
69
|
+
className={cn(
|
|
70
|
+
'flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2',
|
|
71
|
+
className,
|
|
72
|
+
)}
|
|
73
|
+
{...props}
|
|
74
|
+
/>
|
|
75
|
+
)
|
|
76
|
+
AlertDialogFooter.displayName = 'AlertDialogFooter'
|
|
77
|
+
|
|
78
|
+
const AlertDialogTitle = ({
|
|
79
|
+
ref,
|
|
80
|
+
className,
|
|
81
|
+
...props
|
|
82
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Title>) => (
|
|
83
|
+
<AlertDialogPrimitive.Title
|
|
84
|
+
ref={ref}
|
|
85
|
+
className={cn('text-lg font-semibold', className)}
|
|
86
|
+
{...props}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName
|
|
90
|
+
|
|
91
|
+
const AlertDialogDescription = ({
|
|
92
|
+
ref,
|
|
93
|
+
className,
|
|
94
|
+
...props
|
|
95
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Description>) => (
|
|
96
|
+
<AlertDialogPrimitive.Description
|
|
97
|
+
ref={ref}
|
|
98
|
+
className={cn('text-muted-foreground text-sm', className)}
|
|
99
|
+
{...props}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
AlertDialogDescription.displayName =
|
|
103
|
+
AlertDialogPrimitive.Description.displayName
|
|
104
|
+
|
|
105
|
+
const AlertDialogAction = ({
|
|
106
|
+
ref,
|
|
107
|
+
className,
|
|
108
|
+
...props
|
|
109
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Action>) => (
|
|
110
|
+
<AlertDialogPrimitive.Action
|
|
111
|
+
ref={ref}
|
|
112
|
+
className={cn(buttonVariants(), className)}
|
|
113
|
+
{...props}
|
|
114
|
+
/>
|
|
115
|
+
)
|
|
116
|
+
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName
|
|
117
|
+
|
|
118
|
+
const AlertDialogCancel = ({
|
|
119
|
+
ref,
|
|
120
|
+
className,
|
|
121
|
+
...props
|
|
122
|
+
}: React.ComponentProps<typeof AlertDialogPrimitive.Cancel>) => (
|
|
123
|
+
<AlertDialogPrimitive.Cancel
|
|
124
|
+
ref={ref}
|
|
125
|
+
className={cn(
|
|
126
|
+
buttonVariants({ variant: 'outline' }),
|
|
127
|
+
'mt-2 sm:mt-0',
|
|
128
|
+
className,
|
|
129
|
+
)}
|
|
130
|
+
{...props}
|
|
131
|
+
/>
|
|
132
|
+
)
|
|
133
|
+
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName
|
|
134
|
+
|
|
135
|
+
export {
|
|
136
|
+
AlertDialog,
|
|
137
|
+
AlertDialogAction,
|
|
138
|
+
AlertDialogCancel,
|
|
139
|
+
AlertDialogContent,
|
|
140
|
+
AlertDialogDescription,
|
|
141
|
+
AlertDialogFooter,
|
|
142
|
+
AlertDialogHeader,
|
|
143
|
+
AlertDialogOverlay,
|
|
144
|
+
AlertDialogPortal,
|
|
145
|
+
AlertDialogTitle,
|
|
146
|
+
AlertDialogTrigger,
|
|
147
|
+
}
|