create-nextjs-cms 0.9.6 → 0.9.7

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 (184) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +71 -71
  3. package/dist/helpers/check-directory.d.ts +1 -0
  4. package/dist/helpers/check-directory.d.ts.map +1 -1
  5. package/dist/helpers/check-directory.js +98 -23
  6. package/dist/helpers/utils.js +16 -16
  7. package/dist/index.js +13 -8
  8. package/dist/lib/create-project.js +1 -1
  9. package/dist/lib/section-creators.js +166 -166
  10. package/package.json +1 -1
  11. package/templates/default/.eslintrc.json +5 -5
  12. package/templates/default/.prettierignore +7 -7
  13. package/templates/default/.prettierrc.json +27 -27
  14. package/templates/default/CHANGELOG.md +140 -140
  15. package/templates/default/_gitignore +57 -57
  16. package/templates/default/app/(auth)/auth/login/LoginPage.tsx +192 -192
  17. package/templates/default/app/(auth)/auth/login/page.tsx +11 -11
  18. package/templates/default/app/(auth)/auth-language-provider.tsx +34 -34
  19. package/templates/default/app/(auth)/layout.tsx +81 -81
  20. package/templates/default/app/(rootLayout)/(plugins)/[...slug]/page.tsx +40 -40
  21. package/templates/default/app/(rootLayout)/(plugins)/[...slug]/plugin-server-registry.ts +16 -16
  22. package/templates/default/app/(rootLayout)/admins/page.tsx +10 -10
  23. package/templates/default/app/(rootLayout)/browse/[section]/[page]/page.tsx +22 -22
  24. package/templates/default/app/(rootLayout)/categorized/[section]/page.tsx +15 -15
  25. package/templates/default/app/(rootLayout)/dashboard/page.tsx +63 -63
  26. package/templates/default/app/(rootLayout)/edit/[section]/[itemId]/page.tsx +20 -20
  27. package/templates/default/app/(rootLayout)/layout.tsx +81 -81
  28. package/templates/default/app/(rootLayout)/loading.tsx +10 -10
  29. package/templates/default/app/(rootLayout)/log/page.tsx +7 -7
  30. package/templates/default/app/(rootLayout)/new/[section]/page.tsx +15 -15
  31. package/templates/default/app/(rootLayout)/section/[section]/page.tsx +19 -19
  32. package/templates/default/app/(rootLayout)/settings/page.tsx +13 -13
  33. package/templates/default/app/_trpc/client.ts +3 -3
  34. package/templates/default/app/api/auth/csrf/route.ts +25 -25
  35. package/templates/default/app/api/auth/refresh/route.ts +10 -10
  36. package/templates/default/app/api/auth/route.ts +49 -49
  37. package/templates/default/app/api/auth/session/route.ts +20 -20
  38. package/templates/default/app/api/document/route.ts +165 -165
  39. package/templates/default/app/api/editor/photo/route.ts +49 -49
  40. package/templates/default/app/api/photo/route.ts +27 -27
  41. package/templates/default/app/api/submit/section/item/[slug]/route.ts +95 -95
  42. package/templates/default/app/api/submit/section/item/route.ts +56 -56
  43. package/templates/default/app/api/submit/section/simple/route.ts +86 -86
  44. package/templates/default/app/api/trpc/[trpc]/route.ts +33 -33
  45. package/templates/default/app/api/video/route.ts +174 -174
  46. package/templates/default/app/globals.css +228 -228
  47. package/templates/default/app/providers.tsx +152 -152
  48. package/templates/default/cms.config.ts +57 -58
  49. package/templates/default/components/AdminCard.tsx +166 -166
  50. package/templates/default/components/AdminEditPage.tsx +124 -124
  51. package/templates/default/components/AdminPrivilegeCard.tsx +185 -185
  52. package/templates/default/components/AdminsPage.tsx +43 -43
  53. package/templates/default/components/AnalyticsPage.tsx +144 -144
  54. package/templates/default/components/BarChartBox.tsx +42 -42
  55. package/templates/default/components/BrowsePage.tsx +106 -106
  56. package/templates/default/components/CategorizedSectionPage.tsx +31 -31
  57. package/templates/default/components/CategoryDeleteConfirmPage.tsx +130 -130
  58. package/templates/default/components/CategorySectionSelectInput.tsx +140 -140
  59. package/templates/default/components/ConditionalFields.tsx +49 -49
  60. package/templates/default/components/ContainerBox.tsx +24 -24
  61. package/templates/default/components/DashboardPageAlt.tsx +45 -45
  62. package/templates/default/components/DefaultNavItems.tsx +3 -3
  63. package/templates/default/components/Dropzone.tsx +154 -154
  64. package/templates/default/components/ErrorComponent.tsx +16 -16
  65. package/templates/default/components/GalleryPhoto.tsx +93 -93
  66. package/templates/default/components/InfoCard.tsx +93 -93
  67. package/templates/default/components/ItemEditPage.tsx +294 -294
  68. package/templates/default/components/Layout.tsx +84 -84
  69. package/templates/default/components/LoadingSpinners.tsx +67 -67
  70. package/templates/default/components/LocaleSwitcher.tsx +89 -89
  71. package/templates/default/components/LogPage.tsx +107 -107
  72. package/templates/default/components/Modal.tsx +166 -166
  73. package/templates/default/components/Navbar.tsx +258 -258
  74. package/templates/default/components/NewAdminForm.tsx +173 -173
  75. package/templates/default/components/NewPage.tsx +206 -206
  76. package/templates/default/components/NewVariantComponent.tsx +229 -229
  77. package/templates/default/components/PhotoGallery.tsx +35 -35
  78. package/templates/default/components/PieChartBox.tsx +101 -101
  79. package/templates/default/components/ProgressBar.tsx +48 -48
  80. package/templates/default/components/ProtectedDocument.tsx +44 -44
  81. package/templates/default/components/ProtectedImage.tsx +143 -143
  82. package/templates/default/components/ProtectedVideo.tsx +76 -76
  83. package/templates/default/components/SectionIcon.tsx +8 -8
  84. package/templates/default/components/SectionItemCard.tsx +144 -144
  85. package/templates/default/components/SectionItemStatusBadge.tsx +17 -17
  86. package/templates/default/components/SectionPage.tsx +205 -205
  87. package/templates/default/components/SelectBox.tsx +98 -98
  88. package/templates/default/components/SelectInputButtons.tsx +125 -125
  89. package/templates/default/components/SettingsPage.tsx +232 -232
  90. package/templates/default/components/Sidebar.tsx +204 -204
  91. package/templates/default/components/SidebarDropdownItem.tsx +83 -83
  92. package/templates/default/components/SidebarItem.tsx +24 -24
  93. package/templates/default/components/ThemeProvider.tsx +8 -8
  94. package/templates/default/components/TooltipComponent.tsx +27 -27
  95. package/templates/default/components/VariantCard.tsx +124 -124
  96. package/templates/default/components/VariantEditPage.tsx +230 -230
  97. package/templates/default/components/analytics/BounceRate.tsx +70 -70
  98. package/templates/default/components/analytics/LivePageViews.tsx +55 -55
  99. package/templates/default/components/analytics/LiveUsersCount.tsx +33 -33
  100. package/templates/default/components/analytics/MonthlyPageViews.tsx +42 -42
  101. package/templates/default/components/analytics/TopCountries.tsx +52 -52
  102. package/templates/default/components/analytics/TopDevices.tsx +46 -46
  103. package/templates/default/components/analytics/TopMediums.tsx +58 -58
  104. package/templates/default/components/analytics/TopSources.tsx +45 -45
  105. package/templates/default/components/analytics/TotalPageViews.tsx +41 -41
  106. package/templates/default/components/analytics/TotalSessions.tsx +41 -41
  107. package/templates/default/components/analytics/TotalUniqueUsers.tsx +41 -41
  108. package/templates/default/components/custom/RightHomeRoomVariantCard.tsx +138 -138
  109. package/templates/default/components/dndKit/Draggable.tsx +21 -21
  110. package/templates/default/components/dndKit/Droppable.tsx +20 -20
  111. package/templates/default/components/dndKit/SortableItem.tsx +18 -18
  112. package/templates/default/components/form/Form.tsx +370 -370
  113. package/templates/default/components/form/FormInputElement.tsx +70 -70
  114. package/templates/default/components/form/FormInputs.tsx +136 -136
  115. package/templates/default/components/form/helpers/_section-hot-reload.js +1 -1
  116. package/templates/default/components/form/helpers/util.ts +17 -17
  117. package/templates/default/components/form/inputs/CheckboxFormInput.tsx +46 -46
  118. package/templates/default/components/form/inputs/ColorFormInput.tsx +44 -44
  119. package/templates/default/components/form/inputs/DateFormInput.tsx +167 -110
  120. package/templates/default/components/form/inputs/DateRangeFormInput.tsx +23 -1
  121. package/templates/default/components/form/inputs/DocumentFormInput.tsx +222 -222
  122. package/templates/default/components/form/inputs/MapFormInput.tsx +140 -140
  123. package/templates/default/components/form/inputs/MultipleSelectFormInput.tsx +85 -85
  124. package/templates/default/components/form/inputs/NumberFormInput.tsx +43 -43
  125. package/templates/default/components/form/inputs/PasswordFormInput.tsx +47 -47
  126. package/templates/default/components/form/inputs/PhotoFormInput.tsx +275 -275
  127. package/templates/default/components/form/inputs/RichTextFormInput.tsx +138 -138
  128. package/templates/default/components/form/inputs/SelectFormInput.tsx +175 -175
  129. package/templates/default/components/form/inputs/SlugFormInput.tsx +131 -131
  130. package/templates/default/components/form/inputs/TagsFormInput.tsx +265 -265
  131. package/templates/default/components/form/inputs/TextFormInput.tsx +51 -51
  132. package/templates/default/components/form/inputs/TextareaFormInput.tsx +50 -50
  133. package/templates/default/components/form/inputs/VideoFormInput.tsx +118 -118
  134. package/templates/default/components/multi-select.tsx +1146 -1146
  135. package/templates/default/components/pagination/Pagination.tsx +36 -36
  136. package/templates/default/components/pagination/PaginationButtons.tsx +147 -147
  137. package/templates/default/components/theme-toggle.tsx +39 -39
  138. package/templates/default/components/ui/accordion.tsx +53 -53
  139. package/templates/default/components/ui/alert-dialog.tsx +157 -157
  140. package/templates/default/components/ui/alert.tsx +47 -47
  141. package/templates/default/components/ui/badge.tsx +38 -38
  142. package/templates/default/components/ui/button.tsx +62 -62
  143. package/templates/default/components/ui/calendar.tsx +166 -166
  144. package/templates/default/components/ui/card.tsx +43 -43
  145. package/templates/default/components/ui/checkbox.tsx +29 -29
  146. package/templates/default/components/ui/command.tsx +137 -137
  147. package/templates/default/components/ui/custom-alert-dialog.tsx +113 -113
  148. package/templates/default/components/ui/custom-dialog.tsx +123 -123
  149. package/templates/default/components/ui/dialog.tsx +123 -123
  150. package/templates/default/components/ui/direction.tsx +22 -22
  151. package/templates/default/components/ui/dropdown-menu.tsx +182 -182
  152. package/templates/default/components/ui/input-group.tsx +54 -54
  153. package/templates/default/components/ui/input.tsx +22 -22
  154. package/templates/default/components/ui/label.tsx +19 -19
  155. package/templates/default/components/ui/popover.tsx +42 -42
  156. package/templates/default/components/ui/progress.tsx +31 -31
  157. package/templates/default/components/ui/scroll-area.tsx +42 -42
  158. package/templates/default/components/ui/select.tsx +165 -165
  159. package/templates/default/components/ui/separator.tsx +28 -28
  160. package/templates/default/components/ui/sheet.tsx +103 -103
  161. package/templates/default/components/ui/spinner.tsx +16 -16
  162. package/templates/default/components/ui/switch.tsx +29 -29
  163. package/templates/default/components/ui/table.tsx +83 -83
  164. package/templates/default/components/ui/tabs.tsx +55 -55
  165. package/templates/default/components/ui/toast.tsx +113 -113
  166. package/templates/default/components/ui/toaster.tsx +35 -35
  167. package/templates/default/components/ui/tooltip.tsx +30 -30
  168. package/templates/default/components/ui/use-toast.ts +188 -188
  169. package/templates/default/components.json +21 -21
  170. package/templates/default/context/ModalProvider.tsx +53 -53
  171. package/templates/default/drizzle.config.ts +4 -4
  172. package/templates/default/dynamic-schemas/schema.ts +475 -0
  173. package/templates/default/env/env.js +130 -130
  174. package/templates/default/envConfig.ts +4 -4
  175. package/templates/default/hooks/useModal.ts +8 -8
  176. package/templates/default/lib/apiHelpers.ts +92 -92
  177. package/templates/default/lib/postinstall.js +14 -14
  178. package/templates/default/lib/utils.ts +6 -6
  179. package/templates/default/next-env.d.ts +6 -6
  180. package/templates/default/next.config.ts +23 -23
  181. package/templates/default/package.json +1 -1
  182. package/templates/default/postcss.config.mjs +6 -6
  183. package/templates/default/proxy.ts +32 -32
  184. package/templates/default/tsconfig.json +48 -48
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2025 create-nextjs-cms
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2025 create-nextjs-cms
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,71 +1,71 @@
1
- # Create Nextjs CMS
2
-
3
- The best and official way to create a nextjs-cms project with all the necessary configuration and dependencies.
4
-
5
- ## Installation
6
-
7
- You can create a new cms project interactively by running:
8
-
9
- ```bash
10
- npx create-nextjs-cms
11
- # or
12
- yarn create nextjs-cms
13
- # or
14
- pnpm create nextjs-cms
15
- # or
16
- bun create nextjs-cms
17
- ```
18
-
19
- ## Project Structure
20
-
21
- After running `create-nextjs-cms`, you'll have a fully configured nextjs-cms project with:
22
-
23
- - ✅ Next.js application setup
24
- - ✅ CMS configuration files
25
- - ✅ Database configuration
26
- - ✅ TypeScript configuration
27
- - ✅ All necessary dependencies
28
- - ✅ Example sections and fields
29
- - ✅ Development scripts
30
-
31
- ## Next Steps
32
-
33
- After creating your project:
34
-
35
- ```bash
36
- cd my-cms-app
37
- pnpm dev
38
- ```
39
-
40
- Then visit `http://localhost:3000` to see your CMS in action!
41
-
42
- ## Requirements
43
-
44
- - Node.js 18+
45
- - A package manager (pnpm, npm, yarn, or bun)
46
-
47
- ## Troubleshooting
48
-
49
- ### Directory already exists
50
-
51
- If you try to create a project in a directory that already exists, you'll get an error. Either:
52
- - Choose a different directory name
53
- - Use `.` to create in the current directory (must be empty)
54
-
55
- ### Installation fails
56
-
57
- If automatic dependency installation fails, you can manually install:
58
-
59
- ```bash
60
- cd my-cms-app
61
- pnpm install
62
- ```
63
-
64
- ### Template not found
65
-
66
- If you see an error about the template directory not being found, ensure you're using the published version of the package from npm, not a local development version.
67
-
68
-
69
- ## License
70
-
71
- MIT License - see LICENSE file for details.
1
+ # Create Nextjs CMS
2
+
3
+ The best and official way to create a nextjs-cms project with all the necessary configuration and dependencies.
4
+
5
+ ## Installation
6
+
7
+ You can create a new cms project interactively by running:
8
+
9
+ ```bash
10
+ npx create-nextjs-cms
11
+ # or
12
+ yarn create nextjs-cms
13
+ # or
14
+ pnpm create nextjs-cms
15
+ # or
16
+ bun create nextjs-cms
17
+ ```
18
+
19
+ ## Project Structure
20
+
21
+ After running `create-nextjs-cms`, you'll have a fully configured nextjs-cms project with:
22
+
23
+ - ✅ Next.js application setup
24
+ - ✅ CMS configuration files
25
+ - ✅ Database configuration
26
+ - ✅ TypeScript configuration
27
+ - ✅ All necessary dependencies
28
+ - ✅ Example sections and fields
29
+ - ✅ Development scripts
30
+
31
+ ## Next Steps
32
+
33
+ After creating your project:
34
+
35
+ ```bash
36
+ cd my-cms-app
37
+ pnpm dev
38
+ ```
39
+
40
+ Then visit `http://localhost:3000` to see your CMS in action!
41
+
42
+ ## Requirements
43
+
44
+ - Node.js 18+
45
+ - A package manager (pnpm, npm, yarn, or bun)
46
+
47
+ ## Troubleshooting
48
+
49
+ ### Directory already exists
50
+
51
+ If you try to create a project in a directory that already exists, you'll get an error. Either:
52
+ - Choose a different directory name
53
+ - Use `.` to create in the current directory (must be empty)
54
+
55
+ ### Installation fails
56
+
57
+ If automatic dependency installation fails, you can manually install:
58
+
59
+ ```bash
60
+ cd my-cms-app
61
+ pnpm install
62
+ ```
63
+
64
+ ### Template not found
65
+
66
+ If you see an error about the template directory not being found, ensure you're using the published version of the package from npm, not a local development version.
67
+
68
+
69
+ ## License
70
+
71
+ MIT License - see LICENSE file for details.
@@ -2,5 +2,6 @@ export declare const resolveDirectory: (appName: string) => Promise<{
2
2
  targetDir: string;
3
3
  projectName: string;
4
4
  targetIsCwd: boolean;
5
+ targetExistedBefore: boolean;
5
6
  }>;
6
7
  //# sourceMappingURL=check-directory.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"check-directory.d.ts","sourceRoot":"","sources":["../../src/helpers/check-directory.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,gBAAgB,GACzB,SAAS,MAAM,KAChB,OAAO,CAAC;IACP,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,OAAO,CAAA;CACvB,CAwCA,CAAA"}
1
+ {"version":3,"file":"check-directory.d.ts","sourceRoot":"","sources":["../../src/helpers/check-directory.ts"],"names":[],"mappings":"AA2HA,eAAO,MAAM,gBAAgB,GACzB,SAAS,MAAM,KAChB,OAAO,CAAC;IACP,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,OAAO,CAAA;IACpB,mBAAmB,EAAE,OAAO,CAAA;CAC/B,CAqCA,CAAA"}
@@ -6,6 +6,85 @@ import fs from 'fs-extra';
6
6
  import { isEmptyDir } from './utils.js';
7
7
  import * as p from '@clack/prompts';
8
8
  import chalk from 'chalk';
9
+ import ora from 'ora';
10
+ const abortInstallation = () => {
11
+ p.cancel('Aborting installation');
12
+ process.exit(1);
13
+ };
14
+ const abortDirectoryCleanup = (targetDir, error) => {
15
+ p.log.error(`Failed to empty ${targetDir === process.cwd() ? 'the current directory' : `"${targetDir}"`}.`);
16
+ p.log.message('Some files may already have been deleted.');
17
+ p.log.message(`Please review and clean this directory manually: ${targetDir}`);
18
+ p.log.message(`Reason: ${error instanceof Error ? error.message : 'Unknown error'}`);
19
+ return abortInstallation();
20
+ };
21
+ const getDirectoryEntriesToDelete = async (targetDir, keepGit) => {
22
+ const entries = await fs.readdir(targetDir);
23
+ return entries.filter((entry) => !(keepGit && entry === '.git'));
24
+ };
25
+ const emptyDirectory = async (targetDir, entries, onEntryDeleted) => {
26
+ let deletedCount = 0;
27
+ for (const entry of entries) {
28
+ await fs.remove(path.join(targetDir, entry));
29
+ deletedCount += 1;
30
+ onEntryDeleted?.(deletedCount, entries.length);
31
+ }
32
+ };
33
+ const runDirectoryCleanup = async ({ targetDir, targetIsCwd, keepGit, }) => {
34
+ const spinnerText = keepGit
35
+ ? `Emptying ${targetIsCwd ? 'the current directory' : `"${targetDir}"`} and keeping .git...`
36
+ : `Emptying ${targetIsCwd ? 'the current directory' : `"${targetDir}"`}...`;
37
+ const successMessage = keepGit
38
+ ? `Emptied ${targetIsCwd ? 'the current directory' : `"${targetDir}"`} and kept ${chalk.green('.git')}.`
39
+ : `Emptied ${targetIsCwd ? 'the current directory' : `"${targetDir}"`}.`;
40
+ const entriesToDelete = await getDirectoryEntriesToDelete(targetDir, keepGit);
41
+ const spinner = ora(entriesToDelete.length > 0 ? `${spinnerText} (0/${entriesToDelete.length})` : spinnerText).start();
42
+ try {
43
+ await emptyDirectory(targetDir, entriesToDelete, (deletedCount, totalCount) => {
44
+ spinner.text = `${spinnerText} (${deletedCount}/${totalCount})`;
45
+ });
46
+ }
47
+ catch (error) {
48
+ spinner.stop();
49
+ abortDirectoryCleanup(targetDir, error);
50
+ }
51
+ spinner.stop();
52
+ p.log.info(successMessage);
53
+ };
54
+ const promptForNonEmptyDirectoryAction = async (targetDir, targetIsCwd) => {
55
+ if (targetIsCwd) {
56
+ p.log.error('Current directory is not empty.');
57
+ p.log.message(chalk.gray('Tip: You can also specify a directory name like this: \n') +
58
+ chalk.green('pnpm create nextjs-cms ') +
59
+ chalk.italic.magenta('my-app'));
60
+ }
61
+ else {
62
+ p.log.error(`Directory "${targetDir}" is not empty.`);
63
+ }
64
+ p.log.message('Choose how you want to proceed:');
65
+ const action = await p.select({
66
+ message: 'How would you like to proceed?',
67
+ initialValue: 'abort',
68
+ options: [
69
+ { value: 'abort', label: 'Abort' },
70
+ { value: 'empty', label: 'Empty directory ⚠️', hint: 'Delete everything in the target directory' },
71
+ {
72
+ value: 'empty-keep-git',
73
+ label: 'Empty directory and keep .git folder ⚠️',
74
+ hint: 'Delete everything except the root .git folder',
75
+ },
76
+ {
77
+ value: 'continue',
78
+ label: 'Continue anyway ⚠️',
79
+ hint: 'Existing files may be overwritten and the app may be unstable',
80
+ },
81
+ ],
82
+ });
83
+ if (p.isCancel(action) || action === 'abort') {
84
+ abortInstallation();
85
+ }
86
+ return action;
87
+ };
9
88
  export const resolveDirectory = async (appName) => {
10
89
  // Resolve target path from the caller's CWD
11
90
  const rawTarget = expandHome(appName);
@@ -13,35 +92,31 @@ export const resolveDirectory = async (appName) => {
13
92
  // Derive package name from final path
14
93
  const projectName = basename(targetDir);
15
94
  const targetIsCwd = path.normalize(targetDir) === path.normalize(process.cwd());
16
- if (targetIsCwd) {
17
- // Using current directory (".")
18
- if (!(await fs.pathExists(targetDir))) {
19
- await fs.ensureDir(targetDir);
20
- }
21
- else if (!(await isEmptyDir(targetDir))) {
22
- p.log.error('Current directory is not empty. Choose an empty folder or a new directory name.');
23
- p.log.message(chalk.gray('Tip: You can also specify a directory name like this: \n') +
24
- chalk.green('pnpm create nextjs-cms ') +
25
- chalk.italic.magenta('my-app'));
26
- p.log.message(' ');
27
- process.exit(1);
28
- }
95
+ const targetExistedBefore = await fs.pathExists(targetDir);
96
+ if (!targetExistedBefore) {
97
+ await fs.ensureDir(targetDir);
29
98
  }
30
- else {
31
- if (await fs.pathExists(targetDir)) {
32
- if (!(await isEmptyDir(targetDir))) {
33
- p.log.error(`Directory "${targetDir}" is not empty.`);
34
- p.log.message('Please choose an empty directory or a different directory name.');
35
- process.exit(1);
36
- }
37
- }
38
- else {
39
- await fs.ensureDir(targetDir);
99
+ else if (!(await isEmptyDir(targetDir))) {
100
+ const action = await promptForNonEmptyDirectoryAction(targetDir, targetIsCwd);
101
+ switch (action) {
102
+ case 'empty':
103
+ await runDirectoryCleanup({ targetDir, targetIsCwd, keepGit: false });
104
+ break;
105
+ case 'empty-keep-git':
106
+ await runDirectoryCleanup({ targetDir, targetIsCwd, keepGit: true });
107
+ break;
108
+ case 'continue':
109
+ p.log.warn('Continuing in a non-empty directory. Existing files may be overwritten.');
110
+ break;
111
+ default:
112
+ action;
113
+ break;
40
114
  }
41
115
  }
42
116
  return {
43
117
  targetDir,
44
118
  projectName,
45
119
  targetIsCwd,
120
+ targetExistedBefore,
46
121
  };
47
122
  };
@@ -4,22 +4,22 @@ import os from 'node:os';
4
4
  import { randomBytes } from 'node:crypto';
5
5
  import { log } from '@clack/prompts';
6
6
  import chalk from 'chalk';
7
- export const TITLE_TEXT = `
8
- _
9
- ___ _ __ ___ __ _| |_ ___
10
- / __| '__/ _ \\/ _\\\` | __/ _ \\
11
- | (__| | | __/ (_| | || __/
12
- \\___|_| \\___|\\__,_|\\__\\___|
13
- _ _
14
- _ __ _____ _| |_ (_)___
15
- | '_ \\ / _ \\ \\/ / __|| / __|
16
- | | | | __/> <| |_ | \\__ \\
17
- |_| |_|\\___/_/\\_\\__|/ |___/
18
- |__/
19
- ___ _ __ ___ ___
20
- / __| '_ \\\` _ \\/ __|
21
- | (__| | | | | \\__ \\
22
- \\___|_| |_| |_|___/
7
+ export const TITLE_TEXT = `
8
+ _
9
+ ___ _ __ ___ __ _| |_ ___
10
+ / __| '__/ _ \\/ _\\\` | __/ _ \\
11
+ | (__| | | __/ (_| | || __/
12
+ \\___|_| \\___|\\__,_|\\__\\___|
13
+ _ _
14
+ _ __ _____ _| |_ (_)___
15
+ | '_ \\ / _ \\ \\/ / __|| / __|
16
+ | | | | __/> <| |_ | \\__ \\
17
+ |_| |_|\\___/_/\\_\\__|/ |___/
18
+ |__/
19
+ ___ _ __ ___ ___
20
+ / __| '_ \\\` _ \\/ __|
21
+ | (__| | | | | \\__ \\
22
+ \\___|_| |_| |_|___/
23
23
  `;
24
24
  /** Expand ~ to home */
25
25
  export function expandHome(p) {
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ async function createNextjsCms() {
21
21
  // Run CLI to get user input
22
22
  const { appName, sectionsToAdd, git /*, databaseProvider*/ } = await runCli();
23
23
  // Resolve directory
24
- const { targetDir, projectName, targetIsCwd } = await resolveDirectory(appName);
24
+ const { targetDir, projectName, targetIsCwd, targetExistedBefore } = await resolveDirectory(appName);
25
25
  try {
26
26
  // Detect package manager
27
27
  const preferredPM = detectPackageManager();
@@ -63,14 +63,19 @@ async function createNextjsCms() {
63
63
  p.outro(chalk.red(`❌ Failed to create project: ${error instanceof Error ? error.message : 'Unknown error'}`));
64
64
  // Clean up partial installation on error
65
65
  if ((await fs.pathExists(targetDir)) && !targetIsCwd) {
66
- p.log.info('🧹 Cleaning up partial installation...');
67
- try {
68
- await fs.remove(targetDir);
69
- p.log.success('✅ Cleanup completed.');
66
+ if (targetExistedBefore) {
67
+ p.log.warn('Project creation failed in a pre-existing directory. Existing files were left in place.');
70
68
  }
71
- catch {
72
- p.log.error('⚠️ Could not clean up partial installation.');
73
- p.log.message(` Please manually remove: ${targetDir}`);
69
+ else {
70
+ p.log.info('🧹 Cleaning up partial installation...');
71
+ try {
72
+ await fs.remove(targetDir);
73
+ p.log.success('✅ Cleanup completed.');
74
+ }
75
+ catch {
76
+ p.log.error('⚠️ Could not clean up partial installation.');
77
+ p.log.message(` Please manually remove: ${targetDir}`);
78
+ }
74
79
  }
75
80
  }
76
81
  process.exit(1);
@@ -22,7 +22,7 @@ export const createProject = async ({ targetDir, sectionsToAdd, projectName, pre
22
22
  !rel.startsWith('.turbo') &&
23
23
  !rel.includes('tsconfig.tsbuildinfo'));
24
24
  },
25
- // Overwrite is safe since target is ensured empty (or new)
25
+ // Overwrite is intentional because the target is new, user-approved, or was explicitly emptied
26
26
  overwrite: true,
27
27
  errorOnExist: false,
28
28
  });