create-modern-react 1.0.1 → 2.1.0

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 (58) hide show
  1. package/README.md +270 -72
  2. package/bin/index.js +9 -7
  3. package/lib/prompts.js +132 -150
  4. package/lib/setup.js +264 -143
  5. package/package.json +17 -8
  6. package/templates/base/.env.example +9 -0
  7. package/templates/base/.eslintrc.cjs +37 -0
  8. package/templates/base/.prettierrc +11 -0
  9. package/templates/base/components.json +17 -0
  10. package/templates/base/index.html +3 -2
  11. package/templates/base/package.json +34 -15
  12. package/templates/base/postcss.config.js +6 -0
  13. package/templates/base/src/App.tsx +7 -22
  14. package/templates/base/src/components/layout/error-boundary.tsx +60 -0
  15. package/templates/base/src/components/layout/index.ts +2 -0
  16. package/templates/base/src/components/layout/root-layout.tsx +36 -0
  17. package/templates/base/src/components/ui/button.tsx +55 -0
  18. package/templates/base/src/components/ui/card.tsx +85 -0
  19. package/templates/base/src/components/ui/index.ts +12 -0
  20. package/templates/base/src/components/ui/input.tsx +24 -0
  21. package/templates/base/src/components/ui/separator.tsx +29 -0
  22. package/templates/base/src/components/ui/skeleton.tsx +15 -0
  23. package/templates/base/src/hooks/index.ts +3 -0
  24. package/templates/base/src/hooks/use-cancel-token.ts +63 -0
  25. package/templates/base/src/hooks/use-debounce.ts +29 -0
  26. package/templates/base/src/hooks/use-loader.ts +39 -0
  27. package/templates/base/src/index.css +74 -61
  28. package/templates/base/src/lib/utils.ts +14 -0
  29. package/templates/base/src/main.tsx +6 -6
  30. package/templates/base/src/providers/index.tsx +27 -0
  31. package/templates/base/src/providers/theme-provider.tsx +92 -0
  32. package/templates/base/src/routes/index.tsx +40 -0
  33. package/templates/base/src/routes/routes.ts +36 -0
  34. package/templates/base/src/screens/home/index.tsx +132 -0
  35. package/templates/base/src/screens/not-found/index.tsx +29 -0
  36. package/templates/base/src/services/alertify-services.ts +133 -0
  37. package/templates/base/src/services/api/api-helpers.ts +130 -0
  38. package/templates/base/src/services/api/axios-instance.ts +77 -0
  39. package/templates/base/src/services/api/index.ts +9 -0
  40. package/templates/base/src/services/index.ts +2 -0
  41. package/templates/base/src/types/index.ts +55 -0
  42. package/templates/base/src/vite-env.d.ts +31 -0
  43. package/templates/base/tailwind.config.js +77 -0
  44. package/templates/base/tsconfig.json +5 -4
  45. package/templates/base/tsconfig.node.json +22 -0
  46. package/templates/base/vite.config.ts +68 -7
  47. package/templates/optional/antd/config-provider.tsx +33 -0
  48. package/templates/optional/antd/index.ts +2 -0
  49. package/templates/optional/antd/styles/antd-overrides.css +104 -0
  50. package/templates/optional/antd/theme.ts +75 -0
  51. package/templates/optional/husky/.husky/pre-commit +1 -0
  52. package/templates/optional/husky/.lintstagedrc.json +6 -0
  53. package/templates/optional/redux/hooks.ts +17 -0
  54. package/templates/optional/redux/index.ts +13 -0
  55. package/templates/optional/redux/provider.tsx +33 -0
  56. package/templates/optional/redux/store/index.ts +45 -0
  57. package/templates/optional/redux/store/slices/app-slice.ts +62 -0
  58. package/templates/base/src/App.css +0 -14
package/lib/setup.js CHANGED
@@ -3,32 +3,63 @@ const path = require('path');
3
3
  const chalk = require('chalk');
4
4
  const { runCommand } = require('./install');
5
5
 
6
+ /**
7
+ * Main setup function - orchestrates the entire project generation
8
+ */
6
9
  async function setupProject(config) {
7
10
  const { projectPath, projectName } = config;
8
11
 
9
- console.log(chalk.blue('\nšŸ—ļø Setting up project structure...'));
12
+ console.log(chalk.blue('\nšŸ—ļø Setting up project structure...\n'));
10
13
 
11
- // Create project directory
14
+ // Step 1: Create project directory
12
15
  await fs.ensureDir(projectPath);
13
16
 
14
- // Copy base template
17
+ // Step 2: Copy base template
18
+ console.log(chalk.gray(' Copying base template...'));
15
19
  const templatePath = path.join(__dirname, '../templates/base');
16
20
  await fs.copy(templatePath, projectPath);
17
21
 
18
- // Update package.json with project name and selected dependencies
19
- await updatePackageJson(config);
22
+ // Step 3: Handle Antd vs Shadcn/ui
23
+ if (config.useAntd) {
24
+ console.log(chalk.gray(' Configuring Ant Design (removing Shadcn/ui)...'));
25
+ await removeDirectory(path.join(projectPath, 'src/components/ui'));
26
+ await fs.remove(path.join(projectPath, 'components.json'));
27
+ await copyOptionalTemplate('antd', projectPath);
28
+ await updateProvidersForAntd(projectPath);
29
+ }
30
+
31
+ // Step 4: Copy optional feature templates
32
+ if (config.useRedux) {
33
+ console.log(chalk.gray(' Adding Redux Toolkit + Redux Persist...'));
34
+ await copyOptionalTemplate('redux', projectPath);
35
+ await updateProvidersForRedux(projectPath, config.useAntd);
36
+ }
37
+
38
+ if (config.useHusky) {
39
+ console.log(chalk.gray(' Adding Husky + lint-staged...'));
40
+ await copyOptionalTemplate('husky', projectPath);
41
+ }
20
42
 
21
- // Configure selected libraries
22
- await configureLibraries(config);
43
+ // Step 5: Update package.json
44
+ console.log(chalk.gray(' Configuring package.json...'));
45
+ await updatePackageJson(config);
23
46
 
24
- // Initialize git if requested
25
- if (config.git && !config.skipGit) {
47
+ // Step 6: Initialize git if requested
48
+ if (config.initGit) {
26
49
  await initializeGit(config);
27
50
  }
28
51
 
29
- console.log(chalk.green('āœ… Project structure created successfully!'));
52
+ // Step 7: Setup Husky if selected
53
+ if (config.useHusky && config.initGit) {
54
+ await setupHusky(projectPath);
55
+ }
56
+
57
+ console.log(chalk.green('\nāœ… Project structure created successfully!\n'));
30
58
  }
31
59
 
60
+ /**
61
+ * Update package.json with project name and selected dependencies
62
+ */
32
63
  async function updatePackageJson(config) {
33
64
  const packageJsonPath = path.join(config.projectPath, 'package.json');
34
65
  const packageJson = await fs.readJson(packageJsonPath);
@@ -36,180 +67,270 @@ async function updatePackageJson(config) {
36
67
  // Update name
37
68
  packageJson.name = config.projectName;
38
69
 
39
- // Add dependencies based on configuration
70
+ // Add optional dependencies
40
71
  const dependencies = { ...packageJson.dependencies };
41
72
  const devDependencies = { ...packageJson.devDependencies };
42
73
 
43
- // UI Library dependencies
44
- if (config.uiLibrary === 'antd') {
45
- dependencies['antd'] = '^5.0.0';
46
- } else if (config.uiLibrary === 'mui') {
47
- dependencies['@mui/material'] = '^5.0.0';
48
- dependencies['@emotion/react'] = '^11.0.0';
49
- dependencies['@emotion/styled'] = '^11.0.0';
50
- } else if (config.uiLibrary === 'chakra') {
51
- dependencies['@chakra-ui/react'] = '^2.0.0';
52
- dependencies['@emotion/react'] = '^11.0.0';
53
- dependencies['@emotion/styled'] = '^11.0.0';
54
- dependencies['framer-motion'] = '^6.0.0';
55
- }
56
-
57
- // CSS Framework dependencies
58
- if (config.cssFramework === 'tailwind') {
59
- devDependencies['tailwindcss'] = '^3.0.0';
60
- devDependencies['postcss'] = '^8.0.0';
61
- devDependencies['autoprefixer'] = '^10.0.0';
62
- } else if (config.cssFramework === 'styled-components') {
63
- dependencies['styled-components'] = '^6.0.0';
64
- devDependencies['@types/styled-components'] = '^5.1.0';
65
- }
66
-
67
- // State Management dependencies
68
- if (config.stateManagement === 'redux-toolkit') {
69
- dependencies['@reduxjs/toolkit'] = '^2.0.0';
70
- dependencies['react-redux'] = '^9.0.0';
74
+ // Redux dependencies
75
+ if (config.useRedux) {
76
+ dependencies['@reduxjs/toolkit'] = '^2.2.0';
77
+ dependencies['react-redux'] = '^9.1.0';
71
78
  dependencies['redux-persist'] = '^6.0.0';
72
- } else if (config.stateManagement === 'zustand') {
73
- dependencies['zustand'] = '^4.0.0';
74
- } else if (config.stateManagement === 'jotai') {
75
- dependencies['jotai'] = '^2.0.0';
76
- }
77
-
78
- // Data Fetching dependencies
79
- if (config.dataFetching === 'react-query') {
80
- dependencies['@tanstack/react-query'] = '^5.0.0';
81
- dependencies['@tanstack/react-query-devtools'] = '^5.0.0';
82
- } else if (config.dataFetching === 'swr') {
83
- dependencies['swr'] = '^2.0.0';
84
- } else if (config.dataFetching === 'apollo') {
85
- dependencies['@apollo/client'] = '^3.0.0';
86
- dependencies['graphql'] = '^16.0.0';
87
79
  }
88
80
 
89
- // Routing dependencies
90
- if (config.routing === 'react-router') {
91
- dependencies['react-router-dom'] = '^6.0.0';
92
- } else if (config.routing === 'wouter') {
93
- dependencies['wouter'] = '^3.0.0';
81
+ // Ant Design dependencies (replaces Shadcn)
82
+ if (config.useAntd) {
83
+ dependencies['antd'] = '^5.20.0';
84
+ dependencies['@ant-design/icons'] = '^5.4.0';
85
+ // Remove Radix dependency when using Antd
86
+ delete dependencies['@radix-ui/react-slot'];
94
87
  }
95
88
 
96
- // Icon dependencies
97
- if (config.icons === 'lucide') {
98
- dependencies['lucide-react'] = '^0.400.0';
99
- } else if (config.icons === 'react-icons') {
100
- dependencies['react-icons'] = '^5.0.0';
101
- } else if (config.icons === 'heroicons') {
102
- dependencies['@heroicons/react'] = '^2.0.0';
103
- }
89
+ // Husky dependencies
90
+ if (config.useHusky) {
91
+ devDependencies['husky'] = '^9.1.0';
92
+ devDependencies['lint-staged'] = '^15.2.0';
104
93
 
105
- // Development Tools dependencies
106
- if (config.devTools.includes('storybook')) {
107
- devDependencies['@storybook/react-vite'] = '^8.0.0';
108
- devDependencies['@storybook/addon-essentials'] = '^8.0.0';
109
- devDependencies['storybook'] = '^8.0.0';
94
+ // Add prepare script for husky
95
+ packageJson.scripts = packageJson.scripts || {};
96
+ packageJson.scripts.prepare = 'husky';
110
97
  }
111
98
 
112
- if (config.devTools.includes('testing')) {
113
- devDependencies['jest'] = '^29.0.0';
114
- devDependencies['@testing-library/react'] = '^14.0.0';
115
- devDependencies['@testing-library/jest-dom'] = '^6.0.0';
116
- devDependencies['@testing-library/user-event'] = '^14.0.0';
117
- }
99
+ packageJson.dependencies = sortObjectKeys(dependencies);
100
+ packageJson.devDependencies = sortObjectKeys(devDependencies);
118
101
 
119
- if (config.devTools.includes('husky')) {
120
- devDependencies['husky'] = '^9.0.0';
121
- devDependencies['lint-staged'] = '^15.0.0';
122
- }
102
+ await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
103
+ }
123
104
 
124
- // PWA dependencies
125
- if (config.pwa) {
126
- devDependencies['vite-plugin-pwa'] = '^0.20.0';
105
+ /**
106
+ * Copy an optional template to the project
107
+ */
108
+ async function copyOptionalTemplate(templateName, projectPath) {
109
+ const optionalTemplatePath = path.join(
110
+ __dirname,
111
+ '../templates/optional',
112
+ templateName
113
+ );
114
+
115
+ if (await fs.pathExists(optionalTemplatePath)) {
116
+ // For redux and antd, copy to src directory
117
+ if (templateName === 'redux') {
118
+ await fs.copy(optionalTemplatePath, path.join(projectPath, 'src/redux'));
119
+ } else if (templateName === 'antd') {
120
+ await fs.copy(optionalTemplatePath, path.join(projectPath, 'src/antd'));
121
+ // Also copy the styles file to src/styles
122
+ const stylesFile = path.join(optionalTemplatePath, 'styles/antd-overrides.css');
123
+ if (await fs.pathExists(stylesFile)) {
124
+ await fs.ensureDir(path.join(projectPath, 'src/styles'));
125
+ await fs.copy(
126
+ stylesFile,
127
+ path.join(projectPath, 'src/styles/antd-overrides.css')
128
+ );
129
+ }
130
+ } else if (templateName === 'husky') {
131
+ // Copy husky files to root
132
+ await fs.copy(
133
+ path.join(optionalTemplatePath, '.husky'),
134
+ path.join(projectPath, '.husky')
135
+ );
136
+ await fs.copy(
137
+ path.join(optionalTemplatePath, '.lintstagedrc.json'),
138
+ path.join(projectPath, '.lintstagedrc.json')
139
+ );
140
+ }
127
141
  }
142
+ }
128
143
 
129
- packageJson.dependencies = dependencies;
130
- packageJson.devDependencies = devDependencies;
144
+ /**
145
+ * Update providers/index.tsx to include Antd ConfigProvider
146
+ */
147
+ async function updateProvidersForAntd(projectPath) {
148
+ const providersContent = `import { type ReactNode } from 'react';
149
+ import { ThemeProvider } from './theme-provider';
150
+ import { RootLayout } from '~/components/layout';
151
+ import { ErrorBoundary } from '~/components/layout';
152
+ import { AntdConfigProvider } from '~/antd';
153
+ import '~/styles/antd-overrides.css';
154
+
155
+ interface ProvidersProps {
156
+ children: ReactNode;
157
+ }
131
158
 
132
- await fs.writeJson(packageJsonPath, packageJson, { spaces: 2 });
159
+ /**
160
+ * Application providers composition
161
+ * Wraps the app with all necessary context providers
162
+ */
163
+ export function Providers({ children }: ProvidersProps) {
164
+ return (
165
+ <ErrorBoundary>
166
+ <ThemeProvider defaultTheme="system" storageKey="app-theme">
167
+ <AntdConfigProvider>
168
+ <RootLayout>{children}</RootLayout>
169
+ </AntdConfigProvider>
170
+ </ThemeProvider>
171
+ </ErrorBoundary>
172
+ );
133
173
  }
134
174
 
135
- async function configureLibraries(config) {
136
- const { projectPath } = config;
175
+ export { ThemeProvider, useTheme } from './theme-provider';
176
+ `;
137
177
 
138
- // Configure Tailwind if selected
139
- if (config.cssFramework === 'tailwind') {
140
- await configureTailwind(projectPath);
141
- }
178
+ await fs.writeFile(
179
+ path.join(projectPath, 'src/providers/index.tsx'),
180
+ providersContent
181
+ );
142
182
 
143
- // Configure Vite plugins based on selections
144
- await configureVite(config);
183
+ // Create styles directory if it doesn't exist
184
+ await fs.ensureDir(path.join(projectPath, 'src/styles'));
185
+ }
145
186
 
146
- // Add configuration files for selected libraries
147
- await addConfigFiles(config);
187
+ /**
188
+ * Update providers/index.tsx to include Redux Provider
189
+ */
190
+ async function updateProvidersForRedux(projectPath, hasAntd) {
191
+ let providersContent;
192
+
193
+ if (hasAntd) {
194
+ providersContent = `import { type ReactNode } from 'react';
195
+ import { ThemeProvider } from './theme-provider';
196
+ import { RootLayout } from '~/components/layout';
197
+ import { ErrorBoundary } from '~/components/layout';
198
+ import { AntdConfigProvider } from '~/antd';
199
+ import { ReduxProvider } from '~/redux';
200
+ import '~/styles/antd-overrides.css';
201
+
202
+ interface ProvidersProps {
203
+ children: ReactNode;
148
204
  }
149
205
 
150
- async function configureTailwind(projectPath) {
151
- const tailwindConfig = `/** @type {import('tailwindcss').Config} */
152
- export default {
153
- content: [
154
- "./index.html",
155
- "./src/**/*.{js,ts,jsx,tsx}",
156
- ],
157
- theme: {
158
- extend: {},
159
- },
160
- plugins: [],
161
- }`;
162
-
163
- const postcssConfig = `export default {
164
- plugins: {
165
- tailwindcss: {},
166
- autoprefixer: {},
167
- },
168
- }`;
169
-
170
- await fs.writeFile(path.join(projectPath, 'tailwind.config.js'), tailwindConfig);
171
- await fs.writeFile(path.join(projectPath, 'postcss.config.js'), postcssConfig);
172
-
173
- // Add Tailwind directives to CSS
174
- const cssPath = path.join(projectPath, 'src/index.css');
175
- const tailwindDirectives = `@tailwind base;
176
- @tailwind components;
177
- @tailwind utilities;
206
+ /**
207
+ * Application providers composition
208
+ * Wraps the app with all necessary context providers
209
+ *
210
+ * Order: ErrorBoundary > Redux > Theme > Antd > Layout
211
+ */
212
+ export function Providers({ children }: ProvidersProps) {
213
+ return (
214
+ <ErrorBoundary>
215
+ <ReduxProvider>
216
+ <ThemeProvider defaultTheme="system" storageKey="app-theme">
217
+ <AntdConfigProvider>
218
+ <RootLayout>{children}</RootLayout>
219
+ </AntdConfigProvider>
220
+ </ThemeProvider>
221
+ </ReduxProvider>
222
+ </ErrorBoundary>
223
+ );
224
+ }
178
225
 
226
+ export { ThemeProvider, useTheme } from './theme-provider';
179
227
  `;
180
-
181
- if (await fs.pathExists(cssPath)) {
182
- const existingCss = await fs.readFile(cssPath, 'utf8');
183
- await fs.writeFile(cssPath, tailwindDirectives + existingCss);
184
228
  } else {
185
- await fs.writeFile(cssPath, tailwindDirectives);
186
- }
229
+ providersContent = `import { type ReactNode } from 'react';
230
+ import { ThemeProvider } from './theme-provider';
231
+ import { RootLayout } from '~/components/layout';
232
+ import { ErrorBoundary } from '~/components/layout';
233
+ import { ReduxProvider } from '~/redux';
234
+
235
+ interface ProvidersProps {
236
+ children: ReactNode;
237
+ }
238
+
239
+ /**
240
+ * Application providers composition
241
+ * Wraps the app with all necessary context providers
242
+ *
243
+ * Order: ErrorBoundary > Redux > Theme > Layout
244
+ */
245
+ export function Providers({ children }: ProvidersProps) {
246
+ return (
247
+ <ErrorBoundary>
248
+ <ReduxProvider>
249
+ <ThemeProvider defaultTheme="system" storageKey="app-theme">
250
+ <RootLayout>{children}</RootLayout>
251
+ </ThemeProvider>
252
+ </ReduxProvider>
253
+ </ErrorBoundary>
254
+ );
187
255
  }
188
256
 
189
- async function configureVite(config) {
190
- // This would configure vite.config.ts based on selected options
191
- // For now, we'll use the existing base template configuration
257
+ export { ThemeProvider, useTheme } from './theme-provider';
258
+ `;
259
+ }
260
+
261
+ await fs.writeFile(
262
+ path.join(projectPath, 'src/providers/index.tsx'),
263
+ providersContent
264
+ );
192
265
  }
193
266
 
194
- async function addConfigFiles(config) {
195
- // Add configuration files for selected tools
196
- // This would add ESLint, Prettier, Jest configs, etc.
267
+ /**
268
+ * Remove a directory and all its contents
269
+ */
270
+ async function removeDirectory(dirPath) {
271
+ if (await fs.pathExists(dirPath)) {
272
+ await fs.remove(dirPath);
273
+ }
197
274
  }
198
275
 
276
+ /**
277
+ * Initialize git repository
278
+ */
199
279
  async function initializeGit(config) {
200
280
  const { projectPath } = config;
201
281
 
202
282
  try {
203
- console.log(chalk.blue('šŸ”§ Initializing Git repository...'));
283
+ console.log(chalk.gray(' Initializing Git repository...'));
204
284
 
205
285
  await runCommand('git', ['init'], projectPath);
206
286
  await runCommand('git', ['add', '.'], projectPath);
207
- await runCommand('git', ['commit', '-m', 'Initial commit from create-modern-react'], projectPath);
287
+ await runCommand(
288
+ 'git',
289
+ ['commit', '-m', 'Initial commit from create-modern-react'],
290
+ projectPath
291
+ );
208
292
 
209
- console.log(chalk.green('āœ… Git repository initialized!'));
293
+ console.log(chalk.green(' āœ… Git repository initialized!'));
210
294
  } catch (error) {
211
- console.warn(chalk.yellow('āš ļø Could not initialize Git repository:'), error.message);
295
+ console.warn(
296
+ chalk.yellow(' āš ļø Could not initialize Git repository:'),
297
+ error.message
298
+ );
212
299
  }
213
300
  }
214
301
 
215
- module.exports = { setupProject };
302
+ /**
303
+ * Setup Husky hooks after git init
304
+ */
305
+ async function setupHusky(projectPath) {
306
+ try {
307
+ console.log(chalk.gray(' Setting up Husky git hooks...'));
308
+
309
+ // Make pre-commit hook executable
310
+ const preCommitPath = path.join(projectPath, '.husky/pre-commit');
311
+ if (await fs.pathExists(preCommitPath)) {
312
+ await fs.chmod(preCommitPath, '755');
313
+ }
314
+
315
+ console.log(chalk.green(' āœ… Husky configured!'));
316
+ } catch (error) {
317
+ console.warn(
318
+ chalk.yellow(' āš ļø Could not setup Husky:'),
319
+ error.message
320
+ );
321
+ }
322
+ }
323
+
324
+ /**
325
+ * Sort object keys alphabetically
326
+ */
327
+ function sortObjectKeys(obj) {
328
+ return Object.keys(obj)
329
+ .sort()
330
+ .reduce((sorted, key) => {
331
+ sorted[key] = obj[key];
332
+ return sorted;
333
+ }, {});
334
+ }
335
+
336
+ module.exports = { setupProject };
package/package.json CHANGED
@@ -1,29 +1,38 @@
1
1
  {
2
2
  "name": "create-modern-react",
3
- "version": "1.0.1",
4
- "description": "Create a modern React application with Vite, TypeScript, and your choice of modern libraries",
3
+ "version": "2.1.0",
4
+ "description": "Create production-ready React + TypeScript + Tailwind applications in seconds",
5
5
  "main": "bin/index.js",
6
6
  "bin": {
7
7
  "create-modern-react": "./bin/index.js"
8
8
  },
9
9
  "engines": {
10
- "node": ">=16.0.0"
10
+ "node": ">=18.0.0"
11
11
  },
12
12
  "keywords": [
13
13
  "react",
14
- "vite",
15
14
  "typescript",
15
+ "vite",
16
+ "tailwindcss",
16
17
  "cli",
18
+ "scaffold",
17
19
  "boilerplate",
18
- "template",
19
- "modern",
20
- "scaffold"
20
+ "create-react-app",
21
+ "starter-kit",
22
+ "shadcn-ui",
23
+ "react-starter",
24
+ "vite-template",
25
+ "react-boilerplate",
26
+ "npx",
27
+ "frontend",
28
+ "antd",
29
+ "redux"
21
30
  ],
22
31
  "author": "Abhay Rana",
23
32
  "license": "MIT",
24
33
  "repository": {
25
34
  "type": "git",
26
- "url": "https://github.com/abhay-rana/create-modern-react.git"
35
+ "url": "git+https://github.com/abhay-rana/create-modern-react.git"
27
36
  },
28
37
  "bugs": {
29
38
  "url": "https://github.com/abhay-rana/create-modern-react/issues"
@@ -0,0 +1,9 @@
1
+ # API Configuration
2
+ VITE_API_URL=http://localhost:8000/api
3
+
4
+ # App Configuration
5
+ VITE_APP_NAME=Modern React App
6
+ VITE_APP_VERSION=1.0.0
7
+
8
+ # Feature Flags
9
+ VITE_ENABLE_DEVTOOLS=true
@@ -0,0 +1,37 @@
1
+ module.exports = {
2
+ root: true,
3
+ env: { browser: true, es2020: true },
4
+ extends: [
5
+ 'eslint:recommended',
6
+ 'plugin:@typescript-eslint/recommended',
7
+ 'plugin:react-hooks/recommended',
8
+ ],
9
+ ignorePatterns: ['dist', '.eslintrc.cjs'],
10
+ parser: '@typescript-eslint/parser',
11
+ plugins: ['react-refresh', 'unused-imports'],
12
+ rules: {
13
+ 'react-refresh/only-export-components': [
14
+ 'warn',
15
+ { allowConstantExport: true },
16
+ ],
17
+ // Unused imports
18
+ 'unused-imports/no-unused-imports': 'error',
19
+ 'unused-imports/no-unused-vars': [
20
+ 'warn',
21
+ {
22
+ vars: 'all',
23
+ varsIgnorePattern: '^_',
24
+ args: 'after-used',
25
+ argsIgnorePattern: '^_',
26
+ },
27
+ ],
28
+ // TypeScript
29
+ '@typescript-eslint/no-unused-vars': 'off', // Handled by unused-imports
30
+ '@typescript-eslint/no-explicit-any': 'warn',
31
+ '@typescript-eslint/prefer-as-const': 'error',
32
+ // General
33
+ 'no-console': ['warn', { allow: ['warn', 'error'] }],
34
+ 'prefer-const': 'error',
35
+ 'no-var': 'error',
36
+ },
37
+ };
@@ -0,0 +1,11 @@
1
+ {
2
+ "semi": true,
3
+ "singleQuote": true,
4
+ "tabWidth": 2,
5
+ "trailingComma": "es5",
6
+ "printWidth": 80,
7
+ "bracketSpacing": true,
8
+ "arrowParens": "always",
9
+ "endOfLine": "lf",
10
+ "plugins": ["prettier-plugin-tailwindcss"]
11
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "https://ui.shadcn.com/schema.json",
3
+ "style": "default",
4
+ "rsc": false,
5
+ "tsx": true,
6
+ "tailwind": {
7
+ "config": "tailwind.config.js",
8
+ "css": "src/index.css",
9
+ "baseColor": "slate",
10
+ "cssVariables": true,
11
+ "prefix": ""
12
+ },
13
+ "aliases": {
14
+ "components": "~/components",
15
+ "utils": "~/lib/utils"
16
+ }
17
+ }
@@ -1,13 +1,14 @@
1
1
  <!doctype html>
2
- <html lang="en">
2
+ <html lang="en" class="light">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
5
  <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
+ <meta name="description" content="Modern React application built with create-modern-react" />
7
8
  <title>Modern React App</title>
8
9
  </head>
9
10
  <body>
10
11
  <div id="root"></div>
11
12
  <script type="module" src="/src/main.tsx"></script>
12
13
  </body>
13
- </html>
14
+ </html>