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.
Files changed (187) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +71 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +395 -0
  6. package/dist/lib/utils.d.ts +11 -0
  7. package/dist/lib/utils.d.ts.map +1 -0
  8. package/dist/lib/utils.js +48 -0
  9. package/package.json +44 -0
  10. package/templates/default/.env +24 -0
  11. package/templates/default/.env.development +8 -0
  12. package/templates/default/.eslintrc.json +5 -0
  13. package/templates/default/.prettierignore +7 -0
  14. package/templates/default/.prettierrc.json +19 -0
  15. package/templates/default/CHANGELOG.md +77 -0
  16. package/templates/default/README.md +45 -0
  17. package/templates/default/app/(auth)/auth/login/LoginPage.tsx +175 -0
  18. package/templates/default/app/(auth)/auth/login/page.tsx +12 -0
  19. package/templates/default/app/(rootLayout)/admins/page.tsx +5 -0
  20. package/templates/default/app/(rootLayout)/advanced/page.tsx +5 -0
  21. package/templates/default/app/(rootLayout)/analytics/page.tsx +7 -0
  22. package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +7 -0
  23. package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +7 -0
  24. package/templates/default/app/(rootLayout)/dashboard/page.tsx +7 -0
  25. package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +7 -0
  26. package/templates/default/app/(rootLayout)/emails/page.tsx +6 -0
  27. package/templates/default/app/(rootLayout)/layout.tsx +5 -0
  28. package/templates/default/app/(rootLayout)/loading.tsx +10 -0
  29. package/templates/default/app/(rootLayout)/log/page.tsx +7 -0
  30. package/templates/default/app/(rootLayout)/new/[section]/page.tsx +7 -0
  31. package/templates/default/app/(rootLayout)/page.tsx +9 -0
  32. package/templates/default/app/(rootLayout)/section/[section]/page.tsx +7 -0
  33. package/templates/default/app/(rootLayout)/settings/page.tsx +7 -0
  34. package/templates/default/app/_trpc/client.ts +4 -0
  35. package/templates/default/app/api/auth/csrf/route.ts +25 -0
  36. package/templates/default/app/api/auth/refresh/route.ts +10 -0
  37. package/templates/default/app/api/auth/route.ts +23 -0
  38. package/templates/default/app/api/auth/session/route.ts +20 -0
  39. package/templates/default/app/api/editor/photo/route.ts +42 -0
  40. package/templates/default/app/api/photo/route.ts +27 -0
  41. package/templates/default/app/api/placeholder/route.ts +7 -0
  42. package/templates/default/app/api/submit/section/item/[slug]/route.ts +63 -0
  43. package/templates/default/app/api/submit/section/item/route.ts +53 -0
  44. package/templates/default/app/api/submit/section/simple/route.ts +54 -0
  45. package/templates/default/app/api/trpc/[trpc]/route.ts +33 -0
  46. package/templates/default/app/api/video/route.ts +174 -0
  47. package/templates/default/app/dictionaries.ts +14 -0
  48. package/templates/default/app/layout.tsx +28 -0
  49. package/templates/default/app/providers.tsx +151 -0
  50. package/templates/default/cli.ts +4 -0
  51. package/templates/default/components/AdminCard.tsx +163 -0
  52. package/templates/default/components/AdminEditPage.tsx +123 -0
  53. package/templates/default/components/AdminPrivilegeCard.tsx +184 -0
  54. package/templates/default/components/AdminsPage.tsx +43 -0
  55. package/templates/default/components/AdvancedSettingsPage.tsx +167 -0
  56. package/templates/default/components/AnalyticsPage.tsx +127 -0
  57. package/templates/default/components/BarChartBox.tsx +43 -0
  58. package/templates/default/components/BrowsePage.tsx +119 -0
  59. package/templates/default/components/CategorizedSectionPage.tsx +36 -0
  60. package/templates/default/components/CategoryDeleteConfirmPage.tsx +129 -0
  61. package/templates/default/components/CategorySectionSelectInput.tsx +139 -0
  62. package/templates/default/components/ConditionalFields.tsx +49 -0
  63. package/templates/default/components/ContainerBox.tsx +24 -0
  64. package/templates/default/components/DashboardPage.tsx +187 -0
  65. package/templates/default/components/DashboardPageAlt.tsx +43 -0
  66. package/templates/default/components/DefaultNavItems.tsx +3 -0
  67. package/templates/default/components/Dropzone.tsx +153 -0
  68. package/templates/default/components/EmailCard.tsx +137 -0
  69. package/templates/default/components/EmailPasswordForm.tsx +84 -0
  70. package/templates/default/components/EmailQuotaForm.tsx +72 -0
  71. package/templates/default/components/EmailsPage.tsx +48 -0
  72. package/templates/default/components/GalleryPhoto.tsx +93 -0
  73. package/templates/default/components/InfoCard.tsx +94 -0
  74. package/templates/default/components/ItemEditPage.tsx +217 -0
  75. package/templates/default/components/Layout.tsx +70 -0
  76. package/templates/default/components/LoadingSpinners.tsx +67 -0
  77. package/templates/default/components/LogPage.tsx +17 -0
  78. package/templates/default/components/Modal.tsx +99 -0
  79. package/templates/default/components/Navbar.tsx +29 -0
  80. package/templates/default/components/NavbarAlt.tsx +182 -0
  81. package/templates/default/components/NewAdminForm.tsx +172 -0
  82. package/templates/default/components/NewEmailForm.tsx +131 -0
  83. package/templates/default/components/NewPage.tsx +206 -0
  84. package/templates/default/components/NewVariantComponent.tsx +228 -0
  85. package/templates/default/components/PhotoGallery.tsx +35 -0
  86. package/templates/default/components/PieChartBox.tsx +101 -0
  87. package/templates/default/components/ProgressBar.tsx +24 -0
  88. package/templates/default/components/ProtectedDocument.tsx +78 -0
  89. package/templates/default/components/ProtectedImage.tsx +143 -0
  90. package/templates/default/components/ProtectedVideo.tsx +76 -0
  91. package/templates/default/components/SectionItemCard.tsx +143 -0
  92. package/templates/default/components/SectionItemStatusBadge.tsx +16 -0
  93. package/templates/default/components/SectionPage.tsx +124 -0
  94. package/templates/default/components/SelectBox.tsx +99 -0
  95. package/templates/default/components/SelectInputButtons.tsx +124 -0
  96. package/templates/default/components/SettingsPage.tsx +238 -0
  97. package/templates/default/components/Sidebar.tsx +209 -0
  98. package/templates/default/components/SidebarDropdownItem.tsx +74 -0
  99. package/templates/default/components/SidebarItem.tsx +19 -0
  100. package/templates/default/components/TempPage.tsx +12 -0
  101. package/templates/default/components/ThemeProvider.tsx +8 -0
  102. package/templates/default/components/TooltipComponent.tsx +27 -0
  103. package/templates/default/components/VariantCard.tsx +123 -0
  104. package/templates/default/components/VariantEditPage.tsx +229 -0
  105. package/templates/default/components/analytics/BounceRate.tsx +69 -0
  106. package/templates/default/components/analytics/LivePageViews.tsx +54 -0
  107. package/templates/default/components/analytics/LiveUsersCount.tsx +32 -0
  108. package/templates/default/components/analytics/MonthlyPageViews.tsx +41 -0
  109. package/templates/default/components/analytics/TopCountries.tsx +51 -0
  110. package/templates/default/components/analytics/TopDevices.tsx +45 -0
  111. package/templates/default/components/analytics/TopMediums.tsx +57 -0
  112. package/templates/default/components/analytics/TopSources.tsx +44 -0
  113. package/templates/default/components/analytics/TotalPageViews.tsx +40 -0
  114. package/templates/default/components/analytics/TotalSessions.tsx +40 -0
  115. package/templates/default/components/analytics/TotalUniqueUsers.tsx +40 -0
  116. package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +137 -0
  117. package/templates/default/components/dndKit/Draggable.tsx +21 -0
  118. package/templates/default/components/dndKit/Droppable.tsx +20 -0
  119. package/templates/default/components/dndKit/SortableItem.tsx +18 -0
  120. package/templates/default/components/form/DateRangeFormInput.tsx +55 -0
  121. package/templates/default/components/form/Form.tsx +298 -0
  122. package/templates/default/components/form/FormInputElement.tsx +68 -0
  123. package/templates/default/components/form/FormInputs.tsx +108 -0
  124. package/templates/default/components/form/helpers/util.ts +20 -0
  125. package/templates/default/components/form/inputs/CheckboxFormInput.tsx +33 -0
  126. package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -0
  127. package/templates/default/components/form/inputs/DateFormInput.tsx +107 -0
  128. package/templates/default/components/form/inputs/DocumentFormInput.tsx +124 -0
  129. package/templates/default/components/form/inputs/MapFormInput.tsx +139 -0
  130. package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +150 -0
  131. package/templates/default/components/form/inputs/NumberFormInput.tsx +42 -0
  132. package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -0
  133. package/templates/default/components/form/inputs/PhotoFormInput.tsx +218 -0
  134. package/templates/default/components/form/inputs/RichTextFormInput.tsx +133 -0
  135. package/templates/default/components/form/inputs/SelectFormInput.tsx +164 -0
  136. package/templates/default/components/form/inputs/TagsFormInput.tsx +63 -0
  137. package/templates/default/components/form/inputs/TextFormInput.tsx +48 -0
  138. package/templates/default/components/form/inputs/TextareaFormInput.tsx +47 -0
  139. package/templates/default/components/form/inputs/VideoFormInput.tsx +117 -0
  140. package/templates/default/components/pagination/Pagination.tsx +36 -0
  141. package/templates/default/components/pagination/PaginationButtons.tsx +145 -0
  142. package/templates/default/components/ui/accordion.tsx +57 -0
  143. package/templates/default/components/ui/alert.tsx +46 -0
  144. package/templates/default/components/ui/badge.tsx +33 -0
  145. package/templates/default/components/ui/button.tsx +57 -0
  146. package/templates/default/components/ui/calendar.tsx +68 -0
  147. package/templates/default/components/ui/card.tsx +76 -0
  148. package/templates/default/components/ui/checkbox.tsx +29 -0
  149. package/templates/default/components/ui/dropdown-menu.tsx +205 -0
  150. package/templates/default/components/ui/input.tsx +25 -0
  151. package/templates/default/components/ui/label.tsx +26 -0
  152. package/templates/default/components/ui/popover.tsx +31 -0
  153. package/templates/default/components/ui/scroll-area.tsx +42 -0
  154. package/templates/default/components/ui/select.tsx +164 -0
  155. package/templates/default/components/ui/sheet.tsx +107 -0
  156. package/templates/default/components/ui/switch.tsx +29 -0
  157. package/templates/default/components/ui/table.tsx +120 -0
  158. package/templates/default/components/ui/tabs.tsx +55 -0
  159. package/templates/default/components/ui/toast.tsx +113 -0
  160. package/templates/default/components/ui/toaster.tsx +35 -0
  161. package/templates/default/components/ui/tooltip.tsx +30 -0
  162. package/templates/default/components/ui/use-toast.ts +188 -0
  163. package/templates/default/components.json +16 -0
  164. package/templates/default/context/ModalProvider.tsx +53 -0
  165. package/templates/default/drizzle.config.ts +4 -0
  166. package/templates/default/dynamic-schemas/schema.ts +373 -0
  167. package/templates/default/env/env.js +130 -0
  168. package/templates/default/envConfig.ts +4 -0
  169. package/templates/default/hooks/useModal.ts +8 -0
  170. package/templates/default/lib/apiHelpers.ts +106 -0
  171. package/templates/default/lz.config.ts +40 -0
  172. package/templates/default/middleware.ts +33 -0
  173. package/templates/default/next.config.ts +46 -0
  174. package/templates/default/package.json +134 -0
  175. package/templates/default/postcss.config.js +6 -0
  176. package/templates/default/postinstall.js +14 -0
  177. package/templates/default/public/blank_avatar.png +0 -0
  178. package/templates/default/public/favicon.ico +0 -0
  179. package/templates/default/public/img/placeholder.svg +1 -0
  180. package/templates/default/public/lazemni_logo.png +0 -0
  181. package/templates/default/public/next.svg +1 -0
  182. package/templates/default/public/vercel.svg +1 -0
  183. package/templates/default/section-tests.ts +92 -0
  184. package/templates/default/styles/globals.css +88 -0
  185. package/templates/default/tailwind.config.js +95 -0
  186. package/templates/default/test.ts +77 -0
  187. package/templates/default/tsconfig.json +44 -0
@@ -0,0 +1,124 @@
1
+ import getString from 'nextjs-cms/translations'
2
+ import useModal from '@/hooks/useModal'
3
+ import React from 'react'
4
+ import NewPage from '@/components/NewPage'
5
+ import ItemEditPage from '@/components/ItemEditPage'
6
+ import { Button } from '@/components/ui/button'
7
+ import CategoryDeleteConfirmPage from '@/components/CategoryDeleteConfirmPage'
8
+
9
+ export default function SelectInputButtons({
10
+ section,
11
+ sectionTitle,
12
+ value,
13
+ parentId,
14
+ level,
15
+ refetch,
16
+ reset,
17
+ allowRecursiveDelete,
18
+ }: {
19
+ section: string
20
+ sectionTitle: string
21
+ value: string | number | undefined
22
+ parentId: string | number | undefined
23
+ level: number
24
+ refetch: any
25
+ reset: any
26
+ allowRecursiveDelete: boolean
27
+ }) {
28
+ const { setModal } = useModal()
29
+ const newCatInit = () => {
30
+ setModal({
31
+ title: getString('add_new_item'),
32
+ body: (
33
+ <NewPage
34
+ section={section}
35
+ action={refetch}
36
+ sectionType='categorized'
37
+ hiddenInputs={[
38
+ {
39
+ name: 'parent_id',
40
+ value: parentId,
41
+ },
42
+ {
43
+ name: 'level',
44
+ value: level.toString(),
45
+ },
46
+ ]}
47
+ />
48
+ ),
49
+ headerColor: 'bg-emerald-700',
50
+ titleColor: 'text-white',
51
+ lang: 'en',
52
+ size: 'xl',
53
+ })
54
+ }
55
+
56
+ const catEditInit = () => {
57
+ if (value === undefined) return
58
+ setModal({
59
+ title: getString('edit'),
60
+ body: (
61
+ <ItemEditPage
62
+ sectionType='categorized'
63
+ action={() => {
64
+ refetch()
65
+ reset()
66
+ }}
67
+ itemId={value.toString()}
68
+ section={section}
69
+ hiddenInputs={[
70
+ {
71
+ name: 'parent_id',
72
+ value: parentId,
73
+ },
74
+ {
75
+ name: 'level',
76
+ value: level.toString(),
77
+ },
78
+ ]}
79
+ />
80
+ ),
81
+ headerColor: 'bg-blue-700',
82
+ titleColor: 'text-white',
83
+ lang: 'en',
84
+ size: 'xl',
85
+ })
86
+ }
87
+
88
+ const catDeleteInit = () => {
89
+ if (value === undefined) return
90
+ setModal({
91
+ title: getString('delete'),
92
+ body: (
93
+ <CategoryDeleteConfirmPage
94
+ action={() => {
95
+ refetch()
96
+ reset()
97
+ }}
98
+ allowRecursiveDelete={allowRecursiveDelete}
99
+ sectionTitle={sectionTitle}
100
+ section={section}
101
+ id={value.toString()}
102
+ />
103
+ ),
104
+ headerColor: 'bg-red-700',
105
+ titleColor: 'text-white',
106
+ lang: 'en',
107
+ size: 'lg',
108
+ })
109
+ }
110
+
111
+ return (
112
+ <div className='flex flex-row gap-1 pt-1'>
113
+ <Button variant='default' size='sm' onClick={newCatInit} type='button'>
114
+ {getString('add')}
115
+ </Button>
116
+ <Button variant='secondary' size='sm' onClick={catEditInit} type='button' disabled={value === undefined}>
117
+ {getString('edit')}
118
+ </Button>
119
+ <Button variant='destructive' size='sm' onClick={catDeleteInit} disabled={value === undefined}>
120
+ {getString('delete')}
121
+ </Button>
122
+ </div>
123
+ )
124
+ }
@@ -0,0 +1,238 @@
1
+ 'use client'
2
+
3
+ import React, { useEffect, useState } from 'react'
4
+ import getString from 'nextjs-cms/translations'
5
+ import useModal from '@/hooks/useModal'
6
+ import InfoCard from '@/components/InfoCard'
7
+ import LoadingSpinners from '@/components/LoadingSpinners'
8
+ import { useToast } from '@/components/ui/use-toast'
9
+ import { trpc } from '@/app/_trpc/client'
10
+ import Form from '@/components/form/Form'
11
+
12
+ export default function SettingsPage() {
13
+ const [isSubmitting, setIsSubmitting] = useState(false)
14
+ const { setModal, modal, modalResponse, setModalResponse } = useModal()
15
+ const controller = new AbortController()
16
+ const { toast } = useToast()
17
+
18
+ const { isLoading, isError, data, error, refetch } = trpc.accountSettings.get.useQuery()
19
+
20
+ const passwordChangeMutation = trpc.accountSettings.changePassword.useMutation({
21
+ onError: (error) => {
22
+ setIsSubmitting(false)
23
+ setModal({
24
+ title: getString('error'),
25
+ body: (
26
+ <div className='p-4'>
27
+ <InfoCard result={{ key: 'danger', title: error.message }} />
28
+ </div>
29
+ ),
30
+ headerColor: 'bg-red-700',
31
+ titleColor: 'text-white',
32
+ lang: 'en',
33
+ })
34
+ },
35
+
36
+ onSuccess: async (data) => {
37
+ setIsSubmitting(false)
38
+ if (data === true) {
39
+ // Refetch the page
40
+ await refetch()
41
+
42
+ toast({
43
+ title: getString('success'),
44
+ description: getString('success'),
45
+ duration: 2000,
46
+ })
47
+ }
48
+ },
49
+ })
50
+
51
+ const saveMutation = trpc.accountSettings.save.useMutation({
52
+ onError: (error) => {
53
+ setIsSubmitting(false)
54
+ setModal({
55
+ title: getString('error'),
56
+ body: (
57
+ <div className='p-4'>
58
+ <InfoCard result={{ key: 'danger', title: error.message }} />
59
+ </div>
60
+ ),
61
+ headerColor: 'bg-red-700',
62
+ titleColor: 'text-white',
63
+ lang: 'en',
64
+ })
65
+ },
66
+
67
+ onSuccess: async (data) => {
68
+ setIsSubmitting(false)
69
+ if (data === true) {
70
+ // Refetch the page
71
+ await refetch()
72
+
73
+ toast({
74
+ title: getString('success'),
75
+ description: getString('success'),
76
+ duration: 2000,
77
+ })
78
+ }
79
+ },
80
+ })
81
+
82
+ const handlePasswordChange = async (formData: FormData) => {
83
+ setIsSubmitting(true)
84
+ if (isSubmitting) return
85
+ passwordChangeMutation.mutate({
86
+ oldPassword: formData.get('oldPassword') as string,
87
+ newPassword: formData.get('newPassword') as string,
88
+ confirmPassword: formData.get('confirmPassword') as string,
89
+ })
90
+ }
91
+
92
+ const handleSubmit = async (formData: FormData) => {
93
+ setIsSubmitting(true)
94
+ if (isSubmitting) return
95
+ saveMutation.mutate({
96
+ emailAddress: formData.get('emailAddress') as string,
97
+ fullName: formData.get('name') as string,
98
+ phoneNumber: formData.get('phoneNumber') as string,
99
+ })
100
+ }
101
+
102
+ function cancelSubmit() {
103
+ controller.abort()
104
+ setIsSubmitting(false)
105
+ }
106
+
107
+ useEffect(() => {
108
+ return () => {
109
+ cancelSubmit()
110
+ }
111
+ }, [])
112
+
113
+ return (
114
+ <div>
115
+ <div className='w-full overflow-hidden bg-background'>
116
+ <div className='bg-gradient-to-r from-rose-200 via-rose-400 to-sky-400 p-8 font-extrabold text-black'>
117
+ <h1 className='text-3xl'>{getString('accountSettings')}</h1>
118
+ </div>
119
+ <div className='flex w-full flex-col'>
120
+ <div className='flex flex-col'>
121
+ {isLoading ? (
122
+ <div>
123
+ <LoadingSpinners />
124
+ </div>
125
+ ) : (
126
+ <>
127
+ <Form
128
+ buttonType='small'
129
+ data={{
130
+ section: {
131
+ name: 'settings',
132
+ },
133
+
134
+ inputGroups: [
135
+ {
136
+ groupId: 1,
137
+ groupTitle: getString('adminDetails'),
138
+ groupOrder: 1,
139
+ inputs: [
140
+ {
141
+ type: 'text',
142
+ required: false,
143
+ label: getString('username'),
144
+ name: 'username',
145
+ value: data?.username,
146
+ readonly: true,
147
+ conditionalFields: [],
148
+ },
149
+ {
150
+ type: 'text',
151
+ required: false,
152
+ label: getString('name'),
153
+ name: 'name',
154
+ value: data?.fullName,
155
+ readonly: false,
156
+ conditionalFields: [],
157
+ },
158
+ {
159
+ type: 'text',
160
+ required: false,
161
+ label: getString('emailAddress'),
162
+ name: 'emailAddress',
163
+ value: data?.emailAddress,
164
+ readonly: false,
165
+ conditionalFields: [],
166
+ },
167
+ {
168
+ type: 'text',
169
+ required: false,
170
+ label: getString('phoneNumber'),
171
+ name: 'phoneNumber',
172
+ value: data?.phoneNumber,
173
+ readonly: false,
174
+ conditionalFields: [],
175
+ },
176
+ ],
177
+ },
178
+ ],
179
+ }}
180
+ handleSubmit={handleSubmit}
181
+ isSubmitting={isSubmitting}
182
+ />
183
+ <hr />
184
+ <Form
185
+ buttonType='small'
186
+ data={{
187
+ section: {
188
+ name: 'settings',
189
+ },
190
+
191
+ inputGroups: [
192
+ {
193
+ groupId: 1,
194
+ groupTitle: getString('password'),
195
+ groupOrder: 1,
196
+ inputs: [
197
+ {
198
+ type: 'password',
199
+ required: true,
200
+ label: getString('oldPassword'),
201
+ name: 'oldPassword',
202
+ value: undefined,
203
+ readonly: false,
204
+ conditionalFields: [],
205
+ },
206
+ {
207
+ type: 'password',
208
+ required: true,
209
+ label: getString('new_password'),
210
+ name: 'newPassword',
211
+ value: undefined,
212
+ readonly: false,
213
+ conditionalFields: [],
214
+ },
215
+ {
216
+ type: 'password',
217
+ required: true,
218
+ label: getString('confirm_new_password'),
219
+ name: 'confirmPassword',
220
+ value: undefined,
221
+ readonly: false,
222
+ conditionalFields: [],
223
+ },
224
+ ],
225
+ },
226
+ ],
227
+ }}
228
+ handleSubmit={handlePasswordChange}
229
+ isSubmitting={isSubmitting}
230
+ />
231
+ </>
232
+ )}
233
+ </div>
234
+ </div>
235
+ </div>
236
+ </div>
237
+ )
238
+ }
@@ -0,0 +1,209 @@
1
+ import React from 'react'
2
+ import classNames from 'classnames'
3
+ import Link from 'next/link'
4
+ import Image from 'next/image'
5
+ import { SidebarProps } from 'nextjs-cms/core/types'
6
+ import SidebarItem from '@/components/SidebarItem'
7
+ import SidebarDropdownItem from '@/components/SidebarDropdownItem'
8
+ import { ScrollArea } from '@/components/ui/scroll-area'
9
+ import getString from 'nextjs-cms/translations'
10
+ import ProtectedImage from '@/components/ProtectedImage'
11
+ import { trpc } from '@/app/_trpc/client'
12
+ import { useToast } from '@/components/ui/use-toast'
13
+ import { logout, useSession } from 'nextjs-cms/auth/react'
14
+
15
+ const Sidebar = (props: SidebarProps) => {
16
+ const session = useSession()
17
+ const { isLoading, isError, data: navItems, error } = trpc.navigation.getSidebar.useQuery()
18
+ const { toast } = useToast()
19
+ const handleLogout = async (e: React.MouseEvent<HTMLAnchorElement>) => {
20
+ e.preventDefault()
21
+ e.stopPropagation()
22
+ try {
23
+ await logout()
24
+ } catch (error: any) {
25
+ toast({
26
+ variant: 'destructive',
27
+ title: getString('logoutError'),
28
+ description: error.message,
29
+ })
30
+ }
31
+ }
32
+ return (
33
+ <div
34
+ className={classNames({
35
+ 'fixed z-20 h-full bg-gradient-to-br from-indigo-600 to-sky-500 text-zinc-50 dark:from-slate-950 dark:to-pink-950 md:translate-x-0':
36
+ true,
37
+ 'transition-all duration-100 ease-in-out': true,
38
+ 'w-[300px] md:w-[275px]': true,
39
+ '-translate-x-full': !props.mobileSidebar,
40
+ })}
41
+ >
42
+ <div
43
+ className={classNames({
44
+ 'sticky inset-0 flex h-screen flex-col justify-between overflow-auto md:h-full': true,
45
+ })}
46
+ >
47
+ {/* logo and collapse button */}
48
+ <div
49
+ className={classNames({
50
+ 'sticky top-0 flex h-[65px] items-center bg-indigo-700 transition-none dark:bg-slate-900': true,
51
+ 'justify-between p-4': true,
52
+ })}
53
+ >
54
+ <span className='bg-gray-800 px-2 font-bold tracking-tighter text-amber-200 ring-1 ring-sky-500 transition-all duration-150 hover:bg-transparent hover:font-normal hover:tracking-[1em] hover:ring-0'>
55
+ LAZEMNI
56
+ </span>
57
+ </div>
58
+ <ScrollArea type='always' className='flex-grow'>
59
+ <ul
60
+ className={classNames({
61
+ 'my-2 flex flex-col items-stretch gap-2': true,
62
+ })}
63
+ >
64
+ {/*<div className='mx-3 flex flex-col border-b border-blue-900 py-2'>
65
+ <h2 className='my-2 text-xs text-gray-300'>Temp</h2>
66
+ <SidebarItem
67
+ key={123}
68
+ item={{
69
+ path: '/temp',
70
+ title: 'Temp',
71
+ }}
72
+ />
73
+ </div>*/}
74
+ {navItems && (
75
+ <>
76
+ {navItems.fixed_sections && navItems.fixed_sections.length > 0 && (
77
+ <div className='mx-3 flex flex-col border-b border-primary/40 py-2'>
78
+ <h2 className='my-2 text-xs text-gray-300'>Main</h2>
79
+ {navItems.fixed_sections.map((item, index) => {
80
+ return (
81
+ <SidebarItem
82
+ closeSideBar={props.closeSideBar}
83
+ key={index}
84
+ item={item}
85
+ />
86
+ )
87
+ })}
88
+ </div>
89
+ )}
90
+
91
+ {navItems.cat_sections && navItems.cat_sections.length > 0 && (
92
+ <div className='mx-3 flex flex-col border-b border-primary/40 py-2'>
93
+ <h2 className='my-2 text-xs text-gray-300'>Category Sections</h2>
94
+ {navItems.cat_sections.map((item, index) => {
95
+ return (
96
+ <SidebarItem
97
+ closeSideBar={props.closeSideBar}
98
+ key={index}
99
+ item={item}
100
+ />
101
+ )
102
+ })}
103
+ </div>
104
+ )}
105
+
106
+ {navItems.has_items_sections && navItems.has_items_sections.length > 0 && (
107
+ <div className='mx-3 flex flex-col border-b border-primary/40 py-2'>
108
+ <h2 className='my-2 text-xs text-gray-300'>Sections with Items</h2>
109
+ <div className='flex flex-col gap-y-2'>
110
+ {navItems.has_items_sections.map((item, index) => {
111
+ return (
112
+ <SidebarDropdownItem
113
+ closeSideBar={props.closeSideBar}
114
+ key={index}
115
+ item={item}
116
+ />
117
+ )
118
+ })}
119
+ </div>
120
+ </div>
121
+ )}
122
+ {navItems.simple_sections && navItems.simple_sections.length > 0 && (
123
+ <div className='mx-3 flex flex-col border-b border-blue-900 py-2'>
124
+ <h2 className='my-2 text-xs text-gray-300'>Simple Sections</h2>
125
+ {navItems.simple_sections.map((item, index) => {
126
+ return (
127
+ <SidebarItem
128
+ closeSideBar={props.closeSideBar}
129
+ key={index}
130
+ item={item}
131
+ />
132
+ )
133
+ })}
134
+ </div>
135
+ )}
136
+ <div className='mx-3 flex flex-col py-2'>
137
+ <h2 className='my-2 text-xs text-gray-300'>Settings</h2>
138
+ <SidebarItem
139
+ closeSideBar={props.closeSideBar}
140
+ key={101}
141
+ item={{
142
+ path: '/settings',
143
+ title: getString('accountSettings'),
144
+ }}
145
+ />
146
+ <SidebarItem
147
+ closeSideBar={props.closeSideBar}
148
+ key={102}
149
+ item={{
150
+ path: '/advanced',
151
+ title: getString('advancedSettings'),
152
+ }}
153
+ />
154
+ <Link
155
+ href='#'
156
+ onClick={handleLogout}
157
+ className={classNames({
158
+ 'rounded-lg text-white hover:bg-indigo-900 dark:hover:bg-emerald-600': true, //colors
159
+ 'transition-colors duration-100': false, //animation
160
+ 'gap-4 p-2': true,
161
+ })}
162
+ >
163
+ <span>{getString('logout')}</span>
164
+ </Link>
165
+ </div>
166
+ </>
167
+ )}
168
+ </ul>
169
+ </ScrollArea>
170
+ <div
171
+ className={classNames({
172
+ 'grid place-content-stretch bg-indigo-700 p-2 dark:bg-slate-800': true,
173
+ })}
174
+ >
175
+ <div className='flex h-12 items-center gap-4'>
176
+ {session?.data?.user.image ? (
177
+ <ProtectedImage
178
+ section={'admins'}
179
+ photo={session.data.user.image}
180
+ isThumb={true}
181
+ alt={session?.data?.user.name}
182
+ width={40}
183
+ height={40}
184
+ // fill={true}
185
+ className='rounded-full ring ring-foreground'
186
+ />
187
+ ) : (
188
+ <Image
189
+ src='/blank_avatar.png'
190
+ height={36}
191
+ width={36}
192
+ alt='profile image'
193
+ className='rounded-full ring-2 ring-inset ring-amber-300'
194
+ />
195
+ )}
196
+
197
+ <div className='flex flex-col'>
198
+ <span className='my-0 text-indigo-50'>{session?.data?.user.name}</span>
199
+ <Link href='/settings' className='text-sm text-indigo-200'>
200
+ {getString('settings')}
201
+ </Link>
202
+ </div>
203
+ </div>
204
+ </div>
205
+ </div>
206
+ </div>
207
+ )
208
+ }
209
+ export default Sidebar
@@ -0,0 +1,74 @@
1
+ import Link from 'next/link'
2
+ import classNames from 'classnames'
3
+ import React, { useState } from 'react'
4
+ import { SidebarItemProps } from 'nextjs-cms/core/types'
5
+ import { useAutoAnimate } from '@formkit/auto-animate/react'
6
+ import { ChevronDownIcon, ChevronUpIcon, FolderIcon, PlusCircleIcon, PlusIcon } from 'lucide-react'
7
+
8
+ export default function SidebarDropdownItem({ item, closeSideBar }: SidebarItemProps) {
9
+ const [parent, enableAnimations] = useAutoAnimate(/* optional config */)
10
+ const [open, setOpen] = useState(false)
11
+ return (
12
+ <div ref={parent}>
13
+ <div
14
+ className={classNames({
15
+ 'flex text-white hover:bg-indigo-900 dark:hover:bg-emerald-600': true, //colors
16
+ 'transition-colors duration-100': false, //animation
17
+ 'gap-4 rounded-md p-2': true,
18
+ 'rounded-b-none bg-indigo-700 dark:bg-emerald-600': open,
19
+ })}
20
+ onClick={() => setOpen((prev) => !prev)}
21
+ >
22
+ <li className='relative flex w-full items-center justify-between gap-2'>
23
+ {/*<span>{item.icon}</span>*/}
24
+ <span>{item.title}</span>
25
+ <span>
26
+ {open ? <ChevronUpIcon className='h-5 w-5' /> : <ChevronDownIcon className='h-5 w-5' />}
27
+ </span>
28
+ </li>
29
+ </div>
30
+ {open && (
31
+ <div
32
+ className={classNames({
33
+ 'rounded border border-t-0 border-indigo-700/50 text-white dark:border-emerald-600/50': true, //colors
34
+ 'transition-colors duration-100': false, //animation
35
+ 'flex flex-col items-stretch rounded-md rounded-t-none py-2': true,
36
+ })}
37
+ >
38
+ <Link
39
+ onClick={closeSideBar}
40
+ href={`/new${item.path}`}
41
+ className={classNames({
42
+ 'flex rounded text-white hover:underline': true, //colors
43
+ 'transition-colors duration-100': false, //animation
44
+ 'mx-3 gap-4 p-2': true,
45
+ })}
46
+ >
47
+ <li className='flex flex-row items-center gap-1'>
48
+ <span>
49
+ <PlusIcon className='size-4' />
50
+ </span>
51
+ <span>New</span>
52
+ </li>
53
+ </Link>
54
+ <Link
55
+ onClick={closeSideBar}
56
+ href={`/browse${item.path}`}
57
+ className={classNames({
58
+ 'flex rounded text-white hover:underline': true, //colors
59
+ 'transition-colors duration-100': false, //animation
60
+ 'mx-3 gap-4 p-2': true,
61
+ })}
62
+ >
63
+ <li className='flex flex-row items-center gap-1'>
64
+ <span>
65
+ <FolderIcon className='size-4' />
66
+ </span>
67
+ <span>Browse</span>
68
+ </li>
69
+ </Link>
70
+ </div>
71
+ )}
72
+ </div>
73
+ )
74
+ }
@@ -0,0 +1,19 @@
1
+ import Link from 'next/link'
2
+ import classNames from 'classnames'
3
+ import { SidebarItemProps } from 'nextjs-cms/core/types'
4
+
5
+ export default function SidebarItem({ item, closeSideBar }: SidebarItemProps) {
6
+ return (
7
+ <Link
8
+ onClick={closeSideBar}
9
+ href={item.path}
10
+ className={classNames({
11
+ 'rounded-lg text-white hover:bg-indigo-900 dark:hover:bg-emerald-600': true, //colors
12
+ 'transition-colors duration-100': false, //animation
13
+ 'gap-4 p-2': true,
14
+ })}
15
+ >
16
+ <span>{item.title}</span>
17
+ </Link>
18
+ )
19
+ }
@@ -0,0 +1,12 @@
1
+ 'use client'
2
+
3
+ import { trpc } from '@/app/_trpc/client'
4
+
5
+ export default function TempPage() {
6
+ const hello = trpc.getHello1.useQuery()
7
+ return (
8
+ <div>
9
+ <p>api data: {JSON.stringify(hello.data)}</p>
10
+ </div>
11
+ )
12
+ }