create-bubbles 0.1.24 → 0.1.26

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 (204) hide show
  1. package/dist/index.js +15 -0
  2. package/package.json +1 -2
  3. package/template-nextjs-vinext-eslint/Dockerfile +4 -4
  4. package/template-nextjs-vinext-eslint/README.md +6 -2
  5. package/template-nextjs-vinext-eslint/docker-compose.yaml +4 -4
  6. package/template-nextjs-vinext-eslint/eslint.config.js +2 -0
  7. package/template-nextjs-vinext-eslint/package.json +28 -26
  8. package/template-nextjs-vinext-eslint/pnpm-workspace.yaml +13 -1
  9. package/template-nextjs-vinext-eslint/src/utils/request/core/index.ts +63 -45
  10. package/template-nextjs-vinext-eslint/src/utils/request/core/utils.ts +12 -6
  11. package/template-nextjs-vinext-eslint/vite.config.ts +1 -1
  12. package/template-react-rsbuild-biome/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  13. package/template-react-rsbuild-biome/AGENTS.md +11 -0
  14. package/template-react-rsbuild-biome/index.html +2 -2
  15. package/template-react-rsbuild-biome/package.json +25 -24
  16. package/template-react-rsbuild-biome/pnpm-workspace.yaml +5 -0
  17. package/template-react-rsbuild-biome/rsbuild.config.ts +1 -1
  18. package/template-react-rsbuild-biome/src/assets/icon/logo.svg +1 -1
  19. package/template-react-rsbuild-biome/src/assets/svg/draft.svg +4 -0
  20. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/README.md +37 -0
  21. package/template-react-rsbuild-biome/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  22. package/template-react-rsbuild-biome/src/env.d.ts +7 -0
  23. package/template-react-rsbuild-biome/src/utils/request/index.ts +3 -4
  24. package/template-react-rsbuild-biome/tsconfig.json +1 -2
  25. package/template-taro-react-oxc/.oxlintrc.json +0 -1
  26. package/template-taro-react-oxc/package.json +53 -52
  27. package/template-taro-react-oxc/pnpm-workspace.yaml +46 -0
  28. package/template-taro-vue-eslint/package.json +56 -56
  29. package/template-vp-monorepo-react-hono/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  30. package/template-vp-monorepo-react-hono/apps/web/AGENTS.md +11 -0
  31. package/template-vp-monorepo-react-hono/apps/web/package.json +1 -0
  32. package/template-vp-monorepo-react-hono/apps/web/src/assets/svg/draft.svg +4 -0
  33. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  34. package/template-vp-monorepo-react-hono/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  35. package/template-vp-monorepo-react-hono/apps/web/tsconfig.json +1 -1
  36. package/template-vp-monorepo-react-hono/apps/web/vite.config.ts +2 -0
  37. package/template-vp-monorepo-react-hono/pnpm-workspace.yaml +1 -0
  38. package/template-vp-monorepo-react-nestjs/.agents/rules//344/273/243/347/240/201/350/256/276/350/256/241.md +4 -0
  39. package/template-vp-monorepo-react-nestjs/.agents/rules//345/205/261/344/272/253/344/273/243/347/240/201.md +4 -0
  40. package/template-vp-monorepo-react-nestjs/.spaces/01./344/274/201/344/270/232/347/272/247/351/241/271/347/233/256/347/272/247//351/234/200/346/261/202/346/226/207/346/241/243.md +177 -0
  41. package/template-vp-monorepo-react-nestjs/.spaces/server/04.upload.md +4504 -0
  42. package/template-vp-monorepo-react-nestjs/.spaces/server/05./344/270/212/344/274/240/346/224/271/351/200/240/346/226/271/346/241/210/README.md +858 -0
  43. package/template-vp-monorepo-react-nestjs/.spaces/server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210/README.md +1890 -0
  44. package/template-vp-monorepo-react-nestjs/.spaces/server/06./345/205/254/345/205/261/351/230/237/345/210/227/346/216/245/345/205/245/346/226/271/346/241/210//344/270/212/344/274/240/346/270/205/347/220/206.md +1465 -0
  45. package/template-vp-monorepo-react-nestjs/AGENTS.md +8 -12
  46. package/template-vp-monorepo-react-nestjs/apps/server/.agents/rules/error-handling.md +84 -0
  47. package/template-vp-monorepo-react-nestjs/apps/server/.env.development +60 -0
  48. package/template-vp-monorepo-react-nestjs/apps/server/.env.production +16 -0
  49. package/template-vp-monorepo-react-nestjs/apps/server/AGENTS.md +9 -0
  50. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0000_military_colonel_america.sql +11 -0
  51. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/0001_loud_siren.sql +27 -0
  52. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0000_snapshot.json +97 -0
  53. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/0001_snapshot.json +354 -0
  54. package/template-vp-monorepo-react-nestjs/apps/server/drizzle/meta/_journal.json +20 -0
  55. package/template-vp-monorepo-react-nestjs/apps/server/package.json +4 -0
  56. package/template-vp-monorepo-react-nestjs/apps/server/src/app.module.ts +14 -2
  57. package/template-vp-monorepo-react-nestjs/apps/server/src/common/adapters/fastify.adapter.ts +6 -0
  58. package/template-vp-monorepo-react-nestjs/apps/server/src/config/index.ts +2 -0
  59. package/template-vp-monorepo-react-nestjs/apps/server/src/config/queue.config.ts +105 -0
  60. package/template-vp-monorepo-react-nestjs/apps/server/src/config/storage.config.ts +33 -0
  61. package/template-vp-monorepo-react-nestjs/apps/server/src/database/schema.ts +57 -1
  62. package/template-vp-monorepo-react-nestjs/apps/server/src/main.ts +1 -0
  63. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/auth.service.ts +1 -3
  64. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/auth/dto/auth-repsponse.dto.ts +2 -2
  65. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/queue-worker.bootstrap.ts +24 -0
  66. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.constants.ts +24 -0
  67. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.contracts.ts +35 -0
  68. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.module.ts +56 -0
  69. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.processor.ts +62 -0
  70. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/task-queue/task-queue.service.ts +58 -0
  71. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/test/error-catelog.spec.ts +34 -0
  72. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/initiate-mutipart-upload.dto.ts +26 -0
  73. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/dto/upload-params.dto.ts +15 -0
  74. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/exact-size.transform.ts +66 -0
  75. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/minio-storage.adapter.ts +239 -0
  76. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/storage/storage.port.ts +61 -0
  77. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.constants.ts +23 -0
  78. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.controller.ts +109 -0
  79. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.errors.ts +80 -0
  80. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.module.ts +20 -0
  81. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.reponsitory.ts +166 -0
  82. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/upload.service.ts +696 -0
  83. package/template-vp-monorepo-react-nestjs/apps/server/src/modules/upload/utils/object-key.ts +10 -0
  84. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.integration.spec.ts +120 -0
  85. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.processor.spec.ts +63 -0
  86. package/template-vp-monorepo-react-nestjs/apps/server/test/task-queue.service.spec.ts +106 -0
  87. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  88. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//345/274/271/347/252/227/347/273/204/344/273/266.md +4 -0
  89. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//346/226/207/344/273/266/346/213/206/345/210/206.md +4 -0
  90. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//347/273/204/344/273/266/345/221/275/345/220/215.md +3 -0
  91. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//350/241/250/346/240/274/351/241/265/351/235/242.md +11 -0
  92. package/template-vp-monorepo-react-nestjs/apps/web/.agents/rules//351/241/265/351/235/242/346/216/245/345/217/243.md +3 -0
  93. package/template-vp-monorepo-react-nestjs/apps/web/.env.dev +1 -1
  94. package/template-vp-monorepo-react-nestjs/apps/web/AGENTS.md +16 -0
  95. package/template-vp-monorepo-react-nestjs/apps/web/README.MD +153 -0
  96. package/template-vp-monorepo-react-nestjs/apps/web/index.html +3 -2
  97. package/template-vp-monorepo-react-nestjs/apps/web/package.json +6 -1
  98. package/template-vp-monorepo-react-nestjs/apps/web/public/favicon.svg +9 -1
  99. package/template-vp-monorepo-react-nestjs/apps/web/src/App.module.css +5 -0
  100. package/template-vp-monorepo-react-nestjs/apps/web/src/App.tsx +16 -9
  101. package/template-vp-monorepo-react-nestjs/apps/web/src/api/auth.ts +9 -0
  102. package/template-vp-monorepo-react-nestjs/apps/web/src/assets/svg/draft.svg +4 -0
  103. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.module.css +78 -0
  104. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/DraftProTable.tsx +99 -0
  105. package/template-vp-monorepo-react-nestjs/apps/web/src/components/DraftProTable/README.md +34 -0
  106. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.module.css +54 -0
  107. package/template-vp-monorepo-react-nestjs/apps/web/src/components/FullHeightProTable/FullHeightProTable.tsx +41 -0
  108. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/README.md +37 -0
  109. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  110. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.module.css +7 -0
  111. package/template-vp-monorepo-react-nestjs/apps/web/src/components/Loading/PageLoading.tsx +2 -1
  112. package/template-vp-monorepo-react-nestjs/apps/web/src/config/theme.ts +20 -0
  113. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.module.css +17 -0
  114. package/template-vp-monorepo-react-nestjs/apps/web/src/layouts/BasicLayout.tsx +106 -0
  115. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.module.css +23 -0
  116. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/i18n/index.tsx +53 -0
  117. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/components/ProjectFormDialog.tsx +132 -0
  118. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/columns.tsx +121 -0
  119. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/config/index.ts +77 -0
  120. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/components/DraftProjectFormDialog.tsx +140 -0
  121. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/columns.tsx +127 -0
  122. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/index.ts +39 -0
  123. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/config/projects.ts +48 -0
  124. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.module.css +49 -0
  125. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/draft/index.tsx +163 -0
  126. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.module.css +53 -0
  127. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/examples/pro-table/index.tsx +135 -0
  128. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.module.css +23 -0
  129. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/home/index.tsx +26 -43
  130. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/api.ts +11 -0
  131. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/index.tsx +183 -0
  132. package/template-vp-monorepo-react-nestjs/apps/web/src/pages/login/login.css +164 -0
  133. package/template-vp-monorepo-react-nestjs/apps/web/src/router/index.tsx +36 -12
  134. package/template-vp-monorepo-react-nestjs/apps/web/src/styles/index.css +11 -4
  135. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/core/index.ts +55 -47
  136. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/request/index.ts +10 -5
  137. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/cookie.ts +50 -0
  138. package/template-vp-monorepo-react-nestjs/apps/web/src/utils/storage/session.ts +33 -0
  139. package/template-vp-monorepo-react-nestjs/apps/web/test/draft-projects.spec.ts +89 -0
  140. package/template-vp-monorepo-react-nestjs/apps/web/test/request.spec.ts +145 -0
  141. package/template-vp-monorepo-react-nestjs/apps/web/test/storage.spec.ts +108 -0
  142. package/template-vp-monorepo-react-nestjs/apps/web/test/tsconfig.json +7 -0
  143. package/template-vp-monorepo-react-nestjs/apps/web/tsconfig.json +1 -1
  144. package/template-vp-monorepo-react-nestjs/apps/web/vite.config.ts +7 -0
  145. package/template-vp-monorepo-react-nestjs/apps/web-vue/tsconfig.tsbuildinfo +1 -0
  146. package/template-vp-monorepo-react-nestjs/docker-compose.yml +19 -0
  147. package/template-vp-monorepo-react-nestjs/mise.toml +1 -1
  148. package/template-vp-monorepo-react-nestjs/package.json +1 -6
  149. package/template-vp-monorepo-react-nestjs/pnpm-workspace.yaml +9 -1
  150. package/template-vp-react/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  151. package/template-vp-react/AGENTS.md +11 -0
  152. package/template-vp-react/commitlint.config.js +0 -0
  153. package/template-vp-react/package.json +21 -26
  154. package/template-vp-react/pnpm-workspace.yaml +6 -0
  155. package/template-vp-react/src/assets/svg/draft.svg +4 -0
  156. package/template-vp-react/src/components/Icon/svg-icon/README.md +37 -0
  157. package/template-vp-react/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  158. package/template-vp-react/src/utils/request/index.ts +18 -5
  159. package/template-vp-react/tsconfig.json +2 -3
  160. package/template-vp-react/vite.config.ts +2 -0
  161. package/template-vp-react-shadcn/.agents/rules/SVG/344/275/277/347/224/250.md +8 -0
  162. package/template-vp-react-shadcn/.vscode/settings.json +2 -2
  163. package/template-vp-react-shadcn/{agents.md → AGENTS.md} +12 -2
  164. package/template-vp-react-shadcn/README.md +41 -0
  165. package/template-vp-react-shadcn/commitlint.config.js +1 -1
  166. package/template-vp-react-shadcn/components.json +1 -1
  167. package/template-vp-react-shadcn/package.json +25 -32
  168. package/template-vp-react-shadcn/pnpm-workspace.yaml +10 -0
  169. package/template-vp-react-shadcn/src/App.tsx +10 -10
  170. package/template-vp-react-shadcn/src/assets/svg/draft.svg +4 -0
  171. package/template-vp-react-shadcn/src/components/Icon/svg-icon/README.md +37 -0
  172. package/template-vp-react-shadcn/src/components/Icon/svg-icon/SvgIcon.tsx +27 -0
  173. package/template-vp-react-shadcn/src/components/Loading/PageLoading.tsx +4 -4
  174. package/template-vp-react-shadcn/src/components/Player/VideoJS/index.tsx +94 -78
  175. package/template-vp-react-shadcn/src/components/Player/index.ts +1 -1
  176. package/template-vp-react-shadcn/src/components/ui/button.tsx +25 -32
  177. package/template-vp-react-shadcn/src/components/ui/spinner.tsx +8 -7
  178. package/template-vp-react-shadcn/src/components/ui/toast.tsx +229 -0
  179. package/template-vp-react-shadcn/src/lib/utils.ts +3 -3
  180. package/template-vp-react-shadcn/src/main.tsx +5 -4
  181. package/template-vp-react-shadcn/src/pages/home/index.tsx +43 -35
  182. package/template-vp-react-shadcn/src/router/index.tsx +15 -15
  183. package/template-vp-react-shadcn/src/styles/index.css +4 -4
  184. package/template-vp-react-shadcn/src/styles/shadcn.css +2 -2
  185. package/template-vp-react-shadcn/src/utils/env/index.tsx +2 -2
  186. package/template-vp-react-shadcn/src/utils/request/alova-core/index.ts +102 -30
  187. package/template-vp-react-shadcn/src/utils/request/alova-core/utils.ts +5 -2
  188. package/template-vp-react-shadcn/src/utils/request/index.ts +32 -19
  189. package/template-vp-react-shadcn/src/utils/request/readme.md +41 -38
  190. package/template-vp-react-shadcn/tsconfig.json +2 -3
  191. package/template-vp-react-shadcn/vite.config.ts +29 -15
  192. package/template-vp-vue-eslint-vapor/package.json +26 -33
  193. package/template-vp-vue-eslint-vapor/pnpm-workspace.yaml +29 -1
  194. package/template-vue-vp-eslint/README.md +3 -10
  195. package/template-vue-vp-eslint/package.json +27 -34
  196. package/template-vue-vp-eslint/pnpm-workspace.yaml +27 -2
  197. package/template-vue-vp-eslint/src/layout/default/index.vue +4 -3
  198. package/dist/index.mjs +0 -422
  199. package/template-vp-monorepo-react-nestjs/.agents/auth.config.ts +0 -0
  200. package/template-vp-monorepo-react-nestjs/.spaces/server/todo.md +0 -991
  201. package/template-vp-monorepo-react-nestjs/apps/server/README.md +0 -3
  202. package/template-vp-react-shadcn/.oxfmtrc.jsonc +0 -8
  203. package/template-vp-react-shadcn/.oxlintrc.jsonc +0 -3
  204. package/template-vp-react-shadcn/src/components/ui/sonner.tsx +0 -43
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round">
2
+ <path d="M6.5 3.5h11L21 12v7a1.5 1.5 0 0 1-1.5 1.5h-15A1.5 1.5 0 0 1 3 19v-7Z" />
3
+ <path d="M3 12h5.25a3.75 3.75 0 0 0 7.5 0H21" />
4
+ </svg>
@@ -0,0 +1,78 @@
1
+ @layer components {
2
+ .toolbar :global(.ant-pro-table-list-toolbar-setting-items) {
3
+ gap: 4px;
4
+ line-height: 1;
5
+ }
6
+
7
+ .toolbar :global(.ant-pro-table-list-toolbar-setting-item) {
8
+ display: flex;
9
+ width: 32px;
10
+ height: 32px;
11
+ align-items: center;
12
+ justify-content: center;
13
+ margin: 0;
14
+ border-radius: var(--ant-border-radius-sm);
15
+ font-size: 18px;
16
+ }
17
+
18
+ .toolbar :global(.ant-pro-table-list-toolbar-setting-item) > span {
19
+ display: flex;
20
+ align-items: center;
21
+ justify-content: center;
22
+ }
23
+
24
+ .toolbar :global(.ant-pro-table-list-toolbar-setting-item):hover {
25
+ background: var(--ant-color-fill-tertiary);
26
+ color: var(--ant-color-primary);
27
+ }
28
+
29
+ .draftBadge {
30
+ color: inherit;
31
+ font-size: inherit;
32
+ }
33
+
34
+ .draftToggle {
35
+ display: flex;
36
+ width: 32px;
37
+ height: 32px;
38
+ align-items: center;
39
+ justify-content: center;
40
+ padding: 0;
41
+ border: 0;
42
+ border-radius: var(--ant-border-radius-sm);
43
+ background: transparent;
44
+ color: inherit;
45
+ font-size: inherit;
46
+ line-height: 1;
47
+ cursor: pointer;
48
+ }
49
+
50
+ .draftToggle:hover {
51
+ background: var(--ant-color-fill-tertiary);
52
+ color: var(--ant-color-primary);
53
+ }
54
+
55
+ .draftToggle[aria-pressed='true'] {
56
+ background: var(--ant-color-primary-bg);
57
+ color: var(--ant-color-primary);
58
+ }
59
+
60
+ .draftToggle[aria-pressed='true']:hover {
61
+ background: var(--ant-color-primary-bg-hover);
62
+ }
63
+
64
+ .draftToggle:focus-visible {
65
+ outline: 2px solid var(--ant-color-primary);
66
+ outline-offset: 2px;
67
+ }
68
+
69
+ .hint {
70
+ display: flex;
71
+ flex-shrink: 0;
72
+ align-items: baseline;
73
+ gap: 8px;
74
+ padding-bottom: 16px;
75
+ color: var(--ant-color-text-tertiary);
76
+ font-size: 13px;
77
+ }
78
+ }
@@ -0,0 +1,99 @@
1
+ import DraftIcon from '@/assets/svg/draft.svg?react'
2
+ import { InfoCircleOutlined } from '@ant-design/icons'
3
+ import type { ParamsType } from '@ant-design/pro-components'
4
+ import { Badge } from 'antd'
5
+ import classNames from 'classnames'
6
+ import type { ReactNode } from 'react'
7
+ import FullHeightProTable, {
8
+ type FullHeightProTableProps,
9
+ } from '../FullHeightProTable/FullHeightProTable'
10
+ import SvgIcon from '../Icon/svg-icon/SvgIcon'
11
+ import styles from './DraftProTable.module.css'
12
+
13
+ export type DraftTableView = 'list' | 'draft'
14
+
15
+ export type DraftProTableProps<
16
+ DataType extends object,
17
+ Params extends ParamsType = ParamsType,
18
+ ValueType = 'text',
19
+ > = FullHeightProTableProps<DataType, Params, ValueType> & {
20
+ view: DraftTableView
21
+ onViewChange: (view: DraftTableView) => void
22
+ draftCount?: number
23
+ draftHint?: ReactNode
24
+ }
25
+
26
+ /** 只封装草稿箱入口和布局,数据、请求、表单和提交规则由业务页面提供。 */
27
+ export default function DraftProTable<
28
+ DataType extends object,
29
+ Params extends ParamsType = ParamsType,
30
+ ValueType = 'text',
31
+ >({
32
+ view,
33
+ onViewChange,
34
+ draftCount,
35
+ draftHint = '草稿提交后进入列表',
36
+ toolbar,
37
+ toolBarRender,
38
+ optionsRender,
39
+ tableViewRender,
40
+ ...props
41
+ }: DraftProTableProps<DataType, Params, ValueType>) {
42
+ const isDraft = view === 'draft'
43
+ const { actions, settings, className: toolbarClassName, ...toolbarProps } = toolbar ?? {}
44
+ const draftToggle = (
45
+ <Badge
46
+ key="draft-toggle"
47
+ className={styles.draftBadge}
48
+ count={draftCount}
49
+ size="small"
50
+ overflowCount={99}
51
+ offset={[-4, 2]}
52
+ title=""
53
+ >
54
+ <button
55
+ type="button"
56
+ className={styles.draftToggle}
57
+ aria-label={draftCount === undefined ? '草稿箱' : `草稿箱,${draftCount} 条草稿`}
58
+ aria-pressed={isDraft}
59
+ onClick={() => onViewChange(isDraft ? 'list' : 'draft')}
60
+ >
61
+ <SvgIcon icon={DraftIcon} />
62
+ </button>
63
+ </Badge>
64
+ )
65
+
66
+ return (
67
+ <FullHeightProTable<DataType, Params, ValueType>
68
+ {...props}
69
+ toolbar={{
70
+ ...toolbarProps,
71
+ className: classNames(styles.toolbar, toolbarClassName),
72
+ ...(settings ? { settings: [draftToggle, ...settings] } : {}),
73
+ }}
74
+ // ProTable 的工具栏 memo 未比较 optionsRender,保留渲染回调以同步草稿选中状态。
75
+ toolBarRender={(action, config) =>
76
+ actions ?? (typeof toolBarRender === 'function' ? toolBarRender(action, config) : [])
77
+ }
78
+ optionsRender={(toolbarOptions, defaultOptions) => [
79
+ draftToggle,
80
+ ...(optionsRender?.(toolbarOptions, defaultOptions) ?? defaultOptions),
81
+ ]}
82
+ tableViewRender={(tableProps, defaultDom) => (
83
+ <>
84
+ {isDraft && draftHint && (
85
+ <div className={styles.hint}>
86
+ <InfoCircleOutlined />
87
+ {draftHint}
88
+ </div>
89
+ )}
90
+ {tableViewRender
91
+ ? tableViewRender(tableProps, defaultDom)
92
+ : typeof defaultDom === 'function'
93
+ ? defaultDom()
94
+ : defaultDom}
95
+ </>
96
+ )}
97
+ />
98
+ )
99
+ }
@@ -0,0 +1,34 @@
1
+ # DraftProTable
2
+
3
+ 基于 `FullHeightProTable`,在工具栏右侧的刷新、列设置图标旁加入“草稿箱”图标,使用带弧形开口的收纳盒轮廓。图标右上角通过小号角标显示草稿数量,数量为 0 或未提供时隐藏,超过 99 显示 `99+`,不显示 Tooltip。默认显示列表,点击图标后以主题色图标和浅色背景高亮选中并显示草稿,再次点击取消选中、回到列表。沿用 ProTable 原生表头和表体滚动,分页位于底部。
4
+
5
+ 新增参数:
6
+
7
+ | 参数 | 说明 |
8
+ | -------------- | ------------------------------------------------------------ |
9
+ | `view` | 当前视图:`list` 或 `draft`,页面初始设为 `list` |
10
+ | `onViewChange` | 切换视图,由业务页面更新数据、重置分页和选择项 |
11
+ | `draftCount` | 草稿总数,可选;右上角角标显示,0 时隐藏,超过 99 显示 `99+` |
12
+ | `draftHint` | 草稿提示,默认“草稿提交后进入列表”,传 `false` 可隐藏 |
13
+
14
+ 其他参数沿用 `ProTableProps`,包括泛型、`request`、`params`、`actionRef`、`columns`、`pagination`、`scroll`、`headerTitle`、`toolBarRender` 等。组件通过 `optionsRender` 将草稿图标加入原生设置区,业务操作沿用 ProTable 的优先级,`toolbar.actions` 优先于 `toolBarRender`。
15
+
16
+ 调用方提供 `optionsRender` 时保留其返回的工具项;提供 `toolbar.settings` 时,草稿图标放在自定义工具项之前。`options={false}` 会随原生设置区隐藏草稿入口,但显式提供 `toolbar.settings` 时仍按该配置显示。
17
+
18
+ ```tsx
19
+ const [view, setView] = useState<DraftTableView>('list')
20
+
21
+ <DraftProTable<Project, ProjectQuery>
22
+ view={view}
23
+ onViewChange={changeView}
24
+ draftCount={draftCount}
25
+ columns={columns}
26
+ actionRef={actionRef}
27
+ params={{ view }}
28
+ request={requestProjects}
29
+ />
30
+ ```
31
+
32
+ 组件只负责 UI,不会自动添加请求参数、过滤数据、保存草稿或判断权限。使用 `request` 时,通过 `params` 带上当前视图;业务页面负责在切换时重置分页、选择项和搜索条件。
33
+
34
+ 示例路由:`/examples/pro-table/draft`。示例使用当前浏览器的本地存储和固定演示用户;真实系统的草稿持久化及可见权限应由后端处理。示例中草稿允许字段不完整,提交时校验必填项,并沿用草稿编号转为正式项目。已提交项目编辑后直接保存。
@@ -0,0 +1,54 @@
1
+ @layer components {
2
+ .proTable {
3
+ display: flex;
4
+ height: 100%;
5
+ min-height: 0;
6
+ flex-direction: column;
7
+ }
8
+
9
+ /* 窄屏展开全部搜索项时,仍为表体保留可见空间。 */
10
+ .proTable > :global(.ant-pro-table-search) {
11
+ max-height: 50%;
12
+ overflow: auto;
13
+ }
14
+
15
+ /* ProTable 会将根 className 同时附加到 tableExtraRender 容器。 */
16
+ .proTable:global(.ant-pro-table-extra) {
17
+ height: auto;
18
+ flex-shrink: 0;
19
+ }
20
+
21
+ .tableCard {
22
+ min-height: 0;
23
+ flex: 1;
24
+ }
25
+
26
+ /* 将搜索区、工具栏和分页之外的剩余高度逐层传给表体。 */
27
+ .tableCard > :global(.ant-pro-card-body),
28
+ .table,
29
+ .table > :global(.ant-spin),
30
+ .table :global(.ant-spin-container),
31
+ .table :global(.ant-table),
32
+ .table :global(.ant-table-container) {
33
+ display: flex;
34
+ min-height: 0;
35
+ flex: 1;
36
+ flex-direction: column;
37
+ }
38
+
39
+ .proTable > :global(.ant-pro-table-search),
40
+ .proTable :global(.ant-pro-table-list-toolbar),
41
+ .proTable :global(.ant-pro-table-alert),
42
+ .table :global(.ant-table-header),
43
+ .table :global(.ant-table-pagination) {
44
+ flex-shrink: 0;
45
+ }
46
+
47
+ .table :global(.ant-table-body) {
48
+ min-height: 0;
49
+ flex: 1;
50
+ overflow-y: auto !important;
51
+ /* 滚动到底部了如果再滚动看页面要不要滚动 */
52
+ overscroll-behavior: contain;
53
+ }
54
+ }
@@ -0,0 +1,41 @@
1
+ import { ProTable, type ParamsType, type ProTableProps } from '@ant-design/pro-components'
2
+ import classNames from 'classnames'
3
+ import styles from './FullHeightProTable.module.css'
4
+
5
+ export type FullHeightProTableProps<
6
+ DataType extends object,
7
+ Params extends ParamsType = ParamsType,
8
+ ValueType = 'text',
9
+ > = ProTableProps<DataType, Params, ValueType>
10
+
11
+ /**
12
+ * 父容器需有明确高度,例如 h-full;位于 flex 布局时还需 min-h-0。
13
+ * 默认使用 ProTable 原生 scroll.y 固定表头,表体占据剩余高度并独立滚动。
14
+ */
15
+ export default function FullHeightProTable<
16
+ DataType extends object,
17
+ Params extends ParamsType = ParamsType,
18
+ ValueType = 'text',
19
+ >({
20
+ className,
21
+ cardProps,
22
+ tableClassName,
23
+ scroll,
24
+ ...props
25
+ }: FullHeightProTableProps<DataType, Params, ValueType>) {
26
+ return (
27
+ <div className="w-full h-full p-[16px]">
28
+ <ProTable<DataType, Params, ValueType>
29
+ {...props}
30
+ className={classNames(styles.proTable, className)}
31
+ cardProps={
32
+ cardProps === false
33
+ ? false
34
+ : { ...cardProps, className: classNames(styles.tableCard, cardProps?.className) }
35
+ }
36
+ tableClassName={classNames(styles.table, tableClassName)}
37
+ scroll={{ x: 'max-content', y: 'auto', ...scroll }}
38
+ />
39
+ </div>
40
+ )
41
+ }
@@ -0,0 +1,37 @@
1
+ # SvgIcon
2
+
3
+ 使用 `vite-plugin-svgr` 将本地 SVG 导入为 React 组件,再由 `SvgIcon` 统一控制大小与颜色。
4
+
5
+ ```tsx
6
+ import DraftIcon from '@/assets/svg/draft.svg?react'
7
+ import SvgIcon from '@/components/Icon/svg-icon/SvgIcon'
8
+ ;<SvgIcon icon={DraftIcon} size={24} color="#1677ff" />
9
+ ```
10
+
11
+ | 参数 | 说明 |
12
+ | -------------------- | ----------------------------------------------------------------- |
13
+ | `icon` | 通过 `?react` 导入的 SVG 组件,必填 |
14
+ | `size` | 字号,数字按 px 处理,也支持 `1.5rem` 等 CSS 长度;不传时继承父级 |
15
+ | `color` | 图标颜色;不传时继承父级 |
16
+ | `className`、`style` | 原生 SVG 样式;`style` 中的同名设置优先 |
17
+
18
+ SVG 的宽高统一为 `1em`,因此 `font-size` 决定图标大小。`ref`、事件和其他 SVG 属性继续透传。默认作为装饰图标隐藏于辅助技术;需要独立表达含义时传 `role="img"` 和 `aria-label`。
19
+
20
+ ```tsx
21
+ <span style={{ fontSize: 20, color: '#1677ff' }}>
22
+ <SvgIcon icon={DraftIcon} />
23
+ 草稿
24
+ </span>
25
+
26
+ <SvgIcon icon={DraftIcon} size={24} role="img" aria-label="草稿" />
27
+ ```
28
+
29
+ 源文件规范:
30
+
31
+ - 保留 `viewBox`,保证缩放正确。
32
+ - 单色填充图标使用 `fill="currentColor"`;线条图标使用 `stroke="currentColor"`。
33
+ - 保留 `fill="none"`、`stroke="none"`,避免填实空心图形。
34
+ - 内部元素若写死颜色,也需要在源文件中改成 `currentColor` 才能跟随文字颜色。
35
+ - SVGR 与组件保留多色和渐变,不会强制覆盖所有颜色。
36
+
37
+ 现有 `draft.svg` 已遵循上述规范。直接导入 `draft.svg` 仍然得到资源 URL,只有 `draft.svg?react` 会转换为 React 组件。
@@ -0,0 +1,27 @@
1
+ import type { ComponentType, SVGProps } from 'react'
2
+
3
+ export type SvgIconProps = Omit<SVGProps<SVGSVGElement>, 'width' | 'height'> & {
4
+ icon: ComponentType<SVGProps<SVGSVGElement>>
5
+ size?: number | string
6
+ }
7
+
8
+ /** SVG 源文件使用 currentColor;不传 size、color 时继承父级文字样式。 */
9
+ export default function SvgIcon({ icon: Icon, size, color, style, ...props }: SvgIconProps) {
10
+ return (
11
+ <Icon
12
+ aria-hidden={props['aria-label'] || props['aria-labelledby'] ? undefined : true}
13
+ focusable="false"
14
+ {...props}
15
+ width="1em"
16
+ height="1em"
17
+ style={{
18
+ display: 'inline-block',
19
+ verticalAlign: '-0.125em',
20
+ flexShrink: 0,
21
+ fontSize: size,
22
+ color,
23
+ ...style,
24
+ }}
25
+ />
26
+ )
27
+ }
@@ -0,0 +1,7 @@
1
+ @layer components {
2
+ .pageLoading {
3
+ display: grid;
4
+ min-height: 50vh;
5
+ place-items: center;
6
+ }
7
+ }
@@ -1,8 +1,9 @@
1
1
  import { Spin } from 'antd'
2
+ import styles from './PageLoading.module.css'
2
3
 
3
4
  const Loading = () => {
4
5
  return (
5
- <div className="flex h-screen w-screen items-center justify-center">
6
+ <div className={styles.pageLoading} role="status" aria-label="页面加载中">
6
7
  <Spin size="large" />
7
8
  </div>
8
9
  )
@@ -0,0 +1,20 @@
1
+ import type { ThemeConfig } from 'antd'
2
+
3
+ /** Ant Design 与 ProComponents 共用的主题入口。 */
4
+ export const appTheme: ThemeConfig = {
5
+ token: {
6
+ colorPrimary: '#176f88',
7
+ colorInfo: '#176f88',
8
+ colorBgLayout: '#f3f6f8',
9
+ colorText: '#1a2938',
10
+ colorBorderSecondary: '#dfe7ed',
11
+ borderRadius: 6,
12
+ fontFamily: '"Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif',
13
+ },
14
+ components: {
15
+ Layout: {
16
+ headerBg: '#ffffff',
17
+ siderBg: '#ffffff',
18
+ },
19
+ },
20
+ }
@@ -0,0 +1,17 @@
1
+ @layer components {
2
+ .brand {
3
+ display: flex;
4
+ align-items: center;
5
+ gap: 12px;
6
+ }
7
+
8
+ .logo {
9
+ color: var(--ant-color-primary);
10
+ font-size: 28px;
11
+ }
12
+
13
+ .brand h1 {
14
+ font-family: Bahnschrift, 'Microsoft YaHei', sans-serif;
15
+ letter-spacing: 0.04em;
16
+ }
17
+ }
@@ -0,0 +1,106 @@
1
+ import {
2
+ AppstoreOutlined,
3
+ DashboardOutlined,
4
+ LogoutOutlined,
5
+ TableOutlined,
6
+ TranslationOutlined,
7
+ } from '@ant-design/icons'
8
+ import { ProLayout } from '@ant-design/pro-components'
9
+ import { useRequest } from 'alova/client'
10
+ import { App, Button } from 'antd'
11
+ import { Suspense } from 'react'
12
+ import { Link, Outlet, useLocation, useNavigate } from 'react-router'
13
+ import PageLoading from '@/components/Loading/PageLoading'
14
+ import { logout } from '@/api/auth'
15
+ import { cookie } from '@/utils/storage/cookie'
16
+ import styles from './BasicLayout.module.css'
17
+
18
+ const menuRoutes = [
19
+ { path: '/home', name: '工作台', icon: <DashboardOutlined /> },
20
+ {
21
+ path: '/examples/pro-table',
22
+ key: 'pro-table-examples',
23
+ name: 'ProTable 示例',
24
+ icon: <TableOutlined />,
25
+ routes: [
26
+ { path: '/examples/pro-table', key: 'pro-table-basic', name: '基础' },
27
+ { path: '/examples/pro-table/draft', name: '草稿' },
28
+ ],
29
+ },
30
+ { path: '/examples/i18n', name: '国际化示例', icon: <TranslationOutlined /> },
31
+ ]
32
+
33
+ export default function BasicLayout() {
34
+ const location = useLocation()
35
+ const navigate = useNavigate()
36
+ const token = cookie.get('token')
37
+ const { message } = App.useApp()
38
+ const { send, loading } = useRequest(logout, { immediate: false })
39
+
40
+ async function handleLogout() {
41
+ if (loading) return
42
+ try {
43
+ await send()
44
+ cookie.remove('token')
45
+ void navigate('/login', { replace: true })
46
+ } catch (error) {
47
+ void message.error(error instanceof Error ? error.message : '退出失败,请重试')
48
+ }
49
+ }
50
+
51
+ return (
52
+ <ProLayout
53
+ className="platform-layout"
54
+ style={{ height: '100dvh', overflow: 'hidden' }}
55
+ contentStyle={{ minHeight: 0, padding: 0, overflow: 'auto' }}
56
+ title="通用平台"
57
+ logo={<AppstoreOutlined className={styles.logo} />}
58
+ layout="mix"
59
+ fixedHeader
60
+ fixSiderbar
61
+ siderWidth={224}
62
+ actionsRender={() =>
63
+ token
64
+ ? [
65
+ <Button
66
+ key="logout"
67
+ type="text"
68
+ icon={<LogoutOutlined />}
69
+ loading={loading}
70
+ onClick={() => void handleLogout()}
71
+ >
72
+ 退出登录
73
+ </Button>,
74
+ ]
75
+ : [
76
+ <Link key="login" to="/login">
77
+ 登录
78
+ </Link>,
79
+ ]
80
+ }
81
+ location={location}
82
+ route={{ path: '/', routes: menuRoutes }}
83
+ menu={{ locale: false }}
84
+ menuProps={{
85
+ selectedKeys: [
86
+ location.pathname === '/examples/pro-table' ? 'pro-table-basic' : location.pathname,
87
+ ],
88
+ }}
89
+ menuItemRender={(item, dom, { isMobile }) => (
90
+ <Link to={item.path ?? '/home'} onClick={isMobile ? item.onClick : undefined}>
91
+ {dom}
92
+ </Link>
93
+ )}
94
+ headerTitleRender={(logo, title) => (
95
+ <Link className={styles.brand} to="/home" aria-label="通用平台首页">
96
+ {logo}
97
+ {title}
98
+ </Link>
99
+ )}
100
+ >
101
+ <Suspense fallback={<PageLoading />}>
102
+ <Outlet />
103
+ </Suspense>
104
+ </ProLayout>
105
+ )
106
+ }
@@ -0,0 +1,23 @@
1
+ @layer components {
2
+ .demo {
3
+ display: flex;
4
+ flex-wrap: wrap;
5
+ gap: 24px;
6
+ }
7
+
8
+ .panel {
9
+ display: flex;
10
+ flex: 1 1 256px;
11
+ flex-direction: column;
12
+ gap: 12px;
13
+ padding: 16px;
14
+ border: 1px solid var(--ant-color-border-secondary);
15
+ border-radius: var(--ant-border-radius);
16
+ }
17
+
18
+ .panel h2 {
19
+ margin: 0;
20
+ font-size: 18px;
21
+ font-weight: 500;
22
+ }
23
+ }
@@ -0,0 +1,53 @@
1
+ import { createJsonStorage, i18n } from '@bubblesjs/i18n-core'
2
+ import I18nProvider, { useI18n } from '@bubblesjs/i18n-react'
3
+ import { PageContainer, ProCard } from '@ant-design/pro-components'
4
+ import { Button } from 'antd'
5
+ import styles from './index.module.css'
6
+
7
+ const leftStore = await i18n.init({
8
+ locale: 'zh_CN',
9
+ loaderMessage: async (locale?: string) => (await import(`@/locales/${locale}.json`))?.default,
10
+ storageKey: 'i18n-home-left',
11
+ storage: createJsonStorage(localStorage),
12
+ })
13
+
14
+ const rightStore = await i18n.init({
15
+ locale: 'en_US',
16
+ loaderMessage: async (locale?: string) => (await import(`@/locales/${locale}.json`))?.default,
17
+ storageKey: 'i18n-home-right',
18
+ storage: createJsonStorage(localStorage),
19
+ })
20
+
21
+ const I18nTestNode = ({ title, switchLocale }: { title: string; switchLocale: string }) => {
22
+ const { tr, loadLocale, locale } = useI18n()
23
+
24
+ return (
25
+ <section className={styles.panel}>
26
+ <h2>{title}</h2>
27
+ <div>{tr('保存')}</div>
28
+ <div>{tr('你好1')}</div>
29
+ <div>目前语言: {locale}</div>
30
+ <Button onClick={() => void loadLocale(switchLocale)}>切换到 {switchLocale}</Button>
31
+ </section>
32
+ )
33
+ }
34
+
35
+ const I18nExample = () => {
36
+ return (
37
+ <PageContainer title="国际化示例" content="两个独立语言作用域,分别切换并保存语言偏好。">
38
+ <ProCard title="语言作用域" variant="outlined">
39
+ <div className={styles.demo}>
40
+ <I18nProvider store={leftStore}>
41
+ <I18nTestNode title="节点 A" switchLocale="en_US" />
42
+ </I18nProvider>
43
+
44
+ <I18nProvider store={rightStore}>
45
+ <I18nTestNode title="节点 B" switchLocale="zh_CN" />
46
+ </I18nProvider>
47
+ </div>
48
+ </ProCard>
49
+ </PageContainer>
50
+ )
51
+ }
52
+
53
+ export default I18nExample