@aditokmo/react-setup-cli 0.1.3 → 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.
package/README.md CHANGED
@@ -62,7 +62,7 @@ TanStack Query is integrated to handle server-state management. It is optional,
62
62
 
63
63
  ### Styling
64
64
 
65
- You can choose between CSS, SCSS (soon), or Tailwind CSS. While I personally recommend Tailwind for modern and faster development, the CLI ensures that regardless of your choice, the project is configured with a global styles directory and a consistent entry point. If you select TailwindCSS you will also have option to use Shadcn/UI, and with that you will have option to choose components that you want to install instead of doing it manually.
65
+ You can choose between CSS, SCSS, or Tailwind CSS. While I personally recommend Tailwind for modern and faster development, the CLI ensures that regardless of your choice, the project is configured with a global styles directory and a consistent entry point. If you select TailwindCSS you will also have option to use Shadcn/UI, and with that you will have option to choose components that you want to install instead of doing it manually.
66
66
 
67
67
  ### Routing
68
68
 
package/dist/index.js CHANGED
@@ -3,12 +3,27 @@ import fs from 'fs-extra';
3
3
  import path from 'path';
4
4
  import { execSync } from 'child_process';
5
5
  import { askQuestions } from './questions.js';
6
- import { copyTemplate, patchViteConfig, finalizeViteConfig, patchAppFile, finalizeAppFile, detectPackageManager, patchIndexHTMLFile } from './utils.js';
6
+ import { copyTemplate, patchViteConfig, finalizeViteConfig, patchAppFile, finalizeAppFile, detectPackageManager, patchPackageJsonFile, patchFileContent } from './utils.js';
7
7
  import { collectDependencies } from './installers.js';
8
8
  import { fileURLToPath } from 'url';
9
9
  import { FONT_QUERIES } from './mapper.js';
10
10
  const __filename = fileURLToPath(import.meta.url);
11
11
  const __dirname = path.dirname(__filename);
12
+ const baseDeps = ['react', 'react-dom'];
13
+ const baseDevDeps = [
14
+ 'vite',
15
+ 'typescript',
16
+ '@types/node',
17
+ '@types/react',
18
+ '@types/react-dom',
19
+ '@vitejs/plugin-react-swc',
20
+ 'eslint',
21
+ '@eslint/js',
22
+ 'eslint-plugin-react-hooks',
23
+ 'eslint-plugin-react-refresh',
24
+ 'globals',
25
+ 'typescript-eslint'
26
+ ];
12
27
  async function main() {
13
28
  console.log('⚛️ Welcome to React CLI Setup by github/aditokmo');
14
29
  let projectDir = '';
@@ -20,10 +35,12 @@ async function main() {
20
35
  projectDir = path.join(process.cwd(), answers.projectName);
21
36
  const templateRoot = path.join(__dirname, '../templates');
22
37
  const appFilePath = path.join(projectDir, 'src', 'App.tsx');
23
- const indexHTMLPath = path.join(projectDir, 'src', 'index.html');
38
+ const indexHTMLPath = path.join(projectDir, 'index.html');
39
+ const notFoundPath = path.join(projectDir, 'src/modules/common/pages/NotFound.tsx');
24
40
  const viteConfigPath = path.join(projectDir, 'vite.config.ts');
25
41
  fs.ensureDirSync(projectDir);
26
42
  copyTemplate(path.join(templateRoot, 'base'), projectDir);
43
+ patchPackageJsonFile(path.join(projectDir, 'package.json'), answers.projectName);
27
44
  // Styles
28
45
  if (answers.style === 'tailwind') {
29
46
  copyTemplate(path.join(templateRoot, 'styles', 'tailwind', 'src'), path.join(projectDir, 'src/styles'));
@@ -34,7 +51,8 @@ async function main() {
34
51
  }
35
52
  if (answers.style === 'scss') {
36
53
  copyTemplate(path.join(templateRoot, 'styles', 'scss', 'src'), path.join(projectDir, 'src/styles'));
37
- patchIndexHTMLFile(path.join(projectDir, 'index.html'), '<link rel="stylesheet" href="./src/styles/main.css" />', '<link rel="stylesheet" href="./src/styles/main.scss" />');
54
+ patchFileContent(notFoundPath, "import '@/styles/404.css'", "import '@/styles/404.scss'");
55
+ patchFileContent(indexHTMLPath, '<link rel="stylesheet" href="./src/styles/main.css" />', '<link rel="stylesheet" href="./src/styles/main.scss" />');
38
56
  }
39
57
  // Fonts
40
58
  if (answers?.fonts && answers.fonts.length > 0) {
@@ -46,12 +64,10 @@ async function main() {
46
64
  <link rel="preconnect" href="https://fonts.googleapis.com">
47
65
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
48
66
  <link href="${url}" rel="stylesheet">`;
49
- patchIndexHTMLFile(path.join(projectDir, 'index.html'), '<!-- [HEAD_LINK_IMPORT] -->', content);
67
+ patchFileContent(indexHTMLPath, '<!-- [HEAD_LINK_IMPORT] -->', content);
50
68
  }
51
69
  else {
52
- let html = fs.readFileSync(indexHTMLPath, 'utf-8');
53
- html = html.replace('', '');
54
- fs.writeFileSync(indexHTMLPath, html);
70
+ patchFileContent(indexHTMLPath, '<!-- [HEAD_LINK_IMPORT] -->', '');
55
71
  }
56
72
  // State Management
57
73
  if (answers.reactQuery) {
@@ -78,16 +94,18 @@ async function main() {
78
94
  finalizeAppFile(appFilePath);
79
95
  finalizeViteConfig(viteConfigPath);
80
96
  const { dependency, devDependency, cmd } = collectDependencies(answers, packageManager);
97
+ const allDeps = [...baseDeps, ...dependency];
98
+ const allDevDeps = [...baseDevDeps, ...devDependency];
81
99
  process.chdir(projectDir);
82
100
  console.log(`📦 Initializing ${packageManager} project...`);
83
101
  execSync(`${packageManager} install`, { stdio: 'inherit' });
84
- if (dependency.length) {
102
+ if (allDeps.length) {
85
103
  console.log('📦 Installing dependencies...');
86
- execSync(`${packageManager} ${installAction} ${dependency.join(' ')}`, { stdio: 'inherit' });
104
+ execSync(`${packageManager} ${installAction} ${allDeps.join(' ')}`, { stdio: 'inherit' });
87
105
  }
88
- if (devDependency.length) {
106
+ if (allDevDeps.length) {
89
107
  console.log('📦 Installing dev dependencies...');
90
- execSync(`${packageManager} ${installAction} -D ${devDependency.join(' ')}`, { stdio: 'inherit' });
108
+ execSync(`${packageManager} ${installAction} -D ${allDevDeps.join(' ')}`, { stdio: 'inherit' });
91
109
  }
92
110
  // Extra cmds like shadcn
93
111
  for (const command of cmd) {
package/dist/questions.js CHANGED
@@ -4,7 +4,6 @@ export async function askQuestions() {
4
4
  projectName: () => text({
5
5
  message: 'Project name:',
6
6
  placeholder: 'my-app',
7
- validate: (value) => (value.length < 0 ? 'Project name is required' : undefined),
8
7
  }),
9
8
  style: () => select({
10
9
  message: 'Choose styling:',
@@ -116,6 +115,7 @@ export async function askQuestions() {
116
115
  }
117
116
  return {
118
117
  ...results,
118
+ projectName: results.projectName || 'my-app',
119
119
  shadcn: results.shadcn,
120
120
  shadcnComponents: (results.shadcnComponents ?? []),
121
121
  fonts: (results.fonts ?? [])
package/dist/utils.js CHANGED
@@ -1,15 +1,17 @@
1
1
  import fs from 'fs-extra';
2
2
  export function copyTemplate(src, path) {
3
3
  if (!fs.existsSync(src)) {
4
- console.warn(`⚠️ Template folder ${src} dosn't exist`);
4
+ console.warn(`⚠️ Template folder ${src} doesn't exist`);
5
5
  return;
6
6
  }
7
7
  fs.copySync(src, path, { overwrite: true });
8
8
  }
9
- export function patchIndexHTMLFile(filePath, importLine, newContent) {
10
- let htmlContent = fs.readFileSync(filePath, 'utf-8');
11
- htmlContent = htmlContent.replace(importLine, newContent);
12
- fs.writeFileSync(filePath, htmlContent);
9
+ export function patchFileContent(filePath, searchValue, replaceValue) {
10
+ if (!fs.existsSync(filePath))
11
+ return;
12
+ const content = fs.readFileSync(filePath, 'utf-8');
13
+ const newContent = content.replace(searchValue, replaceValue);
14
+ fs.writeFileSync(filePath, newContent);
13
15
  }
14
16
  export function patchAppFile(filePath, importLine, openTag, closeTag) {
15
17
  if (!fs.existsSync(filePath))
@@ -33,6 +35,18 @@ export function patchAppFile(filePath, importLine, openTag, closeTag) {
33
35
  }
34
36
  fs.writeFileSync(filePath, content);
35
37
  }
38
+ export function patchPackageJsonFile(filePath, projectName) {
39
+ if (!fs.existsSync(filePath))
40
+ return;
41
+ try {
42
+ const pkg = fs.readJsonSync(filePath);
43
+ pkg.name = projectName;
44
+ fs.writeJsonSync(filePath, pkg, { spaces: 2 });
45
+ }
46
+ catch (error) {
47
+ console.error('⚠️ Could not update package.json name');
48
+ }
49
+ }
36
50
  export function patchViteConfig(filePath, beforeReactPlugin, importLine, pluginLine) {
37
51
  if (!fs.existsSync(filePath))
38
52
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aditokmo/react-setup-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "A fast React CLI to jumpstart your projects. It sets up your libraries and organizes a scalable folder structure so you can skip the configuration and go straight to coding.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -1,7 +1,7 @@
1
1
  {
2
- "name": "vite-project",
2
+ "name": "{{PROJECT_NAME}}",
3
3
  "private": true,
4
- "version": "0.0.0",
4
+ "version": "0.1.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -9,22 +9,6 @@
9
9
  "lint": "eslint .",
10
10
  "preview": "vite preview"
11
11
  },
12
- "dependencies": {
13
- "react": "^19.2.0",
14
- "react-dom": "^19.2.0"
15
- },
16
- "devDependencies": {
17
- "@eslint/js": "^9.39.1",
18
- "@types/node": "^24.10.1",
19
- "@types/react": "^19.2.5",
20
- "@types/react-dom": "^19.2.3",
21
- "@vitejs/plugin-react-swc": "^4.2.2",
22
- "eslint": "^9.39.1",
23
- "eslint-plugin-react-hooks": "^7.0.1",
24
- "eslint-plugin-react-refresh": "^0.4.24",
25
- "globals": "^16.5.0",
26
- "typescript": "~5.9.3",
27
- "typescript-eslint": "^8.46.4",
28
- "vite": "^7.2.4"
29
- }
12
+ "dependencies": {},
13
+ "devDependencies": {}
30
14
  }
@@ -1,4 +1,4 @@
1
- import '@/styles/404.scss';
1
+ import '@/styles/404.css';
2
2
 
3
3
  export const NotFound = () => {
4
4
  return (
@@ -50,7 +50,7 @@
50
50
  .not-found-content a {
51
51
  font-size: 0.9rem;
52
52
  color: var(--white);
53
- background-color: var(--primary-blue);
53
+ background-color: var(--primary);
54
54
  padding: 10px 30px;
55
55
  margin-top: 20px;
56
56
  border-radius: var(--radius-sm);
@@ -61,7 +61,7 @@
61
61
  }
62
62
 
63
63
  .not-found-content a:hover {
64
- background: var(--primary-blue-hover);
64
+ background: var(--primary-hover);
65
65
  }
66
66
 
67
67
  @media (max-width: 768px) {
@@ -50,12 +50,12 @@ p {
50
50
 
51
51
  a {
52
52
  text-decoration: none;
53
- color: var(--primary-blue);
53
+ color: var(--primary);
54
54
  transition: 0.3s ease;
55
55
  }
56
56
 
57
57
  a:hover {
58
- color: var(--primary-blue-hover);
58
+ color: var(--primary-hover);
59
59
  }
60
60
 
61
61
  button {
@@ -1,6 +1,6 @@
1
1
  :root {
2
- --primary-blue: #37538a;
3
- --primary-blue-hover: #263c67;
2
+ --primary: #37538a;
3
+ --primary-hover: #263c67;
4
4
  --bg-light: #e6edfc;
5
5
  --white: #ffffff;
6
6
  --text-dark: #111111;
@@ -48,7 +48,7 @@
48
48
  a {
49
49
  font-size: 0.9rem;
50
50
  color: $white;
51
- background-color: $primary-blue;
51
+ background-color: $primary;
52
52
  padding: 10px 30px;
53
53
  margin-top: 20px;
54
54
  border-radius: $radius-sm;
@@ -58,7 +58,7 @@
58
58
  display: inline-block;
59
59
 
60
60
  &:hover {
61
- background: $primary-blue-hover;
61
+ background: $primary-hover;
62
62
  }
63
63
  }
64
64
 
@@ -1,8 +1,24 @@
1
1
  // Brand Colors
2
2
  $primary: #37538a;
3
+ $primary-hover: #263c67;
3
4
  $primary-dark: #263c67;
4
5
  $accent: #e6edfc;
5
6
 
7
+ // Text
8
+ $text-dark: #111111;
9
+ $text-muted: #666666;
10
+
11
+ // Background
12
+ $bg-light: #e6edfc;
13
+
14
+ // Radius
15
+ $radius-sm: 10px;
16
+ $radius-md: 16px;
17
+ $radius-lg: 24px;
18
+
19
+ // Shadows
20
+ $shadow-main: 0px 0px 14px -14px rgba(0, 0, 0, 0.75);
21
+
6
22
  // Neutrals
7
23
  $white: #ffffff;
8
24
  $black: #111111;
@@ -10,7 +26,3 @@ $gray: #666666;
10
26
 
11
27
  // Fonts
12
28
  $font-main: "Arial", sans-serif;
13
-
14
- // Breakpoints
15
- $breakpoint-tablet: 768px;
16
- $breakpoint-mobile: 480px;
@@ -0,0 +1,98 @@
1
+ .not-found-wrapper {
2
+ display: flex;
3
+ flex-direction: column;
4
+ align-items: center;
5
+ justify-content: center;
6
+ min-height: 100vh;
7
+ padding: 20px;
8
+ text-align: center;
9
+ background: #e6edfc;
10
+ }
11
+
12
+ .not-found-content {
13
+ padding: 100px 70px;
14
+ background: #fff;
15
+ max-width: 700px;
16
+ width: 100%;
17
+ display: flex;
18
+ flex-direction: column;
19
+ justify-content: center;
20
+ align-items: center;
21
+ border-radius: 24px;
22
+ box-shadow: 0px 0px 14px -14px rgba(0, 0, 0, 0.75);
23
+ }
24
+
25
+ .not-found-content span {
26
+ color: #666666;
27
+ font-weight: 700;
28
+ font-size: 6rem;
29
+ line-height: 1;
30
+ }
31
+
32
+ .not-found-content h1 {
33
+ font-size: 2.5rem;
34
+ font-weight: 600;
35
+ margin: 0;
36
+ color: #111111;
37
+ }
38
+
39
+ .not-found-content p {
40
+ font-size: 1rem;
41
+ color: #666666;
42
+ max-width: 360px;
43
+ width: 100%;
44
+ margin: 10px 0;
45
+ }
46
+
47
+ .not-found-content a {
48
+ font-size: 0.9rem;
49
+ color: #fff;
50
+ background-color: #37538a;
51
+ padding: 10px 30px;
52
+ margin-top: 20px;
53
+ border-radius: 10px;
54
+ transition: 0.2s;
55
+ cursor: pointer;
56
+ text-decoration: none;
57
+ display: inline-block;
58
+ }
59
+
60
+ .not-found-content a:hover {
61
+ background: #263c67;
62
+ }
63
+
64
+ @media (max-width: 768px) {
65
+ .not-found-content {
66
+ padding: 60px 40px;
67
+ max-width: 90%;
68
+ }
69
+ .not-found-content span {
70
+ font-size: 4.5rem;
71
+ margin-bottom: 20px;
72
+ }
73
+ .not-found-content h1 {
74
+ font-size: 2rem;
75
+ }
76
+ }
77
+
78
+ @media (max-width: 480px) {
79
+ .not-found-content {
80
+ padding: 40px 20px;
81
+ border-radius: 16px;
82
+ }
83
+ .not-found-content span {
84
+ font-size: 3.5rem;
85
+ margin-bottom: 20px;
86
+ }
87
+ .not-found-content h1 {
88
+ font-size: 1.5rem;
89
+ }
90
+ .not-found-content p {
91
+ font-size: 0.9rem;
92
+ }
93
+ .not-found-content a {
94
+ width: 100%;
95
+ box-sizing: border-box;
96
+ text-align: center;
97
+ }
98
+ }