@skyroc/scripts 2.5.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 (333) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +508 -0
  3. package/dist/cli.mjs +78 -0
  4. package/dist/config-BKkdncJS.mjs +987 -0
  5. package/dist/index.mjs +14 -0
  6. package/package.json +83 -0
  7. package/templates/admin/.env +62 -0
  8. package/templates/admin/.env.prod +7 -0
  9. package/templates/admin/.env.test +7 -0
  10. package/templates/admin/.oxlintrc.json +6 -0
  11. package/templates/admin/README.md +508 -0
  12. package/templates/admin/index.html +14 -0
  13. package/templates/admin/package.json +105 -0
  14. package/templates/admin/public/favicon.svg +3 -0
  15. package/templates/admin/src/App.tsx +71 -0
  16. package/templates/admin/src/assets/audio/wechat-style-notification.wav +0 -0
  17. package/templates/admin/src/assets/imgs/skyroc.jpg +0 -0
  18. package/templates/admin/src/assets/svg-icon/activity.svg +1 -0
  19. package/templates/admin/src/assets/svg-icon/at-sign.svg +1 -0
  20. package/templates/admin/src/assets/svg-icon/avatar.svg +1 -0
  21. package/templates/admin/src/assets/svg-icon/banner.svg +1 -0
  22. package/templates/admin/src/assets/svg-icon/cast.svg +1 -0
  23. package/templates/admin/src/assets/svg-icon/chrome.svg +1 -0
  24. package/templates/admin/src/assets/svg-icon/copy.svg +1 -0
  25. package/templates/admin/src/assets/svg-icon/custom-icon.svg +1 -0
  26. package/templates/admin/src/assets/svg-icon/empty-data.svg +1 -0
  27. package/templates/admin/src/assets/svg-icon/error.svg +1 -0
  28. package/templates/admin/src/assets/svg-icon/expectation.svg +1 -0
  29. package/templates/admin/src/assets/svg-icon/heart.svg +1 -0
  30. package/templates/admin/src/assets/svg-icon/logo.svg +15 -0
  31. package/templates/admin/src/assets/svg-icon/network-error.svg +1 -0
  32. package/templates/admin/src/assets/svg-icon/no-icon.svg +1 -0
  33. package/templates/admin/src/assets/svg-icon/no-permission.svg +1 -0
  34. package/templates/admin/src/assets/svg-icon/not-found.svg +1 -0
  35. package/templates/admin/src/assets/svg-icon/service-error.svg +1 -0
  36. package/templates/admin/src/bootstrap.tsx +60 -0
  37. package/templates/admin/src/components/SkyrocAvatar.tsx +13 -0
  38. package/templates/admin/src/components/SystemLogo.tsx +7 -0
  39. package/templates/admin/src/config.ts +125 -0
  40. package/templates/admin/src/features/antd/AntdProvider.tsx +21 -0
  41. package/templates/admin/src/features/auth/components/UserAvatar.tsx +76 -0
  42. package/templates/admin/src/features/auth/use-auth-form-rules.ts +83 -0
  43. package/templates/admin/src/features/auth/use-auth.ts +96 -0
  44. package/templates/admin/src/features/auth/use-login.ts +72 -0
  45. package/templates/admin/src/features/effects/GlobalEffect.tsx +15 -0
  46. package/templates/admin/src/features/menus/dynamic-routes.ts +10 -0
  47. package/templates/admin/src/features/menus/extras.ts +3 -0
  48. package/templates/admin/src/features/menus/menu-category.ts +14 -0
  49. package/templates/admin/src/features/menus/menu-config.ts +5 -0
  50. package/templates/admin/src/features/router/RouterProvider.tsx +18 -0
  51. package/templates/admin/src/features/router/guard.ts +97 -0
  52. package/templates/admin/src/features/router/index.ts +52 -0
  53. package/templates/admin/src/features/router/routeTree.gen.ts +237 -0
  54. package/templates/admin/src/features/router/router-ref.ts +24 -0
  55. package/templates/admin/src/locales/antd.ts +8 -0
  56. package/templates/admin/src/locales/index.ts +22 -0
  57. package/templates/admin/src/locales/sync.ts +14 -0
  58. package/templates/admin/src/main.tsx +9 -0
  59. package/templates/admin/src/pages/(admin)/home/index.tsx +46 -0
  60. package/templates/admin/src/pages/(admin)/layout.tsx +44 -0
  61. package/templates/admin/src/pages/(auth)/login/index.tsx +102 -0
  62. package/templates/admin/src/pages/(auth)/login/layout.tsx +71 -0
  63. package/templates/admin/src/pages/(auth)/login-out.tsx +27 -0
  64. package/templates/admin/src/pages/(errors)/403.tsx +16 -0
  65. package/templates/admin/src/pages/(errors)/404.tsx +16 -0
  66. package/templates/admin/src/pages/(errors)/500.tsx +16 -0
  67. package/templates/admin/src/pages/__root.tsx +54 -0
  68. package/templates/admin/src/pages/error.tsx +19 -0
  69. package/templates/admin/src/pages/index.tsx +14 -0
  70. package/templates/admin/src/pages/loading.tsx +45 -0
  71. package/templates/admin/src/pages/not-found.tsx +9 -0
  72. package/templates/admin/src/plugins/app.tsx +47 -0
  73. package/templates/admin/src/plugins/assets.ts +4 -0
  74. package/templates/admin/src/plugins/index.ts +32 -0
  75. package/templates/admin/src/service/adapter.ts +63 -0
  76. package/templates/admin/src/service/api/auth/api.ts +31 -0
  77. package/templates/admin/src/service/api/auth/hooks.ts +28 -0
  78. package/templates/admin/src/service/api/auth/index.ts +10 -0
  79. package/templates/admin/src/service/api/auth/keys.ts +7 -0
  80. package/templates/admin/src/service/api/auth/urls.ts +7 -0
  81. package/templates/admin/src/service/api/index.ts +2 -0
  82. package/templates/admin/src/service/api/route/api.ts +7 -0
  83. package/templates/admin/src/service/api/route/hooks.ts +21 -0
  84. package/templates/admin/src/service/api/route/index.ts +10 -0
  85. package/templates/admin/src/service/api/route/keys.ts +3 -0
  86. package/templates/admin/src/service/api/route/urls.ts +5 -0
  87. package/templates/admin/src/service/queryClient.ts +13 -0
  88. package/templates/admin/src/service/request/index.ts +62 -0
  89. package/templates/admin/src/styles/scss/global.scss +1 -0
  90. package/templates/admin/src/styles/scss/scrollbar.scss +28 -0
  91. package/templates/admin/src/types/auto-imports.d.ts +186 -0
  92. package/templates/admin/src/types/global.d.ts +16 -0
  93. package/templates/admin/src/types/router.d.ts +14 -0
  94. package/templates/admin/src/types/storage.d.ts +17 -0
  95. package/templates/admin/src/types/vite-env.d.ts +117 -0
  96. package/templates/admin/src/utils/common.tsx +38 -0
  97. package/templates/admin/src/utils/icon.ts +9 -0
  98. package/templates/admin/src/utils/service.ts +75 -0
  99. package/templates/admin/src/utils/storage.ts +7 -0
  100. package/templates/admin/tsconfig.json +22 -0
  101. package/templates/admin/uno.config.ts +18 -0
  102. package/templates/admin/vite.config.ts +13 -0
  103. package/templates/admin-shell/i18n/atoms/lang.ts +20 -0
  104. package/templates/admin-shell/i18n/config/default.ts +11 -0
  105. package/templates/admin-shell/i18n/features/lang/LangEffect.tsx +25 -0
  106. package/templates/admin-shell/i18n/features/lang/LangSwitch.tsx +49 -0
  107. package/templates/admin-shell/i18n/hooks/use-lang.ts +47 -0
  108. package/templates/admin-shell/i18n/i18n.ts +116 -0
  109. package/templates/admin-shell/i18n/index.ts +23 -0
  110. package/templates/admin-shell/i18n/langs/en-us/common.json +49 -0
  111. package/templates/admin-shell/i18n/langs/en-us/datatable.json +8 -0
  112. package/templates/admin-shell/i18n/langs/en-us/dropdown.json +9 -0
  113. package/templates/admin-shell/i18n/langs/en-us/form.json +27 -0
  114. package/templates/admin-shell/i18n/langs/en-us/icon.json +13 -0
  115. package/templates/admin-shell/i18n/langs/en-us/notification.json +20 -0
  116. package/templates/admin-shell/i18n/langs/en-us/page.json +442 -0
  117. package/templates/admin-shell/i18n/langs/en-us/request.json +8 -0
  118. package/templates/admin-shell/i18n/langs/en-us/route.json +84 -0
  119. package/templates/admin-shell/i18n/langs/en-us/system.json +9 -0
  120. package/templates/admin-shell/i18n/langs/en-us/theme.json +173 -0
  121. package/templates/admin-shell/i18n/langs/index.ts +63 -0
  122. package/templates/admin-shell/i18n/langs/zh-cn/common.json +49 -0
  123. package/templates/admin-shell/i18n/langs/zh-cn/datatable.json +8 -0
  124. package/templates/admin-shell/i18n/langs/zh-cn/dropdown.json +9 -0
  125. package/templates/admin-shell/i18n/langs/zh-cn/form.json +27 -0
  126. package/templates/admin-shell/i18n/langs/zh-cn/icon.json +13 -0
  127. package/templates/admin-shell/i18n/langs/zh-cn/notification.json +20 -0
  128. package/templates/admin-shell/i18n/langs/zh-cn/page.json +442 -0
  129. package/templates/admin-shell/i18n/langs/zh-cn/request.json +8 -0
  130. package/templates/admin-shell/i18n/langs/zh-cn/route.json +84 -0
  131. package/templates/admin-shell/i18n/langs/zh-cn/system.json +9 -0
  132. package/templates/admin-shell/i18n/langs/zh-cn/theme.json +173 -0
  133. package/templates/admin-shell/i18n/types/i18n.ts +29 -0
  134. package/templates/admin-shell/i18n/types.ts +53 -0
  135. package/templates/admin-shell/i18n/utils/helpers.ts +18 -0
  136. package/templates/admin-shell/layouts/AdminLayout.tsx +161 -0
  137. package/templates/admin-shell/layouts/constant.ts +56 -0
  138. package/templates/admin-shell/layouts/context.tsx +101 -0
  139. package/templates/admin-shell/layouts/features/menus/MenuBadge.tsx +76 -0
  140. package/templates/admin-shell/layouts/features/menus/dynamic-routes.ts +146 -0
  141. package/templates/admin-shell/layouts/features/menus/menu-generator.tsx +444 -0
  142. package/templates/admin-shell/layouts/features/menus/menu-renderer.tsx +149 -0
  143. package/templates/admin-shell/layouts/features/menus/permissions.ts +28 -0
  144. package/templates/admin-shell/layouts/features/menus/use-menus.ts +98 -0
  145. package/templates/admin-shell/layouts/features/use-route.ts +30 -0
  146. package/templates/admin-shell/layouts/index.ts +44 -0
  147. package/templates/admin-shell/layouts/materials/index.ts +6 -0
  148. package/templates/admin-shell/layouts/materials/libs/admin-layout/index.module.css +63 -0
  149. package/templates/admin-shell/layouts/materials/libs/admin-layout/index.module.css.d.ts +18 -0
  150. package/templates/admin-shell/layouts/materials/libs/admin-layout/index.tsx +238 -0
  151. package/templates/admin-shell/layouts/materials/libs/admin-layout/shared.ts +67 -0
  152. package/templates/admin-shell/layouts/materials/libs/page-tab/ButtonTab.tsx +44 -0
  153. package/templates/admin-shell/layouts/materials/libs/page-tab/ChromeTab.tsx +54 -0
  154. package/templates/admin-shell/layouts/materials/libs/page-tab/ChromeTabBg.tsx +30 -0
  155. package/templates/admin-shell/layouts/materials/libs/page-tab/SliderTab.tsx +44 -0
  156. package/templates/admin-shell/layouts/materials/libs/page-tab/SvgClose.tsx +51 -0
  157. package/templates/admin-shell/layouts/materials/libs/page-tab/hook.ts +34 -0
  158. package/templates/admin-shell/layouts/materials/libs/page-tab/index.module.css +120 -0
  159. package/templates/admin-shell/layouts/materials/libs/page-tab/index.module.css.d.ts +18 -0
  160. package/templates/admin-shell/layouts/materials/libs/page-tab/index.tsx +76 -0
  161. package/templates/admin-shell/layouts/materials/libs/page-tab/shared.ts +32 -0
  162. package/templates/admin-shell/layouts/materials/types/index.ts +322 -0
  163. package/templates/admin-shell/layouts/modules/AdminContent.tsx +285 -0
  164. package/templates/admin-shell/layouts/modules/AdminFooter.tsx +13 -0
  165. package/templates/admin-shell/layouts/modules/AdminLogo.tsx +28 -0
  166. package/templates/admin-shell/layouts/modules/AdminSider.tsx +50 -0
  167. package/templates/admin-shell/layouts/modules/admin-header/AdminHeader.tsx +132 -0
  168. package/templates/admin-shell/layouts/modules/admin-header/components/Breadcrumb.tsx +62 -0
  169. package/templates/admin-shell/layouts/modules/admin-header/components/ThemeButton.tsx +24 -0
  170. package/templates/admin-shell/layouts/modules/admin-menu/AdminMenu.tsx +37 -0
  171. package/templates/admin-shell/layouts/modules/admin-menu/components/FirstLevelMenu.tsx +156 -0
  172. package/templates/admin-shell/layouts/modules/admin-menu/components/HorizontalMenu.tsx +88 -0
  173. package/templates/admin-shell/layouts/modules/admin-menu/components/MenuPortal.tsx +28 -0
  174. package/templates/admin-shell/layouts/modules/admin-menu/components/VerticalMenu.tsx +123 -0
  175. package/templates/admin-shell/layouts/modules/admin-menu/enum.ts +47 -0
  176. package/templates/admin-shell/layouts/modules/admin-menu/modules/Horizontal.tsx +22 -0
  177. package/templates/admin-shell/layouts/modules/admin-menu/modules/TopHybridHeaderFirst.tsx +15 -0
  178. package/templates/admin-shell/layouts/modules/admin-menu/modules/TopHybridSidebarFirst.tsx +18 -0
  179. package/templates/admin-shell/layouts/modules/admin-menu/modules/Vertical.tsx +14 -0
  180. package/templates/admin-shell/layouts/modules/admin-menu/modules/VerticalHybridHeaderFirst.tsx +18 -0
  181. package/templates/admin-shell/layouts/modules/admin-menu/modules/VerticalMix.tsx +132 -0
  182. package/templates/admin-shell/layouts/modules/admin-search/AdminSearch.tsx +36 -0
  183. package/templates/admin-shell/layouts/modules/admin-search/components/SearchFooter.tsx +38 -0
  184. package/templates/admin-shell/layouts/modules/admin-search/components/SearchModal.tsx +171 -0
  185. package/templates/admin-shell/layouts/modules/admin-search/components/SearchResult.tsx +43 -0
  186. package/templates/admin-shell/layouts/modules/admin-tab/AdminTab.tsx +125 -0
  187. package/templates/admin-shell/layouts/modules/admin-tab/components/TabContextMenu.tsx +107 -0
  188. package/templates/admin-shell/layouts/modules/admin-tab/hooks/useTabScroll.ts +86 -0
  189. package/templates/admin-shell/layouts/modules/shared/logo.ts +42 -0
  190. package/templates/admin-shell/layouts/modules/theme-drawer/ThemeDrawer.tsx +68 -0
  191. package/templates/admin-shell/layouts/modules/theme-drawer/components/AnimatedCollapse.tsx +36 -0
  192. package/templates/admin-shell/layouts/modules/theme-drawer/components/AnimatedItem.tsx +35 -0
  193. package/templates/admin-shell/layouts/modules/theme-drawer/components/LayoutModeCard.tsx +110 -0
  194. package/templates/admin-shell/layouts/modules/theme-drawer/components/SettingItem.tsx +31 -0
  195. package/templates/admin-shell/layouts/modules/theme-drawer/modules/ConfigOperation.tsx +53 -0
  196. package/templates/admin-shell/layouts/modules/theme-drawer/modules/appearance/CustomPicker.tsx +105 -0
  197. package/templates/admin-shell/layouts/modules/theme-drawer/modules/appearance/ThemeColor.tsx +58 -0
  198. package/templates/admin-shell/layouts/modules/theme-drawer/modules/appearance/ThemeSchema.tsx +42 -0
  199. package/templates/admin-shell/layouts/modules/theme-drawer/modules/appearance/ThemeToken.tsx +44 -0
  200. package/templates/admin-shell/layouts/modules/theme-drawer/modules/appearance/index.tsx +23 -0
  201. package/templates/admin-shell/layouts/modules/theme-drawer/modules/general/GlobalSettings.tsx +57 -0
  202. package/templates/admin-shell/layouts/modules/theme-drawer/modules/general/ThemeGeneral.tsx +20 -0
  203. package/templates/admin-shell/layouts/modules/theme-drawer/modules/general/WatermarkSettings.tsx +103 -0
  204. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/ContentSettings.tsx +100 -0
  205. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/FooterSettings.tsx +71 -0
  206. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/HeaderSettings.tsx +63 -0
  207. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/LayoutMode.tsx +73 -0
  208. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/SiderSettings.tsx +124 -0
  209. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/TabSettings.tsx +95 -0
  210. package/templates/admin-shell/layouts/modules/theme-drawer/modules/layout/ThemeLayout.tsx +32 -0
  211. package/templates/admin-shell/layouts/modules/theme-drawer/modules/preset/ThemePreset.tsx +132 -0
  212. package/templates/admin-shell/layouts/options.tsx +79 -0
  213. package/templates/admin-shell/layouts/setup.ts +102 -0
  214. package/templates/admin-shell/layouts/state/AdminEffect.tsx +56 -0
  215. package/templates/admin-shell/layouts/state/AdminTabEffect.tsx +28 -0
  216. package/templates/admin-shell/layouts/state/index.ts +3 -0
  217. package/templates/admin-shell/layouts/state/menus/MenuToggler.tsx +53 -0
  218. package/templates/admin-shell/layouts/state/menus/use-admin-menu-badges.ts +46 -0
  219. package/templates/admin-shell/layouts/state/menus/use-admin-menus.tsx +164 -0
  220. package/templates/admin-shell/layouts/state/tabs/index.ts +1 -0
  221. package/templates/admin-shell/layouts/state/tabs/shared.tsx +148 -0
  222. package/templates/admin-shell/layouts/state/tabs/use-admin-tab.ts +377 -0
  223. package/templates/admin-shell/layouts/state/use-admin-state.ts +118 -0
  224. package/templates/admin-shell/layouts/types/router.d.ts +10 -0
  225. package/templates/admin-shell/layouts/types/storage.ts +18 -0
  226. package/templates/admin-shell/notification/NotificationButton.tsx +91 -0
  227. package/templates/admin-shell/notification/NotificationContext.ts +8 -0
  228. package/templates/admin-shell/notification/NotificationPanel.tsx +194 -0
  229. package/templates/admin-shell/notification/NotificationProvider.tsx +59 -0
  230. package/templates/admin-shell/notification/index.ts +12 -0
  231. package/templates/admin-shell/notification/mock.ts +59 -0
  232. package/templates/admin-shell/notification/notification-store.ts +438 -0
  233. package/templates/admin-shell/notification/notification.css +60 -0
  234. package/templates/admin-shell/notification/types.ts +104 -0
  235. package/templates/admin-shell/notification/use-notification.ts +51 -0
  236. package/templates/admin-shell/notification/useNotificationContext.ts +14 -0
  237. package/templates/admin-shell/runtime/app-update.ts +156 -0
  238. package/templates/admin-shell/runtime/dayjs.ts +20 -0
  239. package/templates/admin-shell/runtime/iconify.ts +17 -0
  240. package/templates/admin-shell/runtime/index.ts +10 -0
  241. package/templates/admin-shell/runtime/nprogress.ts +25 -0
  242. package/templates/admin-shell/runtime/plugins.ts +62 -0
  243. package/templates/admin-shell/styles/global.css +54 -0
  244. package/templates/admin-shell/styles/nprogress.css +85 -0
  245. package/templates/admin-shell/styles/reset.css +378 -0
  246. package/templates/admin-shell/theme/antd/AntdProvider.tsx +106 -0
  247. package/templates/admin-shell/theme/antd/index.ts +23 -0
  248. package/templates/admin-shell/theme/antd/shared.ts +80 -0
  249. package/templates/admin-shell/theme/antd/ui.ts +250 -0
  250. package/templates/admin-shell/theme/antd-algorithm/algorithm/dark/colors.ts +99 -0
  251. package/templates/admin-shell/theme/antd-algorithm/algorithm/dark/index.ts +87 -0
  252. package/templates/admin-shell/theme/antd-algorithm/algorithm/default/colors.ts +91 -0
  253. package/templates/admin-shell/theme/antd-algorithm/algorithm/default/index.ts +77 -0
  254. package/templates/admin-shell/theme/antd-algorithm/index.ts +80 -0
  255. package/templates/admin-shell/theme/antd-algorithm/seed/index.ts +41 -0
  256. package/templates/admin-shell/theme/antd-algorithm/shared/colorAlgorithm.ts +10 -0
  257. package/templates/admin-shell/theme/antd-algorithm/shared/genColorMapToken.ts +165 -0
  258. package/templates/admin-shell/theme/antd-algorithm/shared/genCommonMapToken.ts +23 -0
  259. package/templates/admin-shell/theme/antd-algorithm/shared/genControlHeight.ts +14 -0
  260. package/templates/admin-shell/theme/antd-algorithm/shared/genFontMapToken.ts +274 -0
  261. package/templates/admin-shell/theme/antd-algorithm/shared/genRadiusMapToken.ts +139 -0
  262. package/templates/admin-shell/theme/antd-algorithm/shared/genSizeMapToken.ts +114 -0
  263. package/templates/admin-shell/theme/antd-algorithm/types/index.ts +20 -0
  264. package/templates/admin-shell/theme/components/ThemeEffect.tsx +55 -0
  265. package/templates/admin-shell/theme/components/ThemeSchemaSegmented.tsx +27 -0
  266. package/templates/admin-shell/theme/components/ThemeSchemaSwitch.tsx +77 -0
  267. package/templates/admin-shell/theme/components/shared.ts +5 -0
  268. package/templates/admin-shell/theme/config/default.ts +108 -0
  269. package/templates/admin-shell/theme/config/index.ts +1 -0
  270. package/templates/admin-shell/theme/hooks/index.ts +2 -0
  271. package/templates/admin-shell/theme/hooks/use-theme.ts +244 -0
  272. package/templates/admin-shell/theme/index.ts +78 -0
  273. package/templates/admin-shell/theme/presets/azir.json +39 -0
  274. package/templates/admin-shell/theme/presets/compact.json +38 -0
  275. package/templates/admin-shell/theme/presets/dark.json +93 -0
  276. package/templates/admin-shell/theme/presets/default.json +95 -0
  277. package/templates/admin-shell/theme/presets/index.ts +29 -0
  278. package/templates/admin-shell/theme/presets/shadcn.json +99 -0
  279. package/templates/admin-shell/theme/setup.ts +115 -0
  280. package/templates/admin-shell/theme/types/index.ts +27 -0
  281. package/templates/admin-shell/theme/types/theme.d.ts +316 -0
  282. package/templates/admin-shell/theme/utils/dark-mode.ts +46 -0
  283. package/templates/admin-shell/theme/utils/filters.ts +20 -0
  284. package/templates/admin-shell/theme/utils/index.ts +3 -0
  285. package/templates/admin-shell/theme/utils/settings.ts +43 -0
  286. package/templates/admin-shell/types/api/auth.d.ts +148 -0
  287. package/templates/admin-shell/types/api/common.d.ts +54 -0
  288. package/templates/admin-shell/types/api/route.d.ts +104 -0
  289. package/templates/admin-shell/types/api/service.d.ts +51 -0
  290. package/templates/admin-shell/types/api/system-manage.d.ts +160 -0
  291. package/templates/admin-shell/types/app/common.d.ts +31 -0
  292. package/templates/admin-shell/types/app/global.d.ts +71 -0
  293. package/templates/admin-shell/types/app/menu.d.ts +57 -0
  294. package/templates/admin-shell/types/app/router.d.ts +201 -0
  295. package/templates/admin-shell/types/app/storage.d.ts +10 -0
  296. package/templates/admin-shell/types/app/union-key.d.ts +156 -0
  297. package/templates/admin-shell/types/locales/i18n.d.ts +135 -0
  298. package/templates/admin-shell/ui/antd/components/AppTree.tsx +62 -0
  299. package/templates/admin-shell/ui/antd/components/BeyondHiding.tsx +42 -0
  300. package/templates/admin-shell/ui/antd/components/ButtonIcon.tsx +123 -0
  301. package/templates/admin-shell/ui/antd/components/ButtonLink.tsx +30 -0
  302. package/templates/admin-shell/ui/antd/components/ErrorBoundary.tsx +45 -0
  303. package/templates/admin-shell/ui/antd/components/ExceptionBase.tsx +69 -0
  304. package/templates/admin-shell/ui/antd/components/FullScreen.tsx +33 -0
  305. package/templates/admin-shell/ui/antd/components/PinToggler.tsx +35 -0
  306. package/templates/admin-shell/ui/antd/components/ReloadButton.tsx +20 -0
  307. package/templates/admin-shell/ui/antd/components/index.ts +12 -0
  308. package/templates/admin-shell/ui/antd/components/styles/button-icon-animations.css +246 -0
  309. package/templates/admin-shell/ui/antd/index.ts +1 -0
  310. package/templates/admin-shell/ui/antd/styles.d.ts +1 -0
  311. package/templates/admin-shell/ui/compose/animate-feature.ts +5 -0
  312. package/templates/admin-shell/ui/compose/components/BetterScroll.tsx +51 -0
  313. package/templates/admin-shell/ui/compose/components/DarkModeContainer.tsx +22 -0
  314. package/templates/admin-shell/ui/compose/components/FlipText.tsx +41 -0
  315. package/templates/admin-shell/ui/compose/components/I18nLabel.tsx +18 -0
  316. package/templates/admin-shell/ui/compose/components/LazyAnimate.tsx +10 -0
  317. package/templates/admin-shell/ui/compose/components/LookForward.tsx +24 -0
  318. package/templates/admin-shell/ui/compose/components/NumberTicker.tsx +105 -0
  319. package/templates/admin-shell/ui/compose/components/Portal.tsx +74 -0
  320. package/templates/admin-shell/ui/compose/components/SvgIcon.tsx +39 -0
  321. package/templates/admin-shell/ui/compose/components/TypingAnimation.tsx +83 -0
  322. package/templates/admin-shell/ui/compose/components/WaveBg.tsx +56 -0
  323. package/templates/admin-shell/ui/compose/components/index.ts +11 -0
  324. package/templates/admin-shell/ui/compose/index.ts +2 -0
  325. package/templates/admin-shell/ui/compose/table/DragContent.tsx +239 -0
  326. package/templates/admin-shell/ui/compose/table/TableHeaderOperation.tsx +210 -0
  327. package/templates/admin-shell/ui/compose/table/hooks.ts +196 -0
  328. package/templates/admin-shell/ui/compose/table/index.ts +16 -0
  329. package/templates/admin-shell/ui/compose/table/types.ts +244 -0
  330. package/templates/admin-shell/ui/compose/table/use-table-operate.ts +136 -0
  331. package/templates/admin-shell/ui/compose/table/use-table-scroll.ts +49 -0
  332. package/templates/admin-shell/ui/compose/table/use-table.ts +303 -0
  333. package/templates/admin.meta.json +756 -0
@@ -0,0 +1,124 @@
1
+ import { useSettingsTheme } from '@shell/theme';
2
+ import { SvgIcon } from '@shell/ui/compose';
3
+ import { InputNumber as AInputNumber, Switch as ASwitch, Tooltip as ATooltip } from 'antd';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import {
7
+ HYBRID_LAYOUT_MODES,
8
+ LAYOUT_MODE_VERTICAL,
9
+ LAYOUT_MODE_VERTICAL_MIX,
10
+ MIX_OR_HYBRID_LAYOUT_MODES
11
+ } from '../../../../constant';
12
+ import AnimatedCollapse from '../../components/AnimatedCollapse';
13
+ import SettingItem from '../../components/SettingItem';
14
+
15
+ const SiderSettings = () => {
16
+ const { t } = useTranslation();
17
+
18
+ const { layout, setSettings, sider } = useSettingsTheme();
19
+
20
+ const layoutMode = layout.mode;
21
+ const isMixLayoutMode = MIX_OR_HYBRID_LAYOUT_MODES.includes(layoutMode);
22
+ const isHybridLayoutMode = HYBRID_LAYOUT_MODES.includes(layoutMode);
23
+
24
+ const updateSider = (patch: Partial<typeof sider>) => {
25
+ setSettings({
26
+ sider: {
27
+ ...sider,
28
+ ...patch
29
+ }
30
+ });
31
+ };
32
+
33
+ const handleWidthChange = (width: number | null) => {
34
+ if (width === null) return;
35
+ updateSider({ width });
36
+ };
37
+
38
+ const handleCollapsedWidthChange = (collapsedWidth: number | null) => {
39
+ if (collapsedWidth === null) return;
40
+ updateSider({ collapsedWidth });
41
+ };
42
+
43
+ const handleMixWidthChange = (mixWidth: number | null) => {
44
+ if (mixWidth === null) return;
45
+ updateSider({ mixWidth });
46
+ };
47
+
48
+ const handleMixCollapsedWidthChange = (mixCollapsedWidth: number | null) => {
49
+ if (mixCollapsedWidth === null) return;
50
+ updateSider({ mixCollapsedWidth });
51
+ };
52
+
53
+ const handleMixChildMenuWidthChange = (mixChildMenuWidth: number | null) => {
54
+ if (mixChildMenuWidth === null) return;
55
+ updateSider({ mixChildMenuWidth });
56
+ };
57
+
58
+ const handleAutoSelectFirstMenuChange = (autoSelectFirstMenu: boolean) => {
59
+ updateSider({ autoSelectFirstMenu });
60
+ };
61
+
62
+ return (
63
+ <div className="flex-col-stretch gap-12px">
64
+ <AnimatedCollapse className="flex-col-stretch gap-12px" visible={layoutMode === LAYOUT_MODE_VERTICAL}>
65
+ <SettingItem label={t('theme.layout.sider.width')}>
66
+ <AInputNumber className="w-120px" min={0} step={1} value={sider.width} onChange={handleWidthChange} />
67
+ </SettingItem>
68
+
69
+ <SettingItem label={t('theme.layout.sider.collapsedWidth')}>
70
+ <AInputNumber
71
+ className="w-120px"
72
+ min={0}
73
+ step={1}
74
+ value={sider.collapsedWidth}
75
+ onChange={handleCollapsedWidthChange}
76
+ />
77
+ </SettingItem>
78
+ </AnimatedCollapse>
79
+
80
+ <AnimatedCollapse className="flex-col-stretch gap-12px" visible={isMixLayoutMode}>
81
+ <SettingItem label={t('theme.layout.sider.mixWidth')}>
82
+ <AInputNumber className="w-120px" min={0} step={1} value={sider.mixWidth} onChange={handleMixWidthChange} />
83
+ </SettingItem>
84
+
85
+ <SettingItem label={t('theme.layout.sider.mixCollapsedWidth')}>
86
+ <AInputNumber
87
+ className="w-120px"
88
+ min={0}
89
+ step={1}
90
+ value={sider.mixCollapsedWidth}
91
+ onChange={handleMixCollapsedWidthChange}
92
+ />
93
+ </SettingItem>
94
+ </AnimatedCollapse>
95
+
96
+ <AnimatedCollapse visible={layoutMode === LAYOUT_MODE_VERTICAL_MIX}>
97
+ <SettingItem label={t('theme.layout.sider.mixChildMenuWidth')}>
98
+ <AInputNumber
99
+ className="w-120px"
100
+ min={0}
101
+ step={1}
102
+ value={sider.mixChildMenuWidth}
103
+ onChange={handleMixChildMenuWidthChange}
104
+ />
105
+ </SettingItem>
106
+ </AnimatedCollapse>
107
+
108
+ <AnimatedCollapse visible={isHybridLayoutMode}>
109
+ <SettingItem
110
+ label={t('theme.layout.sider.autoSelectFirstMenu')}
111
+ suffix={
112
+ <ATooltip title={t('theme.layout.sider.autoSelectFirstMenuTip')}>
113
+ <SvgIcon className="text-icon-info" icon="mdi:information-outline" />
114
+ </ATooltip>
115
+ }
116
+ >
117
+ <ASwitch checked={sider.autoSelectFirstMenu} onChange={handleAutoSelectFirstMenuChange} />
118
+ </SettingItem>
119
+ </AnimatedCollapse>
120
+ </div>
121
+ );
122
+ };
123
+
124
+ export default SiderSettings;
@@ -0,0 +1,95 @@
1
+ import { useSettingsTheme } from '@shell/theme';
2
+ import { SvgIcon } from '@shell/ui/compose';
3
+ import { InputNumber as AInputNumber, Select as ASelect, Switch as ASwitch, Tooltip as ATooltip } from 'antd';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { themeTabModeOptions, translateOptions } from '../../../../options';
7
+
8
+ import AnimatedCollapse from '../../components/AnimatedCollapse';
9
+ import SettingItem from '../../components/SettingItem';
10
+
11
+ const TabSettings = () => {
12
+ const { t } = useTranslation();
13
+
14
+ const { setSettings, tab } = useSettingsTheme();
15
+
16
+ const tabModeOptions = translateOptions(themeTabModeOptions);
17
+
18
+ const updateTab = (patch: Partial<typeof tab>) => {
19
+ setSettings({
20
+ tab: {
21
+ ...tab,
22
+ ...patch
23
+ }
24
+ });
25
+ };
26
+
27
+ const handleTabVisibleChange = (visible: boolean) => {
28
+ updateTab({ visible });
29
+ };
30
+
31
+ const handleTabCacheChange = (cache: boolean) => {
32
+ updateTab({ cache });
33
+ };
34
+
35
+ const handleTabHeightChange = (height: number | null) => {
36
+ if (height === null) return;
37
+ updateTab({ height });
38
+ };
39
+
40
+ const handleTabModeChange = (mode: UnionKey.ThemeTabMode) => {
41
+ updateTab({ mode });
42
+ };
43
+
44
+ const handleCloseTabByMiddleClickChange = (closeTabByMiddleClick: boolean) => {
45
+ updateTab({ closeTabByMiddleClick });
46
+ };
47
+
48
+ return (
49
+ <div className="flex-col-stretch gap-12px">
50
+ <SettingItem label={t('theme.layout.tab.visible')}>
51
+ <ASwitch checked={tab.visible} onChange={handleTabVisibleChange} />
52
+ </SettingItem>
53
+
54
+ <AnimatedCollapse className="flex-col-stretch gap-12px" visible={tab.visible}>
55
+ <SettingItem
56
+ label={t('theme.layout.tab.cache')}
57
+ suffix={
58
+ <ATooltip title={t('theme.layout.tab.cacheTip')}>
59
+ <SvgIcon className="text-icon-info" icon="mdi:information-outline" />
60
+ </ATooltip>
61
+ }
62
+ >
63
+ <ASwitch checked={tab.cache} onChange={handleTabCacheChange} />
64
+ </SettingItem>
65
+
66
+ <SettingItem label={t('theme.layout.tab.height')}>
67
+ <AInputNumber className="w-120px" min={0} step={1} value={tab.height} onChange={handleTabHeightChange} />
68
+ </SettingItem>
69
+
70
+ <SettingItem label={t('theme.layout.tab.mode.title')}>
71
+ <ASelect
72
+ className="w-120px"
73
+ options={tabModeOptions}
74
+ size="small"
75
+ value={tab.mode}
76
+ onChange={handleTabModeChange}
77
+ />
78
+ </SettingItem>
79
+
80
+ <SettingItem
81
+ label={t('theme.layout.tab.closeByMiddleClick')}
82
+ suffix={
83
+ <ATooltip title={t('theme.layout.tab.closeByMiddleClickTip')}>
84
+ <SvgIcon className="text-icon-info" icon="mdi:information-outline" />
85
+ </ATooltip>
86
+ }
87
+ >
88
+ <ASwitch checked={tab.closeTabByMiddleClick} onChange={handleCloseTabByMiddleClickChange} />
89
+ </SettingItem>
90
+ </AnimatedCollapse>
91
+ </div>
92
+ );
93
+ };
94
+
95
+ export default TabSettings;
@@ -0,0 +1,32 @@
1
+ import { Divider as ADivider } from 'antd';
2
+ import { useTranslation } from 'react-i18next';
3
+
4
+ import ContentSettings from './ContentSettings';
5
+ import FooterSettings from './FooterSettings';
6
+ import HeaderSettings from './HeaderSettings';
7
+ import LayoutMode from './LayoutMode';
8
+ import SiderSettings from './SiderSettings';
9
+ import TabSettings from './TabSettings';
10
+
11
+ const ThemeLayout = () => {
12
+ const { t } = useTranslation();
13
+
14
+ return (
15
+ <div className="flex-col-stretch gap-16px">
16
+ <ADivider>{t('theme.layout.layoutMode.title')}</ADivider>
17
+ <LayoutMode />
18
+ <ADivider>{t('theme.layout.tab.title')}</ADivider>
19
+ <TabSettings />
20
+ <ADivider>{t('theme.layout.header.title')}</ADivider>
21
+ <HeaderSettings />
22
+ <ADivider>{t('theme.layout.sider.title')}</ADivider>
23
+ <SiderSettings />
24
+ <ADivider>{t('theme.layout.footer.title')}</ADivider>
25
+ <FooterSettings />
26
+ <ADivider>{t('theme.layout.content.title')}</ADivider>
27
+ <ContentSettings />
28
+ </div>
29
+ );
30
+ };
31
+
32
+ export default ThemeLayout;
@@ -0,0 +1,132 @@
1
+ import { defaultThemeSettings, getAllPresets, showSuccessMessage, useSettingsTheme } from '@shell/theme';
2
+ import { Badge as ABadge, Button as AButton, Divider as ADivider } from 'antd';
3
+ import { defu } from 'defu';
4
+ import { useMemo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ const ThemePreset = () => {
8
+ const { t } = useTranslation();
9
+
10
+ const {
11
+ setColourWeakness,
12
+ setGrayscale,
13
+ setSettings,
14
+ setThemeLayout,
15
+ setThemeScheme,
16
+ setWatermarkEnableTime,
17
+ setWatermarkEnableUserName
18
+ } = useSettingsTheme();
19
+
20
+ // Get presets from package (sorted by order)
21
+ const presets = useMemo(() => {
22
+ return getAllPresets().map(preset => ({
23
+ id: preset.name.toLowerCase().replace(/\s+/g, '-'),
24
+ ...preset
25
+ }));
26
+ }, []);
27
+
28
+ function getPresetName(preset: Theme.ThemePreset): string {
29
+ if (!preset.i18nkey) return preset.name;
30
+ try {
31
+ const key = `${preset.i18nkey}.name` as I18n.I18nKey;
32
+ const translated = t(key);
33
+ return translated !== key ? translated : preset.name;
34
+ } catch {
35
+ return preset.name;
36
+ }
37
+ }
38
+
39
+ function getPresetDesc(preset: Theme.ThemePreset): string {
40
+ if (!preset.i18nkey) return preset.desc;
41
+ try {
42
+ const key = `${preset.i18nkey}.desc` as I18n.I18nKey;
43
+ const translated = t(key);
44
+ return translated !== key ? translated : preset.desc;
45
+ } catch {
46
+ return preset.desc;
47
+ }
48
+ }
49
+
50
+ function applyPreset(preset: Theme.ThemePreset): void {
51
+ const mergedPreset = defu(preset, defaultThemeSettings);
52
+ const { colourWeakness, grayscale, layout, themeScheme, watermark, ...rest } = mergedPreset;
53
+
54
+ setThemeScheme(themeScheme);
55
+ setGrayscale(grayscale);
56
+ setColourWeakness(colourWeakness);
57
+ setThemeLayout(layout.mode);
58
+ setWatermarkEnableUserName(watermark.enableUserName);
59
+ setWatermarkEnableTime(watermark.enableTime);
60
+
61
+ setSettings({
62
+ ...rest,
63
+ layout: { ...layout },
64
+ page: { ...rest.page },
65
+ header: { ...rest.header },
66
+ tab: { ...rest.tab },
67
+ sider: { ...rest.sider },
68
+ footer: { ...rest.footer },
69
+ watermark: { ...watermark },
70
+ tokens: { ...rest.tokens }
71
+ });
72
+
73
+ showSuccessMessage(t('theme.appearance.preset.applySuccess'));
74
+ }
75
+
76
+ return (
77
+ <>
78
+ <ADivider>{t('theme.appearance.preset.title')}</ADivider>
79
+
80
+ <div className="flex flex-col gap-12px">
81
+ {presets.map(preset => (
82
+ <div
83
+ className="cursor-pointer border-primary/10 rd-8px border-solid bg-white/5 p-12px backdrop-blur-10 transition-all duration-300 hover:shadow-md hover:-translate-y-0.5"
84
+ key={preset.id}
85
+ >
86
+ <div className="mb-8px flex items-center justify-between">
87
+ <div className="min-w-0 w-full flex flex-1 items-center justify-between gap-8px">
88
+ <h5 className="m-0 truncate text-14px text-primary font-600">{getPresetName(preset)}</h5>
89
+ <ABadge
90
+ className="shrink-0 opacity-80"
91
+ count={`v${preset.version}`}
92
+ style={{ backgroundColor: '#2080f0' }}
93
+ />
94
+ </div>
95
+ <AButton
96
+ ghost
97
+ className="ml-8px shrink-0"
98
+ shape="round"
99
+ size="small"
100
+ type="primary"
101
+ onClick={() => applyPreset(preset)}
102
+ >
103
+ {t('theme.appearance.preset.apply')}
104
+ </AButton>
105
+ </div>
106
+
107
+ <p className="line-clamp-2 mb-12px text-12px text-gray-500 leading-16px">{getPresetDesc(preset)}</p>
108
+
109
+ <div className="flex items-center justify-between">
110
+ <div className="flex gap-4px">
111
+ {Object.entries({ primary: preset.themeColor, ...preset.otherColor }).map(([key, color]) => (
112
+ <div
113
+ className="h-12px w-12px cursor-pointer border-white/30 rd-full transition-transform hover:scale-110"
114
+ key={key}
115
+ style={{ backgroundColor: color as string }}
116
+ title={key}
117
+ />
118
+ ))}
119
+ </div>
120
+ <div className="flex items-center gap-4px">
121
+ <div className="text-18px">{preset.themeScheme === 'dark' ? '🌙' : '☀️'}</div>
122
+ {preset.grayscale && <div className="text-18px">🎨</div>}
123
+ </div>
124
+ </div>
125
+ </div>
126
+ ))}
127
+ </div>
128
+ </>
129
+ );
130
+ };
131
+
132
+ export default ThemePreset;
@@ -0,0 +1,79 @@
1
+ import { I18nLabel } from '@shell/ui/compose';
2
+
3
+ import {
4
+ LAYOUT_MODE_HORIZONTAL,
5
+ LAYOUT_MODE_TOP_HYBRID_HEADER_FIRST,
6
+ LAYOUT_MODE_TOP_HYBRID_SIDEBAR_FIRST,
7
+ LAYOUT_MODE_VERTICAL,
8
+ LAYOUT_MODE_VERTICAL_HYBRID_HEADER_FIRST,
9
+ LAYOUT_MODE_VERTICAL_MIX
10
+ } from './constant';
11
+
12
+ export function transformRecordToOption<T extends Record<string, string>>(record: T) {
13
+ return Object.entries(record).map(([value, label]) => ({
14
+ label,
15
+ value
16
+ })) as Common.Option<keyof T, T[keyof T]>[];
17
+ }
18
+
19
+ export function translateOptions(options: Common.Option<string, I18n.I18nKey>[]) {
20
+ return options.map(option => ({
21
+ ...option,
22
+ label: <I18nLabel i18nKey={option.label} />
23
+ }));
24
+ }
25
+
26
+ export const themeTabsRecord: Record<string, I18n.I18nKey> = {
27
+ appearance: 'theme.tabs.appearance',
28
+ layout: 'theme.tabs.layout',
29
+ general: 'theme.tabs.general',
30
+ preset: 'theme.tabs.preset'
31
+ };
32
+
33
+ export const themeTabsOptions = transformRecordToOption(themeTabsRecord);
34
+
35
+ export const themeLayoutModeRecord: Record<UnionKey.ThemeLayoutMode, I18n.I18nKey> = {
36
+ [LAYOUT_MODE_VERTICAL]: 'theme.layout.layoutMode.vertical',
37
+ [LAYOUT_MODE_VERTICAL_MIX]: 'theme.layout.layoutMode.vertical-mix',
38
+ [LAYOUT_MODE_VERTICAL_HYBRID_HEADER_FIRST]: 'theme.layout.layoutMode.vertical-hybrid-header-first',
39
+ [LAYOUT_MODE_HORIZONTAL]: 'theme.layout.layoutMode.horizontal',
40
+ [LAYOUT_MODE_TOP_HYBRID_SIDEBAR_FIRST]: 'theme.layout.layoutMode.top-hybrid-sidebar-first',
41
+ [LAYOUT_MODE_TOP_HYBRID_HEADER_FIRST]: 'theme.layout.layoutMode.top-hybrid-header-first'
42
+ };
43
+
44
+ export const themeScrollModeRecord: Record<UnionKey.ThemeScrollMode, I18n.I18nKey> = {
45
+ content: 'theme.layout.content.scrollMode.content',
46
+ wrapper: 'theme.layout.content.scrollMode.wrapper'
47
+ };
48
+
49
+ export const themeScrollModeOptions = transformRecordToOption(themeScrollModeRecord);
50
+
51
+ export const themeTabModeRecord: Record<UnionKey.ThemeTabMode, I18n.I18nKey> = {
52
+ chrome: 'theme.layout.tab.mode.chrome',
53
+ button: 'theme.layout.tab.mode.button',
54
+ slider: 'theme.layout.tab.mode.slider'
55
+ };
56
+
57
+ export const themeTabModeOptions = transformRecordToOption(themeTabModeRecord);
58
+
59
+ export const themePageAnimationModeRecord: Record<UnionKey.ThemePageAnimateMode, I18n.I18nKey> = {
60
+ 'fade-slide': 'theme.layout.content.page.mode.fade-slide',
61
+ fade: 'theme.layout.content.page.mode.fade',
62
+ 'fade-bottom': 'theme.layout.content.page.mode.fade-bottom',
63
+ 'fade-scale': 'theme.layout.content.page.mode.fade-scale',
64
+ 'zoom-fade': 'theme.layout.content.page.mode.zoom-fade',
65
+ 'zoom-out': 'theme.layout.content.page.mode.zoom-out',
66
+ none: 'theme.layout.content.page.mode.none'
67
+ };
68
+
69
+ export const themePageAnimationModeOptions = transformRecordToOption(themePageAnimationModeRecord);
70
+
71
+ export const watermarkTimeFormatOptions = [
72
+ { label: 'YYYY-MM-DD HH:mm', value: 'YYYY-MM-DD HH:mm' },
73
+ { label: 'YYYY-MM-DD HH:mm:ss', value: 'YYYY-MM-DD HH:mm:ss' },
74
+ { label: 'YYYY/MM/DD HH:mm', value: 'YYYY/MM/DD HH:mm' },
75
+ { label: 'YYYY/MM/DD HH:mm:ss', value: 'YYYY/MM/DD HH:mm:ss' },
76
+ { label: 'HH:mm', value: 'HH:mm' },
77
+ { label: 'HH:mm:ss', value: 'HH:mm:ss' },
78
+ { label: 'MM-DD HH:mm', value: 'MM-DD HH:mm' }
79
+ ];
@@ -0,0 +1,102 @@
1
+ import { registerStorage } from '@skyroc/core-state';
2
+ import type { AnyRoute } from '@tanstack/react-router';
3
+ import type { ComponentType } from 'react';
4
+
5
+ /** 布局持久化 atom 解析存储时使用的注册名。 */
6
+ export const ADMIN_LAYOUTS_STORAGE = 'admin-layouts';
7
+
8
+ export interface AdminLayoutsStorage {
9
+ /** 读取布局需要的本地缓存。 */
10
+ get<K extends keyof StorageType.Local>(key: K): StorageType.Local[K] | null;
11
+ /** 删除布局需要的本地缓存。 */
12
+ remove(key: keyof StorageType.Local): void;
13
+ /** 写入布局需要的本地缓存。 */
14
+ set<K extends keyof StorageType.Local>(key: K, value: StorageType.Local[K]): void;
15
+ }
16
+
17
+ export interface AdminLayoutMenuCategory {
18
+ /** 菜单分类标识,通常对应一个布局分组。 */
19
+ key: string;
20
+ /** TanStack Router 中承载该菜单分类的 layout route id。 */
21
+ layout: Router.RouteId;
22
+ }
23
+
24
+ export interface AdminLayoutsDynamicRoutes {
25
+ /** 动态菜单接口返回的首页。 */
26
+ home?: Router.RoutePath | null;
27
+ /** 动态菜单接口返回的路由树。 */
28
+ routes: Api.Route.BackendRoute[];
29
+ }
30
+
31
+ /** 菜单节点扩展配置,用于追加 divider、固定入口或项目级菜单节点。 */
32
+ export type MenuNodeConfig = Partial<Omit<Api.Route.BackendRoute, 'layout' | 'parentId'>>;
33
+
34
+ /**
35
+ * 菜单节点回调函数类型,用于在特定路由节点添加额外菜单。
36
+ *
37
+ * @param routeId 当前路由 ID
38
+ */
39
+ export type MenuNodeCallback = (routeId: Router.RouteId) => MenuNodeConfig[];
40
+
41
+ export interface AdminLayoutsOptions {
42
+ /** 默认首页路由。 */
43
+ defaultHome: Router.RoutePath;
44
+ /** 默认菜单图标。 */
45
+ defaultIcon: string;
46
+ /** 自定义菜单额外内容组件映射,用于标准 badge 无法覆盖的业务 UI。 */
47
+ extras?: Partial<Record<Router.Extra, ComponentType<any>>>;
48
+ /** 动态菜单加载器,仅 routeMode 为 dynamic 时使用。 */
49
+ loadDynamicRoutes?: () => Promise<AdminLayoutsDynamicRoutes>;
50
+ /** 菜单分类配置。 */
51
+ menuCategories: Record<string, AdminLayoutMenuCategory>;
52
+ /** 菜单节点扩展配置。 */
53
+ menuNodeCallback?: MenuNodeCallback;
54
+ /** 权限校验中的超级角色标识。 */
55
+ permissionSuperRole?: string;
56
+ /** 菜单生成模式。 */
57
+ routeMode: 'dynamic' | 'static';
58
+ /** TanStack Router 生成的 routeTree。 */
59
+ routeTree: AnyRoute;
60
+ /** 布局本地缓存适配器。 */
61
+ storage: AdminLayoutsStorage;
62
+ }
63
+
64
+ let options: AdminLayoutsOptions | null = null;
65
+
66
+ export function setupAdminLayouts(adminLayoutsOptions: AdminLayoutsOptions) {
67
+ options = adminLayoutsOptions;
68
+
69
+ // 把宿主传入的 storage 桥接到 core-state 注册表,供 createAtomWithStorage 按名解析。
70
+ registerStorage(ADMIN_LAYOUTS_STORAGE, {
71
+ getItem: key => adminLayoutsOptions.storage.get(key as keyof StorageType.Local),
72
+ removeItem: key => adminLayoutsOptions.storage.remove(key as keyof StorageType.Local),
73
+ setItem: (key, value) =>
74
+ adminLayoutsOptions.storage.set(key as keyof StorageType.Local, value as StorageType.Local[keyof StorageType.Local])
75
+ });
76
+ }
77
+
78
+ export function getAdminLayoutsOptions() {
79
+ if (!options) {
80
+ throw new Error('Admin layouts are not initialized. Call setupAdminLayouts before rendering AdminLayout.');
81
+ }
82
+
83
+ return options;
84
+ }
85
+
86
+ export function getDefaultMenuCategoryKey() {
87
+ const { menuCategories } = getAdminLayoutsOptions();
88
+
89
+ return Object.values(menuCategories)[0]?.key ?? 'admin';
90
+ }
91
+
92
+ export function getMenuCategoryKey(layout: Router.RouteId) {
93
+ const { menuCategories } = getAdminLayoutsOptions();
94
+
95
+ return Object.values(menuCategories).find(category => category.layout === layout)?.key;
96
+ }
97
+
98
+ export function getConfiguredCategoryKeys() {
99
+ const { menuCategories } = getAdminLayoutsOptions();
100
+
101
+ return Object.values(menuCategories).map(category => category.key);
102
+ }
@@ -0,0 +1,56 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ import { useSettingsTheme } from '@shell/theme';
3
+ import { useEffect } from 'react';
4
+
5
+ import { LAYOUT_MODE_VERTICAL } from '../constant';
6
+ import { getAdminLayoutsOptions } from '../setup';
7
+ import AdminTabEffect from './AdminTabEffect';
8
+ import { useAdminState } from './use-admin-state';
9
+
10
+ const AdminEffect = () => {
11
+ const { isMobile, mixSiderFixed, setSiderCollapse, siderCollapse } = useAdminState();
12
+
13
+ const { layout, setThemeLayout } = useSettingsTheme();
14
+ const { storage } = getAdminLayoutsOptions();
15
+
16
+ useEffect(() => {
17
+ if (isMobile) {
18
+ // backup theme setting before is mobile
19
+ storage.set('backupThemeSettingBeforeIsMobile', {
20
+ layout: layout.mode,
21
+ siderCollapse
22
+ });
23
+
24
+ setThemeLayout(LAYOUT_MODE_VERTICAL);
25
+
26
+ setSiderCollapse(true);
27
+ } else {
28
+ // when is not mobile, recover the backup theme setting
29
+ const backup = storage.get('backupThemeSettingBeforeIsMobile');
30
+
31
+ if (backup) {
32
+ setThemeLayout(backup.layout);
33
+
34
+ setSiderCollapse(backup.siderCollapse);
35
+
36
+ storage.remove('backupThemeSettingBeforeIsMobile');
37
+ }
38
+ }
39
+ }, [isMobile]);
40
+
41
+ useEffect(() => {
42
+ function handleBeforeUnload() {
43
+ storage.set('mixSiderFixed', mixSiderFixed ? 'Y' : 'N');
44
+ }
45
+
46
+ window.addEventListener('beforeunload', handleBeforeUnload);
47
+
48
+ return () => {
49
+ window.removeEventListener('beforeunload', handleBeforeUnload);
50
+ };
51
+ }, [mixSiderFixed]);
52
+
53
+ return <AdminTabEffect />;
54
+ };
55
+
56
+ export default AdminEffect;
@@ -0,0 +1,28 @@
1
+ import { useEffect } from 'react';
2
+
3
+ import { useAdminTab } from './tabs/use-admin-tab';
4
+
5
+ /**
6
+ * Admin Tab Effect Component
7
+ *
8
+ * This component handles tab caching on page unload and should be mounted in the admin layout
9
+ */
10
+ const AdminTabEffect = () => {
11
+ const { cacheTabs } = useAdminTab();
12
+
13
+ useEffect(() => {
14
+ function handleBeforeUnload() {
15
+ cacheTabs();
16
+ }
17
+
18
+ window.addEventListener('beforeunload', handleBeforeUnload);
19
+
20
+ return () => {
21
+ window.removeEventListener('beforeunload', handleBeforeUnload);
22
+ };
23
+ }, [cacheTabs]);
24
+
25
+ return null;
26
+ };
27
+
28
+ export default AdminTabEffect;
@@ -0,0 +1,3 @@
1
+ export * from './AdminEffect';
2
+ export * from './tabs';
3
+ export * from './use-admin-state';