@qlover/create-app 0.7.15 → 0.8.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 (340) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/configs/_common/.gitignore.template +6 -0
  3. package/dist/configs/_common/.prettierignore +17 -5
  4. package/dist/configs/_common/.vscode/settings.json +6 -1
  5. package/dist/index.cjs +1 -1
  6. package/dist/index.js +1 -1
  7. package/dist/templates/next-app/.env.template +1 -1
  8. package/dist/templates/next-app/README.en.md +0 -1
  9. package/dist/templates/next-app/README.md +0 -1
  10. package/dist/templates/next-app/config/Identifier/api.ts +5 -5
  11. package/dist/templates/next-app/config/Identifier/common/admint.table.ts +69 -0
  12. package/dist/templates/next-app/config/Identifier/common/common.ts +76 -0
  13. package/dist/templates/next-app/config/Identifier/common/index.ts +3 -0
  14. package/dist/templates/next-app/config/Identifier/{validator.ts → common/validators.ts} +5 -5
  15. package/dist/templates/next-app/config/Identifier/index.ts +2 -12
  16. package/dist/templates/next-app/config/Identifier/pages/index.ts +6 -0
  17. package/dist/templates/next-app/config/Identifier/pages/page.admin.home.ts +27 -0
  18. package/dist/templates/next-app/config/Identifier/pages/page.admin.locales.ts +266 -0
  19. package/dist/templates/next-app/config/Identifier/pages/page.admin.user.ts +293 -0
  20. package/dist/templates/{react-app/config/Identifier → next-app/config/Identifier/pages}/page.home.ts +15 -22
  21. package/dist/templates/next-app/config/Identifier/{page.login.ts → pages/page.login.ts} +28 -34
  22. package/dist/templates/next-app/config/Identifier/{page.register.ts → pages/page.register.ts} +30 -29
  23. package/dist/templates/next-app/config/adminNavs.ts +19 -0
  24. package/dist/templates/next-app/config/common.ts +22 -13
  25. package/dist/templates/next-app/config/i18n/HomeI18n.ts +5 -5
  26. package/dist/templates/next-app/config/i18n/admin18n.ts +61 -19
  27. package/dist/templates/next-app/config/i18n/i18nConfig.ts +2 -0
  28. package/dist/templates/next-app/config/i18n/i18nKeyScheam.ts +36 -0
  29. package/dist/templates/next-app/config/i18n/loginI18n.ts +22 -22
  30. package/dist/templates/next-app/config/i18n/register18n.ts +23 -24
  31. package/dist/templates/next-app/docs/en/index.md +0 -1
  32. package/dist/templates/next-app/docs/en/project-structure.md +0 -1
  33. package/dist/templates/next-app/docs/zh/index.md +0 -1
  34. package/dist/templates/next-app/docs/zh/project-structure.md +0 -1
  35. package/dist/templates/next-app/make/generateLocales.ts +19 -12
  36. package/dist/templates/next-app/migrations/schema/LocalesSchema.ts +15 -0
  37. package/dist/templates/next-app/migrations/sql/1694244000000.sql +11 -0
  38. package/dist/templates/next-app/package.json +7 -3
  39. package/dist/templates/next-app/public/locales/en.json +172 -207
  40. package/dist/templates/next-app/public/locales/zh.json +172 -207
  41. package/dist/templates/next-app/src/app/[locale]/admin/locales/page.tsx +153 -0
  42. package/dist/templates/next-app/src/app/[locale]/admin/users/page.tsx +48 -50
  43. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +2 -2
  44. package/dist/templates/next-app/src/app/api/admin/locales/create/route.ts +34 -0
  45. package/dist/templates/next-app/src/app/api/admin/locales/import/route.ts +40 -0
  46. package/dist/templates/next-app/src/app/api/admin/locales/route.ts +42 -0
  47. package/dist/templates/next-app/src/app/api/admin/locales/update/route.ts +32 -0
  48. package/dist/templates/next-app/src/app/api/locales/json/route.ts +44 -0
  49. package/dist/templates/next-app/src/base/cases/AdminPageManager.ts +1 -13
  50. package/dist/templates/next-app/src/base/cases/Datetime.ts +18 -0
  51. package/dist/templates/next-app/src/base/cases/DialogErrorPlugin.ts +12 -6
  52. package/dist/templates/next-app/src/base/cases/ResourceState.ts +17 -0
  53. package/dist/templates/next-app/src/base/cases/TranslateI18nInterface.ts +25 -0
  54. package/dist/templates/next-app/src/base/cases/ZodColumnBuilder.ts +200 -0
  55. package/dist/templates/next-app/src/base/port/ZodBuilderInterface.ts +8 -0
  56. package/dist/templates/next-app/src/base/services/AdminLocalesService.ts +20 -0
  57. package/dist/templates/next-app/src/base/services/AdminPageEvent.ts +26 -0
  58. package/dist/templates/next-app/src/base/services/AdminPageScheduler.ts +42 -0
  59. package/dist/templates/next-app/src/base/services/ResourceService.ts +122 -0
  60. package/dist/templates/next-app/src/base/services/adminApi/AdminLocalesApi.ts +104 -0
  61. package/dist/templates/next-app/src/base/services/adminApi/AdminUserApi.ts +38 -5
  62. package/dist/templates/next-app/src/base/services/appApi/AppApiPlugin.ts +1 -1
  63. package/dist/templates/next-app/src/i18n/request.ts +30 -1
  64. package/dist/templates/next-app/src/server/PageParams.ts +2 -10
  65. package/dist/templates/next-app/src/server/port/DBBridgeInterface.ts +5 -0
  66. package/dist/templates/next-app/src/server/port/DBTableInterface.ts +2 -0
  67. package/dist/templates/next-app/src/server/port/LocalesRepositoryInterface.ts +43 -0
  68. package/dist/templates/next-app/src/server/repositorys/LocalesRepository.ts +197 -0
  69. package/dist/templates/next-app/src/server/services/ApiLocaleService.ts +122 -0
  70. package/dist/templates/next-app/src/server/sqlBridges/SupabaseBridge.ts +60 -11
  71. package/dist/templates/next-app/src/server/validators/ExtendedExecutorError.ts +6 -0
  72. package/dist/templates/next-app/src/server/validators/LocalesValidator.ts +131 -0
  73. package/dist/templates/next-app/src/server/validators/LoginValidator.ts +2 -5
  74. package/dist/templates/next-app/src/server/validators/PaginationValidator.ts +32 -16
  75. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/_default.css +2 -1
  76. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/dark.css +28 -29
  77. package/dist/templates/next-app/src/styles/css/antd-themes/pagination/pink.css +2 -1
  78. package/dist/templates/next-app/src/uikit/components/AdminLayout.tsx +17 -3
  79. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +5 -4
  80. package/dist/templates/next-app/src/uikit/components/BaseLayout.tsx +5 -4
  81. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +3 -2
  82. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +1 -1
  83. package/dist/templates/next-app/src/uikit/components/EditableCell.tsx +118 -0
  84. package/dist/templates/next-app/src/uikit/components/LogoutButton.tsx +5 -6
  85. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +1 -1
  86. package/dist/templates/next-app/src/uikit/components/With.tsx +2 -2
  87. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportButton.tsx +62 -0
  88. package/dist/templates/next-app/src/uikit/components/localesImportButton/LocalesImportEvent.ts +28 -0
  89. package/dist/templates/next-app/src/uikit/components/localesImportButton/import.module.css +6 -0
  90. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +8 -14
  91. package/dist/templates/next-app/src/uikit/hook/useWarnTranslations.ts +25 -0
  92. package/dist/templates/react-app/.prettierignore +17 -0
  93. package/dist/templates/react-app/README.en.md +71 -54
  94. package/dist/templates/react-app/README.md +35 -18
  95. package/dist/templates/react-app/__tests__/__mocks__/BootstrapTest.ts +14 -0
  96. package/dist/templates/react-app/__tests__/__mocks__/MockAppConfit.ts +1 -1
  97. package/dist/templates/react-app/__tests__/__mocks__/MockDialogHandler.ts +2 -2
  98. package/dist/templates/react-app/__tests__/__mocks__/MockLogger.ts +1 -1
  99. package/dist/templates/react-app/__tests__/__mocks__/components/TestApp.tsx +45 -0
  100. package/dist/templates/react-app/__tests__/__mocks__/components/TestBootstrapsProvider.tsx +34 -0
  101. package/dist/templates/react-app/__tests__/__mocks__/components/TestRouter.tsx +46 -0
  102. package/dist/templates/react-app/__tests__/__mocks__/components/index.ts +12 -0
  103. package/dist/templates/react-app/__tests__/__mocks__/createMockGlobals.ts +1 -2
  104. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOC.ts +51 -0
  105. package/dist/templates/react-app/__tests__/__mocks__/testIOC/TestIOCRegister.ts +69 -0
  106. package/dist/templates/react-app/__tests__/setup/index.ts +1 -51
  107. package/dist/templates/react-app/__tests__/setup/setupGlobal.ts +51 -0
  108. package/dist/templates/react-app/__tests__/src/App.structure.test.tsx +115 -0
  109. package/dist/templates/react-app/__tests__/src/base/cases/AppConfig.test.ts +2 -2
  110. package/dist/templates/react-app/__tests__/src/base/cases/AppError.test.ts +1 -1
  111. package/dist/templates/react-app/__tests__/src/base/cases/DialogHandler.test.ts +3 -5
  112. package/dist/templates/react-app/__tests__/src/base/cases/I18nKeyErrorPlugin.test.ts +13 -2
  113. package/dist/templates/react-app/__tests__/src/base/cases/InversifyContainer.test.ts +1 -1
  114. package/dist/templates/react-app/__tests__/src/base/cases/PublicAssetsPath.test.ts +1 -1
  115. package/dist/templates/react-app/__tests__/src/base/cases/RequestLogger.test.ts +5 -5
  116. package/dist/templates/react-app/__tests__/src/base/cases/RequestStatusCatcher.test.ts +1 -2
  117. package/dist/templates/react-app/__tests__/src/base/cases/RouterLoader.test.ts +25 -15
  118. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +29 -15
  119. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +19 -9
  120. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapClient.test.ts +153 -0
  121. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +9 -7
  122. package/dist/templates/react-app/__tests__/src/main.integration.test.tsx +4 -5
  123. package/dist/templates/react-app/__tests__/src/main.test.tsx +4 -4
  124. package/dist/templates/react-app/__tests__/src/uikit/components/BaseHeader.test.tsx +68 -59
  125. package/dist/templates/react-app/config/IOCIdentifier.ts +8 -8
  126. package/dist/templates/react-app/config/Identifier/{common.error.ts → common/common.error.ts} +5 -5
  127. package/dist/templates/react-app/config/Identifier/{common.ts → common/common.ts} +9 -9
  128. package/dist/templates/react-app/config/Identifier/common/index.ts +2 -0
  129. package/dist/templates/react-app/config/Identifier/index.ts +1 -9
  130. package/dist/templates/react-app/config/Identifier/pages/index.ts +8 -0
  131. package/dist/templates/react-app/config/Identifier/{page.about.ts → pages/page.about.ts} +34 -26
  132. package/dist/templates/react-app/config/Identifier/{page.executor.ts → pages/page.executor.ts} +47 -39
  133. package/dist/templates/{next-app/config/Identifier → react-app/config/Identifier/pages}/page.home.ts +24 -23
  134. package/dist/templates/react-app/config/Identifier/pages/page.identifiter.ts +102 -0
  135. package/dist/templates/react-app/config/Identifier/{page.jsonStorage.ts → pages/page.jsonStorage.ts} +18 -11
  136. package/dist/templates/react-app/config/Identifier/{page.login.ts → pages/page.login.ts} +37 -27
  137. package/dist/templates/react-app/config/Identifier/{page.register.ts → pages/page.register.ts} +37 -25
  138. package/dist/templates/react-app/config/Identifier/{page.request.ts → pages/page.request.ts} +34 -44
  139. package/dist/templates/react-app/config/app.router.ts +66 -69
  140. package/dist/templates/react-app/config/i18n/PageI18nInterface.ts +51 -0
  141. package/dist/templates/react-app/config/i18n/aboutI18n.ts +42 -0
  142. package/dist/templates/react-app/config/i18n/executorI18n.ts +51 -0
  143. package/dist/templates/react-app/config/i18n/homeI18n.ts +24 -0
  144. package/dist/templates/react-app/config/i18n/i18nConfig.ts +30 -0
  145. package/dist/templates/react-app/config/i18n/identifiter18n.ts +30 -0
  146. package/dist/templates/react-app/config/i18n/jsonStorage18n.ts +27 -0
  147. package/dist/templates/react-app/config/i18n/login18n.ts +42 -0
  148. package/dist/templates/react-app/config/i18n/notFoundI18n.ts +34 -0
  149. package/dist/templates/react-app/config/i18n/register18n.ts +40 -0
  150. package/dist/templates/react-app/config/i18n/request18n.ts +41 -0
  151. package/dist/templates/react-app/config/theme.ts +14 -4
  152. package/dist/templates/react-app/docs/en/bootstrap.md +1670 -341
  153. package/dist/templates/react-app/docs/en/development-guide.md +1021 -345
  154. package/dist/templates/react-app/docs/en/env.md +1132 -278
  155. package/dist/templates/react-app/docs/en/i18n.md +858 -147
  156. package/dist/templates/react-app/docs/en/index.md +733 -104
  157. package/dist/templates/react-app/docs/en/ioc.md +1228 -287
  158. package/dist/templates/react-app/docs/en/playwright/e2e-tests.md +321 -0
  159. package/dist/templates/react-app/docs/en/playwright/index.md +19 -0
  160. package/dist/templates/react-app/docs/en/playwright/installation-summary.md +332 -0
  161. package/dist/templates/react-app/docs/en/playwright/overview.md +222 -0
  162. package/dist/templates/react-app/docs/en/playwright/quickstart.md +325 -0
  163. package/dist/templates/react-app/docs/en/playwright/reorganization-notes.md +340 -0
  164. package/dist/templates/react-app/docs/en/playwright/setup-complete.md +290 -0
  165. package/dist/templates/react-app/docs/en/playwright/testing-guide.md +565 -0
  166. package/dist/templates/react-app/docs/en/store.md +1194 -184
  167. package/dist/templates/react-app/docs/en/why-no-globals.md +797 -0
  168. package/dist/templates/react-app/docs/zh/bootstrap.md +1670 -341
  169. package/dist/templates/react-app/docs/zh/development-guide.md +1021 -345
  170. package/dist/templates/react-app/docs/zh/env.md +1132 -275
  171. package/dist/templates/react-app/docs/zh/i18n.md +858 -147
  172. package/dist/templates/react-app/docs/zh/index.md +717 -104
  173. package/dist/templates/react-app/docs/zh/ioc.md +1229 -287
  174. package/dist/templates/react-app/docs/zh/playwright/e2e-tests.md +321 -0
  175. package/dist/templates/react-app/docs/zh/playwright/index.md +19 -0
  176. package/dist/templates/react-app/docs/zh/playwright/installation-summary.md +332 -0
  177. package/dist/templates/react-app/docs/zh/playwright/overview.md +222 -0
  178. package/dist/templates/react-app/docs/zh/playwright/quickstart.md +325 -0
  179. package/dist/templates/react-app/docs/zh/playwright/reorganization-notes.md +340 -0
  180. package/dist/templates/react-app/docs/zh/playwright/setup-complete.md +290 -0
  181. package/dist/templates/react-app/docs/zh/playwright/testing-guide.md +565 -0
  182. package/dist/templates/react-app/docs/zh/store.md +1192 -184
  183. package/dist/templates/react-app/docs/zh/why-no-globals.md +797 -0
  184. package/dist/templates/react-app/e2e/App.spec.ts +319 -0
  185. package/dist/templates/react-app/e2e/fixtures/base.fixture.ts +40 -0
  186. package/dist/templates/react-app/e2e/main.spec.ts +20 -0
  187. package/dist/templates/react-app/e2e/utils/test-helpers.ts +19 -0
  188. package/dist/templates/react-app/eslint.config.mjs +247 -0
  189. package/dist/templates/react-app/makes/eslint-utils.mjs +195 -0
  190. package/dist/templates/react-app/makes/generateTs2LocalesOptions.ts +26 -0
  191. package/dist/templates/react-app/package.json +31 -3
  192. package/dist/templates/react-app/playwright.config.ts +79 -0
  193. package/dist/templates/react-app/public/locales/en/common.json +190 -179
  194. package/dist/templates/react-app/public/locales/zh/common.json +190 -179
  195. package/dist/templates/react-app/src/App.tsx +15 -42
  196. package/dist/templates/react-app/src/base/apis/AiApi.ts +5 -5
  197. package/dist/templates/react-app/src/base/apis/feApi/FeApi.ts +1 -1
  198. package/dist/templates/react-app/src/base/apis/feApi/FeApiAdapter.ts +1 -1
  199. package/dist/templates/react-app/src/base/apis/feApi/FeApiBootstarp.ts +8 -8
  200. package/dist/templates/react-app/src/base/apis/feApi/FeApiType.ts +1 -1
  201. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +6 -6
  202. package/dist/templates/react-app/src/base/apis/userApi/UserApiAdapter.ts +1 -1
  203. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +12 -14
  204. package/dist/templates/react-app/src/base/apis/userApi/UserApiType.ts +1 -1
  205. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +5 -2
  206. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +3 -3
  207. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +3 -3
  208. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +2 -2
  209. package/dist/templates/react-app/src/base/cases/RequestLogger.ts +4 -4
  210. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +1 -1
  211. package/dist/templates/react-app/src/base/cases/ResourceState.ts +23 -0
  212. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +4 -4
  213. package/dist/templates/react-app/src/base/cases/TranslateI18nInterface.ts +26 -0
  214. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +2 -3
  215. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +1 -1
  216. package/dist/templates/react-app/src/base/port/IOCInterface.ts +36 -0
  217. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +2 -1
  218. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +1 -1
  219. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +2 -2
  220. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +9 -5
  221. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +1 -1
  222. package/dist/templates/react-app/src/base/services/I18nService.ts +29 -29
  223. package/dist/templates/react-app/src/base/services/IdentifierService.ts +143 -0
  224. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +3 -3
  225. package/dist/templates/react-app/src/base/services/RouteService.ts +27 -8
  226. package/dist/templates/react-app/src/base/services/UserService.ts +8 -8
  227. package/dist/templates/react-app/src/base/types/Page.ts +14 -2
  228. package/dist/templates/react-app/src/base/types/global.d.ts +1 -1
  229. package/dist/templates/react-app/src/core/IOC.ts +5 -46
  230. package/dist/templates/react-app/src/core/bootstraps/{BootstrapApp.ts → BootstrapClient.ts} +44 -17
  231. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +14 -7
  232. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +1 -1
  233. package/dist/templates/react-app/src/core/bootstraps/PrintBootstrap.ts +1 -1
  234. package/dist/templates/react-app/src/core/clientIoc/ClientIOC.ts +40 -0
  235. package/dist/templates/react-app/src/core/{IocRegisterImpl.ts → clientIoc/ClientIOCRegister.ts} +35 -24
  236. package/dist/templates/react-app/src/core/globals.ts +9 -9
  237. package/dist/templates/react-app/src/main.tsx +4 -4
  238. package/dist/templates/react-app/src/pages/404.tsx +6 -3
  239. package/dist/templates/react-app/src/pages/500.tsx +5 -2
  240. package/dist/templates/react-app/src/pages/NoRouteFound.tsx +5 -0
  241. package/dist/templates/react-app/src/pages/auth/Layout.tsx +9 -6
  242. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +46 -56
  243. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +46 -58
  244. package/dist/templates/react-app/src/pages/base/AboutPage.tsx +35 -40
  245. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +51 -51
  246. package/dist/templates/react-app/src/pages/base/HomePage.tsx +14 -15
  247. package/dist/templates/react-app/src/pages/base/IdentifierPage.tsx +70 -11
  248. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +24 -25
  249. package/dist/templates/react-app/src/pages/base/Layout.tsx +2 -2
  250. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +3 -2
  251. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +41 -59
  252. package/dist/templates/react-app/src/styles/css/antd-themes/{_default.css → _common/_default.css} +85 -0
  253. package/dist/templates/react-app/src/styles/css/antd-themes/{dark.css → _common/dark.css} +99 -0
  254. package/dist/templates/react-app/src/styles/css/antd-themes/_common/index.css +3 -0
  255. package/dist/templates/react-app/src/styles/css/antd-themes/{pink.css → _common/pink.css} +86 -0
  256. package/dist/templates/react-app/src/styles/css/antd-themes/index.css +4 -3
  257. package/dist/templates/react-app/src/styles/css/antd-themes/menu/_default.css +108 -0
  258. package/dist/templates/react-app/src/styles/css/antd-themes/menu/dark.css +67 -0
  259. package/dist/templates/react-app/src/styles/css/antd-themes/menu/index.css +3 -0
  260. package/dist/templates/react-app/src/styles/css/antd-themes/menu/pink.css +67 -0
  261. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/_default.css +34 -0
  262. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/dark.css +31 -0
  263. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/index.css +3 -0
  264. package/dist/templates/react-app/src/styles/css/antd-themes/pagination/pink.css +36 -0
  265. package/dist/templates/react-app/src/styles/css/antd-themes/table/_default.css +44 -0
  266. package/dist/templates/react-app/src/styles/css/antd-themes/table/dark.css +43 -0
  267. package/dist/templates/react-app/src/styles/css/antd-themes/table/index.css +3 -0
  268. package/dist/templates/react-app/src/styles/css/antd-themes/table/pink.css +43 -0
  269. package/dist/templates/react-app/src/styles/css/page.css +4 -3
  270. package/dist/templates/react-app/src/styles/css/themes/_default.css +1 -0
  271. package/dist/templates/react-app/src/styles/css/themes/dark.css +1 -0
  272. package/dist/templates/react-app/src/styles/css/themes/pink.css +1 -0
  273. package/dist/templates/react-app/src/styles/css/zIndex.css +1 -1
  274. package/dist/templates/react-app/src/uikit/bridges/ExecutorPageBridge.ts +3 -3
  275. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +2 -2
  276. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +1 -1
  277. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +3 -3
  278. package/dist/templates/react-app/src/uikit/components/AppRouterProvider.tsx +35 -0
  279. package/dist/templates/react-app/src/uikit/components/BaseHeader.tsx +15 -11
  280. package/dist/templates/react-app/src/uikit/components/BaseRouteProvider.tsx +14 -11
  281. package/dist/templates/react-app/src/uikit/components/BaseRouteSeo.tsx +18 -0
  282. package/dist/templates/react-app/src/uikit/components/BootstrapsProvider.tsx +13 -0
  283. package/dist/templates/react-app/src/uikit/components/ClientSeo.tsx +62 -0
  284. package/dist/templates/react-app/src/uikit/components/ComboProvider.tsx +38 -0
  285. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +48 -27
  286. package/dist/templates/react-app/src/uikit/components/Loading.tsx +4 -2
  287. package/dist/templates/react-app/src/uikit/components/LocaleLink.tsx +4 -5
  288. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +34 -11
  289. package/dist/templates/react-app/src/uikit/components/ProcessExecutorProvider.tsx +9 -5
  290. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +6 -3
  291. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +97 -40
  292. package/dist/templates/react-app/src/uikit/components/UserAuthProvider.tsx +5 -5
  293. package/dist/templates/react-app/src/uikit/components/With.tsx +17 -0
  294. package/dist/templates/react-app/src/uikit/contexts/BaseRouteContext.ts +17 -11
  295. package/dist/templates/react-app/src/uikit/contexts/IOCContext.ts +13 -0
  296. package/dist/templates/react-app/src/uikit/hooks/useAppTranslation.ts +26 -0
  297. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +8 -11
  298. package/dist/templates/react-app/src/uikit/hooks/useI18nInterface.ts +25 -0
  299. package/dist/templates/react-app/src/uikit/hooks/useIOC.ts +35 -0
  300. package/dist/templates/react-app/src/uikit/hooks/useNavigateBridge.ts +3 -3
  301. package/dist/templates/react-app/src/uikit/hooks/useStrictEffect.ts +0 -1
  302. package/dist/templates/react-app/tsconfig.e2e.json +21 -0
  303. package/dist/templates/react-app/tsconfig.json +8 -1
  304. package/dist/templates/react-app/tsconfig.node.json +1 -1
  305. package/dist/templates/react-app/tsconfig.test.json +3 -1
  306. package/dist/templates/react-app/vite.config.ts +50 -34
  307. package/package.json +2 -1
  308. package/dist/configs/react-app/eslint.config.js +0 -94
  309. package/dist/templates/next-app/config/Identifier/common.error.ts +0 -41
  310. package/dist/templates/next-app/config/Identifier/common.ts +0 -69
  311. package/dist/templates/next-app/config/Identifier/page.about.ts +0 -181
  312. package/dist/templates/next-app/config/Identifier/page.admin.ts +0 -48
  313. package/dist/templates/next-app/config/Identifier/page.executor.ts +0 -272
  314. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +0 -39
  315. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +0 -72
  316. package/dist/templates/next-app/config/Identifier/page.request.ts +0 -182
  317. package/dist/templates/next-app/src/base/cases/ChatAction.ts +0 -21
  318. package/dist/templates/next-app/src/base/cases/FocusBarAction.ts +0 -36
  319. package/dist/templates/next-app/src/base/cases/RequestState.ts +0 -20
  320. package/dist/templates/next-app/src/base/port/AdminPageInterface.ts +0 -85
  321. package/dist/templates/next-app/src/base/port/AsyncStateInterface.ts +0 -7
  322. package/dist/templates/next-app/src/base/services/AdminUserService.ts +0 -45
  323. package/dist/templates/next-app/src/uikit/components/ChatRoot.tsx +0 -17
  324. package/dist/templates/next-app/src/uikit/components/chat/ChatActionInterface.ts +0 -30
  325. package/dist/templates/next-app/src/uikit/components/chat/ChatFocusBar.tsx +0 -65
  326. package/dist/templates/next-app/src/uikit/components/chat/ChatMessages.tsx +0 -59
  327. package/dist/templates/next-app/src/uikit/components/chat/ChatWrap.tsx +0 -28
  328. package/dist/templates/next-app/src/uikit/components/chat/FocusBarActionInterface.ts +0 -19
  329. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +0 -17
  330. package/dist/templates/next-app/src/uikit/hook/useStore.ts +0 -15
  331. package/dist/templates/react-app/__tests__/__mocks__/I18nService.ts +0 -13
  332. package/dist/templates/react-app/__tests__/src/App.test.tsx +0 -139
  333. package/dist/templates/react-app/config/Identifier/page.identifiter.ts +0 -39
  334. package/dist/templates/react-app/config/i18n.ts +0 -15
  335. package/dist/templates/react-app/docs/en/project-structure.md +0 -434
  336. package/dist/templates/react-app/docs/zh/project-structure.md +0 -434
  337. package/dist/templates/react-app/src/base/cases/RequestState.ts +0 -20
  338. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +0 -7
  339. package/dist/templates/react-app/src/uikit/hooks/useDocumentTitle.ts +0 -15
  340. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +0 -15
@@ -1,32 +1,31 @@
1
1
  [data-theme='dark'],
2
- [data-theme='dark'] .fe-theme {
2
+ [data-theme='dark'] .fe-theme .ant-pagination-css-var,
3
+ [data-theme='dark'] .fe-theme.ant-pagination {
3
4
  /* Antd Pagination 组件变量 */
4
- .ant-pagination-css-var {
5
- --fe-pagination-item-bg: rgb(var(--color-bg-secondary));
6
- --fe-pagination-item-size: 32px;
7
- --fe-pagination-item-size-sm: 24px;
8
- --fe-pagination-item-active-bg: rgb(var(--color-bg-secondary));
9
- --fe-pagination-item-link-bg: rgb(var(--color-bg-secondary));
10
- --fe-pagination-item-active-color-disabled: rgb(var(--text-tertiary));
11
- --fe-pagination-item-active-bg-disabled: rgba(var(--text-primary), 0.15);
12
- --fe-pagination-item-input-bg: rgb(var(--color-bg-secondary));
13
- --fe-pagination-mini-options-size-changer-top: 0px;
14
- --fe-pagination-padding-block: 4px;
15
- --fe-pagination-padding-block-sm: 0px;
16
- --fe-pagination-padding-block-lg: 7px;
17
- --fe-pagination-padding-inline: 11px;
18
- --fe-pagination-padding-inline-sm: 7px;
19
- --fe-pagination-padding-inline-lg: 11px;
20
- --fe-pagination-addon-bg: rgba(var(--text-primary), 0.02);
21
- --fe-pagination-active-border-color: rgb(var(--color-brand));
22
- --fe-pagination-hover-border-color: rgb(var(--color-brand-hover));
23
- --fe-pagination-active-shadow: 0 0 0 2px rgba(var(--color-brand), 0.2);
24
- --fe-pagination-error-active-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
25
- --fe-pagination-warning-active-shadow: 0 0 0 2px rgba(245, 158, 11, 0.2);
26
- --fe-pagination-hover-bg: rgb(var(--color-bg-elevated));
27
- --fe-pagination-active-bg: rgb(var(--color-bg-elevated));
28
- --fe-pagination-input-font-size: 14px;
29
- --fe-pagination-input-font-size-lg: 16px;
30
- --fe-pagination-input-font-size-sm: 14px;
31
- }
5
+ --fe-pagination-item-bg: rgb(var(--color-bg-secondary));
6
+ --fe-pagination-item-size: 32px;
7
+ --fe-pagination-item-size-sm: 24px;
8
+ --fe-pagination-item-active-bg: rgb(var(--color-bg-secondary));
9
+ --fe-pagination-item-link-bg: rgb(var(--color-bg-secondary));
10
+ --fe-pagination-item-active-color-disabled: rgb(var(--text-tertiary));
11
+ --fe-pagination-item-active-bg-disabled: rgba(var(--text-primary), 0.15);
12
+ --fe-pagination-item-input-bg: rgb(var(--color-bg-secondary));
13
+ --fe-pagination-mini-options-size-changer-top: 0px;
14
+ --fe-pagination-padding-block: 4px;
15
+ --fe-pagination-padding-block-sm: 0px;
16
+ --fe-pagination-padding-block-lg: 7px;
17
+ --fe-pagination-padding-inline: 11px;
18
+ --fe-pagination-padding-inline-sm: 7px;
19
+ --fe-pagination-padding-inline-lg: 11px;
20
+ --fe-pagination-addon-bg: rgba(var(--text-primary), 0.02);
21
+ --fe-pagination-active-border-color: rgb(var(--color-brand));
22
+ --fe-pagination-hover-border-color: rgb(var(--color-brand-hover));
23
+ --fe-pagination-active-shadow: 0 0 0 2px rgba(var(--color-brand), 0.2);
24
+ --fe-pagination-error-active-shadow: 0 0 0 2px rgba(239, 68, 68, 0.2);
25
+ --fe-pagination-warning-active-shadow: 0 0 0 2px rgba(245, 158, 11, 0.2);
26
+ --fe-pagination-hover-bg: rgb(var(--color-bg-elevated));
27
+ --fe-pagination-active-bg: rgb(var(--color-bg-elevated));
28
+ --fe-pagination-input-font-size: 14px;
29
+ --fe-pagination-input-font-size-lg: 16px;
30
+ --fe-pagination-input-font-size-sm: 14px;
32
31
  }
@@ -1,5 +1,6 @@
1
1
  [data-theme='pink'],
2
- [data-theme='pink'] .fe-theme {
2
+ [data-theme='pink'] .fe-theme .ant-pagination-css-var,
3
+ [data-theme='pink'] .fe-theme.ant-pagination {
3
4
  /* Antd Pagination 组件变量 */
4
5
  .ant-pagination-css-var {
5
6
  --fe-pagination-item-bg: var(--ant-color-bg-container);
@@ -2,12 +2,15 @@
2
2
 
3
3
  import {
4
4
  DashboardOutlined,
5
+ GlobalOutlined,
5
6
  UserOutlined,
6
7
  VerticalAlignBottomOutlined,
7
8
  VerticalAlignTopOutlined
8
9
  } from '@ant-design/icons';
10
+ import { useStore } from '@brain-toolkit/react-kit';
9
11
  import { Layout, Menu } from 'antd';
10
12
  import { clsx } from 'clsx';
13
+ import { usePathname } from 'next/navigation';
11
14
  import React, { useMemo, type HTMLAttributes } from 'react';
12
15
  import { AdminPageManager } from '@/base/cases/AdminPageManager';
13
16
  import { BaseHeader } from './BaseHeader';
@@ -16,14 +19,14 @@ import { LocaleLink } from './LocaleLink';
16
19
  import { LogoutButton } from './LogoutButton';
17
20
  import { ThemeSwitcher } from './ThemeSwitcher';
18
21
  import { useIOC } from '../hook/useIOC';
19
- import { useStore } from '../hook/useStore';
20
22
  import type { ItemType } from 'antd/es/menu/interface';
21
23
 
22
24
  const { Sider } = Layout;
23
25
 
24
26
  const IconMap = {
25
27
  dashboard: <DashboardOutlined />,
26
- users: <UserOutlined />
28
+ users: <UserOutlined />,
29
+ locales: <GlobalOutlined />
27
30
  };
28
31
 
29
32
  export interface AdminLayoutProps extends HTMLAttributes<HTMLDivElement> {
@@ -34,10 +37,17 @@ export interface AdminLayoutProps extends HTMLAttributes<HTMLDivElement> {
34
37
  export function AdminLayout(props: AdminLayoutProps) {
35
38
  const { children, className, mainClassName, ...rest } = props;
36
39
 
40
+ const pathname = usePathname();
37
41
  const page = useIOC(AdminPageManager);
38
42
  const collapsedSidebar = useStore(page, page.selectors.collapsedSidebar);
39
43
  const navItems = useStore(page, page.selectors.navItems);
40
44
 
45
+ const selectedKey = useMemo(() => {
46
+ // 移除语言前缀,例如 /en/admin/users -> /admin/users
47
+ const normalizedPath = pathname.replace(/^\/[^/]+/, '');
48
+ return navItems.find((item) => item.pathname === normalizedPath)?.key || '';
49
+ }, [pathname, navItems]);
50
+
41
51
  const sidebarItems = useMemo(() => {
42
52
  return navItems.map((item) => {
43
53
  // TODO: use i18n
@@ -78,7 +88,11 @@ export function AdminLayout(props: AdminLayoutProps) {
78
88
  collapsed={collapsedSidebar}
79
89
  collapsedWidth={46}
80
90
  >
81
- <Menu mode="inline" items={sidebarItems} />
91
+ <Menu
92
+ mode="inline"
93
+ items={sidebarItems}
94
+ selectedKeys={selectedKey ? [selectedKey] : []}
95
+ />
82
96
 
83
97
  <div
84
98
  data-testid="ToggleSidebarButton"
@@ -1,12 +1,13 @@
1
1
  'use client';
2
2
 
3
3
  import { clsx } from 'clsx';
4
- import { useLocale, useTranslations } from 'next-intl';
4
+ import { useLocale } from 'next-intl';
5
5
  import { useMemo } from 'react';
6
6
  import { useIOC } from '@/uikit/hook/useIOC';
7
- import { PAGE_HEAD_ADMIN_TITLE } from '@config/Identifier';
7
+ import { COMMON_ADMIN_TITLE } from '@config/Identifier';
8
8
  import { IOCIdentifier } from '@config/IOCIdentifier';
9
9
  import { LocaleLink } from './LocaleLink';
10
+ import { useWarnTranslations } from '../hook/useWarnTranslations';
10
11
 
11
12
  export type RenderLeftFunction = (props: {
12
13
  locale: string;
@@ -22,11 +23,11 @@ export function BaseHeader(props: {
22
23
  const { href = '/', className, renderLeft, rightActions } = props;
23
24
  const appConfig = useIOC(IOCIdentifier.AppConfig);
24
25
  const locale = useLocale();
25
- const t = useTranslations();
26
+ const t = useWarnTranslations();
26
27
 
27
28
  const tt = {
28
29
  title: appConfig.appName,
29
- admin: t(PAGE_HEAD_ADMIN_TITLE)
30
+ admin: t(COMMON_ADMIN_TITLE)
30
31
  };
31
32
 
32
33
  const leftDefault = useMemo(
@@ -1,12 +1,13 @@
1
1
  import { TeamOutlined } from '@ant-design/icons';
2
- import { useLocale, useTranslations } from 'next-intl';
2
+ import { useLocale } from 'next-intl';
3
3
  import { useMemo, type HTMLAttributes } from 'react';
4
- import { PAGE_HEAD_ADMIN_TITLE } from '@config/Identifier';
4
+ import { COMMON_ADMIN_TITLE } from '@config/Identifier';
5
5
  import { BaseHeader } from './BaseHeader';
6
6
  import { LanguageSwitcher } from './LanguageSwitcher';
7
7
  import { LocaleLink } from './LocaleLink';
8
8
  import { LogoutButton } from './LogoutButton';
9
9
  import { ThemeSwitcher } from './ThemeSwitcher';
10
+ import { useWarnTranslations } from '../hook/useWarnTranslations';
10
11
 
11
12
  export interface BaseLayoutProps extends HTMLAttributes<HTMLDivElement> {
12
13
  showLogoutButton?: boolean;
@@ -22,10 +23,10 @@ export function BaseLayout({
22
23
  ...props
23
24
  }: BaseLayoutProps) {
24
25
  const locale = useLocale();
25
- const t = useTranslations();
26
+ const t = useWarnTranslations();
26
27
 
27
28
  const tt = {
28
- admin: t(PAGE_HEAD_ADMIN_TITLE)
29
+ admin: t(COMMON_ADMIN_TITLE)
29
30
  };
30
31
 
31
32
  const actions = useMemo(
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import '@ant-design/v5-patch-for-react-19';
3
3
  import { useRouter } from 'next/navigation';
4
- import { useLocale, useTranslations } from 'next-intl';
4
+ import { useLocale } from 'next-intl';
5
5
  import { useEffect } from 'react';
6
6
  import { NavigateBridge } from '@/base/cases/NavigateBridge';
7
7
  import type { I18nServiceLocale } from '@/base/port/I18nServiceInterface';
@@ -9,12 +9,13 @@ import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
9
9
  import { clientIOC } from '@/core/clientIoc/ClientIOC';
10
10
  import { I } from '@config/IOCIdentifier';
11
11
  import { IOCContext } from '../context/IOCContext';
12
+ import { useWarnTranslations } from '../hook/useWarnTranslations';
12
13
 
13
14
  export function BootstrapsProvider(props: { children: React.ReactNode }) {
14
15
  const IOC = clientIOC.create();
15
16
  const locale = useLocale();
16
17
  const router = useRouter();
17
- const t = useTranslations();
18
+ const t = useWarnTranslations();
18
19
 
19
20
  useEffect(() => {
20
21
  IOC(I.RouterServiceInterface).setLocale(locale);
@@ -2,12 +2,12 @@
2
2
  import '@ant-design/v5-patch-for-react-19';
3
3
  import { AntdRegistry } from '@ant-design/nextjs-registry';
4
4
  import { AntdThemeProvider } from '@brain-toolkit/antd-theme-override/react';
5
+ import { useMountedClient } from '@brain-toolkit/react-kit';
5
6
  import { ThemeProvider } from 'next-themes';
6
7
  import { clientIOC } from '@/core/clientIoc/ClientIOC';
7
8
  import { IOCIdentifier } from '@config/IOCIdentifier';
8
9
  import type { CommonThemeConfig } from '@config/theme';
9
10
  import { BootstrapsProvider } from './BootstrapsProvider';
10
- import { useMountedClient } from '../hook/useMountedClient';
11
11
 
12
12
  /**
13
13
  * CommonProvider is a provider for the common components
@@ -0,0 +1,118 @@
1
+ 'use client';
2
+
3
+ import {
4
+ EditOutlined,
5
+ CheckOutlined,
6
+ CloseOutlined,
7
+ LoadingOutlined
8
+ } from '@ant-design/icons';
9
+ import { Button, Input } from 'antd';
10
+ import { clsx } from 'clsx';
11
+ import { useState, useRef, useEffect } from 'react';
12
+ import type { InputRef } from 'antd/lib/input';
13
+
14
+ interface EditableCellProps {
15
+ value: string;
16
+ className?: string;
17
+ onSave?: (value: string) => Promise<unknown> | unknown;
18
+ }
19
+
20
+ export const EditableCell: React.FC<EditableCellProps> = ({
21
+ value,
22
+ className,
23
+ onSave
24
+ }) => {
25
+ const [editing, setEditing] = useState(false);
26
+ const [loading, setLoading] = useState(false);
27
+ const [inputValue, setInputValue] = useState(value);
28
+ const inputRef = useRef<InputRef>(null);
29
+
30
+ useEffect(() => {
31
+ if (editing) {
32
+ inputRef.current?.focus();
33
+ }
34
+ }, [editing]);
35
+
36
+ const handleEdit = () => {
37
+ if (loading) return;
38
+ setEditing(true);
39
+ setInputValue(value);
40
+ };
41
+
42
+ const handleSave = async () => {
43
+ if (loading) return;
44
+ if (onSave && inputValue !== value) {
45
+ setLoading(true);
46
+ try {
47
+ await onSave(inputValue);
48
+ setEditing(false);
49
+ } catch (error) {
50
+ console.error(error);
51
+ } finally {
52
+ setLoading(false);
53
+ }
54
+ }
55
+ };
56
+
57
+ const handleCancel = () => {
58
+ if (loading) return;
59
+ setEditing(false);
60
+ setInputValue(value);
61
+ };
62
+
63
+ if (editing) {
64
+ return (
65
+ <div
66
+ data-testid="EditableCellContainer"
67
+ className="flex w-full items-center"
68
+ >
69
+ <Input
70
+ data-testid="EditableCellInput"
71
+ disabled={loading}
72
+ ref={inputRef}
73
+ value={inputValue}
74
+ onChange={(e) => setInputValue(e.target.value)}
75
+ onPressEnter={handleSave}
76
+ onBlur={handleSave}
77
+ />
78
+ <div data-testid="EditableCellActions" className="flex gap-0.5 ">
79
+ <Button
80
+ disabled={loading}
81
+ className="cursor-pointer flex items-center justify-center w-5 h-5 rounded hover:bg-gray-100 text-gray-400 hover:text-blue-500 transition-colors"
82
+ onClick={handleSave}
83
+ >
84
+ {loading ? <LoadingOutlined /> : <CheckOutlined />}
85
+ </Button>
86
+ <Button
87
+ disabled={loading}
88
+ className="cursor-pointer flex items-center justify-center w-5 h-5 rounded hover:bg-gray-100 text-gray-400 hover:text-blue-500 transition-colors"
89
+ onClick={handleCancel}
90
+ >
91
+ <CloseOutlined />
92
+ </Button>
93
+ </div>
94
+ </div>
95
+ );
96
+ }
97
+
98
+ return (
99
+ <div
100
+ data-testid="EditableCellSpan"
101
+ className={clsx(
102
+ 'group flex items-center relative py-0.5 px-1 w-full max-w-48',
103
+ className
104
+ )}
105
+ onDoubleClick={handleEdit}
106
+ >
107
+ <span title={value} className="truncate flex-1">
108
+ {value}
109
+ </span>
110
+ <span
111
+ onClick={handleEdit}
112
+ className="opacity-0 group-hover:opacity-100 transition-opacity duration-200 cursor-pointer ml-2 text-gray-400 hover:text-blue-500"
113
+ >
114
+ <EditOutlined className="text-sm" />
115
+ </span>
116
+ </div>
117
+ );
118
+ };
@@ -3,10 +3,9 @@
3
3
  import { LogoutOutlined } from '@ant-design/icons';
4
4
  import { Tooltip } from 'antd';
5
5
  import { useCallback } from 'react';
6
- import type { PageI18nInterface } from '@config/i18n';
7
6
  import {
8
- AUTH_LOGOUT_DIALOG_CONTENT,
9
- AUTH_LOGOUT_DIALOG_TITLE
7
+ COMMON_LOGOUT_DIALOG_CONTENT,
8
+ COMMON_LOGOUT_DIALOG_TITLE
10
9
  } from '@config/Identifier';
11
10
  import { I } from '@config/IOCIdentifier';
12
11
  import { useI18nInterface } from '../hook/useI18nInterface';
@@ -18,9 +17,9 @@ export function LogoutButton() {
18
17
  const routerService = useIOC(I.RouterServiceInterface);
19
18
 
20
19
  const tt = useI18nInterface({
21
- title: AUTH_LOGOUT_DIALOG_TITLE,
22
- content: AUTH_LOGOUT_DIALOG_CONTENT
23
- } as PageI18nInterface);
20
+ title: COMMON_LOGOUT_DIALOG_TITLE,
21
+ content: COMMON_LOGOUT_DIALOG_CONTENT
22
+ });
24
23
 
25
24
  const onClick = useCallback(() => {
26
25
  dialogHandler.confirm({
@@ -10,12 +10,12 @@ import {
10
10
  MoonFilled,
11
11
  HeartOutlined
12
12
  } from '@ant-design/icons';
13
+ import { useMountedClient } from '@brain-toolkit/react-kit';
13
14
  import { Dropdown } from 'antd';
14
15
  import { clsx } from 'clsx';
15
16
  import { useTheme } from 'next-themes';
16
17
  import { useMemo } from 'react';
17
18
  import { type SupportedTheme, themeConfig } from '@config/theme';
18
- import { useMountedClient } from '../hook/useMountedClient';
19
19
  import type { ItemType } from 'antd/es/menu/interface';
20
20
 
21
21
  const { supportedThemes } = themeConfig;
@@ -5,9 +5,9 @@ export function With<T>(props: {
5
5
  }) {
6
6
  const { fallback, it, children } = props;
7
7
 
8
- if (it) {
8
+ if (it != null && it !== false) {
9
9
  if (typeof children === 'function') {
10
- return children(it);
10
+ return children(it as NonNullable<T>);
11
11
  }
12
12
 
13
13
  return children;
@@ -0,0 +1,62 @@
1
+ import { UploadOutlined } from '@ant-design/icons';
2
+ import { Button, Upload, Popover } from 'antd';
3
+ import type { LocaleType } from '@config/i18n';
4
+ import { i18nConfig } from '@config/i18n';
5
+ import css from './import.module.css';
6
+ import type { LocalesImportEvent } from './LocalesImportEvent';
7
+
8
+ interface LocalesImportButtonProps {
9
+ event: LocalesImportEvent;
10
+ title: string;
11
+ tt: {
12
+ [key in LocaleType]: {
13
+ title: string;
14
+ };
15
+ };
16
+ }
17
+
18
+ export function LocalesImportButton({
19
+ event,
20
+ title,
21
+ tt
22
+ }: LocalesImportButtonProps) {
23
+ const importPanel = (
24
+ <div className="flex flex-col gap-2">
25
+ {i18nConfig.supportedLngs.map((key) => {
26
+ const targetTT = tt[key];
27
+
28
+ return (
29
+ <Upload
30
+ className={css.uploadRoot}
31
+ key={key}
32
+ data-testid={`LocalesImportButton${key}`}
33
+ accept=".json"
34
+ maxCount={1}
35
+ showUploadList={false}
36
+ beforeUpload={(file) => {
37
+ event.onImport(key as LocaleType, file);
38
+ return false;
39
+ }}
40
+ >
41
+ <Button block data-testid="LocalesImportButtonEn">
42
+ {targetTT.title}
43
+ </Button>
44
+ </Upload>
45
+ );
46
+ })}
47
+ </div>
48
+ );
49
+
50
+ return (
51
+ <Popover
52
+ data-testid="LocalesImportPopover"
53
+ content={importPanel}
54
+ trigger={['click']}
55
+ >
56
+ <Button data-testid="LocalesImportButton">
57
+ <UploadOutlined />
58
+ {title}
59
+ </Button>
60
+ </Popover>
61
+ );
62
+ }
@@ -0,0 +1,28 @@
1
+ import { StoreInterface } from '@qlover/corekit-bridge';
2
+ import type { AdminLocalesApi } from '@/base/services/adminApi/AdminLocalesApi';
3
+ import type { LocaleType } from '@config/i18n';
4
+ import type { StoreStateInterface } from '@qlover/corekit-bridge';
5
+
6
+ export class LocalesImportEventState implements StoreStateInterface {}
7
+
8
+ export class LocalesImportEvent extends StoreInterface<LocalesImportEventState> {
9
+ constructor(protected localesApi: AdminLocalesApi) {
10
+ super(() => new LocalesImportEventState());
11
+ }
12
+
13
+ protected validate(file: File): void {
14
+ if (file.type !== 'application/json') {
15
+ throw new Error('File must be a JSON file');
16
+ }
17
+ }
18
+
19
+ async onImport(type: LocaleType, file: File): Promise<void> {
20
+ try {
21
+ this.validate(file);
22
+
23
+ await this.localesApi.import({ [type]: file });
24
+ } catch (error) {
25
+ console.log(error);
26
+ }
27
+ }
28
+ }
@@ -0,0 +1,6 @@
1
+ .uploadRoot {
2
+ width: 100%;
3
+ :global(.ant-upload) {
4
+ width: 100%;
5
+ }
6
+ }
@@ -1,6 +1,6 @@
1
- import { useTranslations } from 'next-intl';
2
1
  import { useMemo } from 'react';
3
- import type { PageI18nInterface } from '@config/i18n/PageI18nInterface';
2
+ import { TranslateI18nInterface } from '@/base/cases/TranslateI18nInterface';
3
+ import { useWarnTranslations } from './useWarnTranslations';
4
4
 
5
5
  /**
6
6
  * Hook to get the i18n interface
@@ -8,21 +8,15 @@ import type { PageI18nInterface } from '@config/i18n/PageI18nInterface';
8
8
  * @param i18nInterface - The i18n interface to get
9
9
  * @returns The i18n interface
10
10
  */
11
- export function useI18nInterface<T extends PageI18nInterface>(
11
+ export function useI18nInterface<T extends Record<string, string>>(
12
12
  i18nInterface: T
13
13
  ): T {
14
- const t = useTranslations();
14
+ const t = useWarnTranslations();
15
15
 
16
- const i18n = useMemo(() => {
17
- return Object.fromEntries(
18
- Object.entries(i18nInterface).map(([key, value]) => {
19
- if (typeof value === 'string') {
20
- return [key, t(value)];
21
- }
22
- return [key, value];
23
- })
24
- ) as T;
25
- }, [i18nInterface, t]);
16
+ const i18n = useMemo(
17
+ () => TranslateI18nInterface.translate(i18nInterface, t),
18
+ [i18nInterface, t]
19
+ );
26
20
 
27
21
  return i18n;
28
22
  }
@@ -0,0 +1,25 @@
1
+ import { useTranslations as useNextTranslations } from 'next-intl';
2
+ import { useCallback } from 'react';
3
+ import { i18nWarnMissingTranslation } from '@config/common';
4
+
5
+ export function useWarnTranslations() {
6
+ const t = useNextTranslations();
7
+
8
+ const overrideT = useCallback(
9
+ (key: string) => {
10
+ if (!i18nWarnMissingTranslation) {
11
+ return t(key);
12
+ }
13
+
14
+ if (t.has(key)) {
15
+ return t(key);
16
+ }
17
+
18
+ console.warn(`[i18n] Missing translation: ${key}`);
19
+ return key;
20
+ },
21
+ [t]
22
+ );
23
+
24
+ return Object.assign(overrideT, t);
25
+ }
@@ -0,0 +1,17 @@
1
+ # Build output
2
+ dist
3
+ dist/**
4
+
5
+ # Dependencies
6
+ node_modules
7
+
8
+ # Generated files
9
+ public/locales/**
10
+
11
+ # Coverage
12
+ coverage
13
+
14
+ # Playwright reports
15
+ playwright-report
16
+ test-results
17
+