create-nextjs-cms 0.8.10 → 0.9.1
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 +2 -2
- package/templates/default/app/(auth)/auth/login/LoginPage.tsx +9 -9
- package/templates/default/app/(auth)/auth-language-provider.tsx +34 -0
- package/templates/default/app/(auth)/layout.tsx +10 -10
- package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +4 -1
- package/templates/default/app/(rootLayout)/layout.tsx +5 -5
- package/templates/default/app/(rootLayout)/section/[section]/page.tsx +4 -1
- package/templates/default/app/api/auth/route.ts +2 -2
- package/templates/default/app/api/submit/section/item/[slug]/route.ts +32 -3
- package/templates/default/app/api/submit/section/simple/route.ts +32 -3
- package/templates/default/app/globals.css +9 -0
- package/templates/default/cms.config.ts +4 -4
- package/templates/default/components/ItemEditPage.tsx +82 -2
- package/templates/default/components/LocaleSwitcher.tsx +89 -0
- package/templates/default/components/Navbar.tsx +5 -5
- package/templates/default/components/NewPage.tsx +1 -0
- package/templates/default/components/SectionPage.tsx +81 -1
- package/templates/default/components/form/ContentLocaleContext.tsx +11 -0
- package/templates/default/components/form/Form.tsx +48 -5
- package/templates/default/components/form/FormInputs.tsx +16 -7
- package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
- package/templates/default/components/form/inputs/NumberFormInput.tsx +2 -1
- package/templates/default/components/form/inputs/PhotoFormInput.tsx +168 -112
- package/templates/default/components/form/inputs/RichTextFormInput.tsx +3 -0
- package/templates/default/components/form/inputs/SelectFormInput.tsx +1 -1
- package/templates/default/components/form/inputs/TagsFormInput.tsx +6 -2
- package/templates/default/components/form/inputs/TextFormInput.tsx +3 -0
- package/templates/default/components/form/inputs/TextareaFormInput.tsx +3 -0
- package/templates/default/components/{locale-dropdown.tsx → language-dropdown.tsx} +74 -74
- package/templates/default/components/{locale-picker.tsx → language-picker.tsx} +85 -85
- package/templates/default/components/login-language-dropdown.tsx +46 -0
- package/templates/default/components/ui/alert.tsx +2 -1
- package/templates/default/dynamic-schemas/schema.ts +475 -448
- package/templates/default/package.json +1 -1
- package/templates/default/app/(auth)/auth-locale-provider.tsx +0 -34
- package/templates/default/components/login-locale-dropdown.tsx +0 -46
|
@@ -1,85 +1,85 @@
|
|
|
1
|
-
'use client'
|
|
2
|
-
|
|
3
|
-
import { Languages } from 'lucide-react'
|
|
4
|
-
import {
|
|
5
|
-
DropdownMenu,
|
|
6
|
-
DropdownMenuContent,
|
|
7
|
-
DropdownMenuItem,
|
|
8
|
-
DropdownMenuTrigger,
|
|
9
|
-
} from '@/components/ui/dropdown-menu'
|
|
10
|
-
import { Spinner } from '@/components/ui/spinner'
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
en: 'English',
|
|
15
|
-
ar: 'العربية',
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
function displayName(code: string): string {
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface
|
|
23
|
-
supportedLanguages: readonly string[]
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
disabled?: boolean
|
|
27
|
-
loading?: boolean
|
|
28
|
-
ariaLabel: string
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Shared
|
|
33
|
-
* Parent controls data source and onSelect behavior (tRPC + refresh vs cookie + refresh).
|
|
34
|
-
*/
|
|
35
|
-
export default function
|
|
36
|
-
supportedLanguages,
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
disabled = false,
|
|
40
|
-
loading = false,
|
|
41
|
-
ariaLabel,
|
|
42
|
-
}:
|
|
43
|
-
if (supportedLanguages.length < 2) return null
|
|
44
|
-
|
|
45
|
-
const isRTL =
|
|
46
|
-
|
|
47
|
-
return (
|
|
48
|
-
<DropdownMenu>
|
|
49
|
-
<DropdownMenuTrigger
|
|
50
|
-
asChild
|
|
51
|
-
className='text-foreground hover:text-foreground/90 relative rounded-full focus:outline-hidden cursor-pointer'
|
|
52
|
-
>
|
|
53
|
-
<button
|
|
54
|
-
type='button'
|
|
55
|
-
className='flex h-10 items-center justify-center'
|
|
56
|
-
aria-label={ariaLabel}
|
|
57
|
-
disabled={disabled}
|
|
58
|
-
>
|
|
59
|
-
{loading ? (
|
|
60
|
-
<Spinner className='size-5' />
|
|
61
|
-
) : (
|
|
62
|
-
<Languages className='h-5 w-5' aria-hidden='true' />
|
|
63
|
-
)}
|
|
64
|
-
</button>
|
|
65
|
-
</DropdownMenuTrigger>
|
|
66
|
-
<DropdownMenuContent
|
|
67
|
-
align={'end'}
|
|
68
|
-
sideOffset={12}
|
|
69
|
-
className='ring-1 ring-sky-400/80 dark:ring-amber-900'
|
|
70
|
-
>
|
|
71
|
-
{supportedLanguages.map((code) => (
|
|
72
|
-
<DropdownMenuItem
|
|
73
|
-
key={code}
|
|
74
|
-
onClick={() =>
|
|
75
|
-
disabled={disabled}
|
|
76
|
-
className='cursor-pointer'
|
|
77
|
-
>
|
|
78
|
-
{displayName(code)}
|
|
79
|
-
{code ===
|
|
80
|
-
</DropdownMenuItem>
|
|
81
|
-
))}
|
|
82
|
-
</DropdownMenuContent>
|
|
83
|
-
</DropdownMenu>
|
|
84
|
-
)
|
|
85
|
-
}
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { Languages } from 'lucide-react'
|
|
4
|
+
import {
|
|
5
|
+
DropdownMenu,
|
|
6
|
+
DropdownMenuContent,
|
|
7
|
+
DropdownMenuItem,
|
|
8
|
+
DropdownMenuTrigger,
|
|
9
|
+
} from '@/components/ui/dropdown-menu'
|
|
10
|
+
import { Spinner } from '@/components/ui/spinner'
|
|
11
|
+
import { RTL_LANGUAGES } from 'nextjs-cms/translations'
|
|
12
|
+
|
|
13
|
+
const LANGUAGE_DISPLAY_NAMES: Record<string, string> = {
|
|
14
|
+
en: 'English',
|
|
15
|
+
ar: 'العربية',
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function displayName(code: string): string {
|
|
19
|
+
return LANGUAGE_DISPLAY_NAMES[code] ?? code
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface LanguagePickerProps {
|
|
23
|
+
supportedLanguages: readonly string[]
|
|
24
|
+
currentLanguage: string
|
|
25
|
+
onLanguageChange: (language: string) => void
|
|
26
|
+
disabled?: boolean
|
|
27
|
+
loading?: boolean
|
|
28
|
+
ariaLabel: string
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Shared language dropdown UI. Use in Navbar (app) or Login page.
|
|
33
|
+
* Parent controls data source and onSelect behavior (tRPC + refresh vs cookie + refresh).
|
|
34
|
+
*/
|
|
35
|
+
export default function LanguagePicker({
|
|
36
|
+
supportedLanguages,
|
|
37
|
+
currentLanguage,
|
|
38
|
+
onLanguageChange,
|
|
39
|
+
disabled = false,
|
|
40
|
+
loading = false,
|
|
41
|
+
ariaLabel,
|
|
42
|
+
}: LanguagePickerProps) {
|
|
43
|
+
if (supportedLanguages.length < 2) return null
|
|
44
|
+
|
|
45
|
+
const isRTL = RTL_LANGUAGES.has(currentLanguage)
|
|
46
|
+
|
|
47
|
+
return (
|
|
48
|
+
<DropdownMenu>
|
|
49
|
+
<DropdownMenuTrigger
|
|
50
|
+
asChild
|
|
51
|
+
className='text-foreground hover:text-foreground/90 relative rounded-full focus:outline-hidden cursor-pointer'
|
|
52
|
+
>
|
|
53
|
+
<button
|
|
54
|
+
type='button'
|
|
55
|
+
className='flex h-10 items-center justify-center'
|
|
56
|
+
aria-label={ariaLabel}
|
|
57
|
+
disabled={disabled}
|
|
58
|
+
>
|
|
59
|
+
{loading ? (
|
|
60
|
+
<Spinner className='size-5' />
|
|
61
|
+
) : (
|
|
62
|
+
<Languages className='h-5 w-5' aria-hidden='true' />
|
|
63
|
+
)}
|
|
64
|
+
</button>
|
|
65
|
+
</DropdownMenuTrigger>
|
|
66
|
+
<DropdownMenuContent
|
|
67
|
+
align={'end'}
|
|
68
|
+
sideOffset={12}
|
|
69
|
+
className='ring-1 ring-sky-400/80 dark:ring-amber-900'
|
|
70
|
+
>
|
|
71
|
+
{supportedLanguages.map((code) => (
|
|
72
|
+
<DropdownMenuItem
|
|
73
|
+
key={code}
|
|
74
|
+
onClick={() => onLanguageChange(code)}
|
|
75
|
+
disabled={disabled}
|
|
76
|
+
className='cursor-pointer'
|
|
77
|
+
>
|
|
78
|
+
{displayName(code)}
|
|
79
|
+
{code === currentLanguage ? ' ✓' : ''}
|
|
80
|
+
</DropdownMenuItem>
|
|
81
|
+
))}
|
|
82
|
+
</DropdownMenuContent>
|
|
83
|
+
</DropdownMenu>
|
|
84
|
+
)
|
|
85
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { useCallback } from 'react'
|
|
4
|
+
import { useRouter } from 'next/navigation'
|
|
5
|
+
import { useI18n } from 'nextjs-cms/translations/client'
|
|
6
|
+
import { setLoginPageLanguageCookie, markLanguageChangedOnLogin } from 'nextjs-cms/translations'
|
|
7
|
+
import LanguagePicker from './language-picker'
|
|
8
|
+
|
|
9
|
+
export interface LoginLanguageDropdownProps {
|
|
10
|
+
supportedLanguages: readonly string[]
|
|
11
|
+
fallbackLanguage: string
|
|
12
|
+
initialLanguage: string
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Language dropdown for the login page (unauthenticated).
|
|
17
|
+
* Persists via nextjs-cms-locale cookie; auth layout reads it when no session.
|
|
18
|
+
*/
|
|
19
|
+
export default function LoginLanguageDropdown({
|
|
20
|
+
supportedLanguages,
|
|
21
|
+
fallbackLanguage,
|
|
22
|
+
initialLanguage,
|
|
23
|
+
}: LoginLanguageDropdownProps) {
|
|
24
|
+
const t = useI18n()
|
|
25
|
+
const router = useRouter()
|
|
26
|
+
const currentLanguage = initialLanguage || fallbackLanguage
|
|
27
|
+
|
|
28
|
+
const handleSelect = useCallback(
|
|
29
|
+
(language: string) => {
|
|
30
|
+
if (language === currentLanguage) return
|
|
31
|
+
setLoginPageLanguageCookie(language)
|
|
32
|
+
markLanguageChangedOnLogin()
|
|
33
|
+
router.refresh()
|
|
34
|
+
},
|
|
35
|
+
[currentLanguage, router],
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
<LanguagePicker
|
|
40
|
+
supportedLanguages={supportedLanguages}
|
|
41
|
+
currentLanguage={currentLanguage}
|
|
42
|
+
onLanguageChange={handleSelect}
|
|
43
|
+
ariaLabel={t('language')}
|
|
44
|
+
/>
|
|
45
|
+
)
|
|
46
|
+
}
|
|
@@ -12,7 +12,8 @@ const alertVariants = cva(
|
|
|
12
12
|
destructive:
|
|
13
13
|
'border-destructive/90 bg-destructive/10 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
|
14
14
|
light: 'bg-gray-100 text-gray-900 dark:bg-gray-950 dark:text-gray-100',
|
|
15
|
-
info: 'bg-info text-info
|
|
15
|
+
info: 'border-info bg-info/10 text-info-foreground [&>svg]:text-info',
|
|
16
|
+
warning: 'bg-warning text-warning dark:bg-warning dark:text-warning',
|
|
16
17
|
},
|
|
17
18
|
},
|
|
18
19
|
defaultVariants: {
|