create-react-scaffold-cli 1.0.7 → 1.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 (196) hide show
  1. package/bin/index.js +15 -5
  2. package/package.json +1 -1
  3. package/scripts/createProject.js +8 -2
  4. package/templates/{base → base-js}/src/shared/utils/parser.js +1 -1
  5. package/templates/base-ts/.husky/pre-commit +1 -0
  6. package/templates/base-ts/.husky/pre-push +0 -0
  7. package/templates/base-ts/.prettierrc +8 -0
  8. package/templates/base-ts/.vscode/extensions.json +8 -0
  9. package/templates/base-ts/.vscode/settings.json +16 -0
  10. package/templates/base-ts/README.md +165 -0
  11. package/templates/base-ts/docs/DOCS.md +7 -0
  12. package/templates/base-ts/eslint.config.js +56 -0
  13. package/templates/base-ts/index.html +16 -0
  14. package/templates/base-ts/jsconfig.json +7 -0
  15. package/templates/base-ts/package.json +69 -0
  16. package/templates/base-ts/postcss.config.mjs +7 -0
  17. package/templates/base-ts/public/icons/react.svg +1 -0
  18. package/templates/base-ts/src/app/APP.md +74 -0
  19. package/templates/base-ts/src/app/App.tsx +15 -0
  20. package/templates/base-ts/src/app/Router.tsx +48 -0
  21. package/templates/base-ts/src/app/index.css +37 -0
  22. package/templates/base-ts/src/app/main.tsx +13 -0
  23. package/templates/base-ts/src/app/middlewares/AuthMiddleware.tsx +6 -0
  24. package/templates/base-ts/src/app/middlewares/index.ts +1 -0
  25. package/templates/base-ts/src/app/providers/QueryProvider.tsx +75 -0
  26. package/templates/base-ts/src/app/providers/index.ts +1 -0
  27. package/templates/base-ts/src/app/routes.registry.ts +9 -0
  28. package/templates/base-ts/src/features/FEATURES.md +102 -0
  29. package/templates/base-ts/src/features/sample/components/index.ts +0 -0
  30. package/templates/base-ts/src/features/sample/constants/index.ts +3 -0
  31. package/templates/base-ts/src/features/sample/constants/sample.assets.ts +8 -0
  32. package/templates/base-ts/src/features/sample/constants/sample.navigations.ts +5 -0
  33. package/templates/base-ts/src/features/sample/constants/sample.queryKeys.ts +3 -0
  34. package/templates/base-ts/src/features/sample/hooks/index.ts +0 -0
  35. package/templates/base-ts/src/features/sample/index.ts +1 -0
  36. package/templates/base-ts/src/features/sample/pages/SamplePage.tsx +7 -0
  37. package/templates/base-ts/src/features/sample/pages/index.ts +1 -0
  38. package/templates/base-ts/src/features/sample/sample.routes.ts +13 -0
  39. package/templates/base-ts/src/features/welcome/components/CodeLine.tsx +59 -0
  40. package/templates/base-ts/src/features/welcome/components/Divider.tsx +11 -0
  41. package/templates/base-ts/src/features/welcome/components/Footer.tsx +78 -0
  42. package/templates/base-ts/src/features/welcome/components/Hero.tsx +131 -0
  43. package/templates/base-ts/src/features/welcome/components/IconLink.tsx +24 -0
  44. package/templates/base-ts/src/features/welcome/components/QuickStartPanel.tsx +63 -0
  45. package/templates/base-ts/src/features/welcome/components/RingSoft.tsx +21 -0
  46. package/templates/base-ts/src/features/welcome/components/StorySections.tsx +63 -0
  47. package/templates/base-ts/src/features/welcome/components/WhatYouGet.tsx +49 -0
  48. package/templates/base-ts/src/features/welcome/components/index.ts +5 -0
  49. package/templates/base-ts/src/features/welcome/constants/index.ts +2 -0
  50. package/templates/base-ts/src/features/welcome/constants/welcome.constants.ts +21 -0
  51. package/templates/base-ts/src/features/welcome/constants/welcome.navigations.ts +3 -0
  52. package/templates/base-ts/src/features/welcome/index.ts +1 -0
  53. package/templates/base-ts/src/features/welcome/pages/WelcomePage.tsx +28 -0
  54. package/templates/base-ts/src/features/welcome/pages/index.ts +1 -0
  55. package/templates/base-ts/src/features/welcome/welcome.routes.ts +13 -0
  56. package/templates/base-ts/src/shared/SHARED.md +104 -0
  57. package/templates/base-ts/src/shared/constants/app.constants.ts +11 -0
  58. package/templates/base-ts/src/shared/constants/assets.constants.ts +5 -0
  59. package/templates/base-ts/src/shared/constants/index.ts +2 -0
  60. package/templates/base-ts/src/shared/contexts/index.ts +0 -0
  61. package/templates/base-ts/src/shared/hooks/index.ts +3 -0
  62. package/templates/base-ts/src/shared/hooks/useBooleanState.ts +19 -0
  63. package/templates/base-ts/src/shared/hooks/useDebounce.ts +17 -0
  64. package/templates/base-ts/src/shared/hooks/useToggleState.ts +11 -0
  65. package/templates/base-ts/src/shared/layouts/index.ts +0 -0
  66. package/templates/base-ts/src/shared/libs/axios.ts +6 -0
  67. package/templates/base-ts/src/shared/libs/cn.ts +6 -0
  68. package/templates/base-ts/src/shared/libs/index.ts +2 -0
  69. package/templates/base-ts/src/shared/theme/index.ts +1 -0
  70. package/templates/base-ts/src/shared/theme/theme.ts +2149 -0
  71. package/templates/base-ts/src/shared/types/navigation.ts +9 -0
  72. package/templates/base-ts/src/shared/types/ui.ts +5 -0
  73. package/templates/base-ts/src/shared/ui/Box.tsx +153 -0
  74. package/templates/base-ts/src/shared/ui/Button.tsx +124 -0
  75. package/templates/base-ts/src/shared/ui/Checkbox.tsx +87 -0
  76. package/templates/base-ts/src/shared/ui/DropdownMenu.tsx +134 -0
  77. package/templates/base-ts/src/shared/ui/Flex.tsx +96 -0
  78. package/templates/base-ts/src/shared/ui/FlexItem.tsx +67 -0
  79. package/templates/base-ts/src/shared/ui/FormField.tsx +139 -0
  80. package/templates/base-ts/src/shared/ui/Grid.tsx +96 -0
  81. package/templates/base-ts/src/shared/ui/GridItem.tsx +67 -0
  82. package/templates/base-ts/src/shared/ui/Modal.tsx +42 -0
  83. package/templates/base-ts/src/shared/ui/Scrollable.tsx +48 -0
  84. package/templates/base-ts/src/shared/ui/Select.tsx +212 -0
  85. package/templates/base-ts/src/shared/ui/Sheet.tsx +126 -0
  86. package/templates/base-ts/src/shared/ui/Text.tsx +99 -0
  87. package/templates/base-ts/src/shared/ui/Toaster.tsx +31 -0
  88. package/templates/base-ts/src/shared/ui/index.ts +20 -0
  89. package/templates/base-ts/src/shared/utils/getClassName.ts +8 -0
  90. package/templates/base-ts/src/shared/utils/index.ts +4 -0
  91. package/templates/base-ts/src/shared/utils/localStorage.ts +18 -0
  92. package/templates/base-ts/src/shared/utils/memo.ts +9 -0
  93. package/templates/base-ts/src/shared/utils/motion.ts +0 -0
  94. package/templates/base-ts/src/shared/utils/parser.ts +41 -0
  95. package/templates/base-ts/src/shared/utils/regix.ts +3 -0
  96. package/templates/base-ts/src/shared/utils/tryCatch.ts +16 -0
  97. package/templates/base-ts/src/vite-env.d.ts +1 -0
  98. package/templates/base-ts/tsconfig.json +33 -0
  99. package/templates/base-ts/tsconfig.node.json +11 -0
  100. package/templates/base-ts/tsconfig.tsbuildinfo +1 -0
  101. package/templates/base-ts/vercel.json +3 -0
  102. package/templates/base-ts/vite.config.d.ts +2 -0
  103. package/templates/base-ts/vite.config.ts +18 -0
  104. /package/templates/{base → base-js}/.husky/pre-commit +0 -0
  105. /package/templates/{base → base-js}/.husky/pre-push +0 -0
  106. /package/templates/{base → base-js}/.prettierrc +0 -0
  107. /package/templates/{base → base-js}/.vscode/extensions.json +0 -0
  108. /package/templates/{base → base-js}/.vscode/settings.json +0 -0
  109. /package/templates/{base → base-js}/README.md +0 -0
  110. /package/templates/{base → base-js}/docs/DOCS.md +0 -0
  111. /package/templates/{base → base-js}/eslint.config.js +0 -0
  112. /package/templates/{base → base-js}/index.html +0 -0
  113. /package/templates/{base → base-js}/jsconfig.json +0 -0
  114. /package/templates/{base → base-js}/package.json +0 -0
  115. /package/templates/{base → base-js}/postcss.config.mjs +0 -0
  116. /package/templates/{base → base-js}/public/icons/react.svg +0 -0
  117. /package/templates/{base → base-js}/src/app/APP.md +0 -0
  118. /package/templates/{base → base-js}/src/app/App.jsx +0 -0
  119. /package/templates/{base → base-js}/src/app/Router.jsx +0 -0
  120. /package/templates/{base → base-js}/src/app/index.css +0 -0
  121. /package/templates/{base → base-js}/src/app/main.jsx +0 -0
  122. /package/templates/{base → base-js}/src/app/middlewares/AuthMiddleware.jsx +0 -0
  123. /package/templates/{base → base-js}/src/app/middlewares/index.js +0 -0
  124. /package/templates/{base → base-js}/src/app/providers/QueryProvider.jsx +0 -0
  125. /package/templates/{base → base-js}/src/app/providers/index.js +0 -0
  126. /package/templates/{base → base-js}/src/app/routes.registry.js +0 -0
  127. /package/templates/{base → base-js}/src/features/FEATURES.md +0 -0
  128. /package/templates/{base → base-js}/src/features/sample/components/index.js +0 -0
  129. /package/templates/{base → base-js}/src/features/sample/constants/index.js +0 -0
  130. /package/templates/{base → base-js}/src/features/sample/constants/sample.assets.js +0 -0
  131. /package/templates/{base → base-js}/src/features/sample/constants/sample.constants.js +0 -0
  132. /package/templates/{base → base-js}/src/features/sample/constants/sample.navigations.js +0 -0
  133. /package/templates/{base → base-js}/src/features/sample/constants/sample.queryKeys.js +0 -0
  134. /package/templates/{base → base-js}/src/features/sample/hooks/index.js +0 -0
  135. /package/templates/{base → base-js}/src/features/sample/index.js +0 -0
  136. /package/templates/{base → base-js}/src/features/sample/pages/SamplePage.jsx +0 -0
  137. /package/templates/{base → base-js}/src/features/sample/pages/index.js +0 -0
  138. /package/templates/{base → base-js}/src/features/sample/sample.context.js +0 -0
  139. /package/templates/{base → base-js}/src/features/sample/sample.routes.js +0 -0
  140. /package/templates/{base → base-js}/src/features/welcome/components/CodeLine.jsx +0 -0
  141. /package/templates/{base → base-js}/src/features/welcome/components/Divider.jsx +0 -0
  142. /package/templates/{base → base-js}/src/features/welcome/components/Footer.jsx +0 -0
  143. /package/templates/{base → base-js}/src/features/welcome/components/Hero.jsx +0 -0
  144. /package/templates/{base → base-js}/src/features/welcome/components/IconLink.jsx +0 -0
  145. /package/templates/{base → base-js}/src/features/welcome/components/QuickStartPanel.jsx +0 -0
  146. /package/templates/{base → base-js}/src/features/welcome/components/RingSoft.jsx +0 -0
  147. /package/templates/{base → base-js}/src/features/welcome/components/StorySections.jsx +0 -0
  148. /package/templates/{base → base-js}/src/features/welcome/components/WhatYouGet.jsx +0 -0
  149. /package/templates/{base → base-js}/src/features/welcome/components/index.js +0 -0
  150. /package/templates/{base → base-js}/src/features/welcome/constants/index.js +0 -0
  151. /package/templates/{base → base-js}/src/features/welcome/constants/welcome.constants.js +0 -0
  152. /package/templates/{base → base-js}/src/features/welcome/constants/welcome.navigations.js +0 -0
  153. /package/templates/{base → base-js}/src/features/welcome/index.js +0 -0
  154. /package/templates/{base → base-js}/src/features/welcome/pages/WelcomePage.jsx +0 -0
  155. /package/templates/{base → base-js}/src/features/welcome/pages/index.js +0 -0
  156. /package/templates/{base → base-js}/src/features/welcome/welcome.routes.js +0 -0
  157. /package/templates/{base → base-js}/src/shared/SHARED.md +0 -0
  158. /package/templates/{base → base-js}/src/shared/constants/app.constants.js +0 -0
  159. /package/templates/{base → base-js}/src/shared/constants/assets.constants.js +0 -0
  160. /package/templates/{base → base-js}/src/shared/constants/index.js +0 -0
  161. /package/templates/{base → base-js}/src/shared/contexts/index.js +0 -0
  162. /package/templates/{base → base-js}/src/shared/hooks/index.js +0 -0
  163. /package/templates/{base → base-js}/src/shared/hooks/useBooleanState.js +0 -0
  164. /package/templates/{base → base-js}/src/shared/hooks/useDebounce.js +0 -0
  165. /package/templates/{base → base-js}/src/shared/hooks/useToggleState.js +0 -0
  166. /package/templates/{base → base-js}/src/shared/layouts/index.js +0 -0
  167. /package/templates/{base → base-js}/src/shared/libs/axios.js +0 -0
  168. /package/templates/{base → base-js}/src/shared/libs/cn.js +0 -0
  169. /package/templates/{base → base-js}/src/shared/libs/index.js +0 -0
  170. /package/templates/{base → base-js}/src/shared/theme/index.js +0 -0
  171. /package/templates/{base → base-js}/src/shared/theme/theme.js +0 -0
  172. /package/templates/{base → base-js}/src/shared/ui/Box.jsx +0 -0
  173. /package/templates/{base → base-js}/src/shared/ui/Button.jsx +0 -0
  174. /package/templates/{base → base-js}/src/shared/ui/Checkbox.jsx +0 -0
  175. /package/templates/{base → base-js}/src/shared/ui/DropdownMenu.jsx +0 -0
  176. /package/templates/{base → base-js}/src/shared/ui/Flex.jsx +0 -0
  177. /package/templates/{base → base-js}/src/shared/ui/FlexItem.jsx +0 -0
  178. /package/templates/{base → base-js}/src/shared/ui/FormField.jsx +0 -0
  179. /package/templates/{base → base-js}/src/shared/ui/Grid.jsx +0 -0
  180. /package/templates/{base → base-js}/src/shared/ui/GridItem.jsx +0 -0
  181. /package/templates/{base → base-js}/src/shared/ui/Modal.jsx +0 -0
  182. /package/templates/{base → base-js}/src/shared/ui/Scrollable.jsx +0 -0
  183. /package/templates/{base → base-js}/src/shared/ui/Select.jsx +0 -0
  184. /package/templates/{base → base-js}/src/shared/ui/Sheet.jsx +0 -0
  185. /package/templates/{base → base-js}/src/shared/ui/Text.jsx +0 -0
  186. /package/templates/{base → base-js}/src/shared/ui/Toaster.jsx +0 -0
  187. /package/templates/{base → base-js}/src/shared/ui/index.js +0 -0
  188. /package/templates/{base → base-js}/src/shared/utils/getClassName.js +0 -0
  189. /package/templates/{base → base-js}/src/shared/utils/index.js +0 -0
  190. /package/templates/{base → base-js}/src/shared/utils/localStorage.js +0 -0
  191. /package/templates/{base → base-js}/src/shared/utils/memo.js +0 -0
  192. /package/templates/{base → base-js}/src/shared/utils/motion.js +0 -0
  193. /package/templates/{base → base-js}/src/shared/utils/regix.js +0 -0
  194. /package/templates/{base → base-js}/src/shared/utils/tryCatch.js +0 -0
  195. /package/templates/{base → base-js}/vercel.json +0 -0
  196. /package/templates/{base → base-js}/vite.config.js +0 -0
package/bin/index.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
 
3
3
  import prompts from 'prompts';
4
4
  import { createProject } from '../scripts/createProject.js';
@@ -11,24 +11,34 @@ async function init() {
11
11
  message: 'What is your project name?',
12
12
  validate: (value) => (value ? true : 'Project name is required'),
13
13
  },
14
+ {
15
+ type: 'select',
16
+ name: 'language',
17
+ message: 'Choose a language:',
18
+ choices: [
19
+ { title: 'JavaScript', value: 'javascript' },
20
+ { title: 'TypeScript', value: 'typescript' },
21
+ ],
22
+ initial: 0,
23
+ },
14
24
  {
15
25
  type: 'toggle',
16
26
  name: 'installDeps',
17
27
  message: 'Do you want to install dependencies now?',
18
28
  initial: true,
19
- active: 'yes',
20
- inactive: 'no',
29
+ active: 'Yes',
30
+ inactive: 'No',
21
31
  },
22
32
  ]);
23
33
 
24
- const { projectName, installDeps } = responses;
34
+ const { projectName, installDeps, language } = responses;
25
35
 
26
36
  if (!projectName) {
27
37
  console.log('❌ Project creation cancelled');
28
38
  process.exit(1);
29
39
  }
30
40
 
31
- await createProject(projectName, { installDeps });
41
+ await createProject(projectName, { installDeps, language });
32
42
  }
33
43
 
34
44
  init();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-react-scaffold-cli",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "main": "index.js",
5
5
  "scripts": {
6
6
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -7,12 +7,18 @@ const __filename = fileURLToPath(import.meta.url);
7
7
  const __dirname = path.dirname(__filename);
8
8
 
9
9
  export async function createProject(name, options) {
10
- const { installDeps } = options;
10
+ const { installDeps, language = 'javascript' } = options;
11
11
 
12
12
  const targetDir = path.resolve(process.cwd(), name);
13
- const templateDir = path.resolve(__dirname, '../templates/base');
13
+
14
+ const templateFolder = language === 'typescript' ? 'base-ts' : 'base-js';
15
+
16
+ const templateDir = path.resolve(__dirname, `../templates/${templateFolder}`);
14
17
 
15
18
  console.log(`📁 Creating project: ${name}`);
19
+ console.log(
20
+ `🧩 Template: ${language === 'typescript' ? 'TypeScript' : 'JavaScript'}`,
21
+ );
16
22
 
17
23
  await fs.copy(templateDir, targetDir);
18
24
 
@@ -21,7 +21,7 @@ export const parseNumberForValidator = (value) => {
21
21
  if (isNullish) return fallback;
22
22
  const isValid = typeof value === 'number';
23
23
  if (!isValid) return fallback;
24
- return fallback;
24
+ return value;
25
25
  };
26
26
 
27
27
  export const parseJSON = (value) => {
@@ -0,0 +1 @@
1
+ npx lint-staged
@@ -0,0 +1,8 @@
1
+ {
2
+ "singleQuote": true,
3
+ "semi": true,
4
+ "trailingComma": "es5",
5
+ "printWidth": 100,
6
+ "tabWidth": 2,
7
+ "plugins": ["prettier-plugin-jsdoc"]
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "recommendations": [
3
+ "dbaeumer.vscode-eslint",
4
+ "esbenp.prettier-vscode",
5
+ "bradlc.vscode-tailwindcss",
6
+ "dsznajder.es7-react-js-snippets"
7
+ ]
8
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "typescript.updateImportsOnFileMove.enabled": "always",
3
+ "javascript.updateImportsOnFileMove.enabled": "always",
4
+ "editor.formatOnPaste": true,
5
+ "editor.formatOnSave": true,
6
+ "editor.cursorSmoothCaretAnimation": "on",
7
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
8
+ "editor.codeActionsOnSave": {
9
+ "source.fixAll.eslint": "explicit"
10
+ },
11
+ "cSpell.words": ["premiumlogo"],
12
+ "[javascriptreact]": {
13
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
14
+ },
15
+ "liveServer.settings.port": 5501
16
+ }
@@ -0,0 +1,165 @@
1
+ # React Feature‑First Scaffold
2
+
3
+ ## Purpose
4
+
5
+ This repository is an **opinionated React scaffold** designed for large-scale frontend applications. It enforces a **feature‑first architecture**, clear ownership boundaries, and predictable patterns so teams can scale safely without architectural drift.
6
+
7
+ This scaffold will later be distributed via an internal **NPM CLI** (similar to `create-react-app`) to bootstrap projects with best practices preconfigured.
8
+
9
+ ---
10
+
11
+ ## Core Principles
12
+
13
+ - **Feature-first, not layer-first**
14
+ - **Explicit boundaries** between app / features / shared
15
+ - **Locality of logic** (keep things close to where they are used)
16
+ - **Predictable imports** and naming conventions
17
+ - **Low cognitive load** for new developers
18
+
19
+ ---
20
+
21
+ ## Tech Stack
22
+
23
+ ### Runtime
24
+
25
+ - **React 19** – UI layer
26
+ - **Vite** – fast dev & build tooling
27
+
28
+ ### Styling
29
+
30
+ - **Tailwind CSS** – utility-first styling
31
+ - **tailwind-merge** – class conflict resolution
32
+ - **clsx** – conditional class composition
33
+
34
+ ### Data & State
35
+
36
+ - **@tanstack/react-query** – server-state management
37
+ - **Axios** – HTTP client
38
+
39
+ ### UI Utilities
40
+
41
+ - **Radix UI** – accessible headless components
42
+ - **react-hot-toast** – notifications
43
+ - **react-icons** – icon system
44
+
45
+ ### Code Quality
46
+
47
+ - **ESLint** – linting with strict rules
48
+ - **Prettier** – formatting
49
+ - **Husky + lint-staged** – pre-commit enforcement
50
+
51
+ ---
52
+
53
+ ## High-Level Folder Structure
54
+
55
+ ```txt
56
+ src/
57
+ app/ # Application bootstrap & global wiring
58
+ features/ # Business features (isolated, self-contained)
59
+ shared/ # Cross-feature reusable modules
60
+ ```
61
+
62
+ Each top-level folder has **its own README** explaining rules and responsibilities.
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ > CLI installation instructions.
69
+
70
+ ```bash
71
+ npx create-react-scaffold-cli
72
+
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Documentation Index
78
+
79
+ - `src/app/README.md` – Application bootstrap & providers
80
+ - `src/features/README.md` – Feature architecture rules
81
+ - `src/shared/README.md` – Shared modules & reuse policy
82
+
83
+ ---
84
+
85
+ ## Set Up
86
+
87
+ ### Install dependencies
88
+
89
+ ```bash
90
+ npm i
91
+ ```
92
+
93
+ ### Run application
94
+
95
+ ---
96
+
97
+ ```
98
+ npm run dev
99
+ ```
100
+
101
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
102
+
103
+ ### Lint application
104
+
105
+ ```
106
+ npm run lint
107
+ ```
108
+
109
+ ### Prettify code
110
+
111
+ ```
112
+ npm run prettier
113
+ ```
114
+
115
+ ### Build application
116
+
117
+ ```
118
+ npm run build
119
+ ```
120
+
121
+ ### Preview application
122
+
123
+ ```
124
+ npm run preview
125
+ ```
126
+
127
+ Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
128
+
129
+ # Learning Resources
130
+
131
+ ## Tailwind CSS
132
+
133
+ To learn more about `Tailwind CSS`, take a look at the following resources:
134
+
135
+ - [Tailwind ](https://tailwindcss.com) - Tailwind documentation and related resources.
136
+
137
+ ## Framer Motion
138
+
139
+ To learn more about `Framer Motion`, take a look at the following resources:
140
+
141
+ - [Framer Motion](https://www.framer.com/motion) - Framer Motion documentation and related resources.
142
+
143
+ ## React Query
144
+
145
+ To learn more about `TanStack Query`, take a look at the following resources:
146
+
147
+ - [TanStack Query](https://tanstack.com/query/latest) - React Query documentation and related resources.
148
+
149
+ ## Nuqs
150
+
151
+ To learn more about `Nuqs`, take a look at the following resources:
152
+
153
+ - [Nuqs](https://nuqs.dev/) - React Query documentation and related resources.
154
+
155
+ ## Philosophy
156
+
157
+ > **Architecture is a product feature.**
158
+
159
+ This scaffold exists to reduce decision fatigue, prevent architectural erosion, and help teams move faster with confidence.
160
+
161
+ ---
162
+
163
+ ## Ownership
164
+
165
+ This scaffold is maintained internally and should be treated as a **living standard**. Changes must be intentional, documented, and agreed upon by the frontend team.
@@ -0,0 +1,7 @@
1
+ # Scaffold Guides
2
+
3
+ ## Codebase Modules (source of truth)
4
+
5
+ - [app](../src/app/app.readme.md)
6
+ - [shared](../src/shared/shared.readme.md)
7
+ - [features](../src/features/features.readme.md)
@@ -0,0 +1,56 @@
1
+ import js from '@eslint/js';
2
+ import react from 'eslint-plugin-react';
3
+ import reactHooks from 'eslint-plugin-react-hooks';
4
+ import reactRefresh from 'eslint-plugin-react-refresh';
5
+ import globals from 'globals';
6
+ import tseslint from 'typescript-eslint';
7
+
8
+ export default tseslint.config(
9
+ { ignores: ['dist'] },
10
+ {
11
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
12
+ files: ['**/*.{ts,tsx}'],
13
+ languageOptions: {
14
+ ecmaVersion: 2020,
15
+ globals: globals.browser,
16
+ },
17
+ plugins: {
18
+ react,
19
+ 'react-hooks': reactHooks,
20
+ 'react-refresh': reactRefresh,
21
+ },
22
+ rules: {
23
+ ...reactHooks.configs.recommended.rules,
24
+ 'react-refresh/only-export-components': [
25
+ 'warn',
26
+ { allowConstantExport: true },
27
+ ],
28
+ 'no-console': 'error',
29
+ 'prefer-const': 'error',
30
+ 'no-duplicate-imports': 'error',
31
+ '@typescript-eslint/no-explicit-any': 'warn',
32
+ '@typescript-eslint/no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
33
+ },
34
+ },
35
+ {
36
+ files: ['**/*.{js,jsx}'],
37
+ languageOptions: {
38
+ ecmaVersion: 2020,
39
+ globals: globals.browser,
40
+ parserOptions: {
41
+ ecmaFeatures: { jsx: true },
42
+ },
43
+ sourceType: 'module',
44
+ },
45
+ plugins: {
46
+ react,
47
+ 'react-hooks': reactHooks,
48
+ 'react-refresh': reactRefresh,
49
+ },
50
+ rules: {
51
+ ...reactHooks.configs.recommended.rules,
52
+ 'react/jsx-uses-react': 'off',
53
+ 'react/react-in-jsx-scope': 'off',
54
+ },
55
+ }
56
+ );
@@ -0,0 +1,16 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <link rel="icon" type="image/svg+xml" href="/public/icons/react.svg" />
6
+ <meta
7
+ name="viewport"
8
+ content="width=device-width, initial-scale=1, viewport-fit=cover, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"
9
+ />
10
+ <title>React Scaffold App</title>
11
+ </head>
12
+ <body>
13
+ <div id="root"></div>
14
+ <script type="module" src="/src/app/main.tsx"></script>
15
+ </body>
16
+ </html>
@@ -0,0 +1,7 @@
1
+ {
2
+ "compilerOptions": {
3
+ "paths": {
4
+ "@/*": ["./src/*"]
5
+ }
6
+ }
7
+ }
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "vite-project",
3
+ "private": true,
4
+ "version": "0.0.0",
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vite",
8
+ "build": "tsc -b && vite build",
9
+ "lint": "eslint .",
10
+ "preview": "vite preview",
11
+ "prepare": "husky"
12
+ },
13
+ "lint-staged": {
14
+ "src/**/*.{js,jsx}": [
15
+ "eslint --fix",
16
+ "prettier --write"
17
+ ],
18
+ "src/**/*.css": [
19
+ "prettier --write"
20
+ ],
21
+ "package.json": [
22
+ "prettier --write"
23
+ ]
24
+ },
25
+ "dependencies": {
26
+ "@radix-ui/react-dialog": "^1.1.15",
27
+ "@radix-ui/react-dropdown-menu": "^2.1.16",
28
+ "@radix-ui/react-scroll-area": "^1.2.10",
29
+ "@radix-ui/react-select": "^2.2.6",
30
+ "@tailwindcss/postcss": "^4.1.18",
31
+ "@tanstack/react-query": "^5.90.16",
32
+ "@tanstack/react-query-devtools": "^5.91.2",
33
+ "axios": "^1.13.2",
34
+ "clsx": "^2.1.1",
35
+ "framer-motion": "^12.26.2",
36
+ "nuqs": "^2.8.6",
37
+ "postcss": "^8.5.6",
38
+ "react": "^19.2.0",
39
+ "react-dom": "^19.2.0",
40
+ "react-hot-toast": "^2.6.0",
41
+ "react-icons": "^5.5.0",
42
+ "react-router-dom": "^7.12.0",
43
+ "tailwind-merge": "^3.4.0",
44
+ "tailwindcss": "^4.1.18"
45
+ },
46
+ "devDependencies": {
47
+ "@eslint/js": "^9.39.2",
48
+ "@types/node": "^25.2.3",
49
+ "@types/react": "^19.2.14",
50
+ "@types/react-dom": "^19.2.3",
51
+ "@typescript-eslint/eslint-plugin": "^8.51.0",
52
+ "@typescript-eslint/parser": "^8.51.0",
53
+ "@vitejs/plugin-react": "^5.1.4",
54
+ "eslint": "^9.39.2",
55
+ "eslint-config-prettier": "^10.1.8",
56
+ "eslint-plugin-react": "^7.37.5",
57
+ "eslint-plugin-react-hooks": "^7.0.1",
58
+ "eslint-plugin-react-refresh": "^0.4.26",
59
+ "eslint-plugin-unused-imports": "^4.3.0",
60
+ "globals": "^16.5.0",
61
+ "husky": "^9.1.7",
62
+ "lint-staged": "^16.2.7",
63
+ "prettier": "3.7.4",
64
+ "prettier-plugin-jsdoc": "^1.8.0",
65
+ "typescript": "^5.9.3",
66
+ "typescript-eslint": "^8.55.0",
67
+ "vite": "^7.2.4"
68
+ }
69
+ }
@@ -0,0 +1,7 @@
1
+ const config = {
2
+ plugins: {
3
+ "@tailwindcss/postcss": {},
4
+ },
5
+ };
6
+
7
+ export default config;
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 32 32"><g transform="matrix(.05696 0 0 .05696 .647744 2.43826)" fill="none" fill-rule="evenodd"><circle r="50.167" cy="237.628" cx="269.529" fill="#00d8ff"/><g stroke="#00d8ff" stroke-width="24"><path d="M269.53 135.628c67.356 0 129.928 9.665 177.107 25.907 56.844 19.57 91.794 49.233 91.794 76.093 0 27.99-37.04 59.503-98.083 79.728-46.15 15.29-106.88 23.272-170.818 23.272-65.554 0-127.63-7.492-174.3-23.44-59.046-20.182-94.61-52.103-94.61-79.56 0-26.642 33.37-56.076 89.415-75.616 47.355-16.51 111.472-26.384 179.486-26.384z"/><path d="M180.736 186.922c33.65-58.348 73.28-107.724 110.92-140.48C337.006 6.976 380.163-8.48 403.43 4.937c24.248 13.983 33.042 61.814 20.067 124.796-9.8 47.618-33.234 104.212-65.176 159.6-32.75 56.788-70.25 106.82-107.377 139.272-46.98 41.068-92.4 55.93-116.185 42.213-23.08-13.3-31.906-56.92-20.834-115.233 9.355-49.27 32.832-109.745 66.8-168.664z"/><path d="M180.82 289.482C147.075 231.2 124.1 172.195 114.51 123.227c-11.544-59-3.382-104.11 19.864-117.566 24.224-14.024 70.055 2.244 118.14 44.94 36.356 32.28 73.688 80.837 105.723 136.173 32.844 56.733 57.46 114.21 67.036 162.582 12.117 61.213 2.31 107.984-21.453 121.74-23.057 13.348-65.25-.784-110.24-39.5-38.013-32.71-78.682-83.253-112.76-142.115z"/></g></g></svg>
@@ -0,0 +1,74 @@
1
+ # App Module
2
+
3
+ ## Purpose
4
+ The `app` layer is responsible for **bootstrapping the application**. It wires together global providers, routing, and application-level configuration.
5
+
6
+ This folder should remain **small, boring, and stable**.
7
+
8
+ > If something changes frequently, it probably does NOT belong here.
9
+
10
+ ---
11
+
12
+ ## Responsibilities
13
+
14
+ The `app` module may contain:
15
+
16
+ - Application entry point (`main.jsx`)
17
+ - Root component (`App.jsx`)
18
+ - Global providers (React Query, Theme, etc.)
19
+ - Application router
20
+ - Global middlewares
21
+ - One-time initialization logic
22
+
23
+ ---
24
+
25
+ ## Folder Structure
26
+
27
+ ```txt
28
+ app/
29
+ middlewares/ # Global middlewares (logging, guards, etc.)
30
+ providers/ # Global providers (QueryProvider, ThemeProvider)
31
+ App.jsx # Root component
32
+ Router.jsx # App-level router
33
+ main.jsx # Application entry
34
+ index.css # Global styles
35
+ ```
36
+
37
+ ---
38
+
39
+ ## Rules
40
+
41
+ ### ✅ Allowed
42
+ - Global providers
43
+ - App-wide configuration
44
+ - Router composition
45
+
46
+ ### ❌ Not Allowed
47
+ - Feature-specific logic
48
+ - Business rules
49
+ - UI components
50
+ - API calls
51
+ - Feature contexts
52
+
53
+ ---
54
+
55
+ ## Import Rules
56
+
57
+ ```js
58
+ // ✅ Allowed
59
+ import { QueryProvider } from './providers';
60
+ import { AppRouter } from './Router';
61
+
62
+ // ❌ Not Allowed
63
+ import { LoginForm } from '@/features/auth/components';
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Philosophy
69
+
70
+ The `app` layer is a **composition root**, not a feature owner.
71
+
72
+ Keep it minimal.
73
+ Keep it predictable.
74
+
@@ -0,0 +1,15 @@
1
+ import { Scrollable, Toaster } from '@/shared/ui';
2
+ import { QueryProvider } from './providers';
3
+ import { Router } from './Router';
4
+ import { memo } from '@/shared/utils';
5
+
6
+ export const App = memo(() => {
7
+ return (
8
+ <QueryProvider>
9
+ <Scrollable>
10
+ <Router />
11
+ </Scrollable>
12
+ <Toaster />
13
+ </QueryProvider>
14
+ );
15
+ });
@@ -0,0 +1,48 @@
1
+ import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
2
+ import { featureRoutes } from './routes.registry';
3
+ import { AuthMiddleware } from './middlewares';
4
+ import { Layouts } from '@/shared/constants';
5
+ import { memo } from '@/shared/utils';
6
+ import { ComponentType, ReactNode } from 'react';
7
+
8
+ const layoutMap: Record<string, ComponentType<{ children: ReactNode }> | null> = {
9
+ dashboard: null, // Placeholder, should be DashboardLayout
10
+ none: ({ children }) => <>{children}</>,
11
+ };
12
+
13
+ export const Router = memo(() => {
14
+ return (
15
+ <BrowserRouter>
16
+ <Routes>
17
+ {featureRoutes.map((route, index) => {
18
+ const Layout = layoutMap[route.layout ?? Layouts.None];
19
+ const Page = route.element as ComponentType;
20
+
21
+ if (!Layout) {
22
+ return <Route key={index} path={route.path} element={<Page />} />;
23
+ }
24
+
25
+ let element = (
26
+ <Layout>
27
+ <Page />
28
+ </Layout>
29
+ );
30
+
31
+ if (route.protected) {
32
+ element = (
33
+ <AuthMiddleware>
34
+ <Layout>
35
+ <Page />
36
+ </Layout>
37
+ </AuthMiddleware>
38
+ );
39
+ }
40
+
41
+ return <Route key={index} path={route.path} element={element} />;
42
+ })}
43
+
44
+ <Route path="/*" element={<Navigate to="/welcome" replace />} />
45
+ </Routes>
46
+ </BrowserRouter>
47
+ );
48
+ });
@@ -0,0 +1,37 @@
1
+ @import 'tailwindcss';
2
+ @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:ital,wght@0,200..800;1,200..800&display=swap');
3
+ @import url('https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&display=swap');
4
+
5
+ @theme {
6
+ /* Colors */
7
+ --color-primary: #3452ff;
8
+ --color-primary-foreground: #ffffff;
9
+ --color-badge: #fef1a7;
10
+
11
+ --color-bg: #ffffff;
12
+ --color-surface: #f7f7f7;
13
+
14
+ --color-ink: #03003e;
15
+ --color-muted: #797979;
16
+
17
+ --color-ring: color-mix(in oklab, var(--color-primary) 35%, transparent);
18
+ --color-border: color-mix(in oklab, var(--color-ink) 10%, transparent);
19
+ --color-soft: color-mix(in oklab, var(--color-primary) 10%, transparent);
20
+
21
+ /* Fonts */
22
+ --font-plus-jakarta-sans:
23
+ 'Plus Jakarta Sans', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
24
+ --font-inter: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Arial, sans-serif;
25
+ }
26
+
27
+ :root {
28
+ color: var(--color-ink);
29
+ background: var(--color-bg);
30
+ text-rendering: optimizeLegibility;
31
+ -webkit-font-smoothing: antialiased;
32
+ -moz-osx-font-smoothing: grayscale;
33
+ }
34
+
35
+ body {
36
+ font-family: var(--font-inter);
37
+ }
@@ -0,0 +1,13 @@
1
+ import { StrictMode } from 'react';
2
+ import { createRoot } from 'react-dom/client';
3
+ import './index.css';
4
+ import { App } from './App';
5
+
6
+ const rootElement = document.getElementById('root');
7
+ if (rootElement) {
8
+ createRoot(rootElement).render(
9
+ <StrictMode>
10
+ <App />
11
+ </StrictMode>
12
+ );
13
+ }
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ import { memo } from '@/shared/utils';
3
+
4
+ export const AuthMiddleware = memo(({ children }: { children: ReactNode }) => {
5
+ return <>{children}</>;
6
+ });
@@ -0,0 +1 @@
1
+ export { AuthMiddleware } from './AuthMiddleware';