create-next-mui 0.1.2 → 0.1.4

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 (53) hide show
  1. package/README.md +149 -54
  2. package/{next-mui-template-ts → next-mui-templates/base-js}/package-lock.json +39 -5
  3. package/{next-mui-template-js → next-mui-templates/base-js}/package.json +1 -1
  4. package/{next-mui-template-js → next-mui-templates/base-ts}/package-lock.json +37 -3
  5. package/{next-mui-template-ts → next-mui-templates/base-ts}/package.json +1 -1
  6. package/package.json +2 -4
  7. package/src/index.js +249 -60
  8. /package/{next-mui-template-js → next-mui-templates/base-js}/.vscode/settings.json +0 -0
  9. /package/{next-mui-template-js → next-mui-templates/base-js}/.vscode/typescript.code-snippets +0 -0
  10. /package/{next-mui-template-js → next-mui-templates/base-js}/eslint.config.mjs +0 -0
  11. /package/{next-mui-template-js → next-mui-templates/base-js}/jsconfig.json +0 -0
  12. /package/{next-mui-template-js → next-mui-templates/base-js}/next.config.js +0 -0
  13. /package/{next-mui-template-js → next-mui-templates/base-js}/public/mui.svg +0 -0
  14. /package/{next-mui-template-js → next-mui-templates/base-js}/public/next.svg +0 -0
  15. /package/{next-mui-template-js → next-mui-templates/base-js}/public/vercel.svg +0 -0
  16. /package/{next-mui-template-js → next-mui-templates/base-js}/src/app/favicon.ico +0 -0
  17. /package/{next-mui-template-js → next-mui-templates/base-js}/src/app/globals.css +0 -0
  18. /package/{next-mui-template-js → next-mui-templates/base-js}/src/app/layout.jsx +0 -0
  19. /package/{next-mui-template-js → next-mui-templates/base-js}/src/app/page.jsx +0 -0
  20. /package/{next-mui-template-js → next-mui-templates/base-js}/src/config-global.js +0 -0
  21. /package/{next-mui-template-js → next-mui-templates/base-js}/src/lib/router-link/index.js +0 -0
  22. /package/{next-mui-template-js → next-mui-templates/base-js}/src/sections/home/view.jsx +0 -0
  23. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/colors.json +0 -0
  24. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/components/button.js +0 -0
  25. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/components/card.js +0 -0
  26. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/components/index.js +0 -0
  27. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/palette.js +0 -0
  28. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/core/typography.js +0 -0
  29. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/create-theme.js +0 -0
  30. /package/{next-mui-template-js → next-mui-templates/base-js}/src/theme/theme-provider.jsx +0 -0
  31. /package/{next-mui-template-ts → next-mui-templates/base-ts}/.vscode/settings.json +0 -0
  32. /package/{next-mui-template-ts → next-mui-templates/base-ts}/.vscode/typescript.code-snippets +0 -0
  33. /package/{next-mui-template-ts → next-mui-templates/base-ts}/eslint.config.mjs +0 -0
  34. /package/{next-mui-template-ts → next-mui-templates/base-ts}/next.config.ts +0 -0
  35. /package/{next-mui-template-ts → next-mui-templates/base-ts}/public/mui.svg +0 -0
  36. /package/{next-mui-template-ts → next-mui-templates/base-ts}/public/next.svg +0 -0
  37. /package/{next-mui-template-ts → next-mui-templates/base-ts}/public/vercel.svg +0 -0
  38. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/app/favicon.ico +0 -0
  39. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/app/globals.css +0 -0
  40. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/app/layout.tsx +0 -0
  41. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/app/page.tsx +0 -0
  42. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/config-global.ts +0 -0
  43. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/lib/router-link/index.ts +0 -0
  44. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/sections/home/view.tsx +0 -0
  45. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/colors.json +0 -0
  46. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/components/button.ts +0 -0
  47. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/components/card.ts +0 -0
  48. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/components/index.ts +0 -0
  49. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/palette.ts +0 -0
  50. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/core/typography.ts +0 -0
  51. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/create-theme.ts +0 -0
  52. /package/{next-mui-template-ts → next-mui-templates/base-ts}/src/theme/theme-provider.tsx +0 -0
  53. /package/{next-mui-template-ts → next-mui-templates/base-ts}/tsconfig.json +0 -0
package/README.md CHANGED
@@ -1,122 +1,217 @@
1
- <img width="1420" height="308" alt="CREATE-NEXT-MUI-BANNER" src="https://github.com/user-attachments/assets/11e72fc8-6b6d-40c4-97a1-c05f7b943e02" />
1
+ <img width="1420" alt="CREATE-NEXT-MUI-BANNER" src="https://github.com/user-attachments/assets/11e72fc8-6b6d-40c4-97a1-c05f7b943e02" />
2
2
 
3
- # create-next-mui 🚀
3
+ # create-next-mui
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/create-next-mui?style=flat&logo=npm&color=CB3837)](https://www.npmjs.com/package/create-next-mui)
6
- [![Next.js v19](https://img.shields.io/badge/Next.js-v19-000000?style=flat&logo=nextdotjs&logoColor=white)](https://nextjs.org/)
7
- [![MUI v9](https://img.shields.io/badge/MUI-v9-007FFF?style=flat&logo=mui&logoColor=white)](https://mui.com/)
6
+ [![Next.js](https://img.shields.io/badge/Next.js-v19-000000?style=flat&logo=nextdotjs&logoColor=white)](https://nextjs.org/)
7
+ [![MUI](https://img.shields.io/badge/MUI-v9-007FFF?style=flat&logo=mui&logoColor=white)](https://mui.com/)
8
8
 
9
- A blazing-fast, interactive CLI tool to instantly scaffold production-ready **Next.js** applications pre-configured with **Material UI (MUI)**, robust theme providers, and an elite architectural linting layout.
9
+ Scaffold a production-ready **Next.js + Material UI** application in seconds.
10
10
 
11
- Stop wasting time wiring up Emotion caches, Next.js App Router layout configs, or sorting your imports manually. Launch your next project perfectly in under 10 seconds.
11
+ The generated project comes preconfigured with:
12
+
13
+ - ⚡ Next.js App Router
14
+ - 🎨 Material UI
15
+ - 📦 TypeScript or JavaScript templates
16
+ - 🧹 ESLint Flat Config
17
+ - 📁 Scalable project structure
18
+
19
+ No global installation required.
12
20
 
13
21
  ---
14
22
 
15
- ## 🚀 Quick Start
23
+ # Quick Start
24
+
25
+ Create a new project:
26
+
27
+ ```bash
28
+ npx create-next-mui my-app
29
+ ```
16
30
 
17
- You don't need to install anything globally. Just run the following command in your terminal:
31
+ or
18
32
 
19
33
  ```bash
20
- npx create-next-mui my-next-mui-app
34
+ npm init next-mui
35
+ ```
21
36
 
22
- # or use prompts
37
+ If no project name is provided, the CLI will guide you through the setup interactively.
23
38
 
39
+ ```bash
24
40
  npx create-next-mui
41
+ ```
25
42
 
26
- # or
43
+ ---
27
44
 
28
- npm init next-mui
45
+ # Non-interactive Mode
46
+
47
+ Use the `--yes` (or `-y`) flag to skip prompts and accept the default configuration.
48
+
49
+ ```bash
50
+ npx create-next-mui my-app --yes
29
51
  ```
30
52
 
31
- Passing a project name creates that folder and uses the same name in the generated project metadata. If you omit the name, the interactive prompt engine (powered by `@clack/prompts`) will guide you through naming your project and selecting your preferred flavor.
53
+ This will automatically:
32
54
 
33
- ---
55
+ - use the provided project name
56
+ - select the **TypeScript** template
57
+ - generate the project without prompting
34
58
 
35
- ## Key Features
59
+ This is especially useful for:
36
60
 
37
- - **⚡ Modern Architecture:** Built natively on top of the Next.js App Router structure.
38
- - **🎨 Material UI Ready:** Seamless compilation of MUI components inside Server and Client Components with pre-configured UI themes.
39
- - **🧩 Dual-Template Architecture:** Full support for both **TypeScript** and **JavaScript** boilerplates.
40
- - **🧼 Perfectionist Linting Config:** Pre-packaged with **ESLint v9 Flat Config** (`eslint.config.mjs`) utilizing `eslint-plugin-perfectionist` and `eslint-plugin-unused-imports`.
41
- - **📦 Pure & Lightweight:** Zero bloat. Template files are automatically stripped of development artifacts (`node_modules`, caches) before build deployment.
61
+ - CI/CD pipelines
62
+ - automation scripts
63
+ - testing
64
+ - quick project generation
42
65
 
43
66
  ---
44
67
 
45
- ## 📦 Choice of Flavors
68
+ # Interactive Setup
69
+
70
+ Without `--yes`, the CLI walks you through the available options.
46
71
 
47
- During the prompt sequence, you can choose between two completely separate architectures, both fine-tuned for high-performance builds:
72
+ Current prompts include:
48
73
 
49
- 1. **TypeScript Template (`next-mui-template-ts`)** Out-of-the-box strong typing, custom theme module augmentations, and strict `@typescript-eslint` checking.
50
- 2. **JavaScript Template (`next-mui-template-js`)** Lightweight, clean vanilla ES modern syntax with optimized configuration overhead.
74
+ - Project name
75
+ - Language selection
76
+ - TypeScript (recommended)
77
+ - JavaScript
78
+ - Features
79
+ - Zustand
80
+ - React Query ( TanStack Query )
51
81
 
52
82
  ---
53
83
 
54
- ## 📐 Generated Project Structure
84
+ # Available Templates
85
+
86
+ ## TypeScript
87
+
88
+ Recommended for most projects.
89
+
90
+ Includes:
91
+
92
+ - TypeScript
93
+ - strict type checking
94
+ - MUI theme typings
95
+ - ESLint Flat Config
96
+
97
+ ## JavaScript
98
+
99
+ For developers who prefer JavaScript.
55
100
 
56
- No matter which path you choose, `create-next-mui` prints out an organized, production-grade layout optimized for scalability:
101
+ Includes:
102
+
103
+ - modern JavaScript
104
+ - Material UI
105
+ - ESLint Flat Config
106
+
107
+ ## Features
108
+
109
+ - Zustand
110
+ - React Query ( TanStack Query )
111
+
112
+ ---
113
+
114
+ # Generated Project Structure
57
115
 
58
116
  ```text
59
- my-awesome-app/
117
+ my-app/
60
118
  ├── src/
61
119
  │ ├── app/
62
- ├── layout.js/ts # Handles App Router initialization & MUI Cache Provider
63
- │ │ └── page.js/ts # Pre-built home view utilizing responsive MUI layouts
64
- │ ├── components/ # Reusable global presentation components
120
+ │ ├── components/
65
121
  │ └── theme/
66
- ├── index.js/ts # Deep theme customization (palette, typography, overrides)
67
- │ └── theme-provider.js # Keeps layout tree hydrations isolated and performant
68
- ├── eslint.config.mjs # Elite natural line-length linting layout
69
- ├── next.config.js # Configured optimization vectors
122
+ ├── eslint.config.mjs
123
+ ├── next.config.js
70
124
  ├── package.json
71
125
  └── README.md
72
-
73
126
  ```
74
127
 
75
128
  ---
76
129
 
77
- ## 🎨 Elite Linting Layout (Perfectionist Grouping)
130
+ # What's Included
78
131
 
79
- Both boilerplate environments contain a fine-tuned, strict importing arrangement rule framework using `line-length` natural alpha sorting. Your files are automatically linted and organized cleanly on save down this architectural chain:
132
+ Every generated project comes configured with:
80
133
 
81
- 1. **React Core APIs** (`react`)
82
- 2. **Next.js Framework Hooks & Context** (`next/*`)
83
- 3. **Material UI Design Tokens & Engine** (`@mui/*`, `@emotion/*`)
84
- 4. **External Third-Party Libraries**
85
- 5. **Internal Layer Architectures** (`@/types`, `@/lib`, `@/components`, `@/theme`)
134
+ - Next.js App Router
135
+ - Material UI
136
+ - Theme Provider
137
+ - Emotion integration
138
+ - ESLint v9 Flat Config
139
+ - eslint-plugin-perfectionist
140
+ - eslint-plugin-unused-imports
141
+ - organized project structure
86
142
 
87
- Say goodbye to disorganized, messy blocks of import statements!
143
+ Development artifacts such as `node_modules`, `.next`, and build caches are excluded from generated projects.
88
144
 
89
145
  ---
90
146
 
91
- ## ⚙️ Development Scripts
147
+ # Getting Started
92
148
 
93
- Once your scaffolding finishes generating, step inside your directory and run the standard lifecycle workflows:
149
+ After scaffolding:
94
150
 
95
151
  ```bash
96
- # Install dependencies
152
+ cd my-app
97
153
  npm install
154
+ npm run dev
155
+ ```
98
156
 
99
- # Boot up local development server
157
+ Useful scripts:
158
+
159
+ ```bash
100
160
  npm run dev
161
+ ```
162
+
163
+ Start the development server.
101
164
 
102
- # Run ESLint validation checks with automated file ordering adjustment
165
+ ```bash
103
166
  npm run lint
167
+ ```
104
168
 
105
- # Compile production-ready code bundles
169
+ Run ESLint.
170
+
171
+ ```bash
106
172
  npm run build
173
+ ```
174
+
175
+ Create a production build.
176
+
177
+ ---
178
+
179
+ # CLI Reference
107
180
 
181
+ ## Create a project
182
+
183
+ ```bash
184
+ npx create-next-mui my-app
185
+ ```
186
+
187
+ ## Interactive mode
188
+
189
+ ```bash
190
+ npx create-next-mui
191
+ ```
192
+
193
+ ## Accept defaults
194
+
195
+ ```bash
196
+ npx create-next-mui my-app --yes
197
+ ```
198
+
199
+ or
200
+
201
+ ```bash
202
+ npx create-next-mui my-app -y
108
203
  ```
109
204
 
110
205
  ---
111
206
 
112
- ## 🤝 Contributing & Feedback
207
+ # Contributing
113
208
 
114
- Issues and pull requests are highly welcome! If you want to expand the templates or suggest additional components, feel free to open an issue or submit a pull request on the official repository.
209
+ Issues and pull requests are welcome.
115
210
 
116
- Maintained with 💻 by [thatonevikash](https://github.com/thatonevikash).
211
+ If you'd like to improve the templates or add new features, feel free to open an issue or submit a PR.
117
212
 
118
213
  ---
119
214
 
120
- ## 📜 License
215
+ # License
121
216
 
122
- This project is licensed under the MIT License - see the LICENSE file for details.
217
+ MIT
@@ -1,11 +1,11 @@
1
1
  {
2
- "name": "next-mui-template",
2
+ "name": "create-next-mui",
3
3
  "version": "0.0.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
- "name": "next-mui-template",
8
+ "name": "create-next-mui",
9
9
  "version": "0.0.1",
10
10
  "dependencies": {
11
11
  "@emotion/react": "^11.14.0",
@@ -276,9 +276,9 @@
276
276
  }
277
277
  },
278
278
  "node_modules/@emnapi/wasi-threads": {
279
- "version": "1.2.1",
280
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
281
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
279
+ "version": "1.2.2",
280
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
281
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
282
282
  "dev": true,
283
283
  "license": "MIT",
284
284
  "optional": true,
@@ -2312,6 +2312,40 @@
2312
2312
  "node": ">=14.0.0"
2313
2313
  }
2314
2314
  },
2315
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": {
2316
+ "version": "1.10.0",
2317
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
2318
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
2319
+ "dev": true,
2320
+ "license": "MIT",
2321
+ "optional": true,
2322
+ "dependencies": {
2323
+ "@emnapi/wasi-threads": "1.2.1",
2324
+ "tslib": "^2.4.0"
2325
+ }
2326
+ },
2327
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": {
2328
+ "version": "1.10.0",
2329
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
2330
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
2331
+ "dev": true,
2332
+ "license": "MIT",
2333
+ "optional": true,
2334
+ "dependencies": {
2335
+ "tslib": "^2.4.0"
2336
+ }
2337
+ },
2338
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
2339
+ "version": "1.2.1",
2340
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
2341
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
2342
+ "dev": true,
2343
+ "license": "MIT",
2344
+ "optional": true,
2345
+ "dependencies": {
2346
+ "tslib": "^2.4.0"
2347
+ }
2348
+ },
2315
2349
  "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
2316
2350
  "version": "1.12.2",
2317
2351
  "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz",
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "next-mui-template",
2
+ "name": "create-next-mui",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
5
  "scripts": {
@@ -276,9 +276,9 @@
276
276
  }
277
277
  },
278
278
  "node_modules/@emnapi/wasi-threads": {
279
- "version": "1.2.1",
280
- "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
281
- "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
279
+ "version": "1.2.2",
280
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz",
281
+ "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==",
282
282
  "dev": true,
283
283
  "license": "MIT",
284
284
  "optional": true,
@@ -2312,6 +2312,40 @@
2312
2312
  "node": ">=14.0.0"
2313
2313
  }
2314
2314
  },
2315
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/core": {
2316
+ "version": "1.10.0",
2317
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
2318
+ "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
2319
+ "dev": true,
2320
+ "license": "MIT",
2321
+ "optional": true,
2322
+ "dependencies": {
2323
+ "@emnapi/wasi-threads": "1.2.1",
2324
+ "tslib": "^2.4.0"
2325
+ }
2326
+ },
2327
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/runtime": {
2328
+ "version": "1.10.0",
2329
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
2330
+ "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
2331
+ "dev": true,
2332
+ "license": "MIT",
2333
+ "optional": true,
2334
+ "dependencies": {
2335
+ "tslib": "^2.4.0"
2336
+ }
2337
+ },
2338
+ "node_modules/@unrs/resolver-binding-wasm32-wasi/node_modules/@emnapi/wasi-threads": {
2339
+ "version": "1.2.1",
2340
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
2341
+ "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==",
2342
+ "dev": true,
2343
+ "license": "MIT",
2344
+ "optional": true,
2345
+ "dependencies": {
2346
+ "tslib": "^2.4.0"
2347
+ }
2348
+ },
2315
2349
  "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
2316
2350
  "version": "1.12.2",
2317
2351
  "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz",
@@ -1,5 +1,5 @@
1
1
  {
2
- "name": "next-mui-template",
2
+ "name": "create-next-mui",
3
3
  "version": "0.0.1",
4
4
  "private": true,
5
5
  "scripts": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-next-mui",
3
- "version": "0.1.2",
3
+ "version": "0.1.4",
4
4
  "description": "spin up your nextjs project with mui setup",
5
5
  "keywords": [
6
6
  "nextjs",
@@ -23,8 +23,7 @@
23
23
  },
24
24
  "files": [
25
25
  "src",
26
- "next-mui-template-ts",
27
- "next-mui-template-js"
26
+ "next-mui-templates"
28
27
  ],
29
28
  "main": "index.js",
30
29
  "scripts": {
@@ -32,7 +31,6 @@
32
31
  },
33
32
  "dependencies": {
34
33
  "@clack/prompts": "^1.5.0",
35
- "degit": "^3.3.2",
36
34
  "picocolors": "^1.1.1"
37
35
  }
38
36
  }
package/src/index.js CHANGED
@@ -6,11 +6,15 @@ import fs from "node:fs/promises";
6
6
  import path from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
 
9
- // Resolve the directory where this CLI package actually lives on the user's system
9
+ // ----------------------------------------------------------------------
10
+
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = path.dirname(__filename);
12
13
 
13
14
  const args = process.argv.slice(2);
15
+ const command = args[0];
16
+ const featureName = args[1];
17
+
14
18
  const positionalArgs = args.filter(
15
19
  (arg) => !["--yes", "-y", "--js"].includes(arg),
16
20
  );
@@ -23,6 +27,38 @@ const hasJsFlag = args.includes("--js");
23
27
 
24
28
  const DEFAULT_LANGUAGE = hasJsFlag ? "js" : "ts";
25
29
 
30
+ // ----------------------------------------------------------------------
31
+
32
+ const LANG = [
33
+ {
34
+ value: "ts",
35
+ label: "TypeScript (Recommended)",
36
+ hint: "Strict typings, clean architecture",
37
+ },
38
+ {
39
+ value: "js",
40
+ label: "JavaScript",
41
+ hint: "Vanilla JS configuration",
42
+ },
43
+ ];
44
+
45
+ const FEATURES = [
46
+ {
47
+ value: "react-query",
48
+ label: "React Query",
49
+ hint: "TanStack Query configuration",
50
+ },
51
+ {
52
+ value: "zustand",
53
+ label: "Zustand",
54
+ hint: "Lightweight global state management",
55
+ },
56
+ ];
57
+
58
+ // ----------------------------------------------------------------------
59
+ // Helper Functions
60
+ // ----------------------------------------------------------------------
61
+
26
62
  function validateProjectName(value) {
27
63
  if (value.length === 0) return "Project name is required!";
28
64
 
@@ -39,36 +75,192 @@ function getPackageName(projectName, targetProjectDir) {
39
75
  }
40
76
 
41
77
  async function updateProjectName(targetProjectDir, packageName) {
42
- const files = ["package.json", "package-lock.json"];
78
+ const filePath = path.join(targetProjectDir, "package.json");
79
+ try {
80
+ const content = await fs.readFile(filePath, "utf8");
81
+ const json = JSON.parse(content);
82
+ json.name = packageName;
43
83
 
44
- await Promise.all(
45
- files.map(async (file) => {
46
- const filePath = path.join(targetProjectDir, file);
84
+ if (json.packages?.[""]?.name) {
85
+ json.packages[""].name = packageName;
86
+ }
87
+ await fs.writeFile(filePath, `${JSON.stringify(json, null, 2)}\n`);
88
+ } catch (error) {
89
+ if (error.code === "ENOENT") return;
90
+ throw error;
91
+ }
92
+ }
93
+
94
+ async function mergePackageJson(targetProjectDir, manifest) {
95
+ const filePath = path.join(targetProjectDir, "package.json");
96
+ try {
97
+ const content = await fs.readFile(filePath, "utf8");
98
+ const json = JSON.parse(content);
47
99
 
48
- try {
49
- const content = await fs.readFile(filePath, "utf8");
50
- const json = JSON.parse(content);
100
+ json.dependencies = {
101
+ ...json.dependencies,
102
+ ...(manifest.dependencies || {}),
103
+ };
51
104
 
52
- json.name = packageName;
105
+ json.devDependencies = {
106
+ ...json.devDependencies,
107
+ ...(manifest.devDependencies || {}),
108
+ };
53
109
 
54
- if (json.packages?.[""]?.name) {
55
- json.packages[""].name = packageName;
56
- }
110
+ await fs.writeFile(filePath, `${JSON.stringify(json, null, 2)}\n`);
111
+ } catch (error) {
112
+ if (error.code === "ENOENT") return;
113
+ throw error;
114
+ }
115
+ }
116
+
117
+ async function injectProviderToLayout(targetProjectDir, manifest, language) {
118
+ const ext = language === "ts" ? "tsx" : "jsx";
119
+ const layoutPath = path.join(targetProjectDir, "src", "app", `layout.${ext}`);
120
+
121
+ try {
122
+ let content = await fs.readFile(layoutPath, "utf8");
57
123
 
58
- await fs.writeFile(filePath, `${JSON.stringify(json, null, 2)}\n`);
59
- } catch (error) {
60
- if (error.code === "ENOENT") return;
124
+ // 1. Inject the Import Line safely below the last import
125
+ if (manifest.importLine && !content.includes(manifest.importLine)) {
126
+ const lines = content.split("\n");
127
+ const lastImportIndex = lines.findLastIndex((line) =>
128
+ line.trim().startsWith("import"),
129
+ );
61
130
 
62
- throw error;
131
+ if (lastImportIndex !== -1) {
132
+ lines.splice(lastImportIndex + 1, 0, manifest.importLine);
133
+ content = lines.join("\n");
134
+ } else {
135
+ content = `${manifest.importLine}\n${content}`;
63
136
  }
64
- }),
137
+ }
138
+
139
+ // 2. Wrap {children} dynamically
140
+ if (manifest.expression) {
141
+ const openTag = manifest.expression.open;
142
+ const closeTag = manifest.expression.close;
143
+
144
+ if (!content.includes(openTag)) {
145
+ content = content.replace(
146
+ /(\>\s*)\{\s*children\s*\}(\s*\<)/,
147
+ `$1${openTag} {children} ${closeTag}$2`,
148
+ );
149
+ }
150
+ }
151
+
152
+ await fs.writeFile(layoutPath, content, "utf8");
153
+ } catch (error) {
154
+ if (error.code === "ENOENT") return;
155
+ throw error;
156
+ }
157
+ }
158
+
159
+ async function applyFeature(feature, targetProjectDir, language) {
160
+ const featureDir = path.resolve(
161
+ __dirname,
162
+ "..",
163
+ "next-mui-features",
164
+ feature,
65
165
  );
166
+ const manifestPath = path.join(featureDir, "manifest.json");
167
+ const ext = language == "ts" ? "tsx" : "jsx";
168
+
169
+ let manifest = {};
170
+ try {
171
+ const manifestContent = await fs.readFile(manifestPath, "utf8");
172
+ manifest = JSON.parse(manifestContent);
173
+ } catch {
174
+ // Fail-safe if manifest is missing or malformed
175
+ return;
176
+ }
177
+
178
+ // 1. Copy feature-specific files from the language subdirectory
179
+ if (manifest.files) {
180
+ for (const file of manifest.files) {
181
+ const srcPath = path.resolve(featureDir, language, `${file.src}.${ext}`);
182
+ const destPath = path.resolve(targetProjectDir, `${file.dest}.${ext}`);
183
+
184
+ await fs.mkdir(path.dirname(destPath), { recursive: true });
185
+ await fs.copyFile(srcPath, destPath);
186
+ }
187
+ }
188
+
189
+ // 2. Merge dependencies into package.json
190
+ await mergePackageJson(targetProjectDir, manifest);
191
+
192
+ // 3. Perform dynamic layout file nesting
193
+ await injectProviderToLayout(targetProjectDir, manifest, language);
66
194
  }
67
195
 
196
+ // ----------------------------------------------------------------------
197
+ // Main Execution Control Loop
198
+ // ----------------------------------------------------------------------
199
+
68
200
  async function main() {
69
201
  console.clear();
202
+
70
203
  p.intro(color.bgBlue(color.white(" create-next-mui ")));
71
204
 
205
+ // ----------------------------------------------------------------------
206
+ // Add Feature Command Pipeline
207
+ // ----------------------------------------------------------------------
208
+
209
+ if (command === "add") {
210
+ if (!featureName) {
211
+ p.cancel(
212
+ "Please specify a feature.\n\nExample:\ncreate-next-mui add react-query",
213
+ );
214
+ process.exit(1);
215
+ }
216
+
217
+ if (!FEATURES.some((f) => f.value === featureName)) {
218
+ p.cancel(`Unknown feature "${featureName}".`);
219
+ process.exit(1);
220
+ }
221
+
222
+ const projectRoot = process.cwd();
223
+
224
+ // Verify package.json exists in target execution environment
225
+ try {
226
+ await fs.access(path.join(projectRoot, "package.json"));
227
+ } catch {
228
+ p.cancel(
229
+ "No package.json found.\nRun this command inside a Next.js project.",
230
+ );
231
+ process.exit(1);
232
+ }
233
+
234
+ // Auto-detect layout flavor via tsconfig existence
235
+ let language = "js";
236
+ try {
237
+ await fs.access(path.join(projectRoot, "tsconfig.json"));
238
+ language = "ts";
239
+ } catch {
240
+ // Keep fallback as js configuration
241
+ }
242
+
243
+ const spinner = p.spinner();
244
+ spinner.start(`Installing ${featureName}...`);
245
+
246
+ try {
247
+ await applyFeature(featureName, projectRoot, language);
248
+
249
+ spinner.stop(color.green(`${featureName} installed successfully.`));
250
+ p.note(`${color.cyan("npm install")}`, "Next Step");
251
+ p.outro(`✨ ${featureName} added successfully!`);
252
+ return;
253
+ } catch (error) {
254
+ spinner.stop(color.red("Failed to install feature."));
255
+ p.note(error.message, "Error");
256
+ process.exit(1);
257
+ }
258
+ }
259
+
260
+ // ----------------------------------------------------------------------
261
+ // Interactive Fresh Workspace Scaffolding Pipeline
262
+ // ----------------------------------------------------------------------
263
+
72
264
  const projectNameError = hasInitialProjectName
73
265
  ? validateProjectName(PROJECT_NAME)
74
266
  : undefined;
@@ -88,23 +280,22 @@ async function main() {
88
280
  placeholder: "my-next-mui-app (or '.' for current directory)",
89
281
  validate: validateProjectName,
90
282
  }),
283
+
91
284
  language: () =>
92
285
  hasYesFlag
93
286
  ? Promise.resolve(DEFAULT_LANGUAGE)
94
287
  : p.select({
95
288
  message: "Choose your language flavor:",
96
- options: [
97
- {
98
- value: "ts",
99
- label: "TypeScript (Recommended)",
100
- hint: "Strict typings, clean architecture",
101
- },
102
- {
103
- value: "js",
104
- label: "JavaScript",
105
- hint: "Vanilla JS configuration",
106
- },
107
- ],
289
+ options: LANG,
290
+ }),
291
+
292
+ features: () =>
293
+ hasYesFlag
294
+ ? Promise.resolve([])
295
+ : p.multiselect({
296
+ message: "Select optional features:",
297
+ required: false,
298
+ options: FEATURES,
108
299
  }),
109
300
  },
110
301
  {
@@ -115,71 +306,69 @@ async function main() {
115
306
  },
116
307
  );
117
308
 
118
- // Define local source paths (inside this CLI package folder)
119
- const templateFolderName =
120
- project.language === "ts" ? "next-mui-template-ts" : "next-mui-template-js";
121
- const sourceTemplateDir = path.resolve(__dirname, "..", templateFolderName);
309
+ const baseTemplateDir = path.resolve(
310
+ __dirname,
311
+ "..",
312
+ "next-mui-templates",
313
+ `base-${project.language}`,
314
+ );
122
315
 
123
- // Define destination paths (where the user is running the command)
124
316
  const targetProjectDir = path.resolve(process.cwd(), project.name);
125
317
  const packageName = getPackageName(project.name, targetProjectDir);
126
318
 
127
- // If targeting current directory, make sure it's clean
128
319
  if (project.name === ".") {
129
320
  try {
130
- const existingFiles = await fs.readdir(targetProjectDir);
131
- if (existingFiles.length > 0) {
321
+ const files = await fs.readdir(targetProjectDir);
322
+ if (files.length > 0) {
132
323
  p.log.error(
133
324
  color.red(
134
- "The current directory is not empty! Please clear it or specify a project name.",
325
+ "The current directory is not empty! Please clear it or specify another project name.",
135
326
  ),
136
327
  );
137
328
  process.exit(1);
138
329
  }
139
- } catch (err) {
140
- // If the directory reading fails completely, we exit safely
330
+ } catch {
141
331
  process.exit(1);
142
332
  }
143
333
  }
144
334
 
145
335
  const s = p.spinner();
146
- s.start("Unboxing your Next.js + MUI foundation locally...");
336
+ s.start("Scaffolding your Next.js + MUI workspace...");
147
337
 
148
338
  try {
149
- // Native high-speed recursive copy
150
- await fs.cp(sourceTemplateDir, targetProjectDir, {
339
+ // 1. Unpack base layout system
340
+ await fs.cp(baseTemplateDir, targetProjectDir, {
151
341
  recursive: true,
152
342
  filter: (src) => {
153
- const targetName = path.basename(src);
154
- return (
155
- targetName !== "node_modules" &&
156
- targetName !== ".next" &&
157
- targetName !== "out" &&
158
- targetName !== "build"
159
- );
343
+ const name = path.basename(src);
344
+ return !["node_modules", ".next", "out", "build"].includes(name);
160
345
  },
161
346
  });
347
+
348
+ // 2. Map and loop over chosen features sequentially
349
+ for (const feature of project.features) {
350
+ await applyFeature(feature, targetProjectDir, project.language);
351
+ }
352
+
353
+ // 3. Finalize package.json configuration naming
162
354
  await updateProjectName(targetProjectDir, packageName);
163
355
 
164
356
  s.stop(color.green("Workspace scaffolded successfully!"));
165
357
  } catch (error) {
166
- s.stop(color.red("Failed to build workspace structure."));
167
- p.note(color.yellow(`Error details: ${error.message}`), "Troubleshooting:");
358
+ s.stop(color.red("Failed to scaffold workspace."));
359
+ p.note(color.yellow(error.message), "Troubleshooting");
168
360
  process.exit(1);
169
361
  }
170
362
 
171
- // Clear instructions for the developer
172
- const isCurrentDir = project.name === ".";
173
- const cdInstruction = isCurrentDir
174
- ? ""
175
- : `${color.cyan(`cd ${project.name}`)}\n`;
363
+ const cd =
364
+ project.name === "." ? "" : `${color.cyan(`cd ${project.name}`)}\n`;
176
365
 
177
366
  p.note(
178
- `${cdInstruction}${color.cyan("npm install")}\n${color.cyan("npm run dev")}`,
179
- "Next Steps to Get Started:",
367
+ `${cd}${color.cyan("npm install")}\n${color.cyan("npm run dev")}`,
368
+ "Next Steps",
180
369
  );
181
370
 
182
- p.outro(`✨ Code cleanly, sort perfectly. Built with create-next-mui!`);
371
+ p.outro("✨ Build clean and fast with create-next-mui!");
183
372
  }
184
373
 
185
374
  main().catch(console.error);