create-nextjs-cms 0.5.8
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/LICENSE +21 -0
- package/README.md +71 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +395 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.d.ts.map +1 -0
- package/dist/lib/utils.js +48 -0
- package/package.json +44 -0
- package/templates/default/.env +24 -0
- package/templates/default/.env.development +8 -0
- package/templates/default/.eslintrc.json +5 -0
- package/templates/default/.prettierignore +7 -0
- package/templates/default/.prettierrc.json +19 -0
- package/templates/default/CHANGELOG.md +77 -0
- package/templates/default/README.md +45 -0
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +175 -0
- package/templates/default/app/(auth)/auth/login/page.tsx +12 -0
- package/templates/default/app/(rootLayout)/admins/page.tsx +5 -0
- package/templates/default/app/(rootLayout)/advanced/page.tsx +5 -0
- package/templates/default/app/(rootLayout)/analytics/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/dashboard/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/emails/page.tsx +6 -0
- package/templates/default/app/(rootLayout)/layout.tsx +5 -0
- package/templates/default/app/(rootLayout)/loading.tsx +10 -0
- package/templates/default/app/(rootLayout)/log/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/new/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/page.tsx +9 -0
- package/templates/default/app/(rootLayout)/section/[section]/page.tsx +7 -0
- package/templates/default/app/(rootLayout)/settings/page.tsx +7 -0
- package/templates/default/app/_trpc/client.ts +4 -0
- package/templates/default/app/api/auth/csrf/route.ts +25 -0
- package/templates/default/app/api/auth/refresh/route.ts +10 -0
- package/templates/default/app/api/auth/route.ts +23 -0
- package/templates/default/app/api/auth/session/route.ts +20 -0
- package/templates/default/app/api/editor/photo/route.ts +42 -0
- package/templates/default/app/api/photo/route.ts +27 -0
- package/templates/default/app/api/placeholder/route.ts +7 -0
- package/templates/default/app/api/submit/section/item/[slug]/route.ts +63 -0
- package/templates/default/app/api/submit/section/item/route.ts +53 -0
- package/templates/default/app/api/submit/section/simple/route.ts +54 -0
- package/templates/default/app/api/trpc/[trpc]/route.ts +33 -0
- package/templates/default/app/api/video/route.ts +174 -0
- package/templates/default/app/dictionaries.ts +14 -0
- package/templates/default/app/layout.tsx +28 -0
- package/templates/default/app/providers.tsx +151 -0
- package/templates/default/cli.ts +4 -0
- package/templates/default/components/AdminCard.tsx +163 -0
- package/templates/default/components/AdminEditPage.tsx +123 -0
- package/templates/default/components/AdminPrivilegeCard.tsx +184 -0
- package/templates/default/components/AdminsPage.tsx +43 -0
- package/templates/default/components/AdvancedSettingsPage.tsx +167 -0
- package/templates/default/components/AnalyticsPage.tsx +127 -0
- package/templates/default/components/BarChartBox.tsx +43 -0
- package/templates/default/components/BrowsePage.tsx +119 -0
- package/templates/default/components/CategorizedSectionPage.tsx +36 -0
- package/templates/default/components/CategoryDeleteConfirmPage.tsx +129 -0
- package/templates/default/components/CategorySectionSelectInput.tsx +139 -0
- package/templates/default/components/ConditionalFields.tsx +49 -0
- package/templates/default/components/ContainerBox.tsx +24 -0
- package/templates/default/components/DashboardPage.tsx +187 -0
- package/templates/default/components/DashboardPageAlt.tsx +43 -0
- package/templates/default/components/DefaultNavItems.tsx +3 -0
- package/templates/default/components/Dropzone.tsx +153 -0
- package/templates/default/components/EmailCard.tsx +137 -0
- package/templates/default/components/EmailPasswordForm.tsx +84 -0
- package/templates/default/components/EmailQuotaForm.tsx +72 -0
- package/templates/default/components/EmailsPage.tsx +48 -0
- package/templates/default/components/GalleryPhoto.tsx +93 -0
- package/templates/default/components/InfoCard.tsx +94 -0
- package/templates/default/components/ItemEditPage.tsx +217 -0
- package/templates/default/components/Layout.tsx +70 -0
- package/templates/default/components/LoadingSpinners.tsx +67 -0
- package/templates/default/components/LogPage.tsx +17 -0
- package/templates/default/components/Modal.tsx +99 -0
- package/templates/default/components/Navbar.tsx +29 -0
- package/templates/default/components/NavbarAlt.tsx +182 -0
- package/templates/default/components/NewAdminForm.tsx +172 -0
- package/templates/default/components/NewEmailForm.tsx +131 -0
- package/templates/default/components/NewPage.tsx +206 -0
- package/templates/default/components/NewVariantComponent.tsx +228 -0
- package/templates/default/components/PhotoGallery.tsx +35 -0
- package/templates/default/components/PieChartBox.tsx +101 -0
- package/templates/default/components/ProgressBar.tsx +24 -0
- package/templates/default/components/ProtectedDocument.tsx +78 -0
- package/templates/default/components/ProtectedImage.tsx +143 -0
- package/templates/default/components/ProtectedVideo.tsx +76 -0
- package/templates/default/components/SectionItemCard.tsx +143 -0
- package/templates/default/components/SectionItemStatusBadge.tsx +16 -0
- package/templates/default/components/SectionPage.tsx +124 -0
- package/templates/default/components/SelectBox.tsx +99 -0
- package/templates/default/components/SelectInputButtons.tsx +124 -0
- package/templates/default/components/SettingsPage.tsx +238 -0
- package/templates/default/components/Sidebar.tsx +209 -0
- package/templates/default/components/SidebarDropdownItem.tsx +74 -0
- package/templates/default/components/SidebarItem.tsx +19 -0
- package/templates/default/components/TempPage.tsx +12 -0
- package/templates/default/components/ThemeProvider.tsx +8 -0
- package/templates/default/components/TooltipComponent.tsx +27 -0
- package/templates/default/components/VariantCard.tsx +123 -0
- package/templates/default/components/VariantEditPage.tsx +229 -0
- package/templates/default/components/analytics/BounceRate.tsx +69 -0
- package/templates/default/components/analytics/LivePageViews.tsx +54 -0
- package/templates/default/components/analytics/LiveUsersCount.tsx +32 -0
- package/templates/default/components/analytics/MonthlyPageViews.tsx +41 -0
- package/templates/default/components/analytics/TopCountries.tsx +51 -0
- package/templates/default/components/analytics/TopDevices.tsx +45 -0
- package/templates/default/components/analytics/TopMediums.tsx +57 -0
- package/templates/default/components/analytics/TopSources.tsx +44 -0
- package/templates/default/components/analytics/TotalPageViews.tsx +40 -0
- package/templates/default/components/analytics/TotalSessions.tsx +40 -0
- package/templates/default/components/analytics/TotalUniqueUsers.tsx +40 -0
- package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +137 -0
- package/templates/default/components/dndKit/Draggable.tsx +21 -0
- package/templates/default/components/dndKit/Droppable.tsx +20 -0
- package/templates/default/components/dndKit/SortableItem.tsx +18 -0
- package/templates/default/components/form/DateRangeFormInput.tsx +55 -0
- package/templates/default/components/form/Form.tsx +298 -0
- package/templates/default/components/form/FormInputElement.tsx +68 -0
- package/templates/default/components/form/FormInputs.tsx +108 -0
- package/templates/default/components/form/helpers/util.ts +20 -0
- package/templates/default/components/form/inputs/CheckboxFormInput.tsx +33 -0
- package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -0
- package/templates/default/components/form/inputs/DateFormInput.tsx +107 -0
- package/templates/default/components/form/inputs/DocumentFormInput.tsx +124 -0
- package/templates/default/components/form/inputs/MapFormInput.tsx +139 -0
- package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +150 -0
- package/templates/default/components/form/inputs/NumberFormInput.tsx +42 -0
- package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -0
- package/templates/default/components/form/inputs/PhotoFormInput.tsx +218 -0
- package/templates/default/components/form/inputs/RichTextFormInput.tsx +133 -0
- package/templates/default/components/form/inputs/SelectFormInput.tsx +164 -0
- package/templates/default/components/form/inputs/TagsFormInput.tsx +63 -0
- package/templates/default/components/form/inputs/TextFormInput.tsx +48 -0
- package/templates/default/components/form/inputs/TextareaFormInput.tsx +47 -0
- package/templates/default/components/form/inputs/VideoFormInput.tsx +117 -0
- package/templates/default/components/pagination/Pagination.tsx +36 -0
- package/templates/default/components/pagination/PaginationButtons.tsx +145 -0
- package/templates/default/components/ui/accordion.tsx +57 -0
- package/templates/default/components/ui/alert.tsx +46 -0
- package/templates/default/components/ui/badge.tsx +33 -0
- package/templates/default/components/ui/button.tsx +57 -0
- package/templates/default/components/ui/calendar.tsx +68 -0
- package/templates/default/components/ui/card.tsx +76 -0
- package/templates/default/components/ui/checkbox.tsx +29 -0
- package/templates/default/components/ui/dropdown-menu.tsx +205 -0
- package/templates/default/components/ui/input.tsx +25 -0
- package/templates/default/components/ui/label.tsx +26 -0
- package/templates/default/components/ui/popover.tsx +31 -0
- package/templates/default/components/ui/scroll-area.tsx +42 -0
- package/templates/default/components/ui/select.tsx +164 -0
- package/templates/default/components/ui/sheet.tsx +107 -0
- package/templates/default/components/ui/switch.tsx +29 -0
- package/templates/default/components/ui/table.tsx +120 -0
- package/templates/default/components/ui/tabs.tsx +55 -0
- package/templates/default/components/ui/toast.tsx +113 -0
- package/templates/default/components/ui/toaster.tsx +35 -0
- package/templates/default/components/ui/tooltip.tsx +30 -0
- package/templates/default/components/ui/use-toast.ts +188 -0
- package/templates/default/components.json +16 -0
- package/templates/default/context/ModalProvider.tsx +53 -0
- package/templates/default/drizzle.config.ts +4 -0
- package/templates/default/dynamic-schemas/schema.ts +373 -0
- package/templates/default/env/env.js +130 -0
- package/templates/default/envConfig.ts +4 -0
- package/templates/default/hooks/useModal.ts +8 -0
- package/templates/default/lib/apiHelpers.ts +106 -0
- package/templates/default/lz.config.ts +40 -0
- package/templates/default/middleware.ts +33 -0
- package/templates/default/next.config.ts +46 -0
- package/templates/default/package.json +134 -0
- package/templates/default/postcss.config.js +6 -0
- package/templates/default/postinstall.js +14 -0
- package/templates/default/public/blank_avatar.png +0 -0
- package/templates/default/public/favicon.ico +0 -0
- package/templates/default/public/img/placeholder.svg +1 -0
- package/templates/default/public/lazemni_logo.png +0 -0
- package/templates/default/public/next.svg +1 -0
- package/templates/default/public/vercel.svg +1 -0
- package/templates/default/section-tests.ts +92 -0
- package/templates/default/styles/globals.css +88 -0
- package/templates/default/tailwind.config.js +95 -0
- package/templates/default/test.ts +77 -0
- package/templates/default/tsconfig.json +44 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import React, { useRef, useState } from 'react'
|
|
2
|
+
import getString from 'nextjs-cms/translations'
|
|
3
|
+
import FormInputElement from '@/components/form/FormInputElement'
|
|
4
|
+
import ProtectedVideo from '@/components/ProtectedVideo'
|
|
5
|
+
import { VideoFieldClientConfig } from 'nextjs-cms/core/fields'
|
|
6
|
+
import { ChevronRight, X } from 'lucide-react'
|
|
7
|
+
import { useController, useFormContext } from 'react-hook-form'
|
|
8
|
+
|
|
9
|
+
export default function VideoFormInput({ input, sectionName }: { input: VideoFieldClientConfig; sectionName: string }) {
|
|
10
|
+
const { control } = useFormContext()
|
|
11
|
+
const {
|
|
12
|
+
field,
|
|
13
|
+
fieldState: { invalid, isTouched, isDirty, error },
|
|
14
|
+
} = useController({
|
|
15
|
+
name: input.name,
|
|
16
|
+
control,
|
|
17
|
+
defaultValue: input.value ?? '',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const [fileName, setFileName] = useState(getString('no_file_selected'))
|
|
21
|
+
const fileInputContainerRef = useRef<HTMLInputElement>(null)
|
|
22
|
+
const [image, setImage] = useState<string | null>(null)
|
|
23
|
+
|
|
24
|
+
const onImageChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
|
25
|
+
if (event.target.files && event.target.files[0]) {
|
|
26
|
+
setFileName(event.target.files?.[0].name || getString('no_file_selected'))
|
|
27
|
+
setImage(URL.createObjectURL(event.target.files[0]))
|
|
28
|
+
} else {
|
|
29
|
+
setFileName(getString('no_file_selected'))
|
|
30
|
+
setImage(null)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const protectedVideo = (
|
|
35
|
+
<ProtectedVideo
|
|
36
|
+
section={sectionName}
|
|
37
|
+
fieldName={input.name}
|
|
38
|
+
file={input.value}
|
|
39
|
+
width={400}
|
|
40
|
+
height={280}
|
|
41
|
+
className='mb-4 rounded p-1 ring ring-gray-400'
|
|
42
|
+
/>
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<FormInputElement
|
|
47
|
+
validationError={error}
|
|
48
|
+
value={protectedVideo}
|
|
49
|
+
readonly={input.readonly}
|
|
50
|
+
label={input.label}
|
|
51
|
+
required={input.required}
|
|
52
|
+
>
|
|
53
|
+
<div className='flex flex-row gap-2'>
|
|
54
|
+
{input.value ? protectedVideo : null}
|
|
55
|
+
{image && (
|
|
56
|
+
<div className='relative flex items-center'>
|
|
57
|
+
<ChevronRight fontSize='large' />
|
|
58
|
+
<div className='relative'>
|
|
59
|
+
<X
|
|
60
|
+
className='absolute -right-3 -top-3 cursor-pointer rounded-full border-2 border-gray-500 bg-white p-1'
|
|
61
|
+
onClick={() => {
|
|
62
|
+
setImage(null)
|
|
63
|
+
setFileName(getString('no_file_selected'))
|
|
64
|
+
field.onChange(undefined)
|
|
65
|
+
/**
|
|
66
|
+
* Clear the child input value
|
|
67
|
+
*/
|
|
68
|
+
if (fileInputContainerRef.current?.firstChild) {
|
|
69
|
+
;(fileInputContainerRef.current.firstChild as HTMLInputElement).value = ''
|
|
70
|
+
}
|
|
71
|
+
}}
|
|
72
|
+
/>
|
|
73
|
+
<embed
|
|
74
|
+
src={image}
|
|
75
|
+
className='mb-4 max-w-full rounded p-1 ring ring-green-600'
|
|
76
|
+
width={300}
|
|
77
|
+
height={190}
|
|
78
|
+
/>
|
|
79
|
+
</div>
|
|
80
|
+
</div>
|
|
81
|
+
)}
|
|
82
|
+
</div>
|
|
83
|
+
<div ref={fileInputContainerRef}>
|
|
84
|
+
<input
|
|
85
|
+
type='file'
|
|
86
|
+
className='hidden'
|
|
87
|
+
name={field.name}
|
|
88
|
+
ref={field.ref}
|
|
89
|
+
onChange={(e) => {
|
|
90
|
+
onImageChange(e)
|
|
91
|
+
if (!input.value) {
|
|
92
|
+
field.onChange(e.target?.files?.length ? e.target.files[0] : undefined)
|
|
93
|
+
}
|
|
94
|
+
}}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
<div className='flex flex-col items-center gap-2 md:flex-row'>
|
|
98
|
+
<div className='w-full flex-1 md:flex-[0.5]'>
|
|
99
|
+
<button
|
|
100
|
+
type='button'
|
|
101
|
+
className='w-full rounded border bg-gradient-to-r from-blue-700 to-sky-500 p-2 text-center text-sm font-bold uppercase text-white drop-shadow'
|
|
102
|
+
onClick={() => {
|
|
103
|
+
if (fileInputContainerRef.current?.firstChild) {
|
|
104
|
+
;(fileInputContainerRef.current.firstChild as HTMLInputElement).click()
|
|
105
|
+
}
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
Upload
|
|
109
|
+
</button>
|
|
110
|
+
</div>
|
|
111
|
+
<div className='w-full flex-1'>
|
|
112
|
+
<span>{fileName}</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
</FormInputElement>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import PaginationButtons from './PaginationButtons'
|
|
3
|
+
|
|
4
|
+
export default function Pagination({
|
|
5
|
+
page,
|
|
6
|
+
totalCount,
|
|
7
|
+
limit,
|
|
8
|
+
route,
|
|
9
|
+
lang = 'ar',
|
|
10
|
+
paginationLinksToShow,
|
|
11
|
+
searchParams = null,
|
|
12
|
+
}: {
|
|
13
|
+
page: number
|
|
14
|
+
totalCount: number
|
|
15
|
+
limit: number
|
|
16
|
+
route: string
|
|
17
|
+
lang?: string
|
|
18
|
+
paginationLinksToShow?: number
|
|
19
|
+
searchParams?: string | null
|
|
20
|
+
}) {
|
|
21
|
+
return (
|
|
22
|
+
<>
|
|
23
|
+
<div className='my-3 flex w-full items-center justify-center gap-1 p-3 text-center font-bold'>
|
|
24
|
+
<PaginationButtons
|
|
25
|
+
paginationLinksToShow={paginationLinksToShow}
|
|
26
|
+
page={page}
|
|
27
|
+
totalCount={totalCount}
|
|
28
|
+
limit={limit}
|
|
29
|
+
route={route}
|
|
30
|
+
lang={lang}
|
|
31
|
+
searchParams={searchParams}
|
|
32
|
+
/>
|
|
33
|
+
</div>
|
|
34
|
+
</>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import Link from 'next/link'
|
|
3
|
+
|
|
4
|
+
export default function PaginationButtons({
|
|
5
|
+
page,
|
|
6
|
+
totalCount,
|
|
7
|
+
limit,
|
|
8
|
+
route,
|
|
9
|
+
lang = 'ar',
|
|
10
|
+
paginationLinksToShow = 5,
|
|
11
|
+
searchParams = null,
|
|
12
|
+
useLangInRoute = false,
|
|
13
|
+
}: {
|
|
14
|
+
page: number
|
|
15
|
+
totalCount: number
|
|
16
|
+
limit: number
|
|
17
|
+
route: string
|
|
18
|
+
lang?: string
|
|
19
|
+
paginationLinksToShow?: number
|
|
20
|
+
searchParams?: string | null
|
|
21
|
+
useLangInRoute?: boolean
|
|
22
|
+
}) {
|
|
23
|
+
// Remove first and trailing slashes from route
|
|
24
|
+
route = route.replace(/^\/|\/$/g, '')
|
|
25
|
+
const paginationLinksCount = Math.ceil(totalCount / limit)
|
|
26
|
+
let paginationLinksArray = []
|
|
27
|
+
switch (page) {
|
|
28
|
+
case 1: // If first page
|
|
29
|
+
for (let i = 1; i <= paginationLinksToShow; i++) {
|
|
30
|
+
if (i > paginationLinksCount) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
paginationLinksArray[i] = {
|
|
35
|
+
route: route + '/' + i,
|
|
36
|
+
html: i,
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
paginationLinksArray[0] = {
|
|
41
|
+
route: route + '/' + 1,
|
|
42
|
+
html: lang === 'ar' ? 'الأولى' : 'First',
|
|
43
|
+
disabled: true,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let lastDisabled = true
|
|
47
|
+
if (paginationLinksCount > 1) {
|
|
48
|
+
lastDisabled = false
|
|
49
|
+
}
|
|
50
|
+
paginationLinksArray[paginationLinksCount + 1] = {
|
|
51
|
+
route: route + '/' + paginationLinksCount,
|
|
52
|
+
html: lang === 'ar' ? 'الأخيرة' : 'Last',
|
|
53
|
+
disabled: lastDisabled,
|
|
54
|
+
}
|
|
55
|
+
break
|
|
56
|
+
case paginationLinksCount: // If last page
|
|
57
|
+
let j = paginationLinksCount
|
|
58
|
+
for (j; j > paginationLinksCount - paginationLinksToShow; j--) {
|
|
59
|
+
if (j < 1) {
|
|
60
|
+
continue
|
|
61
|
+
}
|
|
62
|
+
paginationLinksArray[j] = {
|
|
63
|
+
route: route + '/' + j,
|
|
64
|
+
html: j,
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
paginationLinksArray[0] = {
|
|
69
|
+
route: route + '/' + 1,
|
|
70
|
+
html: lang === 'ar' ? 'الأولى' : 'First',
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
paginationLinksArray[paginationLinksCount + 1] = {
|
|
74
|
+
route: route + '/' + paginationLinksCount,
|
|
75
|
+
html: lang === 'ar' ? 'الأخيرة' : 'Last',
|
|
76
|
+
disabled: true,
|
|
77
|
+
}
|
|
78
|
+
break
|
|
79
|
+
default: // If in between
|
|
80
|
+
let start = Math.max(1, page - Math.floor(paginationLinksToShow / 2))
|
|
81
|
+
let end = Math.min(paginationLinksCount, start + paginationLinksToShow - 1)
|
|
82
|
+
start = Math.max(1, end - paginationLinksToShow + 1) // Adjust start if end is less than paginationLinksToShow
|
|
83
|
+
|
|
84
|
+
for (let i = start; i <= end; i++) {
|
|
85
|
+
paginationLinksArray[i] = {
|
|
86
|
+
route: route + '/' + i,
|
|
87
|
+
html: i,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
paginationLinksArray[0] = {
|
|
92
|
+
route: route + '/' + 1,
|
|
93
|
+
html: lang === 'ar' ? 'الأولى' : 'First',
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
paginationLinksArray[paginationLinksCount + 1] = {
|
|
97
|
+
route: route + '/' + paginationLinksCount,
|
|
98
|
+
html: lang === 'ar' ? 'الأخيرة' : 'Last',
|
|
99
|
+
}
|
|
100
|
+
break
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (paginationLinksCount === 0) {
|
|
104
|
+
paginationLinksArray = []
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return (
|
|
108
|
+
<>
|
|
109
|
+
{paginationLinksArray.map((item, i) => {
|
|
110
|
+
const href = useLangInRoute ? `${lang}/${item.route}` : item.route
|
|
111
|
+
if (i === page) {
|
|
112
|
+
return (
|
|
113
|
+
<div
|
|
114
|
+
className='active rounded border border-neutral-400 bg-blue-950 px-3 py-1 text-amber-50 dark:border-neutral-100'
|
|
115
|
+
key={i.toString()}
|
|
116
|
+
>
|
|
117
|
+
<span className='page-link'>{item.html}</span>
|
|
118
|
+
</div>
|
|
119
|
+
)
|
|
120
|
+
} else {
|
|
121
|
+
if (item.disabled) {
|
|
122
|
+
return (
|
|
123
|
+
<div
|
|
124
|
+
className='active rounded border border-neutral-400 bg-gray-300 px-3 py-1 text-black/40 opacity-70 dark:border-neutral-100 dark:bg-black dark:text-gray-500/60'
|
|
125
|
+
key={i.toString()}
|
|
126
|
+
>
|
|
127
|
+
{item.html}
|
|
128
|
+
</div>
|
|
129
|
+
)
|
|
130
|
+
} else {
|
|
131
|
+
return (
|
|
132
|
+
<Link
|
|
133
|
+
href={searchParams ? `/${href}?${searchParams}` : `/${href}`}
|
|
134
|
+
className='active rounded border border-neutral-400 bg-white px-3 py-1 text-blue-950 hover:bg-emerald-100 dark:border-neutral-100 dark:bg-neutral-800 dark:text-gray-50 dark:hover:bg-neutral-600'
|
|
135
|
+
key={i.toString()}
|
|
136
|
+
>
|
|
137
|
+
{item.html}
|
|
138
|
+
</Link>
|
|
139
|
+
)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
})}
|
|
143
|
+
</>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import * as AccordionPrimitive from "@radix-ui/react-accordion"
|
|
5
|
+
import { ChevronDownIcon } from "@radix-ui/react-icons"
|
|
6
|
+
|
|
7
|
+
import { cn } from "nextjs-cms/utils"
|
|
8
|
+
|
|
9
|
+
const Accordion = AccordionPrimitive.Root
|
|
10
|
+
|
|
11
|
+
const AccordionItem = React.forwardRef<
|
|
12
|
+
React.ElementRef<typeof AccordionPrimitive.Item>,
|
|
13
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Item>
|
|
14
|
+
>(({ className, ...props }, ref) => (
|
|
15
|
+
<AccordionPrimitive.Item
|
|
16
|
+
ref={ref}
|
|
17
|
+
className={cn("border-b", className)}
|
|
18
|
+
{...props}
|
|
19
|
+
/>
|
|
20
|
+
))
|
|
21
|
+
AccordionItem.displayName = "AccordionItem"
|
|
22
|
+
|
|
23
|
+
const AccordionTrigger = React.forwardRef<
|
|
24
|
+
React.ElementRef<typeof AccordionPrimitive.Trigger>,
|
|
25
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Trigger>
|
|
26
|
+
>(({ className, children, ...props }, ref) => (
|
|
27
|
+
<AccordionPrimitive.Header className="flex">
|
|
28
|
+
<AccordionPrimitive.Trigger
|
|
29
|
+
ref={ref}
|
|
30
|
+
className={cn(
|
|
31
|
+
"flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180",
|
|
32
|
+
className
|
|
33
|
+
)}
|
|
34
|
+
{...props}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
<ChevronDownIcon className="h-4 w-4 shrink-0 text-muted-foreground transition-transform duration-200" />
|
|
38
|
+
</AccordionPrimitive.Trigger>
|
|
39
|
+
</AccordionPrimitive.Header>
|
|
40
|
+
))
|
|
41
|
+
AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName
|
|
42
|
+
|
|
43
|
+
const AccordionContent = React.forwardRef<
|
|
44
|
+
React.ElementRef<typeof AccordionPrimitive.Content>,
|
|
45
|
+
React.ComponentPropsWithoutRef<typeof AccordionPrimitive.Content>
|
|
46
|
+
>(({ className, children, ...props }, ref) => (
|
|
47
|
+
<AccordionPrimitive.Content
|
|
48
|
+
ref={ref}
|
|
49
|
+
className="overflow-hidden text-sm data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down"
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
<div className={cn("pb-4 pt-0", className)}>{children}</div>
|
|
53
|
+
</AccordionPrimitive.Content>
|
|
54
|
+
))
|
|
55
|
+
AccordionContent.displayName = AccordionPrimitive.Content.displayName
|
|
56
|
+
|
|
57
|
+
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
import { cn } from 'nextjs-cms/utils'
|
|
5
|
+
|
|
6
|
+
const alertVariants = cva(
|
|
7
|
+
'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'bg-background text-foreground',
|
|
12
|
+
destructive:
|
|
13
|
+
'border-destructive/90 bg-destructive/10 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
|
14
|
+
light: 'bg-gray-100 text-gray-900 dark:bg-gray-950 dark:text-gray-100',
|
|
15
|
+
info: 'bg-info text-info dark:bg-info dark:text-info',
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
defaultVariants: {
|
|
19
|
+
variant: 'default',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
const Alert = React.forwardRef<
|
|
25
|
+
HTMLDivElement,
|
|
26
|
+
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
|
27
|
+
>(({ className, variant, ...props }, ref) => (
|
|
28
|
+
<div ref={ref} role='alert' className={cn(alertVariants({ variant }), className)} {...props} />
|
|
29
|
+
))
|
|
30
|
+
Alert.displayName = 'Alert'
|
|
31
|
+
|
|
32
|
+
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
33
|
+
({ className, ...props }, ref) => (
|
|
34
|
+
<h5 ref={ref} className={cn('mb-1 font-medium leading-none tracking-tight', className)} {...props} />
|
|
35
|
+
),
|
|
36
|
+
)
|
|
37
|
+
AlertTitle.displayName = 'AlertTitle'
|
|
38
|
+
|
|
39
|
+
const AlertDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
|
|
40
|
+
({ className, ...props }, ref) => (
|
|
41
|
+
<div ref={ref} className={cn('text-sm [&_p]:leading-relaxed', className)} {...props} />
|
|
42
|
+
),
|
|
43
|
+
)
|
|
44
|
+
AlertDescription.displayName = 'AlertDescription'
|
|
45
|
+
|
|
46
|
+
export { Alert, AlertTitle, AlertDescription }
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as React from 'react'
|
|
2
|
+
import { cva, type VariantProps } from 'class-variance-authority'
|
|
3
|
+
|
|
4
|
+
import { cn } from 'nextjs-cms/utils'
|
|
5
|
+
|
|
6
|
+
const badgeVariants = cva(
|
|
7
|
+
'inline-flex items-center rounded-md border px-1.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
|
|
8
|
+
{
|
|
9
|
+
variants: {
|
|
10
|
+
variant: {
|
|
11
|
+
default: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
12
|
+
secondary: 'border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
|
13
|
+
destructive:
|
|
14
|
+
'border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80',
|
|
15
|
+
outline: 'text-foreground',
|
|
16
|
+
primary: 'border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80',
|
|
17
|
+
success: 'border-transparent bg-success text-success-foreground shadow hover:bg-success/80',
|
|
18
|
+
warning: 'border-transparent bg-warning text-warning-foreground shadow hover:bg-warning/80',
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
defaultVariants: {
|
|
22
|
+
variant: 'default',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
export interface BadgeProps extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof badgeVariants> {}
|
|
28
|
+
|
|
29
|
+
function Badge({ className, variant, ...props }: BadgeProps) {
|
|
30
|
+
return <div className={cn(badgeVariants({ variant }), className)} {...props} />
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export { Badge, badgeVariants }
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
import { Slot } from "@radix-ui/react-slot"
|
|
3
|
+
import { cva, type VariantProps } from "class-variance-authority"
|
|
4
|
+
|
|
5
|
+
import { cn } from 'nextjs-cms/utils'
|
|
6
|
+
|
|
7
|
+
const buttonVariants = cva(
|
|
8
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
9
|
+
{
|
|
10
|
+
variants: {
|
|
11
|
+
variant: {
|
|
12
|
+
default:
|
|
13
|
+
"bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
14
|
+
destructive:
|
|
15
|
+
"bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
16
|
+
outline:
|
|
17
|
+
"border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
18
|
+
secondary:
|
|
19
|
+
"bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
20
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
21
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
22
|
+
},
|
|
23
|
+
size: {
|
|
24
|
+
default: "h-9 px-4 py-2",
|
|
25
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
26
|
+
lg: "h-10 rounded-md px-8",
|
|
27
|
+
icon: "h-9 w-9",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
defaultVariants: {
|
|
31
|
+
variant: "default",
|
|
32
|
+
size: "default",
|
|
33
|
+
},
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
export interface ButtonProps
|
|
38
|
+
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
|
39
|
+
VariantProps<typeof buttonVariants> {
|
|
40
|
+
asChild?: boolean
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
44
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
45
|
+
const Comp = asChild ? Slot : "button"
|
|
46
|
+
return (
|
|
47
|
+
<Comp
|
|
48
|
+
className={cn(buttonVariants({ variant, size, className }))}
|
|
49
|
+
ref={ref}
|
|
50
|
+
{...props}
|
|
51
|
+
/>
|
|
52
|
+
)
|
|
53
|
+
}
|
|
54
|
+
)
|
|
55
|
+
Button.displayName = "Button"
|
|
56
|
+
|
|
57
|
+
export { Button, buttonVariants }
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { DayPicker } from 'react-day-picker'
|
|
5
|
+
|
|
6
|
+
import { cn } from 'nextjs-cms/utils'
|
|
7
|
+
import { buttonVariants } from '@/components/ui/button'
|
|
8
|
+
import { ChevronLeftIcon, ChevronRightIcon } from '@radix-ui/react-icons'
|
|
9
|
+
|
|
10
|
+
export type CalendarProps = React.ComponentProps<typeof DayPicker>
|
|
11
|
+
|
|
12
|
+
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
|
13
|
+
return (
|
|
14
|
+
<DayPicker
|
|
15
|
+
showOutsideDays={showOutsideDays}
|
|
16
|
+
className={cn('p-3', className)}
|
|
17
|
+
classNames={{
|
|
18
|
+
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
|
|
19
|
+
month: 'space-y-4',
|
|
20
|
+
caption: 'flex justify-center pt-1 relative items-center',
|
|
21
|
+
caption_label: 'text-sm font-medium',
|
|
22
|
+
nav: 'space-x-1 flex items-center',
|
|
23
|
+
nav_button: cn(
|
|
24
|
+
buttonVariants({ variant: 'outline' }),
|
|
25
|
+
'h-7 w-7 bg-transparent p-0 opacity-50 hover:opacity-100',
|
|
26
|
+
),
|
|
27
|
+
nav_button_previous: 'absolute left-1',
|
|
28
|
+
nav_button_next: 'absolute right-1',
|
|
29
|
+
table: 'w-full border-collapse space-y-1',
|
|
30
|
+
head_row: 'flex',
|
|
31
|
+
head_cell: 'text-muted-foreground rounded-md w-8 font-normal text-[0.8rem]',
|
|
32
|
+
row: 'flex w-full mt-2',
|
|
33
|
+
cell: cn(
|
|
34
|
+
'relative p-0 text-center text-sm focus-within:relative focus-within:z-20 [&:has([aria-selected])]:bg-accent [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected].day-range-end)]:rounded-r-md',
|
|
35
|
+
props.mode === 'range'
|
|
36
|
+
? '[&:has(>.day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md'
|
|
37
|
+
: '[&:has([aria-selected])]:rounded-md',
|
|
38
|
+
),
|
|
39
|
+
day: cn(buttonVariants({ variant: 'ghost' }), 'h-8 w-8 p-0 font-normal aria-selected:opacity-100'),
|
|
40
|
+
day_range_start: 'day-range-start',
|
|
41
|
+
day_range_end: 'day-range-end',
|
|
42
|
+
day_selected:
|
|
43
|
+
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
|
|
44
|
+
day_today: 'bg-accent text-accent-foreground',
|
|
45
|
+
day_outside:
|
|
46
|
+
'day-outside text-muted-foreground aria-selected:bg-accent/50 aria-selected:text-muted-foreground',
|
|
47
|
+
day_disabled: 'text-muted-foreground opacity-50',
|
|
48
|
+
day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
|
49
|
+
day_hidden: 'invisible',
|
|
50
|
+
...classNames,
|
|
51
|
+
}}
|
|
52
|
+
components={{
|
|
53
|
+
IconLeft: ({ className, ...props }) => (
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
<ChevronLeftIcon className={cn('h-4 w-4', className)} {...props} />
|
|
56
|
+
),
|
|
57
|
+
IconRight: ({ className, ...props }) => (
|
|
58
|
+
// @ts-ignore
|
|
59
|
+
<ChevronRightIcon className={cn('h-4 w-4', className)} {...props} />
|
|
60
|
+
),
|
|
61
|
+
}}
|
|
62
|
+
{...props}
|
|
63
|
+
/>
|
|
64
|
+
)
|
|
65
|
+
}
|
|
66
|
+
Calendar.displayName = 'Calendar'
|
|
67
|
+
|
|
68
|
+
export { Calendar }
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import * as React from "react"
|
|
2
|
+
|
|
3
|
+
import { cn } from 'nextjs-cms/utils'
|
|
4
|
+
|
|
5
|
+
const Card = React.forwardRef<
|
|
6
|
+
HTMLDivElement,
|
|
7
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
8
|
+
>(({ className, ...props }, ref) => (
|
|
9
|
+
<div
|
|
10
|
+
ref={ref}
|
|
11
|
+
className={cn(
|
|
12
|
+
"rounded-xl border bg-card text-card-foreground shadow",
|
|
13
|
+
className
|
|
14
|
+
)}
|
|
15
|
+
{...props}
|
|
16
|
+
/>
|
|
17
|
+
))
|
|
18
|
+
Card.displayName = "Card"
|
|
19
|
+
|
|
20
|
+
const CardHeader = React.forwardRef<
|
|
21
|
+
HTMLDivElement,
|
|
22
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
23
|
+
>(({ className, ...props }, ref) => (
|
|
24
|
+
<div
|
|
25
|
+
ref={ref}
|
|
26
|
+
className={cn("flex flex-col space-y-1.5 p-6", className)}
|
|
27
|
+
{...props}
|
|
28
|
+
/>
|
|
29
|
+
))
|
|
30
|
+
CardHeader.displayName = "CardHeader"
|
|
31
|
+
|
|
32
|
+
const CardTitle = React.forwardRef<
|
|
33
|
+
HTMLParagraphElement,
|
|
34
|
+
React.HTMLAttributes<HTMLHeadingElement>
|
|
35
|
+
>(({ className, ...props }, ref) => (
|
|
36
|
+
<h3
|
|
37
|
+
ref={ref}
|
|
38
|
+
className={cn("font-semibold leading-none tracking-tight", className)}
|
|
39
|
+
{...props}
|
|
40
|
+
/>
|
|
41
|
+
))
|
|
42
|
+
CardTitle.displayName = "CardTitle"
|
|
43
|
+
|
|
44
|
+
const CardDescription = React.forwardRef<
|
|
45
|
+
HTMLParagraphElement,
|
|
46
|
+
React.HTMLAttributes<HTMLParagraphElement>
|
|
47
|
+
>(({ className, ...props }, ref) => (
|
|
48
|
+
<p
|
|
49
|
+
ref={ref}
|
|
50
|
+
className={cn("text-sm text-muted-foreground", className)}
|
|
51
|
+
{...props}
|
|
52
|
+
/>
|
|
53
|
+
))
|
|
54
|
+
CardDescription.displayName = "CardDescription"
|
|
55
|
+
|
|
56
|
+
const CardContent = React.forwardRef<
|
|
57
|
+
HTMLDivElement,
|
|
58
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
59
|
+
>(({ className, ...props }, ref) => (
|
|
60
|
+
<div ref={ref} className={cn("p-6 pt-0", className)} {...props} />
|
|
61
|
+
))
|
|
62
|
+
CardContent.displayName = "CardContent"
|
|
63
|
+
|
|
64
|
+
const CardFooter = React.forwardRef<
|
|
65
|
+
HTMLDivElement,
|
|
66
|
+
React.HTMLAttributes<HTMLDivElement>
|
|
67
|
+
>(({ className, ...props }, ref) => (
|
|
68
|
+
<div
|
|
69
|
+
ref={ref}
|
|
70
|
+
className={cn("flex items-center p-6 pt-0", className)}
|
|
71
|
+
{...props}
|
|
72
|
+
/>
|
|
73
|
+
))
|
|
74
|
+
CardFooter.displayName = "CardFooter"
|
|
75
|
+
|
|
76
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import * as CheckboxPrimitive from '@radix-ui/react-checkbox'
|
|
5
|
+
import { CheckIcon, DividerHorizontalIcon } from '@radix-ui/react-icons'
|
|
6
|
+
|
|
7
|
+
import { cn } from 'nextjs-cms/utils'
|
|
8
|
+
|
|
9
|
+
const Checkbox = React.forwardRef<
|
|
10
|
+
React.ElementRef<typeof CheckboxPrimitive.Root>,
|
|
11
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
|
|
12
|
+
>(({ className, ...props }, ref) => (
|
|
13
|
+
<CheckboxPrimitive.Root
|
|
14
|
+
ref={ref}
|
|
15
|
+
className={cn(
|
|
16
|
+
'peer h-4 w-4 shrink-0 rounded-sm border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state="indeterminate"]:bg-gray-300 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state="indeterminate"]:bg-gray-500',
|
|
17
|
+
className,
|
|
18
|
+
)}
|
|
19
|
+
{...props}
|
|
20
|
+
>
|
|
21
|
+
<CheckboxPrimitive.Indicator className={cn('flex items-center justify-center text-current')}>
|
|
22
|
+
{props.checked === 'indeterminate' && <DividerHorizontalIcon />}
|
|
23
|
+
{props.checked === true && <CheckIcon />}
|
|
24
|
+
</CheckboxPrimitive.Indicator>
|
|
25
|
+
</CheckboxPrimitive.Root>
|
|
26
|
+
))
|
|
27
|
+
Checkbox.displayName = CheckboxPrimitive.Root.displayName
|
|
28
|
+
|
|
29
|
+
export { Checkbox }
|