create-react-scaffold-cli 1.0.6 → 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 +21 -7
  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
@@ -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';
@@ -0,0 +1,75 @@
1
+ import { ReactNode, useState } from 'react';
2
+ import { AxiosError } from 'axios';
3
+ import toast from 'react-hot-toast';
4
+ import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
5
+ import { MutationCache, QueryCache, QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
+
7
+ export const QueryProvider = ({ children }: { children: ReactNode }) => {
8
+ const [queryCache] = useState(
9
+ new QueryCache({
10
+ onError: () => {},
11
+ })
12
+ );
13
+
14
+ const [mutationCache] = useState(
15
+ new MutationCache({
16
+ onError: (error) => {
17
+ const isAxiosError = error instanceof AxiosError;
18
+
19
+ if (!isAxiosError) {
20
+ return toast.error('Something went wrong.');
21
+ }
22
+ if (error.code === AxiosError.ERR_NETWORK) {
23
+ return toast.error('Network Error');
24
+ }
25
+ if (error.status === 500) {
26
+ return toast.error('Network Error');
27
+ }
28
+ const { response } = error;
29
+ if (!response) {
30
+ return toast.error('Something went wrong');
31
+ }
32
+ const { data } = response;
33
+ if (!data) {
34
+ return toast.error('Something went wrong');
35
+ }
36
+ const { message } = data as { message: string | string[] };
37
+ if (!message) {
38
+ return toast.error('Something went wrong');
39
+ }
40
+ const isIterable = Array.isArray(message);
41
+ if (!isIterable) {
42
+ return toast.error(message);
43
+ }
44
+ for (let index = 0; index < message.length; index++) {
45
+ const errorMsg = message[index];
46
+ toast.error(errorMsg);
47
+ }
48
+ },
49
+ })
50
+ );
51
+
52
+ const [client] = useState(
53
+ new QueryClient({
54
+ queryCache: queryCache,
55
+ mutationCache: mutationCache,
56
+ defaultOptions: {
57
+ queries: {
58
+ retry: false,
59
+ refetchOnWindowFocus: false,
60
+ refetchOnReconnect: false,
61
+ },
62
+ mutations: {
63
+ retry: false,
64
+ },
65
+ },
66
+ })
67
+ );
68
+
69
+ return (
70
+ <QueryClientProvider client={client}>
71
+ {children}
72
+ <ReactQueryDevtools />
73
+ </QueryClientProvider>
74
+ );
75
+ };
@@ -0,0 +1 @@
1
+ export { QueryProvider } from './QueryProvider';
@@ -0,0 +1,9 @@
1
+ import { sampleRoutes } from '@/features/sample';
2
+ import { welcomeRoutes } from '@/features/welcome';
3
+ import { AppRoute } from '@/shared/types/navigation';
4
+
5
+ export const featureRoutes: AppRoute[] = [
6
+ ...sampleRoutes,
7
+ ...welcomeRoutes,
8
+ // ...otherFeatureRoutes
9
+ ];
@@ -0,0 +1,102 @@
1
+ # Features Module
2
+
3
+ ## Purpose
4
+
5
+ The `features` folder is the **core of the application**.
6
+
7
+ Each feature represents a **self-contained unit of business functionality** with clear ownership and boundaries.
8
+
9
+ > If a user-facing requirement exists, it belongs to a feature.
10
+
11
+ ---
12
+
13
+ ## Feature-First Architecture
14
+
15
+ Instead of grouping by technical layers (components, hooks, services), we group by **business capability**.
16
+
17
+ This improves:
18
+
19
+ - Scalability
20
+ - Ownership
21
+ - Discoverability
22
+ - Refactor safety
23
+
24
+ ---
25
+
26
+ ## Feature Structure
27
+
28
+ ```txt
29
+ features/<feature-name>/
30
+ assets/ # Feature-specific images/icons
31
+ components/ # Reusable UI within the feature
32
+ constants/ # Feature constants
33
+ hooks/ # Feature-specific hooks
34
+ pages/ # Route-level components
35
+
36
+ <feature>.assets.js
37
+ <feature>.context.js
38
+ <feature>.navigations.js
39
+ <feature>.queryKeys.js
40
+ <feature>.routes.jsx
41
+
42
+ index.js # Public API of the feature
43
+ ```
44
+
45
+ ---
46
+
47
+ ## Rules
48
+
49
+ ### Feature Ownership
50
+
51
+ - A feature **owns its logic, UI, assets, and state**
52
+ - Features should not depend on other features
53
+
54
+ ### Imports
55
+
56
+ ```js
57
+ // ✅ Allowed
58
+ import { Button } from '@/shared/ui';
59
+ import { useAuth } from '@/features/auth';
60
+
61
+ // ❌ Not Allowed
62
+ import { useProfile } from '@/features/profile';
63
+ ```
64
+
65
+ ---
66
+
67
+ ## Constants Policy
68
+
69
+ Feature constants include:
70
+
71
+ - Query keys
72
+ - Navigation definitions
73
+ - Route names
74
+ - Feature-level config
75
+
76
+ > Constants should stay **inside the feature** unless reused across multiple features.
77
+
78
+ ---
79
+
80
+ ## Contexts
81
+
82
+ - Contexts should be **feature-scoped by default**
83
+ - Global contexts require strong justification
84
+
85
+ ---
86
+
87
+ ## Deletion Rule
88
+
89
+ If a feature is removed:
90
+
91
+ - Delete the entire folder
92
+ - No side effects elsewhere
93
+
94
+ If deletion breaks other features, boundaries are violated.
95
+
96
+ ---
97
+
98
+ ## Example Feature
99
+
100
+ `sample/` is a reference feature and can be safely removed.
101
+
102
+ Use it as a blueprint for new features.
@@ -0,0 +1,3 @@
1
+ export { SampleAssets } from './sample.assets';
2
+ export { SampleNavigation, SampleSearchParamsKey } from './sample.navigations';
3
+ export { sampleQueryKey } from './sample.queryKeys';
@@ -0,0 +1,8 @@
1
+ export const SampleAssets = {
2
+ Images: {
3
+ Sample: './assets/images/',
4
+ },
5
+ Icons: {
6
+ Sample: './assets/icons/',
7
+ },
8
+ };
@@ -0,0 +1,5 @@
1
+ export const SampleNavigation = {
2
+ Sample: '/sample',
3
+ } as const;
4
+
5
+ export const SampleSearchParamsKey = {};
@@ -0,0 +1,3 @@
1
+ export const sampleQueryKey = {
2
+ all: ['sample'],
3
+ } as const;
@@ -0,0 +1 @@
1
+ export { sampleRoutes } from './sample.routes';
@@ -0,0 +1,7 @@
1
+ import { memo } from '@/shared/utils';
2
+
3
+ const SamplePage = memo(() => {
4
+ return <div>SamplePage</div>;
5
+ });
6
+
7
+ export default SamplePage;
@@ -0,0 +1 @@
1
+ export { default as SamplePage } from './SamplePage';
@@ -0,0 +1,13 @@
1
+ import { Layouts } from '@/shared/constants';
2
+ import { SamplePage } from './pages';
3
+ import { SampleNavigation } from './constants';
4
+ import { AppRoute } from '@/shared/types/navigation';
5
+
6
+ export const sampleRoutes: AppRoute[] = [
7
+ {
8
+ path: SampleNavigation.Sample,
9
+ element: SamplePage,
10
+ protected: true,
11
+ layout: Layouts.None,
12
+ },
13
+ ];
@@ -0,0 +1,59 @@
1
+ import { memo, useCallback } from 'react';
2
+ import { PiCopySimpleBold, PiCheckBold } from 'react-icons/pi';
3
+ import { Flex } from '@/shared/ui/Flex';
4
+ import { Text } from '@/shared/ui/Text';
5
+ import { useToggleState } from '@/shared/hooks';
6
+ import { Box, FlexItem } from '@/shared/ui';
7
+ import { cn } from '@/shared/libs';
8
+
9
+ interface CodeLineProps {
10
+ value: string;
11
+ isStorySection?: boolean;
12
+ }
13
+
14
+ export const CodeLine = memo(({ value, isStorySection }: CodeLineProps) => {
15
+ const [copied, toggleCopied] = useToggleState();
16
+
17
+ const onCopy = useCallback(async () => {
18
+ try {
19
+ await navigator.clipboard.writeText(value);
20
+ } catch {
21
+ const ta = document.createElement('textarea');
22
+ ta.value = value;
23
+ document.body.appendChild(ta);
24
+ ta.select();
25
+ document.execCommand('copy');
26
+ document.body.removeChild(ta);
27
+ }
28
+ toggleCopied();
29
+ window.setTimeout(() => toggleCopied(), 1200);
30
+ }, [value, toggleCopied]);
31
+
32
+ return (
33
+ <Box
34
+ radius="xl"
35
+ padding={{ x: 4, y: 2 }}
36
+ className={cn('ring-1 ring-border/50', isStorySection ? 'bg-surface' : 'bg-bg/80 ')}
37
+ >
38
+ <Flex gap={3} align="center" justify="between">
39
+ <FlexItem className="min-w-0">
40
+ <Text size="sm" color="ink" truncate>
41
+ {value}
42
+ </Text>
43
+ </FlexItem>
44
+
45
+ <FlexItem>
46
+ <button
47
+ type="button"
48
+ onClick={onCopy}
49
+ className="shrink-0 inline-flex size-9 items-center justify-center rounded-lg bg-black/5 text-ink hover:bg-black/10 transition-colors cursor-pointer"
50
+ aria-label={copied ? 'Copied' : 'Copy command'}
51
+ title={copied ? 'Copied' : 'Copy'}
52
+ >
53
+ {copied ? <PiCheckBold className="size-4" /> : <PiCopySimpleBold className="size-4" />}
54
+ </button>
55
+ </FlexItem>
56
+ </Flex>
57
+ </Box>
58
+ );
59
+ });
@@ -0,0 +1,11 @@
1
+ import { memo } from 'react';
2
+ import { cn } from '@/shared/libs';
3
+ import { Box } from '@/shared/ui';
4
+
5
+ interface DividerProps {
6
+ className?: string;
7
+ }
8
+
9
+ export const Divider = memo(({ className = '' }: DividerProps) => {
10
+ return <Box className={cn('h-px w-full bg-border/70', className)} />;
11
+ });
@@ -0,0 +1,78 @@
1
+ import { memo } from 'react';
2
+ import { Box, Flex, FlexItem, Text } from '@/shared/ui';
3
+ import { Links } from '../constants';
4
+ import { Divider } from './Divider';
5
+
6
+ export const Footer = memo(() => {
7
+ return (
8
+ <Box className="mt-12 pt-8">
9
+ <Divider className="mb-6" />
10
+
11
+ <Flex
12
+ gap={4}
13
+ align={{ md: 'center' }}
14
+ justify={{ md: 'between' }}
15
+ direction={{ base: 'column', md: 'row' }}
16
+ >
17
+ <FlexItem>
18
+ <Text size="sm" color="muted">
19
+ <span className="font-semibold text-ink">React Scaffold</span>
20
+ <>
21
+ <span className="mx-2">•</span>
22
+ Created by{' '}
23
+ <a
24
+ href={Links.CreatorGithub}
25
+ target="_blank"
26
+ rel="noreferrer"
27
+ className="font-semibold text-ink hover:text-primary transition-colors"
28
+ >
29
+ {Links.CreatorName}
30
+ </a>
31
+ </>
32
+ </Text>
33
+ </FlexItem>
34
+
35
+ <FlexItem>
36
+ <Flex gap={5} className="flex-wrap text-sm font-medium">
37
+ <a
38
+ className="text-muted hover:text-primary"
39
+ href={Links.AppGithub}
40
+ target="_blank"
41
+ rel="noreferrer"
42
+ >
43
+ Project Repo
44
+ </a>
45
+ <a
46
+ className="text-muted hover:text-primary"
47
+ href={Links.CliGithub}
48
+ target="_blank"
49
+ rel="noreferrer"
50
+ >
51
+ CLI Repo
52
+ </a>
53
+ <a
54
+ className="text-muted hover:text-primary"
55
+ href={Links.NpmPackage}
56
+ target="_blank"
57
+ rel="noreferrer"
58
+ >
59
+ NPM Package
60
+ </a>
61
+
62
+ <>
63
+ <span className="text-border">|</span>
64
+ <a
65
+ className="text-muted hover:text-primary"
66
+ href={Links.CreatorLinkedIn}
67
+ target="_blank"
68
+ rel="noreferrer"
69
+ >
70
+ Creator
71
+ </a>
72
+ </>
73
+ </Flex>
74
+ </FlexItem>
75
+ </Flex>
76
+ </Box>
77
+ );
78
+ });
@@ -0,0 +1,131 @@
1
+ import { memo } from 'react';
2
+ import { Box, Button, Flex, FlexItem, Grid, Text } from '@/shared/ui';
3
+ import { FaGithub, FaLinkedin, FaNpm } from 'react-icons/fa';
4
+ import { QuickStartPanel } from './QuickStartPanel';
5
+ import { Links } from '../constants';
6
+ import { IconLink } from './IconLink';
7
+
8
+ export const Hero = memo(() => {
9
+ return (
10
+ <Grid
11
+ align="start"
12
+ gap={{ base: 10, md: 12 }}
13
+ className="md:grid-cols-[1.25fr_0.75fr] md:gap-12"
14
+ >
15
+ <Flex gap={5} direction="column">
16
+ <Box padding={{ x: 3, y: 1 }} width="fit" className="rounded-full bg-badge">
17
+ <Flex gap={2} align="center">
18
+ <FlexItem>
19
+ <Box radius="full" className="size-1.5 bg-primary" />
20
+ </FlexItem>
21
+ <FlexItem>
22
+ <Text size="sm" weight="semibold">
23
+ React Scaffold
24
+ </Text>
25
+ </FlexItem>
26
+ </Flex>
27
+ </Box>
28
+
29
+ <Flex gap={2} align="center" className="-mt-2">
30
+ <FlexItem>
31
+ <Text size="sm" color="muted">
32
+ Created by
33
+ </Text>
34
+ </FlexItem>
35
+ <FlexItem>
36
+ <a
37
+ href={Links.CreatorGithub}
38
+ target="_blank"
39
+ rel="noreferrer"
40
+ className="font-semibold text-ink hover:text-primary transition-colors"
41
+ >
42
+ {Links.CreatorName}
43
+ </a>
44
+ </FlexItem>
45
+ </Flex>
46
+
47
+ <FlexItem>
48
+ <Text
49
+ weight="black"
50
+ font="plus-jakarta-sans"
51
+ size={{ base: '4xl', lg: '5xl', '2xl': '6xl' }}
52
+ className="tracking-tight bg-linear-to-r from-ink to-primary bg-clip-text text-transparent"
53
+ >
54
+ Start building with React Scaffold
55
+ </Text>
56
+ </FlexItem>
57
+
58
+ <FlexItem>
59
+ <Text size="base" color="muted" className="max-w-xl text-base leading-relaxed">
60
+ A modern, opinionated starter that keeps your codebase clean as it grows — feature-first
61
+ structure, shared UI primitives, and best-practice tooling out of the box.
62
+ </Text>
63
+ </FlexItem>
64
+
65
+ <FlexItem>
66
+ <Text size="sm" color="muted" className="max-w-xl">
67
+ This is the default starter page. Replace it with your product UI when you’re ready.
68
+ </Text>
69
+ </FlexItem>
70
+
71
+ <FlexItem>
72
+ <Flex gap={3} direction={{ base: 'column', md: 'row' }} className="mt-2">
73
+ <FlexItem>
74
+ <Button
75
+ className="rounded-full"
76
+ onClick={() => window.open(Links.AppGithub, '_blank', 'noopener,noreferrer')}
77
+ >
78
+ Open Project Repo
79
+ </Button>
80
+ </FlexItem>
81
+
82
+ <FlexItem>
83
+ <Button
84
+ variant="outline"
85
+ className="rounded-full"
86
+ onClick={() => window.open(Links.NpmPackage, '_blank', 'noopener,noreferrer')}
87
+ >
88
+ View NPM Package
89
+ </Button>
90
+ </FlexItem>
91
+ </Flex>
92
+ </FlexItem>
93
+
94
+ <FlexItem>
95
+ <Flex gap={2} align="center">
96
+ <FlexItem>
97
+ <IconLink
98
+ href={Links.AppGithub}
99
+ label="App Repo"
100
+ icon={<FaGithub className="size-4" />}
101
+ />
102
+ </FlexItem>
103
+ <FlexItem>
104
+ <IconLink
105
+ href={Links.CliGithub}
106
+ label="CLI Repo"
107
+ icon={<FaGithub className="size-4" />}
108
+ />
109
+ </FlexItem>
110
+ <FlexItem>
111
+ <IconLink href={Links.NpmPackage} label="NPM" icon={<FaNpm className="size-4" />} />
112
+ </FlexItem>
113
+
114
+ <>
115
+ <span className="text-border -mt-1">•</span>
116
+ <FlexItem>
117
+ <IconLink
118
+ href={Links.CreatorLinkedIn}
119
+ label="Creator"
120
+ icon={<FaLinkedin className="size-4" />}
121
+ />
122
+ </FlexItem>
123
+ </>
124
+ </Flex>
125
+ </FlexItem>
126
+ </Flex>
127
+
128
+ <QuickStartPanel />
129
+ </Grid>
130
+ );
131
+ });
@@ -0,0 +1,24 @@
1
+ import { memo, ReactNode } from 'react';
2
+ import { Text } from '@/shared/ui';
3
+
4
+ interface IconLinkProps {
5
+ href: string;
6
+ icon: ReactNode;
7
+ label: string;
8
+ }
9
+
10
+ export const IconLink = memo(({ href, icon, label }: IconLinkProps) => {
11
+ return (
12
+ <a
13
+ href={href}
14
+ target="_blank"
15
+ rel="noreferrer"
16
+ className="inline-flex items-center gap-2 text-muted hover:text-primary transition-colors"
17
+ >
18
+ <span className="text-primary">{icon}</span>
19
+ <Text size="sm" className="leading-none">
20
+ {label}
21
+ </Text>
22
+ </a>
23
+ );
24
+ });
@@ -0,0 +1,63 @@
1
+ import { memo, ReactNode } from 'react';
2
+ import { Box, Flex, FlexItem, Text } from '@/shared/ui';
3
+ import { RingSoft } from './RingSoft';
4
+ import { CodeLine } from './CodeLine';
5
+ import { Commands } from '../constants';
6
+
7
+ function StepLight({ label, children }: { label: string; children: ReactNode }) {
8
+ return (
9
+ <Box>
10
+ <Text className="text-sm font-semibold text-ink">{label}</Text>
11
+ <Box className="mt-2">{children}</Box>
12
+ </Box>
13
+ );
14
+ }
15
+
16
+ export const QuickStartPanel = memo(() => {
17
+ return (
18
+ <Box className="relative overflow-hidden rounded-2xl bg-surface/70 p-6 md:p-7 ring-1 ring-border">
19
+ <Box className="pointer-events-none absolute inset-0 opacity-100">
20
+ <RingSoft className="right-[-7rem] top-[-6rem]" size="22rem" />
21
+ <RingSoft className="right-[-5rem] top-[9rem]" size="14rem" />
22
+ <RingSoft className="right-[-3.5rem] top-[16rem]" size="6rem" />
23
+ </Box>
24
+
25
+ <Box className="relative z-10 space-y-6">
26
+ <Flex gap={1} direction="column">
27
+ <FlexItem>
28
+ <Text
29
+ size="base"
30
+ weight="bold"
31
+ font="plus-jakarta-sans"
32
+ className="tracking-tight bg-linear-to-r from-primary to-ink bg-clip-text text-transparent"
33
+ >
34
+ Quick start
35
+ </Text>
36
+ </FlexItem>
37
+ <FlexItem>
38
+ <Text size="sm" color="muted">
39
+ Create an app in seconds — clean architecture, ready to scale.
40
+ </Text>
41
+ </FlexItem>
42
+ </Flex>
43
+
44
+ <Flex gap={4} direction="column">
45
+ <FlexItem>
46
+ <StepLight label="1) Scaffold">
47
+ <CodeLine value={Commands.Scaffold} />
48
+ </StepLight>
49
+ </FlexItem>
50
+ <FlexItem>
51
+ <StepLight label="2) Run">
52
+ <CodeLine value={Commands.Run} />
53
+ </StepLight>
54
+ </FlexItem>
55
+ </Flex>
56
+
57
+ <Text size="sm" color="muted">
58
+ Tip: add your first feature inside your feature modules and delete this page when ready.
59
+ </Text>
60
+ </Box>
61
+ </Box>
62
+ );
63
+ });
@@ -0,0 +1,21 @@
1
+ import { memo } from 'react';
2
+ import { Box } from '@/shared/ui/Box';
3
+ import { cn } from '@/shared/libs';
4
+
5
+ interface RingSoftProps {
6
+ className?: string;
7
+ size: string | number;
8
+ }
9
+
10
+ export const RingSoft = memo(({ className, size }: RingSoftProps) => {
11
+ return (
12
+ <Box
13
+ className={cn('absolute rounded-full', className)}
14
+ style={{
15
+ width: size,
16
+ height: size,
17
+ border: '1px solid rgba(52, 82, 255, 0.22)',
18
+ }}
19
+ />
20
+ );
21
+ });