create-nextjs-cms 0.9.28 → 0.9.30
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 -21
- package/README.md +71 -71
- package/dist/helpers/utils.js +16 -16
- package/dist/lib/section-creators.js +166 -166
- package/package.json +2 -2
- package/templates/default/.eslintrc.json +5 -5
- package/templates/default/.prettierignore +7 -7
- package/templates/default/.prettierrc.json +27 -27
- package/templates/default/CHANGELOG.md +140 -140
- package/templates/default/_gitignore +57 -57
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +192 -192
- package/templates/default/app/(auth)/auth/login/page.tsx +11 -11
- package/templates/default/app/(auth)/auth-language-provider.tsx +34 -34
- package/templates/default/app/(auth)/layout.tsx +81 -81
- package/templates/default/app/(rootLayout)/admins/page.tsx +10 -10
- package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +22 -22
- package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +15 -15
- package/templates/default/app/(rootLayout)/dashboard/page.tsx +70 -70
- package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +20 -20
- package/templates/default/app/(rootLayout)/layout.tsx +81 -81
- package/templates/default/app/(rootLayout)/loading.tsx +10 -10
- package/templates/default/app/(rootLayout)/log/page.tsx +7 -7
- package/templates/default/app/(rootLayout)/new/[section]/page.tsx +15 -15
- package/templates/default/app/(rootLayout)/section/[section]/page.tsx +19 -19
- package/templates/default/app/(rootLayout)/settings/page.tsx +13 -13
- package/templates/default/app/api/auth/csrf/route.ts +25 -25
- package/templates/default/app/api/auth/refresh/route.ts +10 -10
- package/templates/default/app/api/auth/route.ts +49 -49
- package/templates/default/app/api/auth/session/route.ts +20 -20
- package/templates/default/app/api/document/route.ts +165 -165
- package/templates/default/app/api/editor/photo/route.ts +49 -49
- package/templates/default/app/api/photo/route.ts +27 -27
- package/templates/default/app/api/submit/section/item/[slug]/route.ts +95 -95
- package/templates/default/app/api/submit/section/item/route.ts +56 -56
- package/templates/default/app/api/submit/section/simple/route.ts +86 -86
- package/templates/default/app/api/video/route.ts +174 -174
- package/templates/default/app/globals.css +236 -236
- package/templates/default/cms.config.ts +56 -56
- package/templates/default/components/admin/admin-card.tsx +165 -165
- package/templates/default/components/admin/admin-edit-page.tsx +124 -124
- package/templates/default/components/admin/admin-privilege-card.tsx +184 -184
- package/templates/default/components/admin/new-admin-form.tsx +172 -172
- package/templates/default/components/container-box.tsx +24 -24
- package/templates/default/components/dnd-kit/draggable.tsx +21 -21
- package/templates/default/components/dnd-kit/droppable.tsx +20 -20
- package/templates/default/components/dnd-kit/sortable-item.tsx +18 -18
- package/templates/default/components/feedback/error-component.tsx +16 -16
- package/templates/default/components/feedback/info-card.tsx +93 -93
- package/templates/default/components/feedback/loading-spinners.tsx +67 -67
- package/templates/default/components/feedback/modal.tsx +166 -166
- package/templates/default/components/feedback/progress-bar.tsx +48 -48
- package/templates/default/components/feedback/tooltip-component.tsx +27 -27
- package/templates/default/components/form/form-input-element.tsx +70 -70
- package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
- package/templates/default/components/form/helpers/util.ts +17 -17
- package/templates/default/components/form/inputs/checkbox-form-input.tsx +46 -46
- package/templates/default/components/form/inputs/color-form-input.tsx +44 -44
- package/templates/default/components/form/inputs/date-form-input.tsx +93 -93
- package/templates/default/components/form/inputs/map-form-input.tsx +141 -141
- package/templates/default/components/form/inputs/multiple-select-form-input.tsx +85 -85
- package/templates/default/components/form/inputs/number-form-input.tsx +43 -43
- package/templates/default/components/form/inputs/password-form-input.tsx +47 -47
- package/templates/default/components/form/inputs/photo-form-input.tsx +279 -279
- package/templates/default/components/form/inputs/rich-text-form-input.tsx +148 -148
- package/templates/default/components/form/inputs/select-form-input.tsx +159 -159
- package/templates/default/components/form/inputs/slug-form-input.tsx +131 -131
- package/templates/default/components/form/inputs/tags-form-input.tsx +255 -255
- package/templates/default/components/form/inputs/text-form-input.tsx +61 -61
- package/templates/default/components/form/inputs/textarea-form-input.tsx +61 -61
- package/templates/default/components/layout/default-nav-items.tsx +3 -3
- package/templates/default/components/layout/layout.tsx +84 -84
- package/templates/default/components/layout/navbar.tsx +258 -258
- package/templates/default/components/layout/sidebar-dropdown-item.tsx +83 -83
- package/templates/default/components/layout/sidebar-item.tsx +24 -24
- package/templates/default/components/layout/sidebar.tsx +229 -229
- package/templates/default/components/layout/theme-provider.tsx +8 -8
- package/templates/default/components/layout/theme-toggle.tsx +39 -39
- package/templates/default/components/locale/locale-switcher.tsx +98 -98
- package/templates/default/components/media/dropzone.tsx +154 -154
- package/templates/default/components/media/protected-document.tsx +44 -44
- package/templates/default/components/media/protected-image.tsx +143 -143
- package/templates/default/components/media/protected-video.tsx +76 -76
- package/templates/default/components/multi-select.tsx +1150 -1150
- package/templates/default/components/pages/admins-page.tsx +43 -43
- package/templates/default/components/pages/browse-page.tsx +106 -106
- package/templates/default/components/pages/categorized-section-page.tsx +31 -31
- package/templates/default/components/pages/dashboard-page-alt.tsx +45 -45
- package/templates/default/components/pages/item-edit-page.tsx +267 -267
- package/templates/default/components/pages/log-page.tsx +107 -107
- package/templates/default/components/pages/new-page.tsx +183 -183
- package/templates/default/components/pages/section-page.tsx +203 -203
- package/templates/default/components/pages/settings-page.tsx +232 -232
- package/templates/default/components/pagination/pagination-buttons.tsx +147 -147
- package/templates/default/components/pagination/pagination.tsx +36 -36
- package/templates/default/components/sections/category-delete-confirm-page.tsx +130 -130
- package/templates/default/components/sections/category-section-select-input.tsx +139 -139
- package/templates/default/components/sections/conditional-fields.tsx +49 -49
- package/templates/default/components/sections/section-icon.tsx +8 -8
- package/templates/default/components/sections/section-item-card.tsx +143 -143
- package/templates/default/components/sections/section-item-status-badge.tsx +17 -17
- package/templates/default/components/sections/select-input-buttons.tsx +125 -125
- package/templates/default/components/select-box.tsx +98 -98
- package/templates/default/components/ui/accordion.tsx +53 -53
- package/templates/default/components/ui/alert-dialog.tsx +113 -113
- package/templates/default/components/ui/alert.tsx +47 -47
- package/templates/default/components/ui/badge.tsx +38 -38
- package/templates/default/components/ui/card.tsx +43 -43
- package/templates/default/components/ui/command.tsx +137 -137
- package/templates/default/components/ui/custom-alert-dialog.tsx +113 -113
- package/templates/default/components/ui/custom-dialog.tsx +123 -123
- package/templates/default/components/ui/dialog.tsx +123 -123
- package/templates/default/components/ui/direction.tsx +22 -22
- package/templates/default/components/ui/dropdown-menu.tsx +182 -182
- package/templates/default/components/ui/input-group.tsx +54 -54
- package/templates/default/components/ui/input.tsx +22 -22
- package/templates/default/components/ui/label.tsx +19 -19
- package/templates/default/components/ui/popover.tsx +42 -42
- package/templates/default/components/ui/progress.tsx +31 -31
- package/templates/default/components/ui/scroll-area.tsx +42 -42
- package/templates/default/components/ui/select.tsx +165 -165
- package/templates/default/components/ui/separator.tsx +28 -28
- package/templates/default/components/ui/sheet.tsx +103 -103
- package/templates/default/components/ui/spinner.tsx +16 -16
- package/templates/default/components/ui/switch.tsx +29 -29
- package/templates/default/components/ui/table.tsx +83 -83
- package/templates/default/components/ui/tabs.tsx +55 -55
- package/templates/default/components/ui/toast.tsx +113 -113
- package/templates/default/components/ui/toaster.tsx +35 -35
- package/templates/default/components/ui/tooltip.tsx +30 -30
- package/templates/default/components/ui/use-toast.ts +187 -187
- package/templates/default/drizzle.config.ts +4 -4
- package/templates/default/dynamic-schemas/schema.ts +75 -225
- package/templates/default/env/env.ts +46 -46
- package/templates/default/envConfig.ts +4 -4
- package/templates/default/lib/postinstall.js +14 -14
- package/templates/default/lib/utils.ts +6 -6
- package/templates/default/next-env.d.ts +6 -6
- package/templates/default/next.config.ts +24 -24
- package/templates/default/package.json +1 -1
- package/templates/default/postcss.config.mjs +6 -6
- package/templates/default/proxy.ts +32 -32
- package/templates/default/tsconfig.json +48 -48
|
@@ -1,229 +1,229 @@
|
|
|
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/layout/sidebar-item'
|
|
7
|
-
import SidebarDropdownItem from '@/components/layout/sidebar-dropdown-item'
|
|
8
|
-
import SidebarPluginGroup from '@/components/layout/sidebar-plugin-group'
|
|
9
|
-
import { ScrollArea } from '@/components/ui/scroll-area'
|
|
10
|
-
import { useI18n } from 'nextjs-cms/translations/client'
|
|
11
|
-
import ProtectedImage from '@/components/media/protected-image'
|
|
12
|
-
import { trpc } from '@/app/_trpc/client'
|
|
13
|
-
import { useToast } from '@/components/ui/use-toast'
|
|
14
|
-
import { logout, useSession } from 'nextjs-cms/auth/react'
|
|
15
|
-
import { LogOut } from 'lucide-react'
|
|
16
|
-
|
|
17
|
-
const Sidebar = (props: SidebarProps & { logoUrlPath: string; logoText: string; isRTL: boolean }) => {
|
|
18
|
-
const t = useI18n()
|
|
19
|
-
const session = useSession()
|
|
20
|
-
const [navItems] = trpc.navigation.getSidebar.useSuspenseQuery()
|
|
21
|
-
const { toast } = useToast()
|
|
22
|
-
const handleLogout = async (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
23
|
-
e.preventDefault()
|
|
24
|
-
e.stopPropagation()
|
|
25
|
-
try {
|
|
26
|
-
await logout()
|
|
27
|
-
} catch (error: any) {
|
|
28
|
-
toast({
|
|
29
|
-
variant: 'destructive',
|
|
30
|
-
title: t('logoutError'),
|
|
31
|
-
description: error.message,
|
|
32
|
-
})
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return (
|
|
36
|
-
<div
|
|
37
|
-
className={classNames({
|
|
38
|
-
'fixed z-20 h-full bg-linear-to-br from-indigo-600 to-sky-500 text-zinc-50 dark:from-slate-950 dark:to-pink-950':
|
|
39
|
-
true,
|
|
40
|
-
'transition-all duration-100 ease-in-out': true,
|
|
41
|
-
'w-[300px] md:w-[275px]': true,
|
|
42
|
-
// LTR: sidebar on left, slides in from left
|
|
43
|
-
'left-0': !props.isRTL,
|
|
44
|
-
'md:translate-x-0': !props.isRTL,
|
|
45
|
-
'-translate-x-full': !props.isRTL && !props.mobileSidebar,
|
|
46
|
-
// RTL: sidebar on right, slides in from right
|
|
47
|
-
'right-0': props.isRTL,
|
|
48
|
-
'translate-x-full md:translate-x-0': props.isRTL && !props.mobileSidebar,
|
|
49
|
-
// Mobile sidebar shown (both LTR and RTL)
|
|
50
|
-
'translate-x-0': props.mobileSidebar,
|
|
51
|
-
})}
|
|
52
|
-
>
|
|
53
|
-
<div
|
|
54
|
-
className={classNames({
|
|
55
|
-
'sticky inset-0 flex h-screen flex-col justify-between overflow-auto md:h-full': true,
|
|
56
|
-
})}
|
|
57
|
-
>
|
|
58
|
-
{/* logo and collapse button */}
|
|
59
|
-
<div
|
|
60
|
-
className={classNames({
|
|
61
|
-
'sticky top-0 flex h-[65px] shrink-0 items-center bg-indigo-700 transition-none dark:bg-slate-900': true,
|
|
62
|
-
'justify-start gap-2 p-4': true,
|
|
63
|
-
})}
|
|
64
|
-
>
|
|
65
|
-
<Image src={props.logoUrlPath} alt={t('logo') as string} width={32} height={32} />
|
|
66
|
-
<span className='bg-transparent px-2 font-normal tracking-[0.1em] text-white/90 transition-all duration-150'>
|
|
67
|
-
{props.logoText}
|
|
68
|
-
</span>
|
|
69
|
-
</div>
|
|
70
|
-
<ScrollArea dir={props.isRTL ? 'rtl' : 'ltr'} type='always' className='grow'>
|
|
71
|
-
<ul
|
|
72
|
-
className={classNames({
|
|
73
|
-
'my-2 flex flex-col items-stretch gap-2': true,
|
|
74
|
-
})}
|
|
75
|
-
>
|
|
76
|
-
{navItems && (
|
|
77
|
-
<>
|
|
78
|
-
{navItems.fixed_sections && navItems.fixed_sections.length > 0 && (
|
|
79
|
-
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
80
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('main')}</h2>
|
|
81
|
-
{navItems.fixed_sections.map((item, index) => {
|
|
82
|
-
return (
|
|
83
|
-
<SidebarItem
|
|
84
|
-
closeSideBar={props.closeSideBar}
|
|
85
|
-
key={index}
|
|
86
|
-
item={item}
|
|
87
|
-
/>
|
|
88
|
-
)
|
|
89
|
-
})}
|
|
90
|
-
</div>
|
|
91
|
-
)}
|
|
92
|
-
|
|
93
|
-
{navItems.plugin_sections && navItems.plugin_sections.length > 0 && (
|
|
94
|
-
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
95
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('plugins')}</h2>
|
|
96
|
-
{navItems.plugin_sections.map((item, index) => {
|
|
97
|
-
if (item.kind === 'group') {
|
|
98
|
-
return (
|
|
99
|
-
<SidebarPluginGroup
|
|
100
|
-
closeSideBar={props.closeSideBar}
|
|
101
|
-
key={index}
|
|
102
|
-
group={item}
|
|
103
|
-
/>
|
|
104
|
-
)
|
|
105
|
-
}
|
|
106
|
-
return (
|
|
107
|
-
<SidebarItem
|
|
108
|
-
closeSideBar={props.closeSideBar}
|
|
109
|
-
key={index}
|
|
110
|
-
item={item}
|
|
111
|
-
/>
|
|
112
|
-
)
|
|
113
|
-
})}
|
|
114
|
-
</div>
|
|
115
|
-
)}
|
|
116
|
-
|
|
117
|
-
{navItems.cat_sections && navItems.cat_sections.length > 0 && (
|
|
118
|
-
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
119
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('categorySections')}</h2>
|
|
120
|
-
{navItems.cat_sections.map((item, index) => {
|
|
121
|
-
return (
|
|
122
|
-
<SidebarItem
|
|
123
|
-
closeSideBar={props.closeSideBar}
|
|
124
|
-
key={index}
|
|
125
|
-
item={item}
|
|
126
|
-
/>
|
|
127
|
-
)
|
|
128
|
-
})}
|
|
129
|
-
</div>
|
|
130
|
-
)}
|
|
131
|
-
|
|
132
|
-
{navItems.has_items_sections && navItems.has_items_sections.length > 0 && (
|
|
133
|
-
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
134
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('sectionsWithItems')}</h2>
|
|
135
|
-
<div className='flex flex-col gap-y-2'>
|
|
136
|
-
{navItems.has_items_sections.map((item, index) => {
|
|
137
|
-
return (
|
|
138
|
-
<SidebarDropdownItem
|
|
139
|
-
closeSideBar={props.closeSideBar}
|
|
140
|
-
key={index}
|
|
141
|
-
item={item}
|
|
142
|
-
/>
|
|
143
|
-
)
|
|
144
|
-
})}
|
|
145
|
-
</div>
|
|
146
|
-
</div>
|
|
147
|
-
)}
|
|
148
|
-
{navItems.simple_sections && navItems.simple_sections.length > 0 && (
|
|
149
|
-
<div className='mx-3 flex flex-col border-b border-blue-900 py-2'>
|
|
150
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('simpleSections')}</h2>
|
|
151
|
-
{navItems.simple_sections.map((item, index) => {
|
|
152
|
-
return (
|
|
153
|
-
<SidebarItem
|
|
154
|
-
closeSideBar={props.closeSideBar}
|
|
155
|
-
key={index}
|
|
156
|
-
item={item}
|
|
157
|
-
/>
|
|
158
|
-
)
|
|
159
|
-
})}
|
|
160
|
-
</div>
|
|
161
|
-
)}
|
|
162
|
-
<div className='mx-3 flex flex-col py-2'>
|
|
163
|
-
<h2 className='my-2 text-start text-xs text-gray-300'>{t('settings')}</h2>
|
|
164
|
-
<SidebarItem
|
|
165
|
-
closeSideBar={props.closeSideBar}
|
|
166
|
-
key={101}
|
|
167
|
-
item={{
|
|
168
|
-
path: '/settings',
|
|
169
|
-
title: t('accountSettings'),
|
|
170
|
-
icon: 'cog'
|
|
171
|
-
}}
|
|
172
|
-
/>
|
|
173
|
-
<Link
|
|
174
|
-
href='#'
|
|
175
|
-
onClick={handleLogout}
|
|
176
|
-
className={classNames({
|
|
177
|
-
'flex flex-row gap-1 items-center rounded-lg hover:text-white hover:bg-indigo-900 dark:hover:bg-emerald-600': true, //colors
|
|
178
|
-
'transition-colors duration-100': false, //animation
|
|
179
|
-
'gap-4 p-2 text-start': true,
|
|
180
|
-
})}
|
|
181
|
-
>
|
|
182
|
-
<LogOut className='size-4' />
|
|
183
|
-
<span>{t('logout')}</span>
|
|
184
|
-
</Link>
|
|
185
|
-
</div>
|
|
186
|
-
</>
|
|
187
|
-
)}
|
|
188
|
-
</ul>
|
|
189
|
-
</ScrollArea>
|
|
190
|
-
<div
|
|
191
|
-
className={classNames({
|
|
192
|
-
'grid place-content-stretch bg-indigo-700 p-2 dark:bg-slate-800': true,
|
|
193
|
-
})}
|
|
194
|
-
>
|
|
195
|
-
<div className='flex h-12 items-center gap-4'>
|
|
196
|
-
{session?.data?.user.image ? (
|
|
197
|
-
<ProtectedImage
|
|
198
|
-
section={'admins'}
|
|
199
|
-
photo={session.data.user.image}
|
|
200
|
-
isThumb={true}
|
|
201
|
-
alt={session?.data?.user.name}
|
|
202
|
-
width={40}
|
|
203
|
-
height={40}
|
|
204
|
-
// fill={true}
|
|
205
|
-
className='ring-foreground rounded-full ring-3'
|
|
206
|
-
/>
|
|
207
|
-
) : (
|
|
208
|
-
<Image
|
|
209
|
-
src='/blank_avatar.png'
|
|
210
|
-
height={36}
|
|
211
|
-
width={36}
|
|
212
|
-
alt={t('profileImage') as string}
|
|
213
|
-
className='rounded-full ring-2 ring-amber-300 ring-inset'
|
|
214
|
-
/>
|
|
215
|
-
)}
|
|
216
|
-
|
|
217
|
-
<div className='flex flex-col text-start'>
|
|
218
|
-
<span className='my-0 text-indigo-50'>{session?.data?.user.name}</span>
|
|
219
|
-
<Link href='/settings' className='text-sm text-indigo-200'>
|
|
220
|
-
{t('settings')}
|
|
221
|
-
</Link>
|
|
222
|
-
</div>
|
|
223
|
-
</div>
|
|
224
|
-
</div>
|
|
225
|
-
</div>
|
|
226
|
-
</div>
|
|
227
|
-
)
|
|
228
|
-
}
|
|
229
|
-
export default Sidebar
|
|
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/layout/sidebar-item'
|
|
7
|
+
import SidebarDropdownItem from '@/components/layout/sidebar-dropdown-item'
|
|
8
|
+
import SidebarPluginGroup from '@/components/layout/sidebar-plugin-group'
|
|
9
|
+
import { ScrollArea } from '@/components/ui/scroll-area'
|
|
10
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
11
|
+
import ProtectedImage from '@/components/media/protected-image'
|
|
12
|
+
import { trpc } from '@/app/_trpc/client'
|
|
13
|
+
import { useToast } from '@/components/ui/use-toast'
|
|
14
|
+
import { logout, useSession } from 'nextjs-cms/auth/react'
|
|
15
|
+
import { LogOut } from 'lucide-react'
|
|
16
|
+
|
|
17
|
+
const Sidebar = (props: SidebarProps & { logoUrlPath: string; logoText: string; isRTL: boolean }) => {
|
|
18
|
+
const t = useI18n()
|
|
19
|
+
const session = useSession()
|
|
20
|
+
const [navItems] = trpc.navigation.getSidebar.useSuspenseQuery()
|
|
21
|
+
const { toast } = useToast()
|
|
22
|
+
const handleLogout = async (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
23
|
+
e.preventDefault()
|
|
24
|
+
e.stopPropagation()
|
|
25
|
+
try {
|
|
26
|
+
await logout()
|
|
27
|
+
} catch (error: any) {
|
|
28
|
+
toast({
|
|
29
|
+
variant: 'destructive',
|
|
30
|
+
title: t('logoutError'),
|
|
31
|
+
description: error.message,
|
|
32
|
+
})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return (
|
|
36
|
+
<div
|
|
37
|
+
className={classNames({
|
|
38
|
+
'fixed z-20 h-full bg-linear-to-br from-indigo-600 to-sky-500 text-zinc-50 dark:from-slate-950 dark:to-pink-950':
|
|
39
|
+
true,
|
|
40
|
+
'transition-all duration-100 ease-in-out': true,
|
|
41
|
+
'w-[300px] md:w-[275px]': true,
|
|
42
|
+
// LTR: sidebar on left, slides in from left
|
|
43
|
+
'left-0': !props.isRTL,
|
|
44
|
+
'md:translate-x-0': !props.isRTL,
|
|
45
|
+
'-translate-x-full': !props.isRTL && !props.mobileSidebar,
|
|
46
|
+
// RTL: sidebar on right, slides in from right
|
|
47
|
+
'right-0': props.isRTL,
|
|
48
|
+
'translate-x-full md:translate-x-0': props.isRTL && !props.mobileSidebar,
|
|
49
|
+
// Mobile sidebar shown (both LTR and RTL)
|
|
50
|
+
'translate-x-0': props.mobileSidebar,
|
|
51
|
+
})}
|
|
52
|
+
>
|
|
53
|
+
<div
|
|
54
|
+
className={classNames({
|
|
55
|
+
'sticky inset-0 flex h-screen flex-col justify-between overflow-auto md:h-full': true,
|
|
56
|
+
})}
|
|
57
|
+
>
|
|
58
|
+
{/* logo and collapse button */}
|
|
59
|
+
<div
|
|
60
|
+
className={classNames({
|
|
61
|
+
'sticky top-0 flex h-[65px] shrink-0 items-center bg-indigo-700 transition-none dark:bg-slate-900': true,
|
|
62
|
+
'justify-start gap-2 p-4': true,
|
|
63
|
+
})}
|
|
64
|
+
>
|
|
65
|
+
<Image src={props.logoUrlPath} alt={t('logo') as string} width={32} height={32} />
|
|
66
|
+
<span className='bg-transparent px-2 font-normal tracking-[0.1em] text-white/90 transition-all duration-150'>
|
|
67
|
+
{props.logoText}
|
|
68
|
+
</span>
|
|
69
|
+
</div>
|
|
70
|
+
<ScrollArea dir={props.isRTL ? 'rtl' : 'ltr'} type='always' className='grow'>
|
|
71
|
+
<ul
|
|
72
|
+
className={classNames({
|
|
73
|
+
'my-2 flex flex-col items-stretch gap-2': true,
|
|
74
|
+
})}
|
|
75
|
+
>
|
|
76
|
+
{navItems && (
|
|
77
|
+
<>
|
|
78
|
+
{navItems.fixed_sections && navItems.fixed_sections.length > 0 && (
|
|
79
|
+
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
80
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('main')}</h2>
|
|
81
|
+
{navItems.fixed_sections.map((item, index) => {
|
|
82
|
+
return (
|
|
83
|
+
<SidebarItem
|
|
84
|
+
closeSideBar={props.closeSideBar}
|
|
85
|
+
key={index}
|
|
86
|
+
item={item}
|
|
87
|
+
/>
|
|
88
|
+
)
|
|
89
|
+
})}
|
|
90
|
+
</div>
|
|
91
|
+
)}
|
|
92
|
+
|
|
93
|
+
{navItems.plugin_sections && navItems.plugin_sections.length > 0 && (
|
|
94
|
+
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
95
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('plugins')}</h2>
|
|
96
|
+
{navItems.plugin_sections.map((item, index) => {
|
|
97
|
+
if (item.kind === 'group') {
|
|
98
|
+
return (
|
|
99
|
+
<SidebarPluginGroup
|
|
100
|
+
closeSideBar={props.closeSideBar}
|
|
101
|
+
key={index}
|
|
102
|
+
group={item}
|
|
103
|
+
/>
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
return (
|
|
107
|
+
<SidebarItem
|
|
108
|
+
closeSideBar={props.closeSideBar}
|
|
109
|
+
key={index}
|
|
110
|
+
item={item}
|
|
111
|
+
/>
|
|
112
|
+
)
|
|
113
|
+
})}
|
|
114
|
+
</div>
|
|
115
|
+
)}
|
|
116
|
+
|
|
117
|
+
{navItems.cat_sections && navItems.cat_sections.length > 0 && (
|
|
118
|
+
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
119
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('categorySections')}</h2>
|
|
120
|
+
{navItems.cat_sections.map((item, index) => {
|
|
121
|
+
return (
|
|
122
|
+
<SidebarItem
|
|
123
|
+
closeSideBar={props.closeSideBar}
|
|
124
|
+
key={index}
|
|
125
|
+
item={item}
|
|
126
|
+
/>
|
|
127
|
+
)
|
|
128
|
+
})}
|
|
129
|
+
</div>
|
|
130
|
+
)}
|
|
131
|
+
|
|
132
|
+
{navItems.has_items_sections && navItems.has_items_sections.length > 0 && (
|
|
133
|
+
<div className='border-primary/40 mx-3 flex flex-col border-b py-2'>
|
|
134
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('sectionsWithItems')}</h2>
|
|
135
|
+
<div className='flex flex-col gap-y-2'>
|
|
136
|
+
{navItems.has_items_sections.map((item, index) => {
|
|
137
|
+
return (
|
|
138
|
+
<SidebarDropdownItem
|
|
139
|
+
closeSideBar={props.closeSideBar}
|
|
140
|
+
key={index}
|
|
141
|
+
item={item}
|
|
142
|
+
/>
|
|
143
|
+
)
|
|
144
|
+
})}
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
{navItems.simple_sections && navItems.simple_sections.length > 0 && (
|
|
149
|
+
<div className='mx-3 flex flex-col border-b border-blue-900 py-2'>
|
|
150
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('simpleSections')}</h2>
|
|
151
|
+
{navItems.simple_sections.map((item, index) => {
|
|
152
|
+
return (
|
|
153
|
+
<SidebarItem
|
|
154
|
+
closeSideBar={props.closeSideBar}
|
|
155
|
+
key={index}
|
|
156
|
+
item={item}
|
|
157
|
+
/>
|
|
158
|
+
)
|
|
159
|
+
})}
|
|
160
|
+
</div>
|
|
161
|
+
)}
|
|
162
|
+
<div className='mx-3 flex flex-col py-2'>
|
|
163
|
+
<h2 className='my-2 text-start text-xs text-gray-300'>{t('settings')}</h2>
|
|
164
|
+
<SidebarItem
|
|
165
|
+
closeSideBar={props.closeSideBar}
|
|
166
|
+
key={101}
|
|
167
|
+
item={{
|
|
168
|
+
path: '/settings',
|
|
169
|
+
title: t('accountSettings'),
|
|
170
|
+
icon: 'cog'
|
|
171
|
+
}}
|
|
172
|
+
/>
|
|
173
|
+
<Link
|
|
174
|
+
href='#'
|
|
175
|
+
onClick={handleLogout}
|
|
176
|
+
className={classNames({
|
|
177
|
+
'flex flex-row gap-1 items-center rounded-lg hover:text-white hover:bg-indigo-900 dark:hover:bg-emerald-600': true, //colors
|
|
178
|
+
'transition-colors duration-100': false, //animation
|
|
179
|
+
'gap-4 p-2 text-start': true,
|
|
180
|
+
})}
|
|
181
|
+
>
|
|
182
|
+
<LogOut className='size-4' />
|
|
183
|
+
<span>{t('logout')}</span>
|
|
184
|
+
</Link>
|
|
185
|
+
</div>
|
|
186
|
+
</>
|
|
187
|
+
)}
|
|
188
|
+
</ul>
|
|
189
|
+
</ScrollArea>
|
|
190
|
+
<div
|
|
191
|
+
className={classNames({
|
|
192
|
+
'grid place-content-stretch bg-indigo-700 p-2 dark:bg-slate-800': true,
|
|
193
|
+
})}
|
|
194
|
+
>
|
|
195
|
+
<div className='flex h-12 items-center gap-4'>
|
|
196
|
+
{session?.data?.user.image ? (
|
|
197
|
+
<ProtectedImage
|
|
198
|
+
section={'admins'}
|
|
199
|
+
photo={session.data.user.image}
|
|
200
|
+
isThumb={true}
|
|
201
|
+
alt={session?.data?.user.name}
|
|
202
|
+
width={40}
|
|
203
|
+
height={40}
|
|
204
|
+
// fill={true}
|
|
205
|
+
className='ring-foreground rounded-full ring-3'
|
|
206
|
+
/>
|
|
207
|
+
) : (
|
|
208
|
+
<Image
|
|
209
|
+
src='/blank_avatar.png'
|
|
210
|
+
height={36}
|
|
211
|
+
width={36}
|
|
212
|
+
alt={t('profileImage') as string}
|
|
213
|
+
className='rounded-full ring-2 ring-amber-300 ring-inset'
|
|
214
|
+
/>
|
|
215
|
+
)}
|
|
216
|
+
|
|
217
|
+
<div className='flex flex-col text-start'>
|
|
218
|
+
<span className='my-0 text-indigo-50'>{session?.data?.user.name}</span>
|
|
219
|
+
<Link href='/settings' className='text-sm text-indigo-200'>
|
|
220
|
+
{t('settings')}
|
|
221
|
+
</Link>
|
|
222
|
+
</div>
|
|
223
|
+
</div>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
)
|
|
228
|
+
}
|
|
229
|
+
export default Sidebar
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import * as React from 'react'
|
|
4
|
-
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
5
|
-
|
|
6
|
-
export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) {
|
|
7
|
-
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
|
8
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import { ThemeProvider as NextThemesProvider } from 'next-themes'
|
|
5
|
+
|
|
6
|
+
export function ThemeProvider({ children, ...props }: React.ComponentProps<typeof NextThemesProvider>) {
|
|
7
|
+
return <NextThemesProvider {...props}>{children}</NextThemesProvider>
|
|
8
|
+
}
|
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
2
|
-
import { useTheme } from 'next-themes'
|
|
3
|
-
import { MoonIcon, SunIcon } from '@radix-ui/react-icons'
|
|
4
|
-
import { Spinner } from '@/components/ui/spinner'
|
|
5
|
-
import { useI18n } from 'nextjs-cms/translations/client'
|
|
6
|
-
|
|
7
|
-
const ThemeToggle = () => {
|
|
8
|
-
const t = useI18n()
|
|
9
|
-
const [mounted, setMounted] = useState(false)
|
|
10
|
-
const { theme, setTheme } = useTheme()
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
setMounted(true)
|
|
14
|
-
}, [])
|
|
15
|
-
|
|
16
|
-
if (!mounted) {
|
|
17
|
-
return <Spinner className='size-6' aria-label={t('loading') as string} />
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
<button
|
|
22
|
-
onClick={() => {
|
|
23
|
-
setTheme(theme === 'dark' ? 'light' : 'dark')
|
|
24
|
-
}}
|
|
25
|
-
type='button'
|
|
26
|
-
className='text-foreground hover:text-foreground/90 relative flex h-10 items-center justify-center rounded-full focus:outline-hidden cursor-pointer'
|
|
27
|
-
>
|
|
28
|
-
<span className='absolute -inset-1.5' />
|
|
29
|
-
<span className='sr-only'>{t('theme')}</span>
|
|
30
|
-
{theme === 'dark' ? (
|
|
31
|
-
<SunIcon className='h-6 w-6' aria-hidden='true' />
|
|
32
|
-
) : (
|
|
33
|
-
<MoonIcon className='h-6 w-6' aria-hidden='true' />
|
|
34
|
-
)}
|
|
35
|
-
</button>
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export default ThemeToggle
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import { useTheme } from 'next-themes'
|
|
3
|
+
import { MoonIcon, SunIcon } from '@radix-ui/react-icons'
|
|
4
|
+
import { Spinner } from '@/components/ui/spinner'
|
|
5
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
6
|
+
|
|
7
|
+
const ThemeToggle = () => {
|
|
8
|
+
const t = useI18n()
|
|
9
|
+
const [mounted, setMounted] = useState(false)
|
|
10
|
+
const { theme, setTheme } = useTheme()
|
|
11
|
+
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
setMounted(true)
|
|
14
|
+
}, [])
|
|
15
|
+
|
|
16
|
+
if (!mounted) {
|
|
17
|
+
return <Spinner className='size-6' aria-label={t('loading') as string} />
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<button
|
|
22
|
+
onClick={() => {
|
|
23
|
+
setTheme(theme === 'dark' ? 'light' : 'dark')
|
|
24
|
+
}}
|
|
25
|
+
type='button'
|
|
26
|
+
className='text-foreground hover:text-foreground/90 relative flex h-10 items-center justify-center rounded-full focus:outline-hidden cursor-pointer'
|
|
27
|
+
>
|
|
28
|
+
<span className='absolute -inset-1.5' />
|
|
29
|
+
<span className='sr-only'>{t('theme')}</span>
|
|
30
|
+
{theme === 'dark' ? (
|
|
31
|
+
<SunIcon className='h-6 w-6' aria-hidden='true' />
|
|
32
|
+
) : (
|
|
33
|
+
<MoonIcon className='h-6 w-6' aria-hidden='true' />
|
|
34
|
+
)}
|
|
35
|
+
</button>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export default ThemeToggle
|