create-nextjs-cms 0.9.14 → 0.9.16
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/package.json +3 -3
- package/templates/default/components/ItemEditPage.tsx +27 -28
- package/templates/default/components/LocaleSwitcher.tsx +32 -23
- package/templates/default/components/SectionPage.tsx +24 -26
- package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
- package/templates/default/next-env.d.ts +1 -1
- package/templates/default/package.json +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-nextjs-cms",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.16",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"tsx": "^4.20.6",
|
|
30
30
|
"typescript": "^5.9.2",
|
|
31
31
|
"@lzcms/eslint-config": "0.3.0",
|
|
32
|
-
"@lzcms/
|
|
33
|
-
"@lzcms/
|
|
32
|
+
"@lzcms/tsconfig": "0.1.0",
|
|
33
|
+
"@lzcms/prettier-config": "0.1.0"
|
|
34
34
|
},
|
|
35
35
|
"prettier": "@lzcms/prettier-config",
|
|
36
36
|
"scripts": {
|
|
@@ -17,7 +17,6 @@ import ErrorComponent from '@/components/ErrorComponent'
|
|
|
17
17
|
import LocaleSwitcher from '@/components/LocaleSwitcher'
|
|
18
18
|
import { Trash2 } from 'lucide-react'
|
|
19
19
|
import { Alert, AlertDescription } from './ui/alert'
|
|
20
|
-
import { ExclamationTriangleIcon } from '@radix-ui/react-icons'
|
|
21
20
|
|
|
22
21
|
export default function ItemEditPage({
|
|
23
22
|
section,
|
|
@@ -52,7 +51,7 @@ export default function ItemEditPage({
|
|
|
52
51
|
const handleDirtyChange = useCallback((isDirty: boolean) => setFormDirty(isDirty), [])
|
|
53
52
|
const dropzoneRef: RefObject<DropzoneHandles | null> = useRef(null)
|
|
54
53
|
const variantRef: RefObject<VariantHandles[]> = useRef([])
|
|
55
|
-
const [data, {refetch}] = trpc.hasItemsSections.editItem.useSuspenseQuery({
|
|
54
|
+
const [data, { refetch }] = trpc.hasItemsSections.editItem.useSuspenseQuery({
|
|
56
55
|
sectionName: section,
|
|
57
56
|
sectionItemId: itemId,
|
|
58
57
|
locale,
|
|
@@ -223,21 +222,21 @@ export default function ItemEditPage({
|
|
|
223
222
|
}, [])
|
|
224
223
|
|
|
225
224
|
if (data.error) {
|
|
226
|
-
|
|
225
|
+
return <ErrorComponent message={data.error.message} />
|
|
227
226
|
}
|
|
228
227
|
|
|
229
228
|
return (
|
|
230
229
|
<div className='flex w-full flex-col overflow-hidden'>
|
|
231
230
|
<div className='flex w-full flex-col'>
|
|
232
|
-
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold
|
|
233
|
-
<div className='absolute
|
|
231
|
+
<div className='text-foreground relative z-1 border-b-2 p-8 pt-12 font-extrabold'>
|
|
232
|
+
<div className='absolute top-0 left-0 z-2 h-4 w-full bg-linear-to-r from-emerald-800 via-emerald-400 to-sky-600'></div>
|
|
234
233
|
<h1 className='pb-4 text-4xl'>{data.section?.title.section}</h1>
|
|
235
234
|
<span>
|
|
236
235
|
/{t('edit')} {data.section?.title.singular}
|
|
237
236
|
</span>
|
|
238
237
|
</div>
|
|
239
|
-
{data.localization
|
|
240
|
-
<div className=
|
|
238
|
+
{data.localization?.localeSwitcherEnabled ? (
|
|
239
|
+
<div className='px-4 pt-4'>
|
|
241
240
|
<LocaleSwitcher
|
|
242
241
|
section={section}
|
|
243
242
|
itemId={itemId}
|
|
@@ -246,32 +245,32 @@ export default function ItemEditPage({
|
|
|
246
245
|
existingTranslations={data.localization.existingTranslations}
|
|
247
246
|
locales={data.localization.locales}
|
|
248
247
|
hasUnsavedChanges={formDirty}
|
|
248
|
+
developerOnly={data.localization.developerNoteEnabled}
|
|
249
249
|
/>
|
|
250
250
|
{locale && (
|
|
251
251
|
<Alert variant='info' className='mt-2 w-full'>
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
</
|
|
271
|
-
</Alert>
|
|
252
|
+
<AlertDescription className='text-md font-bold'>
|
|
253
|
+
<div className='flex items-center justify-between'>
|
|
254
|
+
<span>{t('editingContentTranslation', { locale })}</span>
|
|
255
|
+
{data.localization.existingTranslations.includes(locale) && (
|
|
256
|
+
<button
|
|
257
|
+
type='button'
|
|
258
|
+
onClick={handleDeleteLocale}
|
|
259
|
+
disabled={deleteLocaleMutation.isPending}
|
|
260
|
+
className='inline-flex items-center gap-1.5 rounded-md bg-red-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-red-700 disabled:opacity-50'
|
|
261
|
+
>
|
|
262
|
+
<Trash2 className='h-3.5 w-3.5' />
|
|
263
|
+
{deleteLocaleMutation.isPending
|
|
264
|
+
? t('loading')
|
|
265
|
+
: t('deleteLocaleTranslation')}
|
|
266
|
+
</button>
|
|
267
|
+
)}
|
|
268
|
+
</div>
|
|
269
|
+
</AlertDescription>
|
|
270
|
+
</Alert>
|
|
272
271
|
)}
|
|
273
272
|
</div>
|
|
274
|
-
)}
|
|
273
|
+
) : null}
|
|
275
274
|
<Form
|
|
276
275
|
key={locale ?? 'default'}
|
|
277
276
|
formType='edit'
|
|
@@ -6,6 +6,7 @@ import { Check } from 'lucide-react'
|
|
|
6
6
|
import { useI18n } from 'nextjs-cms/translations/client'
|
|
7
7
|
import { useSession } from 'nextjs-cms/auth/react'
|
|
8
8
|
import ContainerBox from './ContainerBox'
|
|
9
|
+
import { Alert, AlertDescription } from './ui/alert'
|
|
9
10
|
|
|
10
11
|
type LocaleConfig = {
|
|
11
12
|
code: string
|
|
@@ -21,6 +22,7 @@ type Props = {
|
|
|
21
22
|
existingTranslations: string[]
|
|
22
23
|
locales: LocaleConfig[]
|
|
23
24
|
hasUnsavedChanges?: boolean
|
|
25
|
+
developerOnly?: boolean
|
|
24
26
|
/** Base path for locale links. Defaults to `/edit/${section}/${itemId}` for hasItems sections. */
|
|
25
27
|
basePath?: string
|
|
26
28
|
}
|
|
@@ -33,6 +35,7 @@ export default function LocaleSwitcher({
|
|
|
33
35
|
existingTranslations,
|
|
34
36
|
locales,
|
|
35
37
|
hasUnsavedChanges,
|
|
38
|
+
developerOnly,
|
|
36
39
|
basePath,
|
|
37
40
|
}: Props) {
|
|
38
41
|
const t = useI18n()
|
|
@@ -59,31 +62,37 @@ export default function LocaleSwitcher({
|
|
|
59
62
|
|
|
60
63
|
return (
|
|
61
64
|
<ContainerBox title={t('localesHeading')}>
|
|
62
|
-
<div className=
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
<div className='flex flex-wrap items-center gap-2'>
|
|
66
|
+
{locales.map((locale) => {
|
|
67
|
+
const isActive = locale.code === currentLocale.code
|
|
68
|
+
const hasTranslation =
|
|
69
|
+
locale.code === defaultLocale.code || existingTranslations.includes(locale.code)
|
|
70
|
+
const isDefault = locale.code === defaultLocale.code
|
|
67
71
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
72
|
+
return (
|
|
73
|
+
<Link
|
|
74
|
+
key={locale.code}
|
|
75
|
+
href={getHref(locale.code)}
|
|
76
|
+
onClick={(e) => handleClick(e, locale.code)}
|
|
77
|
+
className={cn(
|
|
78
|
+
'border-primary/20 inline-flex items-center gap-1.5 rounded-md border px-3 py-1.5 text-sm font-medium transition-colors',
|
|
79
|
+
isActive
|
|
80
|
+
? 'bg-success text-success-foreground'
|
|
81
|
+
: 'bg-muted text-muted-foreground hover:bg-accent hover:text-accent-foreground',
|
|
82
|
+
)}
|
|
83
|
+
>
|
|
84
|
+
{locale.label}
|
|
85
|
+
{isDefault && <span className='text-[10px] opacity-70'>{t('baseLocaleBadge')}</span>}
|
|
86
|
+
{hasTranslation && !isDefault && <Check className='h-3 w-3' />}
|
|
87
|
+
</Link>
|
|
88
|
+
)
|
|
89
|
+
})}
|
|
86
90
|
</div>
|
|
91
|
+
{developerOnly && (
|
|
92
|
+
<Alert variant='info' className='mt-2 w-full'>
|
|
93
|
+
<AlertDescription className='text-md font-bold'>{t('localeSwitcherDevOnly')}</AlertDescription>
|
|
94
|
+
</Alert>
|
|
95
|
+
)}
|
|
87
96
|
</ContainerBox>
|
|
88
97
|
)
|
|
89
98
|
}
|
|
@@ -32,7 +32,7 @@ export default function SectionPage({ section }: { section: string }) {
|
|
|
32
32
|
const handleDirtyChange = useCallback((isDirty: boolean) => setFormDirty(isDirty), [])
|
|
33
33
|
const dropzoneRef: RefObject<DropzoneHandles | null> = useRef(null)
|
|
34
34
|
|
|
35
|
-
const [data, {refetch, error, isError}] = trpc.simpleSections.create.useSuspenseQuery({
|
|
35
|
+
const [data, { refetch, error, isError }] = trpc.simpleSections.create.useSuspenseQuery({
|
|
36
36
|
sectionName: section,
|
|
37
37
|
locale,
|
|
38
38
|
})
|
|
@@ -98,9 +98,7 @@ export default function SectionPage({ section }: { section: string }) {
|
|
|
98
98
|
toast({
|
|
99
99
|
variant: res.data?.errors?.length ? 'warning' : 'success',
|
|
100
100
|
title: t('sectionUpdatedSuccessfully'),
|
|
101
|
-
description: res.data?.errors?.length
|
|
102
|
-
? t('errorsInSubmit')
|
|
103
|
-
: t('sectionUpdatedSuccessfully'),
|
|
101
|
+
description: res.data?.errors?.length ? t('errorsInSubmit') : t('sectionUpdatedSuccessfully'),
|
|
104
102
|
})
|
|
105
103
|
|
|
106
104
|
// Refetch the page
|
|
@@ -131,9 +129,8 @@ export default function SectionPage({ section }: { section: string }) {
|
|
|
131
129
|
}
|
|
132
130
|
}, [])
|
|
133
131
|
|
|
134
|
-
|
|
135
132
|
if (data.error) {
|
|
136
|
-
|
|
133
|
+
return <ErrorComponent message={data.error.message} />
|
|
137
134
|
}
|
|
138
135
|
|
|
139
136
|
return (
|
|
@@ -141,15 +138,15 @@ export default function SectionPage({ section }: { section: string }) {
|
|
|
141
138
|
{isError ? <div>{error?.message}</div> : null}
|
|
142
139
|
{data ? (
|
|
143
140
|
<div className='flex w-full flex-col'>
|
|
144
|
-
<div className='relative z-1 border-b-2 p-8 pt-12 font-extrabold
|
|
145
|
-
<div className='absolute
|
|
141
|
+
<div className='text-foreground relative z-1 border-b-2 p-8 pt-12 font-extrabold'>
|
|
142
|
+
<div className='absolute top-0 left-0 z-2 h-4 w-full bg-linear-to-r from-emerald-800 via-emerald-400 to-sky-600'></div>
|
|
146
143
|
<h1 className='pb-4 text-4xl'>{data.section?.title}</h1>
|
|
147
144
|
<span>
|
|
148
145
|
/{t('edit')} {data.section?.title}
|
|
149
146
|
</span>
|
|
150
147
|
</div>
|
|
151
|
-
{data.localization
|
|
152
|
-
<div className=
|
|
148
|
+
{data.localization?.localeSwitcherEnabled ? (
|
|
149
|
+
<div className='px-8 pt-4'>
|
|
153
150
|
<LocaleSwitcher
|
|
154
151
|
section={section}
|
|
155
152
|
currentLocale={data.localization.currentLocale}
|
|
@@ -158,31 +155,32 @@ export default function SectionPage({ section }: { section: string }) {
|
|
|
158
155
|
locales={data.localization.locales}
|
|
159
156
|
hasUnsavedChanges={formDirty}
|
|
160
157
|
basePath={`/section/${section}`}
|
|
158
|
+
developerOnly={data.localization.developerNoteEnabled}
|
|
161
159
|
/>
|
|
162
160
|
{locale && (
|
|
163
161
|
<Alert variant='info' className='mt-2 w-full'>
|
|
164
162
|
<AlertDescription className='text-md font-bold'>
|
|
165
163
|
<div className='flex items-center justify-between'>
|
|
166
|
-
|
|
167
|
-
{
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
164
|
+
<span>{t('editingContentTranslation', { locale })}</span>
|
|
165
|
+
{data.localization.existingTranslations.includes(locale) && (
|
|
166
|
+
<button
|
|
167
|
+
type='button'
|
|
168
|
+
onClick={handleDeleteLocale}
|
|
169
|
+
disabled={deleteLocaleMutation.isPending}
|
|
170
|
+
className='inline-flex items-center gap-1.5 rounded-md bg-red-600 px-3 py-1.5 text-xs font-medium text-white transition-colors hover:bg-red-700 disabled:opacity-50'
|
|
171
|
+
>
|
|
172
|
+
<Trash2 className='h-3.5 w-3.5' />
|
|
173
|
+
{deleteLocaleMutation.isPending
|
|
174
|
+
? t('loading')
|
|
175
|
+
: t('deleteLocaleTranslation')}
|
|
176
|
+
</button>
|
|
177
|
+
)}
|
|
178
|
+
</div>
|
|
181
179
|
</AlertDescription>
|
|
182
180
|
</Alert>
|
|
183
181
|
)}
|
|
184
182
|
</div>
|
|
185
|
-
)}
|
|
183
|
+
) : null}
|
|
186
184
|
<Form
|
|
187
185
|
key={locale ?? 'default'}
|
|
188
186
|
formType='edit'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="next" />
|
|
2
2
|
/// <reference types="next/image-types/global" />
|
|
3
|
-
import "./.next/types/routes.d.ts";
|
|
3
|
+
import "./.next/dev/types/routes.d.ts";
|
|
4
4
|
|
|
5
5
|
// NOTE: This file should not be edited
|
|
6
6
|
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
|