create-lumen 1.1.4 → 1.2.0-beta.1

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 (216) hide show
  1. package/README.md +41 -33
  2. package/package.json +1 -1
  3. package/src/configure.js +6 -2
  4. package/src/css.js +71 -24
  5. package/src/injector.js +116 -24
  6. package/src/main.js +3 -1
  7. package/src/readme.js +64 -22
  8. package/templates/architectures/component-based/src/App.jsx +6 -3
  9. package/templates/architectures/component-based/src/App.tsx +6 -3
  10. package/templates/architectures/component-based/src/components/common/Button.jsx +5 -2
  11. package/templates/architectures/component-based/src/components/common/Button.tsx +5 -2
  12. package/templates/architectures/component-based/src/hooks/useApp.js +10 -0
  13. package/templates/architectures/component-based/src/hooks/useApp.ts +10 -0
  14. package/templates/architectures/component-based/src/layouts/MainLayout.jsx +12 -4
  15. package/templates/architectures/component-based/src/layouts/MainLayout.tsx +12 -4
  16. package/templates/architectures/component-based/src/pages/Home/Home.jsx +6 -1
  17. package/templates/architectures/component-based/src/pages/Home/Home.tsx +6 -1
  18. package/templates/architectures/component-based/src/providers/AppProvider.jsx +20 -0
  19. package/templates/architectures/component-based/src/providers/AppProvider.tsx +24 -0
  20. package/templates/architectures/component-based/src/providers/appcontext.js +3 -0
  21. package/templates/architectures/component-based/src/{context/app-context.ts → providers/appcontext.ts} +1 -3
  22. package/templates/architectures/{feature-based → component-based}/src/types/index.js +7 -0
  23. package/templates/architectures/{feature-based → component-based}/src/types/index.ts +5 -0
  24. package/templates/architectures/feature-based/main.jsx +1 -1
  25. package/templates/architectures/feature-based/main.tsx +1 -1
  26. package/templates/architectures/feature-based/scripts/create-feature.mjs +2 -2
  27. package/templates/architectures/feature-based/src/app/App.jsx +15 -4
  28. package/templates/architectures/feature-based/src/app/App.tsx +15 -4
  29. package/templates/architectures/feature-based/src/app/contexts/themecontext.js +3 -0
  30. package/templates/architectures/feature-based/src/app/contexts/themecontext.ts +8 -0
  31. package/templates/architectures/feature-based/src/app/hooks/useTheme.js +10 -0
  32. package/templates/architectures/feature-based/src/app/hooks/useTheme.ts +10 -0
  33. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.jsx +18 -1
  34. package/templates/architectures/feature-based/src/app/providers/ThemeProvider.tsx +19 -2
  35. package/templates/architectures/feature-based/src/features/home/pages/HomePage.jsx +18 -4
  36. package/templates/architectures/feature-based/src/features/home/pages/HomePage.tsx +18 -4
  37. package/templates/architectures/feature-based/src/shared/components/ui/Button.jsx +31 -0
  38. package/templates/architectures/feature-based/src/shared/components/ui/Button.tsx +36 -0
  39. package/templates/architectures/feature-based/src/shared/layouts/.gitkeep +0 -0
  40. package/templates/architectures/feature-based/src/shared/stores/.gitkeep +0 -0
  41. package/templates/architectures/feature-based/src/shared/styles/.gitkeep +0 -0
  42. package/templates/architectures/feature-based/src/shared/types/index.js +20 -0
  43. package/templates/architectures/feature-based/src/shared/types/index.ts +16 -0
  44. package/templates/conditional/axios/component-based/src/config/axios.config.js +7 -0
  45. package/templates/conditional/axios/component-based/src/config/axios.config.ts +7 -0
  46. package/templates/conditional/axios/component-based/src/services/axios.client.js +24 -0
  47. package/templates/conditional/axios/component-based/src/services/axios.client.ts +24 -0
  48. package/templates/conditional/axios/component-based/src/services/user.service.js +33 -0
  49. package/templates/conditional/axios/component-based/src/services/user.service.ts +29 -0
  50. package/templates/conditional/axios/feature-based/src/features/home/services/user.service.js +33 -0
  51. package/templates/conditional/axios/feature-based/src/features/home/services/user.service.ts +29 -0
  52. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.js +24 -0
  53. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.client.ts +24 -0
  54. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.js +7 -0
  55. package/templates/conditional/axios/feature-based/src/shared/lib/axios/api.config.ts +7 -0
  56. package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.js +1 -0
  57. package/templates/conditional/axios/feature-based/src/shared/lib/axios/index.ts +1 -0
  58. package/templates/conditional/fetch/component-based/src/config/api.config.js +7 -0
  59. package/templates/conditional/fetch/component-based/src/config/api.config.ts +7 -0
  60. package/templates/conditional/fetch/component-based/src/services/api.client.js +51 -0
  61. package/templates/conditional/fetch/component-based/src/services/api.client.ts +55 -0
  62. package/templates/conditional/fetch/component-based/src/services/user.service.js +33 -0
  63. package/templates/conditional/fetch/component-based/src/services/user.service.ts +29 -0
  64. package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.js +33 -0
  65. package/templates/conditional/fetch/feature-based/src/features/home/services/user.service.ts +29 -0
  66. package/templates/conditional/fetch/feature-based/src/shared/api/api.client.js +51 -0
  67. package/templates/conditional/fetch/feature-based/src/shared/api/api.client.ts +55 -0
  68. package/templates/conditional/fetch/feature-based/src/shared/api/api.config.js +7 -0
  69. package/templates/conditional/fetch/feature-based/src/shared/api/api.config.ts +7 -0
  70. package/templates/conditional/fetch/feature-based/src/shared/api/index.js +1 -0
  71. package/templates/conditional/fetch/feature-based/src/shared/api/index.ts +1 -0
  72. package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.jsx +20 -0
  73. package/templates/conditional/icons/huge/component-based/bootstrap/src/pages/Home/Home.tsx +20 -0
  74. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.jsx +24 -8
  75. package/templates/conditional/icons/huge/component-based/src/pages/Home/Home.tsx +24 -8
  76. package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.jsx +20 -0
  77. package/templates/conditional/icons/huge/component-based/tailwind/src/pages/Home/Home.tsx +20 -0
  78. package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +20 -0
  79. package/templates/conditional/icons/huge/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +20 -0
  80. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.jsx +25 -9
  81. package/templates/conditional/icons/huge/feature-based/src/features/home/pages/HomePage.tsx +25 -9
  82. package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.jsx +20 -0
  83. package/templates/conditional/icons/huge/feature-based/tailwind/src/features/home/pages/HomePage.tsx +20 -0
  84. package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.jsx +19 -0
  85. package/templates/conditional/icons/lucide/component-based/bootstrap/src/pages/Home/Home.tsx +19 -0
  86. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.jsx +24 -8
  87. package/templates/conditional/icons/lucide/component-based/src/pages/Home/Home.tsx +24 -8
  88. package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.jsx +19 -0
  89. package/templates/conditional/icons/lucide/component-based/tailwind/src/pages/Home/Home.tsx +19 -0
  90. package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.jsx +19 -0
  91. package/templates/conditional/icons/lucide/feature-based/bootstrap/src/features/home/pages/HomePage.tsx +19 -0
  92. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.jsx +25 -9
  93. package/templates/conditional/icons/lucide/feature-based/src/features/home/pages/HomePage.tsx +25 -9
  94. package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.jsx +19 -0
  95. package/templates/conditional/icons/lucide/feature-based/tailwind/src/features/home/pages/HomePage.tsx +19 -0
  96. package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.jsx +17 -0
  97. package/templates/conditional/router/component-based/bootstrap/src/layouts/MainLayout.tsx +17 -0
  98. package/templates/conditional/router/component-based/src/App.jsx +4 -4
  99. package/templates/conditional/router/component-based/src/App.tsx +4 -4
  100. package/templates/conditional/router/component-based/src/layouts/MainLayout.jsx +39 -0
  101. package/templates/conditional/router/component-based/src/layouts/MainLayout.tsx +39 -0
  102. package/templates/conditional/router/component-based/src/router/guards/AuthGuard.jsx +8 -0
  103. package/templates/conditional/router/component-based/src/router/guards/AuthGuard.tsx +14 -0
  104. package/templates/conditional/router/component-based/src/router/guards/GuestGuard.jsx +8 -0
  105. package/templates/conditional/router/component-based/src/router/guards/GuestGuard.tsx +14 -0
  106. package/templates/conditional/router/component-based/src/router/index.jsx +44 -0
  107. package/templates/conditional/router/component-based/src/router/index.tsx +44 -0
  108. package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.jsx +17 -0
  109. package/templates/conditional/router/component-based/tailwind/src/layouts/MainLayout.tsx +17 -0
  110. package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.jsx +9 -0
  111. package/templates/conditional/router/feature-based/bootstrap/src/shared/layouts/RootLayout.tsx +9 -0
  112. package/templates/conditional/router/feature-based/src/app/App.jsx +6 -1
  113. package/templates/conditional/router/feature-based/src/app/App.tsx +6 -1
  114. package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.jsx +8 -0
  115. package/templates/conditional/router/feature-based/src/app/router/guards/AuthGuard.tsx +14 -0
  116. package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.jsx +8 -0
  117. package/templates/conditional/router/feature-based/src/app/router/guards/RoleGuard.tsx +15 -0
  118. package/templates/conditional/router/feature-based/src/app/router/index.jsx +16 -0
  119. package/templates/conditional/router/feature-based/src/app/router/index.tsx +16 -0
  120. package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.jsx +18 -0
  121. package/templates/conditional/router/feature-based/src/app/router/routes/auth.routes.tsx +18 -0
  122. package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.jsx +8 -0
  123. package/templates/conditional/router/feature-based/src/app/router/routes/home.routes.tsx +8 -0
  124. package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.jsx +17 -0
  125. package/templates/conditional/router/feature-based/src/shared/layouts/RootLayout.tsx +17 -0
  126. package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.jsx +9 -0
  127. package/templates/conditional/router/feature-based/tailwind/src/shared/layouts/RootLayout.tsx +9 -0
  128. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.jsx +1 -1
  129. package/templates/conditional/state/redux/feature-based/src/app/providers/StoreProvider.tsx +1 -1
  130. package/templates/css/bootstrap/src/themes.css +14 -0
  131. package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.jsx +17 -0
  132. package/templates/css/component-styles/bootstrap/component-based/src/components/common/Button.tsx +22 -0
  133. package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.jsx +15 -0
  134. package/templates/css/component-styles/bootstrap/component-based/src/layouts/MainLayout.tsx +19 -0
  135. package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.jsx +13 -0
  136. package/templates/css/component-styles/bootstrap/component-based/src/pages/Home/Home.tsx +13 -0
  137. package/templates/css/component-styles/bootstrap/feature-based/src/app/App.jsx +9 -0
  138. package/templates/css/component-styles/bootstrap/feature-based/src/app/App.tsx +9 -0
  139. package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.jsx +13 -0
  140. package/templates/css/component-styles/bootstrap/feature-based/src/features/home/pages/HomePage.tsx +13 -0
  141. package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.jsx +17 -0
  142. package/templates/css/component-styles/bootstrap/feature-based/src/shared/components/ui/Button.tsx +22 -0
  143. package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.jsx +1 -1
  144. package/templates/{architectures/feature-based/src/components/ui → css/component-styles/tailwind/component-based/src/components/common}/Button.tsx +1 -1
  145. package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.jsx +15 -0
  146. package/templates/css/component-styles/tailwind/component-based/src/layouts/MainLayout.tsx +19 -0
  147. package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.jsx +13 -0
  148. package/templates/css/component-styles/tailwind/component-based/src/pages/Home/Home.tsx +13 -0
  149. package/templates/css/component-styles/tailwind/feature-based/src/app/App.jsx +9 -0
  150. package/templates/css/component-styles/tailwind/feature-based/src/app/App.tsx +9 -0
  151. package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.jsx +13 -0
  152. package/templates/css/component-styles/tailwind/feature-based/src/features/home/pages/HomePage.tsx +13 -0
  153. package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.jsx +21 -0
  154. package/templates/css/component-styles/tailwind/feature-based/src/shared/components/ui/Button.tsx +26 -0
  155. package/templates/css/none/src/{index.css → main.css} +2 -0
  156. package/templates/css/none/src/themes.css +19 -0
  157. package/templates/css/tailwind/src/themes.css +9 -0
  158. package/templates/architectures/component-based/src/config/constants.js +0 -1
  159. package/templates/architectures/component-based/src/config/constants.ts +0 -1
  160. package/templates/architectures/component-based/src/config/routes.js +0 -7
  161. package/templates/architectures/component-based/src/config/routes.ts +0 -7
  162. package/templates/architectures/component-based/src/context/AppContext.jsx +0 -12
  163. package/templates/architectures/component-based/src/context/AppContext.tsx +0 -18
  164. package/templates/architectures/component-based/src/context/app-context.js +0 -5
  165. package/templates/architectures/component-based/src/hooks/index.js +0 -1
  166. package/templates/architectures/component-based/src/hooks/index.ts +0 -1
  167. package/templates/architectures/component-based/src/layouts/index.js +0 -1
  168. package/templates/architectures/component-based/src/layouts/index.ts +0 -1
  169. package/templates/architectures/component-based/src/styles/globals.css +0 -7
  170. package/templates/architectures/component-based/src/utils/index.js +0 -1
  171. package/templates/architectures/component-based/src/utils/index.ts +0 -1
  172. package/templates/architectures/feature-based/src/config/constants.js +0 -1
  173. package/templates/architectures/feature-based/src/config/constants.ts +0 -1
  174. package/templates/architectures/feature-based/src/hooks/index.js +0 -1
  175. package/templates/architectures/feature-based/src/hooks/index.ts +0 -1
  176. package/templates/architectures/feature-based/src/utils/index.js +0 -1
  177. package/templates/architectures/feature-based/src/utils/index.ts +0 -1
  178. package/templates/conditional/axios/component-based/src/services/axios.jsx +0 -19
  179. package/templates/conditional/axios/component-based/src/services/axios.ts +0 -19
  180. package/templates/conditional/axios/component-based/src/services/index.js +0 -1
  181. package/templates/conditional/axios/component-based/src/services/index.ts +0 -1
  182. package/templates/conditional/axios/feature-based/src/lib/axios.jsx +0 -19
  183. package/templates/conditional/axios/feature-based/src/lib/axios.ts +0 -19
  184. package/templates/conditional/axios/feature-based/src/lib/index.js +0 -1
  185. package/templates/conditional/axios/feature-based/src/lib/index.ts +0 -1
  186. package/templates/conditional/fetch/component-based/src/services/api.jsx +0 -27
  187. package/templates/conditional/fetch/component-based/src/services/api.ts +0 -27
  188. package/templates/conditional/fetch/component-based/src/services/index.js +0 -1
  189. package/templates/conditional/fetch/component-based/src/services/index.ts +0 -1
  190. package/templates/conditional/fetch/feature-based/src/lib/api.jsx +0 -27
  191. package/templates/conditional/fetch/feature-based/src/lib/api.ts +0 -27
  192. package/templates/conditional/fetch/feature-based/src/lib/index.js +0 -1
  193. package/templates/conditional/fetch/feature-based/src/lib/index.ts +0 -1
  194. package/templates/conditional/router/component-based/src/routes/index.jsx +0 -12
  195. package/templates/conditional/router/component-based/src/routes/index.tsx +0 -12
  196. package/templates/conditional/router/feature-based/src/app/router.jsx +0 -13
  197. package/templates/conditional/router/feature-based/src/app/router.tsx +0 -13
  198. package/templates/css/tailwind/src/index.css +0 -1
  199. /package/templates/architectures/component-based/src/{components/layout → config}/.gitkeep +0 -0
  200. /package/templates/architectures/{feature-based/src/features/home/interfaces → component-based/src/providers}/.gitkeep +0 -0
  201. /package/templates/architectures/{feature-based/src/lib → component-based/src/styles}/.gitkeep +0 -0
  202. /package/templates/architectures/feature-based/src/{stores → features/home/types}/.gitkeep +0 -0
  203. /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.js +0 -0
  204. /package/templates/architectures/feature-based/src/{components → shared/components}/ui/index.ts +0 -0
  205. /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.jsx +0 -0
  206. /package/templates/architectures/feature-based/src/{hooks → shared/hooks}/useLocalStorage.ts +0 -0
  207. /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.jsx +0 -0
  208. /package/templates/architectures/feature-based/src/{utils → shared/utils}/cn.ts +0 -0
  209. /package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.jsx +0 -0
  210. /package/templates/conditional/state/redux/component-based/src/{context → providers}/StoreProvider.tsx +0 -0
  211. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.js +0 -0
  212. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/hooks.ts +0 -0
  213. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.js +0 -0
  214. /package/templates/conditional/state/redux/feature-based/src/{stores → shared/stores}/index.ts +0 -0
  215. /package/templates/css/bootstrap/src/{index.css → globals.css} +0 -0
  216. /package/templates/{architectures/feature-based/src/styles → css/tailwind/src}/globals.css +0 -0
package/README.md CHANGED
@@ -87,36 +87,40 @@ Feature-based (example):
87
87
 
88
88
  ```
89
89
  src/
90
- ├── app
90
+ ├── app # App shell and global providers
91
91
  │   ├── App.tsx
92
+ │   ├── contexts
93
+ │   │   └── themecontext.ts # createContext + ThemeContextValue
92
94
  │   ├── providers
93
- │   │   └── ThemeProvider.tsx
94
- │   └── router.tsx
95
- ├── components
96
- │   └── ui
97
- ├── config
98
- │   └── constants.ts
99
- ├── features
100
- │   └── logout
95
+ │   │   └── ThemeProvider.tsx # Provider component
96
+ │   ├── hooks
97
+ │   │   └── useTheme.ts # Hook that reads ThemeContext
98
+ │   └── router # Data router (per feature area)
99
+ │   ├── guards # AuthGuard, RoleGuard
100
+ │   ├── routes # home.routes, auth.routes
101
+ │   └── index.tsx # createBrowserRouter init
102
+ ├── features # Feature modules (business logic owned per feature)
103
+ │   └── home
101
104
  │   ├── components
102
- │   ├── interfaces
105
+ │   ├── hooks
106
+ │   ├── index.ts # public feature barrel
103
107
  │   ├── layouts
104
108
  │   ├── pages
105
109
  │   ├── services
106
- │   └── store
107
- ├── hooks
108
- │   ├── index.ts
109
- │   └── useLocalStorage.ts
110
- ├── index.css
111
- ├── lib
112
- ├── main.tsx
113
- ├── stores
114
- ├── styles
115
- │   └── globals.css
116
- ├── test
117
- │   └── setup.ts
118
- ├── types
119
- └── utils
110
+ │   ├── store
111
+ │   └── types
112
+ └── shared # Reusable, business-agnostic resources
113
+ ├── api/lib # fetch client → api/; axios init → lib/axios/ (per choice)
114
+ ├── components
115
+ │   └── ui
116
+ ├── hooks
117
+ ├── layouts
118
+ ├── stores
119
+ ├── styles
120
+ │   ├── globals.css # Tailwind/Bootstrap directives (or main.css for vanilla)
121
+ │   └── themes.css # Theme tokens (Tailwind @theme / Bootstrap data-bs-theme / CSS vars)
122
+ ├── types
123
+ └── utils
120
124
  ```
121
125
 
122
126
  Component-based (example):
@@ -126,28 +130,32 @@ src/
126
130
  ├── App.tsx
127
131
  ├── components
128
132
  │   ├── common
129
- │   ├── form
130
- │   └── layout
131
- ├── config
132
- │   ├── constants.ts
133
- │   └── routes.ts
134
- ├── context
133
+ │   └── form
134
+ ├── config # API config (when an axios/fetch client is chosen)
135
135
  ├── hooks
136
- ├── index.css
137
136
  ├── layouts
138
137
  ├── main.tsx
139
138
  ├── pages
140
- ├── routes
139
+ ├── providers # Provider components (createContext + Provider in separate files inside providers/)
140
+ │   ├── appcontext.ts # createContext + AppContextValue
141
+ │   └── AppProvider.tsx # Provider component
142
+ ├── hooks
143
+ │   └── useApp.ts # Hook that reads AppContext
144
+ ├── router # Centralized data router
145
+ │   ├── guards # AuthGuard, GuestGuard
146
+ │   └── index.tsx # Single source of truth for all routes
141
147
  ├── services
142
148
  ├── store
143
149
  ├── styles
150
+ │   ├── globals.css # Tailwind/Bootstrap directives (or main.css for vanilla)
151
+ │   └── themes.css # Theme tokens (Tailwind @theme / Bootstrap data-bs-theme / CSS vars)
144
152
  ├── test
145
153
  └── utils
146
154
  ```
147
155
 
148
156
  ## Roadmap
149
157
 
150
- See `docs/ROADMAP.md` for planned features and upcoming releases.
158
+ Released versions live in [`docs/CHANGELOG.md`](./docs/CHANGELOG.md); planned work is tracked in [`docs/ROADMAP.md`](./docs/ROADMAP.md).
151
159
 
152
160
  ## Requirements
153
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-lumen",
3
- "version": "1.1.4",
3
+ "version": "1.2.0-beta.1",
4
4
  "description": "Scaffold a React + Vite project with architecture choice: feature-based or component-based.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/configure.js CHANGED
@@ -19,7 +19,7 @@ export async function configureProject(projectPath, language, cssFramework) {
19
19
  }
20
20
 
21
21
  // Add scripts to package.json
22
- await configurePackageJson(projectPath);
22
+ await configurePackageJson(projectPath, language);
23
23
  }
24
24
 
25
25
  async function configureTsconfig(projectPath) {
@@ -154,7 +154,7 @@ async function addPathAliasesToViteConfig(projectPath, ext) {
154
154
  }
155
155
  }
156
156
 
157
- async function configurePackageJson(projectPath) {
157
+ async function configurePackageJson(projectPath, language) {
158
158
  const pkgPath = path.join(projectPath, "package.json");
159
159
  try {
160
160
  const content = await readFileContent(pkgPath);
@@ -166,6 +166,10 @@ async function configurePackageJson(projectPath) {
166
166
  pkg.scripts.build = "vite build";
167
167
  pkg.scripts.preview = "vite preview";
168
168
 
169
+ if (language === "ts") {
170
+ pkg.scripts.typecheck = "tsc -b";
171
+ }
172
+
169
173
  await fsp.writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf8");
170
174
  } catch {
171
175
  // file doesn't exist, skip
package/src/css.js CHANGED
@@ -1,4 +1,3 @@
1
- import fs from "fs";
2
1
  import { promises as fsp } from "fs";
3
2
  import path from "path";
4
3
  import { deleteIfExists } from "@/utils/fs.js";
@@ -8,23 +7,27 @@ export async function setupCssFramework({
8
7
  templatesDir,
9
8
  language,
10
9
  cssFramework,
10
+ architecture,
11
11
  ext,
12
12
  pkg,
13
13
  }) {
14
14
  process.chdir(projectPath);
15
15
  const cssDir = path.join(templatesDir, "css");
16
- const indexCssPath = path.join(projectPath, "src", "index.css");
17
- // Feature-based main.* imports ./styles/globals.css; component-based main.*
18
- // imports ./index.css. The chosen framework's styles must land in the file
19
- // the architecture actually imports.
20
- const globalsCssPath = path.join(projectPath, "src", "styles", "globals.css");
16
+ // Feature-based main.* imports ./shared/styles/globals.css (or main.css when
17
+ // framework is "none"); component-based imports ./styles/globals.css (or
18
+ // main.css). The chosen framework's styles land in the file the architecture
19
+ // actually imports.
20
+ const stylesDir =
21
+ architecture === "feature-based"
22
+ ? path.join(projectPath, "src", "shared", "styles")
23
+ : path.join(projectPath, "src", "styles");
21
24
 
22
- async function writeCss(content) {
23
- await fsp.writeFile(indexCssPath, content, "utf8");
24
- try {
25
- await fsp.access(globalsCssPath);
26
- await fsp.writeFile(globalsCssPath, content, "utf8");
27
- } catch {}
25
+ // Vanilla CSS gets a stylesheet named main.css; tailwind/bootstrap keep
26
+ // globals.css (their idiomatic name — they inject framework directives).
27
+ const mainFileName = cssFramework === "none" ? "main.css" : "globals.css";
28
+
29
+ async function writeCss(content, fileName) {
30
+ await fsp.writeFile(path.join(stylesDir, fileName), content, "utf8");
28
31
  }
29
32
 
30
33
  if (cssFramework === "tailwind") {
@@ -36,14 +39,19 @@ export async function setupCssFramework({
36
39
  );
37
40
  await fsp.writeFile(viteConfigTarget, viteConfigContent, "utf8");
38
41
 
39
- const indexCssContent = await fsp.readFile(
40
- path.join(cssDir, "tailwind", "src", "index.css"),
42
+ const globalsContent = await fsp.readFile(
43
+ path.join(cssDir, "tailwind", "src", "globals.css"),
44
+ "utf8"
45
+ );
46
+ const themesContent = await fsp.readFile(
47
+ path.join(cssDir, "tailwind", "src", "themes.css"),
41
48
  "utf8"
42
49
  );
43
- await writeCss(indexCssContent);
50
+ await writeCss(globalsContent, "globals.css");
51
+ await writeCss(themesContent, "themes.css");
44
52
  } else if (cssFramework === "bootstrap") {
45
53
  const mainFile = path.join(projectPath, "src", `main.${ext}`);
46
- if (fs.existsSync(mainFile)) {
54
+ try {
47
55
  let mainContent = await fsp.readFile(mainFile, "utf8");
48
56
  if (
49
57
  !mainContent.includes("bootstrap/dist/css/bootstrap.min.css")
@@ -52,20 +60,59 @@ export async function setupCssFramework({
52
60
  "import 'bootstrap/dist/css/bootstrap.min.css';\n" + mainContent;
53
61
  await fsp.writeFile(mainFile, mainContent, "utf8");
54
62
  }
55
- }
56
- const indexCssContent = await fsp.readFile(
57
- path.join(cssDir, "bootstrap", "src", "index.css"),
63
+ } catch {}
64
+
65
+ const globalsContent = await fsp.readFile(
66
+ path.join(cssDir, "bootstrap", "src", "globals.css"),
58
67
  "utf8"
59
68
  );
60
- await writeCss(indexCssContent);
69
+ const themesContent = await fsp.readFile(
70
+ path.join(cssDir, "bootstrap", "src", "themes.css"),
71
+ "utf8"
72
+ );
73
+ await writeCss(globalsContent, "globals.css");
74
+ await writeCss(themesContent, "themes.css");
61
75
  } else {
62
- const indexCssContent = await fsp.readFile(
63
- path.join(cssDir, "none", "src", "index.css"),
76
+ const mainContent = await fsp.readFile(
77
+ path.join(cssDir, "none", "src", "main.css"),
78
+ "utf8"
79
+ );
80
+ const themesContent = await fsp.readFile(
81
+ path.join(cssDir, "none", "src", "themes.css"),
64
82
  "utf8"
65
83
  );
66
- await writeCss(indexCssContent);
84
+ await writeCss(mainContent, "main.css");
85
+ await writeCss(themesContent, "themes.css");
67
86
  }
68
87
 
69
- // Clean up Vite's default App.css
88
+ // Ensure main.{ext} imports the correct stylesheet name for this framework.
89
+ await syncMainCssImport(projectPath, ext, architecture, mainFileName);
90
+
91
+ // Ensure the styles dir exists (for the .gitkeep placeholder when no real
92
+ // file lives there yet — pruneRedundantGitkeeps removes it after overlays).
93
+ await fsp.mkdir(stylesDir, { recursive: true });
94
+
95
+ // Clean up Vite's default CSS files; src/index.css is the framework-agnostic
96
+ // leftover Vite scaffolds and is never imported in our generated projects.
70
97
  await deleteIfExists(path.join(projectPath, "src", "App.css"));
98
+ await deleteIfExists(path.join(projectPath, "src", "index.css"));
99
+ }
100
+
101
+ // Rewrite the CSS import in main.{ext} so it matches the file the framework
102
+ // actually wrote (main.css for "none", globals.css for tailwind/bootstrap).
103
+ async function syncMainCssImport(projectPath, ext, architecture, mainFileName) {
104
+ const mainPath = path.join(projectPath, "src", `main.${ext}`);
105
+ try {
106
+ let content = await fsp.readFile(mainPath, "utf8");
107
+ const expected =
108
+ architecture === "feature-based"
109
+ ? `./shared/styles/${mainFileName}`
110
+ : `./styles/${mainFileName}`;
111
+ const wrong =
112
+ architecture === "feature-based"
113
+ ? /import ['"]\.\/shared\/styles\/(globals|main)\.css['"]/
114
+ : /import ['"]\.\/styles\/(globals|main)\.css['"]/;
115
+ content = content.replace(wrong, `import '${expected}'`);
116
+ await fsp.writeFile(mainPath, content, "utf8");
117
+ } catch {}
71
118
  }
package/src/injector.js CHANGED
@@ -2,7 +2,25 @@ import { promises as fsp } from "fs";
2
2
  import path from "path";
3
3
  import { copyDirRecursive, writeFileRecursive } from "@/utils/fs.js";
4
4
 
5
- export async function injectArchitecture(projectPath, templatesDir, architecture, language) {
5
+ // Narrow a template tree copy to the selected language: .tsx/.ts for ts,
6
+ // .jsx/.js for js (keeps the opposite language's files out of the project).
7
+ function langFileFilter(language) {
8
+ return (name) => {
9
+ if (language === "ts") {
10
+ if (name.endsWith(".jsx")) return false;
11
+ if (name.endsWith(".js")) return false;
12
+ return true;
13
+ }
14
+ if (language === "js") {
15
+ if (name.endsWith(".tsx")) return false;
16
+ if (name.endsWith(".ts")) return false;
17
+ return true;
18
+ }
19
+ return true;
20
+ };
21
+ }
22
+
23
+ export async function injectArchitecture(projectPath, templatesDir, architecture, language, cssFramework) {
6
24
  const ext = language === "ts" ? "tsx" : "jsx";
7
25
  const srcDir = path.join(templatesDir, "architectures", architecture, "src");
8
26
 
@@ -11,17 +29,13 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
11
29
  const defaultAppJsx = path.join(projectPath, "src", "App.jsx");
12
30
  try { await fsp.rm(defaultAppTsx, { force: true }); } catch {}
13
31
  try { await fsp.rm(defaultAppJsx, { force: true }); } catch {}
32
+ // Remove Vite's default index.css (framework CSS lives in src/styles/,
33
+ // copied below — never at the src/ root).
34
+ try { await fsp.rm(path.join(projectPath, "src", "index.css"), { force: true }); } catch {}
35
+ try { await fsp.rm(path.join(projectPath, "src", "App.css"), { force: true }); } catch {}
14
36
 
15
37
  // Copy the architecture tree into the project's src/
16
- await copyDirRecursive(srcDir, path.join(projectPath, "src"), (name) => {
17
- // Skip files that don't match the language
18
- if (language === "ts" && name.endsWith(".jsx")) return false;
19
- if (language === "js" && name.endsWith(".tsx")) return false;
20
- // Skip .ts files when JS, skip .js when TS (for non-component files)
21
- if (language === "ts" && name.endsWith(".js") && !name.endsWith(".config.js")) return false;
22
- if (language === "js" && name.endsWith(".ts") && !name.endsWith(".config.ts")) return false;
23
- return true;
24
- });
38
+ await copyDirRecursive(srcDir, path.join(projectPath, "src"), langFileFilter(language));
25
39
 
26
40
  // Copy the architecture's main.tsx/main.jsx to src/main.{ext}
27
41
  const mainSrc = path.join(
@@ -41,6 +55,31 @@ export async function injectArchitecture(projectPath, templatesDir, architecture
41
55
  const oppositeExt = language === "ts" ? "jsx" : "tsx";
42
56
  const oppositeMain = path.join(projectPath, "src", `main.${oppositeExt}`);
43
57
  try { await fsp.rm(oppositeMain, { force: true }); } catch {}
58
+
59
+ // Apply the chosen CSS framework's component styling on top of the base
60
+ // (only where the base ships framework-agnostic inline markup). Runs here,
61
+ // before conditional overlays, so icons/router can still override the files
62
+ // they own.
63
+ if (cssFramework === "tailwind" || cssFramework === "bootstrap") {
64
+ const variantSrc = path.join(
65
+ templatesDir,
66
+ "css",
67
+ "component-styles",
68
+ cssFramework,
69
+ architecture,
70
+ "src"
71
+ );
72
+ try {
73
+ await fsp.access(variantSrc);
74
+ await copyDirRecursive(
75
+ variantSrc,
76
+ path.join(projectPath, "src"),
77
+ langFileFilter(language)
78
+ );
79
+ } catch {
80
+ // no component-styles for this arch/framework
81
+ }
82
+ }
44
83
  }
45
84
 
46
85
  export async function injectFormatter(projectPath, templatesDir, responses) {
@@ -153,20 +192,22 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
153
192
 
154
193
  // 2. Router (overwrites App.tsx with routed version)
155
194
  if (responses.router) {
156
- await injectOverlay(
195
+ await injectOverlayVariant(
157
196
  projectPath,
158
197
  templatesDir,
159
- `conditional/router/${architecture}`,
198
+ `router/${architecture}`,
199
+ responses.cssFramework,
160
200
  language
161
201
  );
162
202
  }
163
203
 
164
204
  // 3. Icons (overwrites home page)
165
205
  if (responses.iconLibrary && responses.iconLibrary !== "none") {
166
- await injectOverlay(
206
+ await injectOverlayVariant(
167
207
  projectPath,
168
208
  templatesDir,
169
- `conditional/icons/${responses.iconLibrary}/${architecture}`,
209
+ `icons/${responses.iconLibrary}/${architecture}`,
210
+ responses.cssFramework,
170
211
  language
171
212
  );
172
213
  }
@@ -206,19 +247,70 @@ export async function injectConditionals(projectPath, templatesDir, responses, a
206
247
  if (architecture === "feature-based") {
207
248
  await injectCreateFeatureScript(projectPath, templatesDir, language);
208
249
  }
250
+
251
+ // A .gitkeep only keeps a folder alive when that folder holds nothing else;
252
+ // once an overlay writes real files into it the placeholder is redundant.
253
+ await pruneRedundantGitkeeps(projectPath);
254
+ }
255
+
256
+ // Remove .gitkeep placeholders from src/ directories that now contain real
257
+ // files (e.g. component-based `services/.gitkeep` after the axios/fetch client
258
+ // overlay lands). A folder with nothing but its placeholder keeps it.
259
+ async function pruneRedundantGitkeeps(projectPath) {
260
+ const walk = async (dir) => {
261
+ let entries;
262
+ try {
263
+ entries = await fsp.readdir(dir, { withFileTypes: true });
264
+ } catch {
265
+ return;
266
+ }
267
+ for (const entry of entries) {
268
+ if (entry.isDirectory()) {
269
+ await walk(path.join(dir, entry.name));
270
+ }
271
+ }
272
+ if (entries.some((e) => e.name === ".gitkeep")) {
273
+ const hasRealFiles = entries.some((e) => e.isFile() && e.name !== ".gitkeep");
274
+ if (hasRealFiles) {
275
+ await fsp.rm(path.join(dir, ".gitkeep"), { force: true });
276
+ }
277
+ }
278
+ };
279
+ await walk(path.join(projectPath, "src"));
280
+ }
281
+
282
+ // Overlays that ship presentational components (router, icons) carry optional
283
+ // tailwind/bootstrap subfolders. Copy the root version first — it holds the
284
+ // framework-agnostic skeleton (routed App, route tables) plus the inline
285
+ // markup defaults used for cssFramework "none" — then overlay the framework's
286
+ // subfolder so its markup-specific files (transitive layouts, home pages)
287
+ // win; `copyDirRecursive` overwrites on name collision.
288
+ async function injectOverlayVariant(projectPath, templatesDir, rel, cssFramework, language) {
289
+ const base = `conditional/${rel}`;
290
+ await injectOverlay(projectPath, templatesDir, base, language);
291
+ const variant =
292
+ cssFramework === "tailwind" || cssFramework === "bootstrap"
293
+ ? cssFramework
294
+ : "";
295
+ if (variant) {
296
+ await injectOverlay(
297
+ projectPath,
298
+ templatesDir,
299
+ `${base}/${variant}`,
300
+ language
301
+ );
302
+ }
209
303
  }
210
304
 
211
305
  async function injectOverlay(projectPath, templatesDir, overlayPath, language) {
212
306
  const srcDir = path.join(templatesDir, overlayPath, "src");
213
307
  try {
214
308
  await fsp.access(srcDir);
215
- await copyDirRecursive(srcDir, path.join(projectPath, "src"), (name) => {
216
- if (language === "ts" && name.endsWith(".jsx")) return false;
217
- if (language === "js" && name.endsWith(".tsx")) return false;
218
- if (language === "ts" && name.endsWith(".js") && !name.endsWith(".config.js")) return false;
219
- if (language === "js" && name.endsWith(".ts") && !name.endsWith(".config.ts")) return false;
220
- return true;
221
- });
309
+ await copyDirRecursive(
310
+ srcDir,
311
+ path.join(projectPath, "src"),
312
+ langFileFilter(language)
313
+ );
222
314
  } catch {
223
315
  // overlay src dir doesn't exist
224
316
  }
@@ -332,11 +424,11 @@ async function injectCreateFeatureScript(projectPath, templatesDir, language) {
332
424
  if (language === "js") {
333
425
  // Replace .ts extensions with .js in the initialFiles
334
426
  content = content
335
- .replace(/interfaces\/index\.ts/g, "interfaces/index.js")
336
427
  .replace(/services\/index\.ts/g, "services/index.js")
337
428
  .replace(/store\/index\.ts/g, "store/index.js")
338
429
  .replace(/hooks\/index\.ts/g, "hooks/index.js")
339
- .replace(/pages\/index\.ts/g, "pages/index.js");
430
+ .replace(/pages\/index\.ts/g, "pages/index.js")
431
+ .replace(/types\/index\.ts/g, "types/index.js");
340
432
  }
341
433
 
342
434
  await writeFileRecursive(scriptDest, content);
@@ -373,7 +465,7 @@ async function updateMainWithProvider(projectPath, stateType, architecture, ext)
373
465
  if (!content.includes("StoreProvider")) {
374
466
  content = content.replace(
375
467
  /import App from ['"]\.\/App['"]\n?/,
376
- "import App from './App'\nimport { StoreProvider } from './context/StoreProvider'\n"
468
+ "import App from './App'\nimport { StoreProvider } from './providers/StoreProvider'\n"
377
469
  );
378
470
  content = content.replace(
379
471
  /<App \/>/,
package/src/main.js CHANGED
@@ -111,7 +111,8 @@ export async function main(options = {}) {
111
111
  projectPath,
112
112
  TEMPLATES_DIR,
113
113
  responses.architecture,
114
- responses.language
114
+ responses.language,
115
+ responses.cssFramework
115
116
  );
116
117
  archSpin.stop(chalk.green("Architecture scaffolding complete."));
117
118
  } catch (err) {
@@ -175,6 +176,7 @@ export async function main(options = {}) {
175
176
  templatesDir: TEMPLATES_DIR,
176
177
  language: responses.language,
177
178
  cssFramework: responses.cssFramework,
179
+ architecture: responses.architecture,
178
180
  ext: responses.language === "ts" ? "tsx" : "jsx",
179
181
  pkg,
180
182
  });
package/src/readme.js CHANGED
@@ -80,34 +80,76 @@ function buildScripts(responses) {
80
80
  rows.push("| `npm run format:check` | Verify code is formatted |");
81
81
  }
82
82
 
83
+ if (responses.language === "ts") {
84
+ rows.push("| `npm run typecheck` | Type-check the project (tsc -b) |");
85
+ }
86
+
83
87
  return rows.join("\n");
84
88
  }
85
89
 
86
- function buildProjectStructure(architecture) {
87
- if (architecture === "feature-based") {
90
+ function buildProjectStructure(responses) {
91
+ if (responses.architecture === "feature-based") {
92
+ const shared = [];
93
+ if (responses.apiClient === "fetch") {
94
+ shared.push("api/ # HTTP client (fetch) — not an external dependency");
95
+ } else if (responses.apiClient === "axios") {
96
+ shared.push("lib/ # Third-party library init (axios client)");
97
+ }
98
+ shared.push(
99
+ "components/ # Shared UI components",
100
+ "hooks/ # Shared custom hooks",
101
+ "layouts/ # High-level layout wrappers",
102
+ "stores/ # Global state stores",
103
+ `styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
104
+ "types/ # Global type definitions",
105
+ "utils/ # Pure utility functions"
106
+ );
107
+ const appChildren = [
108
+ "App.tsx",
109
+ "contexts/ # React context objects (createContext)",
110
+ "providers/ # Provider components (ThemeProvider, ...)",
111
+ "hooks/ # Hooks that read the contexts (useTheme, ...)"
112
+ ];
88
113
  return `src/
89
- ├── app/ # App shell and providers
90
- ├── components/ # Shared UI components
91
- ├── config/ # Constants and configuration
92
- ├── features/ # Feature modules (pages, hooks, api)
93
- ├── hooks/ # Shared custom hooks
94
- ├── stores/ # Global state stores
95
- ├── types/ # TypeScript type definitions
96
- └── utils/ # Utility functions`;
114
+ ├── app/ # App shell and global providers
115
+ ${nestedTree(appChildren)}
116
+ ├── features/ # Feature modules (pages, hooks, api, types)
117
+ │ └── home/ # Example feature (components, services, types, store)
118
+ └── shared/ # Reusable, business-agnostic resources
119
+ ${nestedTree(shared)}`;
97
120
  }
98
121
 
122
+ const rows = ["components/ # Reusable UI components (common, form)"];
123
+ if (responses.apiClient !== "none") {
124
+ rows.push("config/ # API configuration (axios/fetch)");
125
+ }
126
+ rows.push(
127
+ "hooks/ # Shared custom hooks",
128
+ "layouts/ # Page layout wrappers",
129
+ "pages/ # Page-level components",
130
+ "providers/ # Provider components (createContext in appcontext.{ts,js}, Provider in AppProvider.{tsx,jsx})"
131
+ );
132
+ if (responses.router) {
133
+ rows.push("router/ # Centralized data router (guards/, index)");
134
+ }
135
+ rows.push(
136
+ "services/ # API service layer",
137
+ "store/ # State store",
138
+ `styles/ # ${responses.cssFramework === "none" ? "main.css (reset) + themes.css (CSS variables)" : "globals.css (framework directives) + themes.css"}`,
139
+ "types/ # TypeScript type definitions",
140
+ "utils/ # Utility functions"
141
+ );
99
142
  return `src/
100
- ├── components/ # Reusable UI components (common, form, layout)
101
- ├── config/ # Constants and route definitions
102
- ├── context/ # React context providers
103
- ├── hooks/ # Shared custom hooks
104
- ├── layouts/ # Page layout wrappers
105
- ├── pages/ # Page-level components
106
- ├── routes/ # Route definitions
107
- ├── services/ # API service layer
108
- ├── store/ # State store
109
- ├── styles/ # Global styles
110
- └── utils/ # Utility functions`;
143
+ ${nestedTree(rows, "")}`;
144
+ }
145
+
146
+ function nestedTree(rows, indent = " ") {
147
+ return rows
148
+ .map((label, i) => {
149
+ const isLast = i === rows.length - 1;
150
+ return `${indent}${isLast ? "└── " : "├── "}${label}`;
151
+ })
152
+ .join("\n");
111
153
  }
112
154
 
113
155
  function buildLicense() {
@@ -153,7 +195,7 @@ function buildDescription(projectName, responses) {
153
195
  function buildReadme(projectName, responses) {
154
196
  const builtWith = buildBuiltWith(responses);
155
197
  const scripts = buildScripts(responses);
156
- const structure = buildProjectStructure(responses.architecture);
198
+ const structure = buildProjectStructure(responses);
157
199
 
158
200
  return `${buildDescription(projectName, responses)}
159
201
 
@@ -1,10 +1,13 @@
1
+ import { AppProvider } from "@/providers/AppProvider";
1
2
  import { MainLayout } from "@/layouts/MainLayout";
2
3
  import { HomePage } from "@/pages/Home/Home";
3
4
 
4
5
  export default function App() {
5
6
  return (
6
- <MainLayout>
7
- <HomePage />
8
- </MainLayout>
7
+ <AppProvider>
8
+ <MainLayout>
9
+ <HomePage />
10
+ </MainLayout>
11
+ </AppProvider>
9
12
  );
10
13
  }
@@ -1,10 +1,13 @@
1
+ import { AppProvider } from "@/providers/AppProvider";
1
2
  import { MainLayout } from "@/layouts/MainLayout";
2
3
  import { HomePage } from "@/pages/Home/Home";
3
4
 
4
5
  export default function App() {
5
6
  return (
6
- <MainLayout>
7
- <HomePage />
8
- </MainLayout>
7
+ <AppProvider>
8
+ <MainLayout>
9
+ <HomePage />
10
+ </MainLayout>
11
+ </AppProvider>
9
12
  );
10
13
  }
@@ -5,8 +5,11 @@ export function Button({
5
5
  ...props
6
6
  }) {
7
7
  const styles = {
8
- primary: { backgroundColor: "#2563eb", color: "white" },
9
- secondary: { backgroundColor: "#e5e7eb", color: "#1f2937" },
8
+ primary: { backgroundColor: "var(--color-primary)", color: "white" },
9
+ secondary: {
10
+ backgroundColor: "var(--color-border)",
11
+ color: "var(--color-fg)",
12
+ },
10
13
  };
11
14
 
12
15
  return (