@qlover/create-app 0.7.5 → 0.7.7

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 (166) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +1 -1
  4. package/dist/templates/next-app/.env.template +22 -0
  5. package/dist/templates/next-app/.prettierignore +58 -0
  6. package/dist/templates/next-app/README.md +36 -0
  7. package/dist/templates/next-app/build/generateLocales.ts +25 -0
  8. package/dist/templates/next-app/config/IOCIdentifier.ts +45 -0
  9. package/dist/templates/next-app/config/Identifier/common.error.ts +34 -0
  10. package/dist/templates/next-app/config/Identifier/common.ts +62 -0
  11. package/dist/templates/next-app/config/Identifier/index.ts +10 -0
  12. package/dist/templates/next-app/config/Identifier/page.about.ts +181 -0
  13. package/dist/templates/next-app/config/Identifier/page.executor.ts +272 -0
  14. package/dist/templates/next-app/config/Identifier/page.home.ts +63 -0
  15. package/dist/templates/next-app/config/Identifier/page.identifiter.ts +39 -0
  16. package/dist/templates/next-app/config/Identifier/page.jsonStorage.ts +72 -0
  17. package/dist/templates/next-app/config/Identifier/page.login.ts +165 -0
  18. package/dist/templates/next-app/config/Identifier/page.register.ts +147 -0
  19. package/dist/templates/next-app/config/Identifier/page.request.ts +182 -0
  20. package/dist/templates/next-app/config/common.ts +34 -0
  21. package/dist/templates/next-app/config/i18n/PageI18nInterface.ts +51 -0
  22. package/dist/templates/next-app/config/i18n/i18nConfig.ts +12 -0
  23. package/dist/templates/next-app/config/i18n/index.ts +3 -0
  24. package/dist/templates/next-app/config/i18n/loginI18n.ts +42 -0
  25. package/dist/templates/next-app/config/theme.ts +23 -0
  26. package/dist/templates/next-app/docs/env.md +94 -0
  27. package/dist/templates/next-app/eslint.config.mjs +181 -0
  28. package/dist/templates/next-app/next.config.ts +21 -0
  29. package/dist/templates/next-app/package.json +58 -0
  30. package/dist/templates/next-app/plugins/eslint-plugin-testid.mjs +94 -0
  31. package/dist/templates/next-app/plugins/generateLocalesPlugin.ts +33 -0
  32. package/dist/templates/next-app/postcss.config.mjs +5 -0
  33. package/dist/templates/next-app/public/file.svg +1 -0
  34. package/dist/templates/next-app/public/globe.svg +1 -0
  35. package/dist/templates/next-app/public/locales/en/common.json +183 -0
  36. package/dist/templates/next-app/public/locales/zh/common.json +183 -0
  37. package/dist/templates/next-app/public/next.svg +1 -0
  38. package/dist/templates/next-app/public/vercel.svg +1 -0
  39. package/dist/templates/next-app/public/window.svg +1 -0
  40. package/dist/templates/next-app/src/app/[locale]/favicon.ico +0 -0
  41. package/dist/templates/next-app/src/app/[locale]/layout.tsx +44 -0
  42. package/dist/templates/next-app/src/app/[locale]/login/FeatureItem.tsx +13 -0
  43. package/dist/templates/next-app/src/app/[locale]/login/LoginForm.tsx +115 -0
  44. package/dist/templates/next-app/src/app/[locale]/login/page.tsx +73 -0
  45. package/dist/templates/next-app/src/app/[locale]/not-found.tsx +24 -0
  46. package/dist/templates/next-app/src/app/[locale]/page.tsx +106 -0
  47. package/dist/templates/next-app/src/base/cases/AppConfig.ts +15 -0
  48. package/dist/templates/next-app/src/base/cases/InversifyContainer.ts +33 -0
  49. package/dist/templates/next-app/src/base/port/I18nServiceInterface.ts +25 -0
  50. package/dist/templates/next-app/src/base/port/UserServiceInterface.ts +11 -0
  51. package/dist/templates/next-app/src/base/services/I18nService.ts +115 -0
  52. package/dist/templates/next-app/src/base/services/UserService.ts +23 -0
  53. package/dist/templates/next-app/src/core/IOC.ts +58 -0
  54. package/dist/templates/next-app/src/core/IocRegisterImpl.ts +100 -0
  55. package/dist/templates/next-app/src/core/bootstraps/BootstrapClient.ts +98 -0
  56. package/dist/templates/next-app/src/core/bootstraps/BootstrapsRegistry.ts +47 -0
  57. package/dist/templates/next-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
  58. package/dist/templates/next-app/src/core/bootstraps/PrintBootstrap.ts +18 -0
  59. package/dist/templates/next-app/src/core/globals.ts +21 -0
  60. package/dist/templates/next-app/src/i18n/request.ts +22 -0
  61. package/dist/templates/next-app/src/i18n/routing.ts +30 -0
  62. package/dist/templates/next-app/src/middleware.ts +22 -0
  63. package/dist/templates/next-app/src/server/getServerI18n.ts +26 -0
  64. package/dist/templates/next-app/src/styles/css/antd-themes/_default.css +239 -0
  65. package/dist/templates/next-app/src/styles/css/antd-themes/dark.css +178 -0
  66. package/dist/templates/next-app/src/styles/css/antd-themes/index.css +3 -0
  67. package/dist/templates/next-app/src/styles/css/antd-themes/no-context.css +34 -0
  68. package/dist/templates/next-app/src/styles/css/antd-themes/pink.css +204 -0
  69. package/dist/templates/next-app/src/styles/css/index.css +6 -0
  70. package/dist/templates/next-app/src/styles/css/page.css +19 -0
  71. package/dist/templates/next-app/src/styles/css/tailwind.css +5 -0
  72. package/dist/templates/next-app/src/styles/css/themes/_default.css +29 -0
  73. package/dist/templates/next-app/src/styles/css/themes/dark.css +29 -0
  74. package/dist/templates/next-app/src/styles/css/themes/index.css +3 -0
  75. package/dist/templates/next-app/src/styles/css/themes/pink.css +29 -0
  76. package/dist/templates/next-app/src/styles/css/zIndex.css +9 -0
  77. package/dist/templates/next-app/src/uikit/components/BaseHeader.tsx +42 -0
  78. package/dist/templates/next-app/src/uikit/components/BootstrapsProvider.tsx +25 -0
  79. package/dist/templates/next-app/src/uikit/components/ComboProvider.tsx +45 -0
  80. package/dist/templates/next-app/src/uikit/components/LanguageSwitcher.tsx +52 -0
  81. package/dist/templates/next-app/src/uikit/components/LocaleLink.tsx +51 -0
  82. package/dist/templates/next-app/src/uikit/components/NextIntlProvider.tsx +21 -0
  83. package/dist/templates/next-app/src/uikit/components/ThemeSwitcher.tsx +86 -0
  84. package/dist/templates/next-app/src/uikit/context/IOCContext.ts +6 -0
  85. package/dist/templates/next-app/src/uikit/hook/useI18nInterface.ts +28 -0
  86. package/dist/templates/next-app/src/uikit/hook/useIOC.ts +37 -0
  87. package/dist/templates/next-app/src/uikit/hook/useMountedClient.ts +11 -0
  88. package/dist/templates/next-app/src/uikit/hook/useStore.ts +15 -0
  89. package/dist/templates/next-app/tailwind.config.ts +8 -0
  90. package/dist/templates/next-app/tsconfig.json +36 -0
  91. package/dist/templates/react-app/.env.template +0 -2
  92. package/dist/templates/react-app/__tests__/src/base/services/I18nService.test.ts +1 -1
  93. package/dist/templates/react-app/__tests__/src/core/IOC.test.ts +6 -31
  94. package/dist/templates/react-app/__tests__/src/core/bootstraps/BootstrapsApp.test.ts +1 -1
  95. package/dist/templates/react-app/config/IOCIdentifier.ts +77 -5
  96. package/dist/templates/react-app/config/app.router.ts +2 -2
  97. package/dist/templates/react-app/package.json +4 -7
  98. package/dist/templates/react-app/public/locales/en/common.json +1 -1
  99. package/dist/templates/react-app/public/locales/zh/common.json +1 -1
  100. package/dist/templates/react-app/src/App.tsx +9 -4
  101. package/dist/templates/react-app/src/base/apis/userApi/UserApi.ts +1 -1
  102. package/dist/templates/react-app/src/base/apis/userApi/UserApiBootstarp.ts +4 -0
  103. package/dist/templates/react-app/src/base/cases/DialogHandler.ts +16 -13
  104. package/dist/templates/react-app/src/base/cases/I18nKeyErrorPlugin.ts +4 -3
  105. package/dist/templates/react-app/src/base/cases/InversifyContainer.ts +2 -2
  106. package/dist/templates/react-app/src/base/cases/RequestLanguages.ts +39 -0
  107. package/dist/templates/react-app/src/base/cases/RequestState.ts +20 -0
  108. package/dist/templates/react-app/src/base/cases/RequestStatusCatcher.ts +2 -2
  109. package/dist/templates/react-app/src/base/cases/RouterLoader.ts +8 -2
  110. package/dist/templates/react-app/src/base/port/AsyncStateInterface.ts +7 -0
  111. package/dist/templates/react-app/src/base/port/ExecutorPageBridgeInterface.ts +24 -0
  112. package/dist/templates/react-app/src/base/port/I18nServiceInterface.ts +10 -0
  113. package/dist/templates/react-app/src/base/port/JSONStoragePageBridgeInterface.ts +20 -0
  114. package/dist/templates/react-app/src/base/port/ProcesserExecutorInterface.ts +20 -0
  115. package/dist/templates/react-app/src/base/port/RequestPageBridgeInterface.ts +23 -0
  116. package/dist/templates/react-app/src/base/port/RequestStatusInterface.ts +5 -0
  117. package/dist/templates/react-app/src/base/port/RouteServiceInterface.ts +27 -0
  118. package/dist/templates/react-app/src/base/port/UserServiceInterface.ts +12 -0
  119. package/dist/templates/react-app/src/base/services/I18nService.ts +10 -6
  120. package/dist/templates/react-app/src/base/services/ProcesserExecutor.ts +23 -5
  121. package/dist/templates/react-app/src/base/services/RouteService.ts +25 -54
  122. package/dist/templates/react-app/src/base/services/UserService.ts +10 -20
  123. package/dist/templates/react-app/src/core/IOC.ts +1 -26
  124. package/dist/templates/react-app/src/core/IocRegisterImpl.ts +125 -0
  125. package/dist/templates/react-app/src/core/bootstraps/BootstrapApp.ts +4 -6
  126. package/dist/templates/react-app/src/core/bootstraps/BootstrapsRegistry.ts +8 -6
  127. package/dist/templates/react-app/src/core/bootstraps/IocIdentifierTest.ts +26 -0
  128. package/dist/templates/react-app/src/pages/auth/Layout.tsx +2 -2
  129. package/dist/templates/react-app/src/pages/auth/LoginPage.tsx +5 -6
  130. package/dist/templates/react-app/src/pages/auth/RegisterPage.tsx +8 -7
  131. package/dist/templates/react-app/src/pages/base/ExecutorPage.tsx +8 -19
  132. package/dist/templates/react-app/src/pages/base/{ErrorIdentifierPage.tsx → IdentifierPage.tsx} +1 -1
  133. package/dist/templates/react-app/src/pages/base/JSONStoragePage.tsx +11 -15
  134. package/dist/templates/react-app/src/pages/base/Layout.tsx +1 -1
  135. package/dist/templates/react-app/src/pages/base/RedirectPathname.tsx +2 -2
  136. package/dist/templates/react-app/src/pages/base/RequestPage.tsx +34 -46
  137. package/dist/templates/react-app/src/styles/css/antd-themes/_default.css +2 -2
  138. package/dist/templates/react-app/src/styles/css/antd-themes/dark.css +2 -2
  139. package/dist/templates/react-app/src/styles/css/antd-themes/pink.css +2 -2
  140. package/dist/templates/react-app/src/styles/css/index.css +1 -0
  141. package/dist/templates/react-app/src/styles/css/page.css +8 -0
  142. package/dist/templates/react-app/src/styles/css/zIndex.css +9 -0
  143. package/dist/templates/react-app/src/uikit/{controllers/ExecutorController.ts → bridges/ExecutorPageBridge.ts} +13 -36
  144. package/dist/templates/react-app/src/uikit/bridges/JSONStoragePageBridge.ts +41 -0
  145. package/dist/templates/react-app/src/uikit/bridges/NavigateBridge.ts +16 -0
  146. package/dist/templates/react-app/src/uikit/bridges/RequestPageBridge.ts +136 -0
  147. package/dist/templates/react-app/src/uikit/components/LanguageSwitcher.tsx +3 -2
  148. package/dist/templates/react-app/src/uikit/components/LogoutButton.tsx +2 -2
  149. package/dist/templates/react-app/src/uikit/{providers → components}/ProcessExecutorProvider.tsx +4 -4
  150. package/dist/templates/react-app/src/uikit/components/RouterRenderComponent.tsx +1 -1
  151. package/dist/templates/react-app/src/uikit/components/ThemeSwitcher.tsx +3 -5
  152. package/dist/templates/react-app/src/uikit/{providers → components}/UserAuthProvider.tsx +3 -3
  153. package/dist/templates/react-app/src/uikit/hooks/useI18nGuard.ts +5 -2
  154. package/dist/templates/react-app/src/uikit/hooks/{userRouterService.ts → useNavigateBridge.ts} +3 -3
  155. package/dist/templates/react-app/src/uikit/hooks/useStore.ts +5 -2
  156. package/dist/templates/react-app/tsconfig.json +1 -4
  157. package/package.json +1 -1
  158. package/dist/templates/react-app/src/base/port/InteractionHubInterface.ts +0 -94
  159. package/dist/templates/react-app/src/base/port/UIDependenciesInterface.ts +0 -37
  160. package/dist/templates/react-app/src/core/registers/IocRegisterImpl.ts +0 -25
  161. package/dist/templates/react-app/src/core/registers/RegisterCommon.ts +0 -74
  162. package/dist/templates/react-app/src/core/registers/RegisterControllers.ts +0 -26
  163. package/dist/templates/react-app/src/core/registers/RegisterGlobals.ts +0 -30
  164. package/dist/templates/react-app/src/uikit/controllers/JSONStorageController.ts +0 -49
  165. package/dist/templates/react-app/src/uikit/controllers/RequestController.ts +0 -158
  166. /package/dist/templates/react-app/src/uikit/{providers → components}/BaseRouteProvider.tsx +0 -0
@@ -0,0 +1,204 @@
1
+ [data-theme='pink'],
2
+ [data-theme='pink'] .fe-theme {
3
+ /* Antd 主色调相关变量 - 玫瑰色主题 */
4
+ --fe-color-primary: #f472b6; /* pink-400 */
5
+ --fe-color-primary-hover: #ec4899; /* pink-500 */
6
+ --fe-color-primary-active: #db2777; /* pink-600 */
7
+ --fe-color-primary-bg: rgba(
8
+ 244,
9
+ 114,
10
+ 182,
11
+ 0.1
12
+ ); /* pink-400 with 0.1 opacity */
13
+ --fe-color-primary-border: #f472b6; /* pink-400 */
14
+ --fe-color-primary-text: #f472b6; /* pink-400 */
15
+ --fe-color-primary-text-hover: #ec4899; /* pink-500 */
16
+ --fe-color-primary-text-active: #db2777; /* pink-600 */
17
+ --fe-color-primary-deprecated-bg: #f472b6; /* pink-400 */
18
+ --fe-color-primary-deprecated-border: #f472b6; /* pink-400 */
19
+
20
+ /* 状态色 */
21
+ --fe-color-success: #52c41a;
22
+ --fe-color-warning: #faad14;
23
+ /* 警告信息相关颜色 - 粉色主题 */
24
+ --fe-color-warning-bg: #fff7e6;
25
+ --fe-color-warning-bg-hover: #fff0d9;
26
+ --fe-color-warning-border: #ffd591;
27
+ --fe-color-warning-border-hover: #ffc069;
28
+ --fe-color-warning-hover: #ffc069;
29
+ --fe-color-warning-active: #d4770c;
30
+ --fe-color-warning-text-hover: #ffc53d;
31
+ --fe-color-warning-text: #faad14;
32
+ --fe-color-warning-text-active: #d4770c;
33
+ --fe-color-error: #fb7185; /* rose-400 for error in pink theme */
34
+ --fe-color-info: var(--fe-color-primary);
35
+ --fe-color-link: var(--fe-color-primary);
36
+
37
+ /* Antd 基础变量 */
38
+ --ant-color-bg-container: rgb(255 241 242);
39
+ --ant-color-bg-elevated: rgb(254 205 211);
40
+ --fe-color-text-heading: rgb(159 18 57); /* rose-800 用于粉色主题标题文本 */
41
+ --ant-color-text: rgba(190 18 60 / 0.85);
42
+ --ant-color-text-secondary: rgba(190 18 60 / 0.45);
43
+ --ant-color-text-tertiary: rgba(190 18 60 / 0.35);
44
+ --ant-color-text-quaternary: rgba(190 18 60 / 0.15);
45
+ --ant-color-text-placeholder: rgba(190 18 60 / 0.25);
46
+ --ant-color-border: rgb(254 205 211);
47
+
48
+ /* Antd 图标相关变量 */
49
+ --fe-color-icon: rgba(190, 18, 60, 0.45); /* 粉色主题下的图标颜色 */
50
+ --fe-color-icon-hover: rgba(190, 18, 60, 0.85); /* 粉色主题下图标悬停颜色 */
51
+ --fe-color-icon-active: var(--fe-color-primary); /* 使用主题粉色 */
52
+ --fe-color-icon-disabled: rgba(190, 18, 60, 0.25); /* 粉色主题下禁用状态 */
53
+
54
+ /* Antd Input 组件变量 */
55
+ .ant-input,
56
+ .ant-input-css-var {
57
+ /* Input 背景色 */
58
+ --fe-input-bg: var(--ant-color-bg-container);
59
+ --fe-input-hover-bg: var(--ant-color-bg-elevated);
60
+ --fe-input-active-bg: var(--ant-color-bg-elevated);
61
+ --fe-input-addon-bg: rgba(190 18 60, 0.02);
62
+
63
+ /* Input 边框颜色 */
64
+ --fe-input-border-color: var(--ant-color-border);
65
+ --fe-input-hover-border-color: rgb(var(--color-brand));
66
+ --fe-input-active-border-color: rgb(var(--color-brand));
67
+
68
+ /* Input 阴影效果 */
69
+ --fe-input-active-shadow: 0 0 0 2px rgba(var(--color-brand), 0.1);
70
+ }
71
+
72
+ /* Antd Button 组件变量 */
73
+ .ant-btn,
74
+ .ant-btn-css-var {
75
+ /* 玫瑰色主题 */
76
+ --fe-button-primary-color: #fff;
77
+ --fe-button-primary-bg: #f472b6; /* pink-400 */
78
+ --fe-button-primary-hover-bg: #ec4899; /* pink-500 */
79
+ --fe-button-primary-active-bg: #db2777; /* pink-600 */
80
+ --fe-button-primary-shadow: 0 2px 0 rgba(219, 39, 119, 0.15);
81
+
82
+ /* 默认按钮 */
83
+ --fe-button-default-color: rgb(190 18 60);
84
+ --fe-button-default-bg: rgb(255 241 242);
85
+ --fe-button-default-border-color: rgb(254 205 211);
86
+ --fe-button-default-hover-bg: rgb(255 241 242);
87
+ --fe-button-default-hover-color: #f472b6;
88
+ --fe-button-default-hover-border-color: #f472b6;
89
+ --fe-button-default-active-bg: rgb(255 241 242);
90
+ --fe-button-default-active-color: #db2777;
91
+ --fe-button-default-active-border-color: #db2777;
92
+ --fe-button-default-shadow: 0 2px 0 rgba(244, 114, 182, 0.1);
93
+
94
+ /* 其他状态 */
95
+ --fe-button-text-hover-bg: rgba(244, 114, 182, 0.08);
96
+ --fe-button-border-color-disabled: rgb(254 205 211);
97
+ }
98
+
99
+ /* Antd Select 组件变量 */
100
+ .ant-select,
101
+ .ant-select-css-var {
102
+ --fe-select-internal_fixed_item_margin: 2px;
103
+ --fe-select-z-index-popup: var(--zi-select);
104
+ --fe-select-option-selected-color: rgba(190, 18, 60, 0.88);
105
+ --fe-select-option-selected-font-weight: 600;
106
+ --fe-select-option-selected-bg: var(--fe-color-primary-bg);
107
+ --fe-select-option-active-bg: rgba(190, 18, 60, 0.04);
108
+ --fe-select-option-padding: 5px 12px;
109
+ --fe-select-option-font-size: 14px;
110
+ --fe-select-option-line-height: 1.5714285714285714;
111
+ --fe-select-option-height: 32px;
112
+ --fe-select-selector-bg: var(--fe-color-bg-container);
113
+ --fe-select-clear-bg: var(--fe-color-bg-container);
114
+ --fe-select-single-item-height-lg: 40px;
115
+ --fe-select-multiple-item-bg: rgba(190, 18, 60, 0.06);
116
+ --fe-select-multiple-item-border-color: transparent;
117
+ --fe-select-multiple-item-height: 24px;
118
+ --fe-select-multiple-item-height-sm: 16px;
119
+ --fe-select-multiple-item-height-lg: 32px;
120
+ --fe-select-multiple-selector-bg-disabled: rgba(190, 18, 60, 0.04);
121
+ --fe-select-multiple-item-color-disabled: rgba(190, 18, 60, 0.25);
122
+ --fe-select-multiple-item-border-color-disabled: transparent;
123
+ --fe-select-show-arrow-padding-inline-end: 18px;
124
+ --fe-select-hover-border-color: var(--fe-color-primary);
125
+ --fe-select-active-border-color: var(--fe-color-primary-active);
126
+ --fe-select-active-outline-color: var(--fe-color-primary-bg);
127
+ --fe-select-select-affix-padding: 4px;
128
+ }
129
+
130
+ /* Antd Tag 组件变量 */
131
+ .ant-tag,
132
+ .ant-tag-css-var {
133
+ --fe-tag-default-bg: var(--fe-color-bg-container);
134
+ --fe-tag-default-color: var(--fe-color-text);
135
+ --fe-tag-default-border-color: var(--fe-color-border);
136
+ --fe-tag-font-size: 12px;
137
+ --fe-tag-line-height: 20px;
138
+ --fe-tag-height: 22px;
139
+ --fe-tag-padding-horizontal: 7px;
140
+ --fe-tag-margin: 0 8px 0 0;
141
+ --fe-tag-border-radius: 4px;
142
+ }
143
+
144
+ /* Antd Progress 组件变量 */
145
+ .ant-progress,
146
+ .ant-progress-css-var {
147
+ --fe-progress-default-color: var(--fe-color-primary);
148
+ --fe-progress-remaining-color: var(--fe-color-bg-elevated);
149
+ --fe-progress-text-color: var(--fe-color-text);
150
+ --fe-progress-line-font-size: 14px;
151
+ --fe-progress-circle-font-size: 14px;
152
+ --fe-progress-circle-text-color: var(--fe-color-text);
153
+ --fe-progress-circle-trail-color: var(--fe-color-bg-elevated);
154
+ --fe-progress-circle-stroke-width: 6px;
155
+ --fe-progress-line-stroke-width: 8px;
156
+ }
157
+
158
+ /* Antd Message 组件变量 */
159
+ .ant-message,
160
+ .ant-message-css-var {
161
+ --fe-message-z-index-popup: var(--zi-message);
162
+ --fe-message-content-bg: var(--ant-color-bg-container);
163
+ --fe-message-content-padding: 9px 12px;
164
+ --fe-message-notice-content-padding: 10px 16px;
165
+ --fe-message-notice-content-bg: var(--ant-color-bg-container);
166
+ --fe-message-notice-content-shadow:
167
+ 0 6px 16px 0 rgba(244, 114, 182, 0.08),
168
+ 0 3px 6px -4px rgba(244, 114, 182, 0.12),
169
+ 0 9px 28px 8px rgba(244, 114, 182, 0.05);
170
+ --fe-message-success-color: #52c41a;
171
+ --fe-message-error-color: #fb7185; /* rose-400 for error in pink theme */
172
+ --fe-message-warning-color: #faad14;
173
+ --fe-message-info-color: var(--fe-color-primary);
174
+ --fe-message-loading-color: var(--fe-color-primary);
175
+ }
176
+
177
+ /* Antd Modal 组件变量 */
178
+ .ant-modal,
179
+ .ant-modal-css-var {
180
+ --fe-modal-footer-bg: transparent;
181
+ --fe-modal-header-bg: var(--ant-color-bg-container);
182
+ --fe-modal-title-line-height: var(--fe-line-height);
183
+ --fe-modal-title-font-size: 16px;
184
+ --fe-modal-content-bg: var(--ant-color-bg-container);
185
+ --fe-modal-title-color: var(--ant-color-text);
186
+ --fe-modal-content-padding: 20px 24px;
187
+ --fe-modal-header-padding: 16px 24px;
188
+ --fe-modal-header-border-bottom: 1px solid var(--ant-color-border);
189
+ --fe-modal-header-margin-bottom: 8px;
190
+ --fe-modal-body-padding: 0px;
191
+ --fe-modal-footer-padding: 10px 16px;
192
+ --fe-modal-footer-border-top: 1px solid var(--ant-color-border);
193
+ --fe-modal-footer-border-radius: var(--fe-border-radius);
194
+ --fe-modal-footer-margin-top: 12px;
195
+ --fe-modal-confirm-body-padding: 32px 32px 24px;
196
+ --fe-modal-confirm-icon-margin-inline-end: 12px;
197
+ --fe-modal-confirm-btns-margin-top: 12px;
198
+ --fe-modal-box-shadow:
199
+ 0 6px 16px 0 rgba(244, 114, 182, 0.08),
200
+ 0 3px 6px -4px rgba(244, 114, 182, 0.12),
201
+ 0 9px 28px 8px rgba(244, 114, 182, 0.05);
202
+ --fe-modal-mask-bg: rgba(244, 114, 182, 0.45);
203
+ }
204
+ }
@@ -0,0 +1,6 @@
1
+ @import './tailwind.css';
2
+ @import './zIndex.css';
3
+
4
+ @import './antd-themes/index.css';
5
+
6
+ @import './page.css';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * This file is used to define the page styles for the app.
3
+ *
4
+ * @example --color-primary
5
+ * ```tsx
6
+ * <div className="bg-primary text-primary border-text-tertiary"></div>
7
+ * ```
8
+ */
9
+ @theme {
10
+ --color-primary: rgba(var(--color-bg-base));
11
+ --color-secondary: rgba(var(--color-bg-secondary));
12
+ --color-elevated: rgba(var(--color-bg-elevated));
13
+ --color-text: rgba(var(--text-primary));
14
+ --color-text-secondary: rgba(var(--text-secondary));
15
+ --color-text-tertiary: rgba(var(--text-tertiary));
16
+ --color-border: rgba(var(--color-border));
17
+ --color-brand: rgba(var(--color-brand));
18
+ --color-brand-hover: rgba(var(--color-brand-hover));
19
+ }
@@ -0,0 +1,5 @@
1
+ @layer theme, base, antd, components, utilities;
2
+
3
+ @import 'tailwindcss';
4
+
5
+ @import './themes/index.css';
@@ -0,0 +1,29 @@
1
+ /* theme variables - for tailwind */
2
+ @layer base {
3
+ :root {
4
+ /* 基础背景色 */
5
+ --color-bg-base: 255 255 255;
6
+ --color-bg-secondary: 241 245 249; /* slate-100 */
7
+ --color-bg-elevated: 248 250 252; /* slate-50 */
8
+
9
+ /* 文字颜色 */
10
+ --text-primary: 15 23 42; /* slate-900 */
11
+ --text-secondary: 71 85 105; /* slate-600 */
12
+ --text-tertiary: 100 116 139; /* slate-500 */
13
+
14
+ /* 边框颜色 */
15
+ --color-border: 226 232 240; /* slate-200 */
16
+
17
+ /* 品牌色 */
18
+ --color-brand: 37 99 235; /* blue-600 */
19
+ --color-brand-hover: 59 130 246; /* blue-500 */
20
+
21
+ /* 登录页特定样式 */
22
+ --login-card-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
23
+ --login-input-bg: var(--fe-color-bg-container);
24
+ --login-input-border: var(--fe-color-border);
25
+ --login-button-text: rgb(255 255 255);
26
+ --login-social-button-bg: var(--fe-color-bg-container);
27
+ --login-social-button-border: var(--fe-color-border);
28
+ }
29
+ }
@@ -0,0 +1,29 @@
1
+ /* theme variables - for tailwind */
2
+ @layer base {
3
+ [data-theme='dark'] {
4
+ /* 基础背景色 */
5
+ --color-bg-base: 15 23 42; /* slate-900 */
6
+ --color-bg-secondary: 30 41 59; /* slate-800 */
7
+ --color-bg-elevated: 51 65 85; /* slate-700 */
8
+
9
+ /* 文字颜色 */
10
+ --text-primary: 255 255 255;
11
+ --text-secondary: 148 163 184; /* slate-400 */
12
+ --text-tertiary: 100 116 139; /* slate-500 */
13
+
14
+ /* 边框颜色 */
15
+ --color-border: 51 65 85; /* slate-700 */
16
+
17
+ /* 品牌色 */
18
+ --color-brand: 37 99 235; /* blue-600 */
19
+ --color-brand-hover: 59 130 246; /* blue-500 */
20
+
21
+ /* 登录页特定样式 */
22
+ --login-card-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
23
+ --login-input-bg: var(--fe-color-bg-container);
24
+ --login-input-border: var(--fe-color-border);
25
+ --login-button-text: rgb(255 255 255);
26
+ --login-social-button-bg: var(--fe-color-bg-container);
27
+ --login-social-button-border: var(--fe-color-border);
28
+ }
29
+ }
@@ -0,0 +1,3 @@
1
+ @import './_default.css';
2
+ @import './dark.css';
3
+ @import './pink.css';
@@ -0,0 +1,29 @@
1
+ /* theme variables - for tailwind */
2
+ @layer base {
3
+ [data-theme='pink'] {
4
+ /* 基础背景色 */
5
+ --color-bg-base: 255 241 242; /* rose-50 */
6
+ --color-bg-secondary: 255 228 230; /* rose-100 */
7
+ --color-bg-elevated: 254 205 211; /* rose-200 */
8
+
9
+ /* 文字颜色 */
10
+ --text-primary: 190 18 60; /* rose-700 */
11
+ --text-secondary: 225 29 72; /* rose-600 */
12
+ --text-tertiary: 244 63 94; /* rose-500 */
13
+
14
+ /* 边框颜色 */
15
+ --color-border: 254 205 211; /* rose-200 */
16
+
17
+ /* 品牌色 */
18
+ --color-brand: 225 29 72; /* rose-600 */
19
+ --color-brand-hover: 244 63 94; /* rose-500 */
20
+
21
+ /* 登录页特定样式 */
22
+ --login-card-shadow: 0 4px 12px rgba(244 63 94 / 0.15);
23
+ --login-input-bg: var(--ant-color-bg-container);
24
+ --login-input-border: var(--ant-color-border);
25
+ --login-button-text: rgb(255 255 255);
26
+ --login-social-button-bg: var(--ant-color-bg-container);
27
+ --login-social-button-border: var(--ant-color-border);
28
+ }
29
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * This file is used to define the z-index values for the app.
3
+ */
4
+ :root {
5
+ /* antd select popup zindex */
6
+ --zi-select: 1050;
7
+ /* antd message zindex */
8
+ --zi-message: 2010;
9
+ }
@@ -0,0 +1,42 @@
1
+ 'use client';
2
+
3
+ import Link from 'next/link';
4
+ import { AppConfig } from '@/base/cases/AppConfig';
5
+ import { IOC } from '@/core/IOC';
6
+ import { LanguageSwitcher } from './LanguageSwitcher';
7
+ import { ThemeSwitcher } from './ThemeSwitcher';
8
+
9
+ export function BaseHeader() {
10
+ return (
11
+ <header
12
+ data-testid="base-header"
13
+ className="h-14 bg-secondary border-b border-border sticky top-0 z-50"
14
+ >
15
+ <div className="flex items-center justify-between h-full px-4 mx-auto max-w-7xl">
16
+ <div className="flex items-center">
17
+ <Link
18
+ href="/"
19
+ className="flex items-center hover:opacity-80 transition-opacity"
20
+ >
21
+ {/* <img
22
+ data-testid="base-header-logo"
23
+ src={IOC(PublicAssetsPath).getPath('/logo.svg')}
24
+ alt="logo"
25
+ className="h-8 w-auto"
26
+ /> */}
27
+ <span
28
+ data-testid="base-header-app-name"
29
+ className="ml-2 text-lg font-semibold text-text"
30
+ >
31
+ {IOC(AppConfig).appName}
32
+ </span>
33
+ </Link>
34
+ </div>
35
+ <div className="flex items-center gap-4">
36
+ <LanguageSwitcher />
37
+ <ThemeSwitcher />
38
+ </div>
39
+ </div>
40
+ </header>
41
+ );
42
+ }
@@ -0,0 +1,25 @@
1
+ 'use client';
2
+ import '@ant-design/v5-patch-for-react-19';
3
+ import { useEffect } from 'react';
4
+ import { BootstrapClient } from '@/core/bootstraps/BootstrapClient';
5
+ import { IOCContext } from '../context/IOCContext';
6
+
7
+ export function BootstrapsProvider(props: { children: React.ReactNode }) {
8
+ const IOC = BootstrapClient.createSingletonIOC();
9
+
10
+ useEffect(() => {
11
+ if (typeof window !== 'undefined') {
12
+ BootstrapClient.main({
13
+ root: window,
14
+ pathname: window.location.pathname,
15
+ IOC: IOC
16
+ });
17
+ }
18
+ }, [IOC]);
19
+
20
+ return (
21
+ <IOCContext.Provider data-testid="BootstrapsProvider" value={IOC}>
22
+ {props.children}
23
+ </IOCContext.Provider>
24
+ );
25
+ }
@@ -0,0 +1,45 @@
1
+ 'use client';
2
+ import '@ant-design/v5-patch-for-react-19';
3
+ import { AntdRegistry } from '@ant-design/nextjs-registry';
4
+ import { AntdThemeProvider } from '@brain-toolkit/antd-theme-override/react';
5
+ import { ThemeProvider } from 'next-themes';
6
+ import { BootstrapsProvider } from './BootstrapsProvider';
7
+ import type { CommonThemeConfig } from '@config/theme';
8
+
9
+ /**
10
+ * CommonProvider is a provider for the common components
11
+ *
12
+ * - IOCProvider
13
+ * - BootstrapsProvider
14
+ * - ThemeProvider
15
+ * - AntdProvider
16
+ *
17
+ * @param param0
18
+ * @returns
19
+ */
20
+ export function ComboProvider(props: {
21
+ themeConfig: CommonThemeConfig;
22
+ children: React.ReactNode;
23
+ }) {
24
+ const { themeConfig, children } = props;
25
+
26
+ return (
27
+ <AntdThemeProvider
28
+ data-testid="ComboProvider"
29
+ theme={themeConfig.antdTheme}
30
+ >
31
+ <ThemeProvider
32
+ themes={themeConfig.supportedThemes as unknown as string[]}
33
+ attribute={themeConfig.domAttribute}
34
+ defaultTheme={themeConfig.defaultTheme}
35
+ enableSystem
36
+ enableColorScheme={false}
37
+ storageKey={themeConfig.storageKey}
38
+ >
39
+ <BootstrapsProvider>
40
+ <AntdRegistry>{children}</AntdRegistry>
41
+ </BootstrapsProvider>
42
+ </ThemeProvider>
43
+ </AntdThemeProvider>
44
+ );
45
+ }
@@ -0,0 +1,52 @@
1
+ 'use client';
2
+
3
+ import { Select } from 'antd';
4
+ import { useLocale } from 'next-intl';
5
+ import { useCallback } from 'react';
6
+ import { i18nConfig } from '@config/i18n';
7
+ import { IOCIdentifier } from '@config/IOCIdentifier';
8
+ import type { I18nServiceLocale } from '@/base/port/I18nServiceInterface';
9
+ import { usePathname, useRouter } from '@/i18n/routing';
10
+ import { useIOC } from '../hook/useIOC';
11
+ import { useStore } from '../hook/useStore';
12
+ import type { LocaleType } from '@config/i18n';
13
+
14
+ export function LanguageSwitcher() {
15
+ const i18nService = useIOC(IOCIdentifier.I18nServiceInterface);
16
+ const { loading } = useStore(i18nService);
17
+ const pathname = usePathname(); // current pathname, aware of i18n
18
+
19
+ const router = useRouter(); // i18n-aware router instance
20
+ const currentLocale = useLocale() as LocaleType; // currently active locale
21
+
22
+ const handleLanguageChange = useCallback(
23
+ async (value: string) => {
24
+ // Set a persistent cookie with the user's preferred locale (valid for 1 year)
25
+ document.cookie = `NEXT_LOCALE=${value}; path=/; max-age=31536000; SameSite=Lax`;
26
+ // Route to the same page in the selected locale
27
+ router.replace(pathname, { locale: value });
28
+
29
+ try {
30
+ await i18nService.changeLanguage(value as I18nServiceLocale);
31
+ } catch (error) {
32
+ console.error('Failed to change language:', error);
33
+ }
34
+ },
35
+ [i18nService, pathname, router]
36
+ );
37
+
38
+ return (
39
+ <Select
40
+ data-testid="LanguageSwitcher"
41
+ loading={loading}
42
+ value={currentLocale}
43
+ onChange={handleLanguageChange}
44
+ options={i18nConfig.supportedLngs.map((lang) => ({
45
+ value: lang,
46
+ label:
47
+ i18nConfig.localeNames[lang as keyof typeof i18nConfig.localeNames]
48
+ }))}
49
+ className="w-24"
50
+ />
51
+ );
52
+ }
@@ -0,0 +1,51 @@
1
+ import Link from 'next/link';
2
+ import { useLocaleRoutes } from '@config/common';
3
+ import { i18nConfig } from '@config/i18n';
4
+ import type { LinkProps } from 'next/link';
5
+ import type { ReactNode } from 'react';
6
+
7
+ interface LocaleLinkProps
8
+ extends Omit<LinkProps, 'href'>,
9
+ React.HTMLAttributes<HTMLAnchorElement> {
10
+ href:
11
+ | string
12
+ | {
13
+ pathname: string;
14
+ query?: Record<string, string>;
15
+ hash?: string;
16
+ };
17
+ locale?: string;
18
+ title: string;
19
+ children: ReactNode;
20
+ defaultLocale?: string;
21
+ className?: string;
22
+ }
23
+
24
+ export const LocaleLink: React.FC<LocaleLinkProps> = ({
25
+ href,
26
+ locale,
27
+ children,
28
+ defaultLocale,
29
+ ...props
30
+ }) => {
31
+ locale = locale || i18nConfig.fallbackLng;
32
+
33
+ const isDefaultLocale = locale === defaultLocale;
34
+ const shouldAddLocale = useLocaleRoutes && !isDefaultLocale;
35
+
36
+ let localizedHref: typeof href;
37
+ if (typeof href === 'string') {
38
+ localizedHref = shouldAddLocale ? `/${locale}${href}` : href;
39
+ } else {
40
+ localizedHref = {
41
+ ...href,
42
+ pathname: shouldAddLocale ? `/${locale}${href.pathname}` : href.pathname
43
+ };
44
+ }
45
+
46
+ return (
47
+ <Link data-testid="locale-link" {...props} href={localizedHref}>
48
+ {children}
49
+ </Link>
50
+ );
51
+ };
@@ -0,0 +1,21 @@
1
+ import { NextIntlClientProvider, useMessages } from 'next-intl';
2
+ import type { ReactNode } from 'react';
3
+
4
+ type Props = {
5
+ children: ReactNode;
6
+ locale: string;
7
+ };
8
+
9
+ export function NextIntlProvider({ children, locale }: Props) {
10
+ const messages = useMessages();
11
+
12
+ return (
13
+ <NextIntlClientProvider
14
+ data-testid="NextIntlProvider"
15
+ locale={locale}
16
+ messages={messages}
17
+ >
18
+ {children}
19
+ </NextIntlClientProvider>
20
+ );
21
+ }
@@ -0,0 +1,86 @@
1
+ 'use client';
2
+
3
+ import {
4
+ BulbOutlined,
5
+ BulbFilled,
6
+ HeartFilled,
7
+ HeartOutlined,
8
+ DesktopOutlined
9
+ } from '@ant-design/icons';
10
+ import { Select } from 'antd';
11
+ import { clsx } from 'clsx';
12
+ import { useTheme } from 'next-themes';
13
+ import { themeConfig } from '@config/theme';
14
+ import { useMountedClient } from '../hook/useMountedClient';
15
+
16
+ const { supportedThemes } = themeConfig;
17
+
18
+ const colorMap: Record<
19
+ string,
20
+ { i18nkey: string; colors: string[]; icons: React.ElementType[] }
21
+ > = {
22
+ system: {
23
+ i18nkey: 'System',
24
+ colors: ['text-text', 'text-text-secondary'],
25
+ icons: [DesktopOutlined, DesktopOutlined]
26
+ },
27
+ light: {
28
+ i18nkey: 'Light',
29
+ colors: ['text-text', 'text-text-secondary'],
30
+ icons: [BulbFilled, BulbOutlined]
31
+ },
32
+ dark: {
33
+ i18nkey: 'Dark',
34
+ colors: ['text-[#9333ea]', 'text-[#a855f7]'],
35
+ icons: [BulbFilled, BulbOutlined]
36
+ },
37
+ pink: {
38
+ i18nkey: 'Pink',
39
+ colors: ['text-[#f472b6]', 'text-[#ec4899]'],
40
+ icons: [HeartFilled, HeartOutlined]
41
+ }
42
+ };
43
+
44
+ export function ThemeSwitcher() {
45
+ const { theme, resolvedTheme, setTheme } = useTheme();
46
+ const mounted = useMountedClient();
47
+
48
+ const themeOptions = ['system', ...supportedThemes!].map((themeName) => {
49
+ const { i18nkey, colors, icons } = colorMap[themeName] || colorMap.light;
50
+ const [currentColor, normalColor] = colors;
51
+ const [CurrentIcon, NormalIcon] = icons;
52
+
53
+ const isCurrentTheme =
54
+ theme === themeName ||
55
+ (themeName === resolvedTheme && theme === 'system');
56
+
57
+ return {
58
+ key: themeName,
59
+ value: themeName,
60
+ label: (
61
+ <div
62
+ className={clsx(
63
+ 'flex items-center gap-2',
64
+ isCurrentTheme ? currentColor : normalColor
65
+ )}
66
+ >
67
+ {isCurrentTheme ? <CurrentIcon /> : <NormalIcon />}
68
+ <span>{i18nkey}</span>
69
+ </div>
70
+ )
71
+ };
72
+ });
73
+
74
+ return (
75
+ <Select
76
+ data-testid="ThemeSwitcher"
77
+ loading={!mounted}
78
+ value={mounted ? theme : themeOptions[0]?.key}
79
+ onChange={setTheme}
80
+ options={themeOptions}
81
+ style={{ width: 120 }}
82
+ className="min-w-40 max-w-full"
83
+ disabled={!mounted}
84
+ />
85
+ );
86
+ }
@@ -0,0 +1,6 @@
1
+ 'use client';
2
+
3
+ import { createContext } from 'react';
4
+ import type { IOC } from '@/core/IOC';
5
+
6
+ export const IOCContext = createContext<typeof IOC | null>(null);