@alepha/ui 0.17.2 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/dist/admin/{AdminApiKeys-CF_qOO3u.js → AdminApiKeys-C-6_Q-lH.js} +56 -192
  2. package/dist/admin/AdminApiKeys-C-6_Q-lH.js.map +1 -0
  3. package/dist/admin/{AdminAudits-BQno3hZG.js → AdminAudits-Bgbf04hO.js} +25 -61
  4. package/dist/admin/AdminAudits-Bgbf04hO.js.map +1 -0
  5. package/dist/admin/{AdminFiles-kvuUaASF.js → AdminFiles-B9a7G3cY.js} +6 -8
  6. package/dist/admin/AdminFiles-B9a7G3cY.js.map +1 -0
  7. package/dist/admin/{AdminJobDashboard-CrPxp0W1.js → AdminJobDashboard-DaTwf5OY.js} +55 -186
  8. package/dist/admin/AdminJobDashboard-DaTwf5OY.js.map +1 -0
  9. package/dist/admin/{AdminJobExecutions-D-b4Zt7W.js → AdminJobExecutions-B9cek5dl.js} +132 -168
  10. package/dist/admin/AdminJobExecutions-B9cek5dl.js.map +1 -0
  11. package/dist/admin/{AdminJobRegistry-CNX5cpDx.js → AdminJobRegistry-DFgV3oqx.js} +60 -83
  12. package/dist/admin/AdminJobRegistry-DFgV3oqx.js.map +1 -0
  13. package/dist/admin/AdminLayout-DHsvWxVB.js +70 -0
  14. package/dist/admin/AdminLayout-DHsvWxVB.js.map +1 -0
  15. package/dist/admin/{AdminParameters-DCGbpt2c.js → AdminParameters-DHw9ATgl.js} +53 -53
  16. package/dist/admin/AdminParameters-DHw9ATgl.js.map +1 -0
  17. package/dist/admin/{AdminSessions-DyhW6RZv.js → AdminSessions-BhGJPI3z.js} +11 -18
  18. package/dist/admin/AdminSessions-BhGJPI3z.js.map +1 -0
  19. package/dist/admin/{AdminUserLayout-CrBj4UuI.js → AdminUserLayout-BdC4Te8m.js} +112 -151
  20. package/dist/admin/AdminUserLayout-BdC4Te8m.js.map +1 -0
  21. package/dist/admin/AdminUserProfile-DAt23fqY.js +69 -0
  22. package/dist/admin/AdminUserProfile-DAt23fqY.js.map +1 -0
  23. package/dist/admin/AdminUserSessions-1uzcx02z.js +109 -0
  24. package/dist/admin/AdminUserSessions-1uzcx02z.js.map +1 -0
  25. package/dist/admin/AdminUsers-C85c3eiQ.js +121 -0
  26. package/dist/admin/AdminUsers-C85c3eiQ.js.map +1 -0
  27. package/dist/{auth/AuthLayout-CdJcrPs4.js → admin/AuthLayout-DFJvCvzw.js} +3 -3
  28. package/dist/{auth/AuthLayout-CdJcrPs4.js.map → admin/AuthLayout-DFJvCvzw.js.map} +1 -1
  29. package/dist/{auth/IconGoogle-Bm18QD2q.js → admin/IconGoogle-CSQLPYwX.js} +1 -1
  30. package/dist/{auth/IconGoogle-Bm18QD2q.js.map → admin/IconGoogle-CSQLPYwX.js.map} +1 -1
  31. package/dist/{demo/DemoLogin-DjJ9314c.js → admin/Login-BGheURrg.js} +15 -129
  32. package/dist/{auth/Login-BS_FYTy0.js.map → admin/Login-BGheURrg.js.map} +1 -1
  33. package/dist/{auth/Profile-CjDsW378.js → admin/Profile-B-c9pCPf.js} +5 -5
  34. package/dist/{auth/Profile-CjDsW378.js.map → admin/Profile-B-c9pCPf.js.map} +1 -1
  35. package/dist/{demo/DemoRegister-DzkJ5M83.js → admin/Register-Cs10l8vX.js} +20 -146
  36. package/dist/{auth/Register-C5eqzAaD.js.map → admin/Register-Cs10l8vX.js.map} +1 -1
  37. package/dist/{demo/DemoResetPassword-DWh4_BpQ.js → admin/ResetPassword-BwDdfkGH.js} +20 -82
  38. package/dist/{auth/ResetPassword-XifinVao.js.map → admin/ResetPassword-BwDdfkGH.js.map} +1 -1
  39. package/dist/{demo/DemoVerifyEmail-DbU_tCj8.js → admin/VerifyEmail-DfXHAiQl.js} +15 -32
  40. package/dist/{auth/VerifyEmail-DTgbeJOO.js.map → admin/VerifyEmail-DfXHAiQl.js.map} +1 -1
  41. package/dist/admin/auth-Dr0Cf8I7.js +319 -0
  42. package/dist/admin/auth-Dr0Cf8I7.js.map +1 -0
  43. package/dist/admin/core-2xoLiT0o.js +4031 -0
  44. package/dist/admin/core-2xoLiT0o.js.map +1 -0
  45. package/dist/admin/index.d.ts +739 -13
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +79 -111
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/rolldown-runtime-CjeV3_4I.js +18 -0
  50. package/dist/auth/AuthLayout-CAE1pX9s.js +22 -0
  51. package/dist/auth/AuthLayout-CAE1pX9s.js.map +1 -0
  52. package/dist/auth/{Login-BS_FYTy0.js → Login-Denw_UGy.js} +8 -8
  53. package/dist/auth/Login-Denw_UGy.js.map +1 -0
  54. package/dist/auth/Profile-BMX_Ar_s.js +155 -0
  55. package/dist/auth/Profile-BMX_Ar_s.js.map +1 -0
  56. package/dist/auth/{Register-C5eqzAaD.js → Register-6hi_cpfF.js} +8 -8
  57. package/dist/auth/Register-6hi_cpfF.js.map +1 -0
  58. package/dist/auth/{ResetPassword-XifinVao.js → ResetPassword-CqfTk1FI.js} +6 -6
  59. package/dist/auth/ResetPassword-CqfTk1FI.js.map +1 -0
  60. package/dist/auth/{VerifyEmail-DTgbeJOO.js → VerifyEmail-nWiSTMjF.js} +5 -5
  61. package/dist/auth/VerifyEmail-nWiSTMjF.js.map +1 -0
  62. package/dist/auth/core-niW0sFLv.js +2264 -0
  63. package/dist/auth/core-niW0sFLv.js.map +1 -0
  64. package/dist/auth/index.d.ts +336 -8
  65. package/dist/auth/index.d.ts.map +1 -1
  66. package/dist/auth/index.js +18 -22
  67. package/dist/auth/index.js.map +1 -1
  68. package/dist/core/index.d.ts +1033 -843
  69. package/dist/core/index.d.ts.map +1 -1
  70. package/dist/core/index.js +1626 -1354
  71. package/dist/core/index.js.map +1 -1
  72. package/dist/demo/AuthLayout-jLa0aKsI.js +22 -0
  73. package/dist/demo/AuthLayout-jLa0aKsI.js.map +1 -0
  74. package/dist/demo/DemoButton-BmaWZVwf.js +178 -0
  75. package/dist/demo/DemoButton-BmaWZVwf.js.map +1 -0
  76. package/dist/demo/{DemoDataTable-lnBKWBf8.js → DemoDataTable-Z9xyV221.js} +18 -18
  77. package/dist/demo/DemoDataTable-Z9xyV221.js.map +1 -0
  78. package/dist/demo/DemoDialog-4ItHLf9t.js +101 -0
  79. package/dist/demo/DemoDialog-4ItHLf9t.js.map +1 -0
  80. package/dist/demo/DemoFlex-EtVq8QfX.js +105 -0
  81. package/dist/demo/DemoFlex-EtVq8QfX.js.map +1 -0
  82. package/dist/demo/DemoHeading-BS-vGfkI.js +18 -0
  83. package/dist/demo/DemoHeading-BS-vGfkI.js.map +1 -0
  84. package/dist/demo/{DemoHome-CUMZsYaH.js → DemoHome-Clbn8AmS.js} +9 -12
  85. package/dist/demo/DemoHome-Clbn8AmS.js.map +1 -0
  86. package/dist/demo/DemoJsonViewer-DkIX_ky2.js +109 -0
  87. package/dist/demo/DemoJsonViewer-DkIX_ky2.js.map +1 -0
  88. package/dist/demo/DemoLayout-C56xb5EE.js +73 -0
  89. package/dist/demo/DemoLayout-C56xb5EE.js.map +1 -0
  90. package/dist/demo/DemoLogin-BZwpicOS.js +128 -0
  91. package/dist/demo/DemoLogin-BZwpicOS.js.map +1 -0
  92. package/dist/demo/DemoRegister-C7_qc4MJ.js +140 -0
  93. package/dist/demo/DemoRegister-C7_qc4MJ.js.map +1 -0
  94. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js +76 -0
  95. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js.map +1 -0
  96. package/dist/demo/{DemoSidebar-C1csnGhX.js → DemoSidebar-CcBo4ltC.js} +6 -9
  97. package/dist/demo/DemoSidebar-CcBo4ltC.js.map +1 -0
  98. package/dist/demo/DemoText-CzXuUn3g.js +124 -0
  99. package/dist/demo/DemoText-CzXuUn3g.js.map +1 -0
  100. package/dist/demo/DemoToast-BgHDhWrX.js +95 -0
  101. package/dist/demo/DemoToast-BgHDhWrX.js.map +1 -0
  102. package/dist/demo/{DemoTypeForm-CWz6fJrJ.js → DemoTypeForm-DDzWoMSV.js} +4 -4
  103. package/dist/demo/{DemoTypeForm-CWz6fJrJ.js.map → DemoTypeForm-DDzWoMSV.js.map} +1 -1
  104. package/dist/demo/DemoVerifyEmail-C_Irdnov.js +30 -0
  105. package/dist/demo/DemoVerifyEmail-C_Irdnov.js.map +1 -0
  106. package/dist/demo/IconGoogle-CSQLPYwX.js +56 -0
  107. package/dist/demo/IconGoogle-CSQLPYwX.js.map +1 -0
  108. package/dist/demo/Login-hSOU3jZc.js +219 -0
  109. package/dist/demo/Login-hSOU3jZc.js.map +1 -0
  110. package/dist/demo/Profile-CWqti7FB.js +155 -0
  111. package/dist/demo/Profile-CWqti7FB.js.map +1 -0
  112. package/dist/demo/Register-a70LPgs2.js +375 -0
  113. package/dist/demo/Register-a70LPgs2.js.map +1 -0
  114. package/dist/demo/ResetPassword-DWN0lzr5.js +286 -0
  115. package/dist/demo/ResetPassword-DWN0lzr5.js.map +1 -0
  116. package/dist/demo/Showcase-Dq3MISpd.js +232 -0
  117. package/dist/demo/Showcase-Dq3MISpd.js.map +1 -0
  118. package/dist/demo/VerifyEmail-DZWL72K4.js +135 -0
  119. package/dist/demo/VerifyEmail-DZWL72K4.js.map +1 -0
  120. package/dist/demo/auth-d6n3xbug.js +257 -0
  121. package/dist/demo/auth-d6n3xbug.js.map +1 -0
  122. package/dist/demo/core-RCUw1Q-a.js +4217 -0
  123. package/dist/demo/core-RCUw1Q-a.js.map +1 -0
  124. package/dist/demo/index.d.ts +17 -6
  125. package/dist/demo/index.d.ts.map +1 -1
  126. package/dist/demo/index.js +92 -24
  127. package/dist/demo/index.js.map +1 -1
  128. package/dist/demo/rolldown-runtime-CjeV3_4I.js +18 -0
  129. package/package.json +16 -20
  130. package/src/admin/AdminRouter.ts +10 -39
  131. package/src/admin/components/AdminLayout.tsx +42 -10
  132. package/src/admin/components/audits/AdminAudits.tsx +10 -64
  133. package/src/admin/components/files/AdminFiles.tsx +2 -3
  134. package/src/admin/components/jobs/AdminJobDashboard.tsx +36 -142
  135. package/src/admin/components/jobs/AdminJobExecutions.tsx +117 -175
  136. package/src/admin/components/jobs/AdminJobRegistry.tsx +58 -73
  137. package/src/admin/components/keys/AdminApiKeys.tsx +21 -169
  138. package/src/admin/components/parameters/AdminParameters.tsx +4 -4
  139. package/src/admin/components/parameters/ParameterEmptyState.tsx +1 -2
  140. package/src/admin/components/parameters/ParameterHistory.tsx +3 -3
  141. package/src/admin/components/parameters/ParameterTree.tsx +2 -8
  142. package/src/admin/components/parameters/types.ts +3 -3
  143. package/src/admin/components/sessions/AdminSessions.tsx +8 -16
  144. package/src/admin/components/users/AdminUserLayout.tsx +113 -150
  145. package/src/admin/components/users/AdminUserProfile.tsx +50 -0
  146. package/src/admin/components/users/AdminUserSessions.tsx +106 -126
  147. package/src/admin/components/users/AdminUsers.tsx +46 -62
  148. package/src/admin/index.ts +0 -4
  149. package/src/auth/components/buttons/UserButton.tsx +1 -1
  150. package/src/auth/index.ts +0 -4
  151. package/src/core/UiRouter.ts +1 -1
  152. package/src/core/atoms/alephaSidebarAtom.ts +7 -31
  153. package/src/core/components/{layout/AlephaMantineProvider.tsx → AlephaMantineProvider.tsx} +3 -4
  154. package/src/core/components/Flex.tsx +63 -0
  155. package/src/core/components/Heading.tsx +19 -0
  156. package/src/core/components/Text.tsx +140 -0
  157. package/src/core/components/buttons/ActionButton.tsx +12 -1
  158. package/src/core/components/buttons/BurgerButton.tsx +3 -3
  159. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  160. package/src/core/components/buttons/ToggleSidebarButton.tsx +1 -4
  161. package/src/core/components/data/DetailDrawer.tsx +144 -0
  162. package/src/core/components/data/DetailList.tsx +64 -0
  163. package/src/core/components/data/StatCards.tsx +50 -0
  164. package/src/core/components/layout/AppBar.tsx +11 -10
  165. package/src/core/components/layout/Breadcrumb.tsx +8 -8
  166. package/src/core/components/layout/Container.tsx +15 -0
  167. package/src/core/components/layout/DashboardShell.tsx +23 -238
  168. package/src/core/components/layout/Omnibar.tsx +1 -2
  169. package/src/core/components/layout/Sidebar.tsx +103 -71
  170. package/src/core/components/layout/index.ts +65 -0
  171. package/src/core/{components/form → form/components}/Control.tsx +32 -14
  172. package/src/core/{components/form → form/components}/ControlArray.tsx +2 -5
  173. package/src/core/{components/form → form/components}/ControlDate.tsx +1 -4
  174. package/src/core/{components/form → form/components}/ControlNumber.tsx +1 -4
  175. package/src/core/{components/form → form/components}/ControlObject.tsx +1 -4
  176. package/src/core/{components/form → form/components}/ControlQueryBuilder.tsx +7 -7
  177. package/src/core/{components/form → form/components}/ControlSelect.tsx +2 -4
  178. package/src/core/{components/form → form/components}/TypeForm.browser.spec.tsx +22 -64
  179. package/src/core/{components/form → form/components}/TypeForm.tsx +1 -3
  180. package/src/core/form/factories/dialogForm.tsx +31 -0
  181. package/src/core/form/index.ts +23 -0
  182. package/src/core/{utils → form/utils}/parseInput.ts +2 -4
  183. package/src/core/index.ts +43 -51
  184. package/src/core/interfaces/AlephaIntent.ts +6 -0
  185. package/src/core/interfaces/AlephaTheme.ts +0 -1
  186. package/src/core/json/factories/dialogJson.tsx +24 -0
  187. package/src/core/json/index.ts +2 -0
  188. package/src/core/primitives/$ui.ts +17 -0
  189. package/src/core/services/DialogService.tsx +1 -48
  190. package/src/core/styles.css +1 -8
  191. package/src/core/{components/table → table/components}/ColumnPicker.tsx +2 -3
  192. package/src/core/{components/table → table/components}/DataTable.tsx +8 -9
  193. package/src/core/{components/table → table/components}/DataTableFilters.tsx +6 -3
  194. package/src/core/{components/table → table/components}/DataTableToolbar.tsx +4 -5
  195. package/src/core/{components/table → table/components}/FilterPicker.tsx +2 -3
  196. package/src/core/table/index.ts +12 -0
  197. package/src/core/{components/table → table/interfaces}/types.ts +2 -2
  198. package/src/demo/DemoRouter.ts +87 -6
  199. package/src/demo/components/DemoHome.tsx +6 -10
  200. package/src/demo/components/DemoLayout.tsx +38 -8
  201. package/src/demo/components/auth/DemoLogin.tsx +1 -1
  202. package/src/demo/components/auth/DemoRegister.tsx +1 -1
  203. package/src/demo/components/auth/DemoResetPassword.tsx +1 -1
  204. package/src/demo/components/auth/DemoVerifyEmail.tsx +1 -1
  205. package/src/demo/components/core/DemoButton.tsx +160 -0
  206. package/src/demo/components/core/DemoFlex.tsx +101 -0
  207. package/src/demo/components/core/DemoHeading.tsx +13 -0
  208. package/src/demo/components/core/DemoText.tsx +110 -0
  209. package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
  210. package/src/demo/components/layout/DemoDialog.tsx +103 -0
  211. package/src/demo/components/{core → layout}/DemoSidebar.tsx +0 -1
  212. package/src/demo/components/layout/DemoToast.tsx +96 -0
  213. package/src/demo/components/shared/MacWindow.tsx +149 -74
  214. package/src/demo/components/shared/Showcase.tsx +4 -8
  215. package/src/demo/index.ts +1 -4
  216. package/src/demo/primitives/$uiDemo.ts +10 -0
  217. package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +0 -1
  218. package/dist/admin/AdminAudits-BQno3hZG.js.map +0 -1
  219. package/dist/admin/AdminFiles-kvuUaASF.js.map +0 -1
  220. package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +0 -1
  221. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +0 -1
  222. package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +0 -1
  223. package/dist/admin/AdminLayout-e-ZP5nWw.js +0 -37
  224. package/dist/admin/AdminLayout-e-ZP5nWw.js.map +0 -1
  225. package/dist/admin/AdminParameters-DCGbpt2c.js.map +0 -1
  226. package/dist/admin/AdminSessions-DyhW6RZv.js.map +0 -1
  227. package/dist/admin/AdminUserAudits-D1GcREEE.js +0 -177
  228. package/dist/admin/AdminUserAudits-D1GcREEE.js.map +0 -1
  229. package/dist/admin/AdminUserCreate-DR8LA0tv.js +0 -104
  230. package/dist/admin/AdminUserCreate-DR8LA0tv.js.map +0 -1
  231. package/dist/admin/AdminUserDetails-CDkZNHQD.js +0 -477
  232. package/dist/admin/AdminUserDetails-CDkZNHQD.js.map +0 -1
  233. package/dist/admin/AdminUserLayout-CrBj4UuI.js.map +0 -1
  234. package/dist/admin/AdminUserSessions-srgFHrqy.js +0 -129
  235. package/dist/admin/AdminUserSessions-srgFHrqy.js.map +0 -1
  236. package/dist/admin/AdminUserSettings-BFuxl-xT.js +0 -167
  237. package/dist/admin/AdminUserSettings-BFuxl-xT.js.map +0 -1
  238. package/dist/admin/AdminUsers-D1pDpiwK.js +0 -118
  239. package/dist/admin/AdminUsers-D1pDpiwK.js.map +0 -1
  240. package/dist/demo/DemoDataTable-lnBKWBf8.js.map +0 -1
  241. package/dist/demo/DemoHome-CUMZsYaH.js.map +0 -1
  242. package/dist/demo/DemoJsonViewer-_uokbGaW.js +0 -429
  243. package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +0 -1
  244. package/dist/demo/DemoLayout-DHVoacE6.js +0 -46
  245. package/dist/demo/DemoLayout-DHVoacE6.js.map +0 -1
  246. package/dist/demo/DemoLogin-DjJ9314c.js.map +0 -1
  247. package/dist/demo/DemoRegister-DzkJ5M83.js.map +0 -1
  248. package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +0 -1
  249. package/dist/demo/DemoSidebar-C1csnGhX.js.map +0 -1
  250. package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +0 -1
  251. package/dist/demo/Showcase-BzoXNlCn.js +0 -185
  252. package/dist/demo/Showcase-BzoXNlCn.js.map +0 -1
  253. package/dist/json/index.d.ts +0 -57
  254. package/dist/json/index.d.ts.map +0 -1
  255. package/dist/json/index.js +0 -325
  256. package/dist/json/index.js.map +0 -1
  257. package/src/admin/components/users/AdminUserAudits.tsx +0 -184
  258. package/src/admin/components/users/AdminUserCreate.tsx +0 -85
  259. package/src/admin/components/users/AdminUserDetails.tsx +0 -431
  260. package/src/admin/components/users/AdminUserSettings.tsx +0 -171
  261. package/src/core/components/data/ErrorViewer.tsx +0 -171
  262. package/src/json/extensions/DialogService.tsx +0 -31
  263. package/src/json/index.ts +0 -18
  264. package/src/json/styles.css +0 -1
  265. /package/dist/{demo → auth}/IconGoogle-Ch1m3Uzl.js +0 -0
  266. /package/dist/{demo → auth}/IconGoogle-Ch1m3Uzl.js.map +0 -0
  267. /package/src/{json → core/json}/components/JsonViewer.css +0 -0
  268. /package/src/{json → core/json}/components/JsonViewer.tsx +0 -0
  269. /package/src/core/{components/table → table/components}/DataTablePagination.tsx +0 -0
  270. /package/src/core/{components/table → table/components}/useTableSelection.ts +0 -0
@@ -0,0 +1,144 @@
1
+ import {
2
+ Drawer,
3
+ type DrawerProps,
4
+ Flex,
5
+ Loader,
6
+ Tabs,
7
+ Text,
8
+ } from "@mantine/core";
9
+ import type { ComponentType, ReactNode } from "react";
10
+ import type { ActionMenuItem } from "../buttons/ActionButton.tsx";
11
+ import ActionButton from "../buttons/ActionButton.tsx";
12
+
13
+ export interface DetailDrawerTab {
14
+ value: string;
15
+ label: string;
16
+ icon?: ComponentType<{ size?: number }>;
17
+ content: ReactNode;
18
+ }
19
+
20
+ export interface DetailDrawerStatus {
21
+ label: string;
22
+ active: boolean;
23
+ }
24
+
25
+ export interface DetailDrawerProps {
26
+ opened: boolean;
27
+ onClose: () => void;
28
+ title: ReactNode;
29
+ subtitle?: ReactNode;
30
+ status?: DetailDrawerStatus;
31
+ actions?: ActionMenuItem[];
32
+ tabs?: DetailDrawerTab[];
33
+ children?: ReactNode;
34
+ loading?: boolean;
35
+ size?: DrawerProps["size"];
36
+ defaultTab?: string;
37
+ }
38
+
39
+ const DetailDrawer = ({
40
+ opened,
41
+ onClose,
42
+ title,
43
+ subtitle,
44
+ status,
45
+ actions,
46
+ tabs,
47
+ children,
48
+ loading,
49
+ size = "xl",
50
+ defaultTab,
51
+ }: DetailDrawerProps) => (
52
+ <Drawer
53
+ opened={opened}
54
+ onClose={onClose}
55
+ position="right"
56
+ size={size}
57
+ withCloseButton={false}
58
+ padding={0}
59
+ >
60
+ {/* Header */}
61
+ <Flex
62
+ p="md"
63
+ justify="space-between"
64
+ align="flex-start"
65
+ style={{ borderBottom: "1px solid var(--mantine-color-default-border)" }}
66
+ >
67
+ <Flex direction="column" gap={2} style={{ minWidth: 0, flex: 1 }}>
68
+ <Flex gap="xs" align="center">
69
+ {status && (
70
+ <Flex
71
+ w={8}
72
+ h={8}
73
+ style={{
74
+ borderRadius: "50%",
75
+ backgroundColor: status.active
76
+ ? "var(--mantine-color-green-6)"
77
+ : "var(--mantine-color-red-6)",
78
+ flexShrink: 0,
79
+ }}
80
+ />
81
+ )}
82
+ <Text size="lg" fw={600} truncate>
83
+ {title}
84
+ </Text>
85
+ </Flex>
86
+ {subtitle && (
87
+ <Text size="sm" c="dimmed" truncate>
88
+ {subtitle}
89
+ </Text>
90
+ )}
91
+ </Flex>
92
+ <Flex gap="xs" align="center" style={{ flexShrink: 0 }}>
93
+ {actions && actions.length > 0 && (
94
+ <ActionButton
95
+ variant="default"
96
+ size="xs"
97
+ menu={{
98
+ items: actions,
99
+ position: "bottom-end",
100
+ width: 200,
101
+ }}
102
+ >
103
+ Actions
104
+ </ActionButton>
105
+ )}
106
+ <ActionButton variant="subtle" size="xs" c="dimmed" onClick={onClose}>
107
+ Close
108
+ </ActionButton>
109
+ </Flex>
110
+ </Flex>
111
+
112
+ {/* Content */}
113
+ {loading ? (
114
+ <Flex flex={1} justify="center" align="center" py="xl">
115
+ <Loader />
116
+ </Flex>
117
+ ) : tabs && tabs.length > 0 ? (
118
+ <Tabs defaultValue={defaultTab || tabs[0].value}>
119
+ <Tabs.List px="md">
120
+ {tabs.map((tab) => (
121
+ <Tabs.Tab
122
+ key={tab.value}
123
+ value={tab.value}
124
+ leftSection={tab.icon ? <tab.icon size={14} /> : undefined}
125
+ >
126
+ {tab.label}
127
+ </Tabs.Tab>
128
+ ))}
129
+ </Tabs.List>
130
+ {tabs.map((tab) => (
131
+ <Tabs.Panel key={tab.value} value={tab.value} p="md">
132
+ {tab.content}
133
+ </Tabs.Panel>
134
+ ))}
135
+ </Tabs>
136
+ ) : (
137
+ <Flex direction="column" p="md">
138
+ {children}
139
+ </Flex>
140
+ )}
141
+ </Drawer>
142
+ );
143
+
144
+ export default DetailDrawer;
@@ -0,0 +1,64 @@
1
+ import { Flex, Grid, Text } from "@mantine/core";
2
+ import type { ReactNode } from "react";
3
+ import ClipboardButton from "../buttons/ClipboardButton.tsx";
4
+
5
+ export interface DetailListItem {
6
+ label: string;
7
+ value: ReactNode;
8
+ hidden?: boolean;
9
+ copyable?: string;
10
+ }
11
+
12
+ export interface DetailListProps {
13
+ items: DetailListItem[];
14
+ columns?: number;
15
+ }
16
+
17
+ const DetailList = ({ items, columns = 1 }: DetailListProps) => {
18
+ const visibleItems = items.filter((item) => !item.hidden);
19
+
20
+ return (
21
+ <Grid gutter="xs">
22
+ {visibleItems.map((item) => (
23
+ <Grid.Col key={item.label} span={12 / columns}>
24
+ <Flex
25
+ py={6}
26
+ justify="space-between"
27
+ align="center"
28
+ style={{
29
+ borderBottom: "1px solid var(--mantine-color-default-border)",
30
+ }}
31
+ >
32
+ <Text size="xs" c="dimmed" style={{ flexShrink: 0 }}>
33
+ {item.label}
34
+ </Text>
35
+ <Flex gap={4} align="center" style={{ minWidth: 0 }}>
36
+ {typeof item.value === "string" ||
37
+ typeof item.value === "number" ? (
38
+ <Text size="sm" fw={500} truncate>
39
+ {item.value || "\u2014"}
40
+ </Text>
41
+ ) : (
42
+ (item.value ?? (
43
+ <Text size="sm" c="dimmed">
44
+ {"\u2014"}
45
+ </Text>
46
+ ))
47
+ )}
48
+ {item.copyable && (
49
+ <ClipboardButton
50
+ value={item.copyable}
51
+ size="xs"
52
+ variant="subtle"
53
+ c="dimmed"
54
+ />
55
+ )}
56
+ </Flex>
57
+ </Flex>
58
+ </Grid.Col>
59
+ ))}
60
+ </Grid>
61
+ );
62
+ };
63
+
64
+ export default DetailList;
@@ -0,0 +1,50 @@
1
+ import { Flex, Paper, Text } from "@mantine/core";
2
+ import type { ComponentType, ReactNode } from "react";
3
+ import { ui } from "../../constants/ui.ts";
4
+
5
+ export interface StatCardItem {
6
+ label: string;
7
+ value: ReactNode;
8
+ icon?: ReactNode | ComponentType<{ size?: number }>;
9
+ }
10
+
11
+ export interface StatCardsProps {
12
+ items: StatCardItem[];
13
+ }
14
+
15
+ const StatCards = ({ items }: StatCardsProps) => (
16
+ <Flex gap="sm" wrap="wrap">
17
+ {items.map((item) => {
18
+ const IconComponent =
19
+ item.icon && typeof item.icon === "function" ? item.icon : null;
20
+ const iconNode = IconComponent ? (
21
+ <IconComponent size={ui.sizes.icon.md} />
22
+ ) : (
23
+ (item.icon as ReactNode)
24
+ );
25
+
26
+ return (
27
+ <Paper
28
+ key={item.label}
29
+ p="md"
30
+ radius="md"
31
+ withBorder
32
+ style={{ flex: "1 1 0", minWidth: 120 }}
33
+ >
34
+ <Flex gap="sm" align="center">
35
+ <Flex direction="column">
36
+ <Text size="xl" fw={700} lh={1}>
37
+ {item.value}
38
+ </Text>
39
+ <Text size="xs" c="dimmed">
40
+ {item.label}
41
+ </Text>
42
+ </Flex>
43
+ </Flex>
44
+ </Paper>
45
+ );
46
+ })}
47
+ </Flex>
48
+ );
49
+
50
+ export default StatCards;
@@ -1,24 +1,25 @@
1
+ import {
2
+ ActionButton,
3
+ type ActionProps,
4
+ BurgerButton,
5
+ DarkModeButton,
6
+ Flex,
7
+ LanguageButton,
8
+ OmnibarButton,
9
+ type OmnibarButtonProps,
10
+ Text,
11
+ } from "@alepha/ui";
1
12
  import {
2
13
  Anchor,
3
14
  Container,
4
15
  type ContainerProps,
5
16
  Divider,
6
- Flex,
7
17
  type FlexProps,
8
18
  Image,
9
- Text,
10
19
  } from "@mantine/core";
11
20
  import { IconArrowLeft } from "@tabler/icons-react";
12
21
  import { Link, useRouter } from "alepha/react/router";
13
22
  import type { ComponentType, ReactNode } from "react";
14
- import type { ActionProps } from "../buttons/ActionButton.tsx";
15
- import ActionButton from "../buttons/ActionButton.tsx";
16
- import BurgerButton from "../buttons/BurgerButton.tsx";
17
- import DarkModeButton from "../buttons/DarkModeButton.tsx";
18
- import LanguageButton from "../buttons/LanguageButton.tsx";
19
- import OmnibarButton, {
20
- type OmnibarButtonProps,
21
- } from "../buttons/OmnibarButton.tsx";
22
23
 
23
24
  export type AppBarItem =
24
25
  | AppBarElement
@@ -1,8 +1,8 @@
1
- import { Anchor, Flex, type FlexProps, Text } from "@mantine/core";
1
+ import { ActionButton, Flex, Text, toTitleCase } from "@alepha/ui";
2
+ import type { FlexProps } from "@mantine/core";
2
3
  import { IconChevronRight } from "@tabler/icons-react";
3
- import { Link, useRouter, useRouterState } from "alepha/react/router";
4
+ import { useRouter, useRouterState } from "alepha/react/router";
4
5
  import type { ReactNode } from "react";
5
- import { toTitleCase } from "../../utils/string.ts";
6
6
 
7
7
  export interface BreadcrumbProps extends FlexProps {
8
8
  /**
@@ -37,7 +37,7 @@ export interface BreadcrumbProps extends FlexProps {
37
37
  const Breadcrumb = ({
38
38
  home = "Home",
39
39
  separator,
40
- size = "xs",
40
+ size = "sm",
41
41
  ...groupProps
42
42
  }: BreadcrumbProps) => {
43
43
  const state = useRouterState();
@@ -69,14 +69,14 @@ const Breadcrumb = ({
69
69
  const sep = separator ?? <IconChevronRight size={12} color="#9ca3af" />;
70
70
 
71
71
  return (
72
- <Flex gap={4} {...groupProps}>
72
+ <Flex gap={"sm"} {...groupProps}>
73
73
  {crumbs.map((crumb, i) => (
74
- <Flex key={crumb.href} gap={4}>
74
+ <Flex align={"center"} key={crumb.href} gap={"sm"}>
75
75
  {i > 0 && sep}
76
76
  {i < crumbs.length - 1 ? (
77
- <Anchor component={Link} href={crumb.href} size={size} c="dimmed">
77
+ <ActionButton anchor href={crumb.href} size={size} c="dimmed">
78
78
  {crumb.label}
79
- </Anchor>
79
+ </ActionButton>
80
80
  ) : (
81
81
  <Text size={size} fw={500}>
82
82
  {crumb.label}
@@ -0,0 +1,15 @@
1
+ import {
2
+ Container as MantineContainer,
3
+ type ContainerProps as MantineContainerProps,
4
+ } from "@mantine/core";
5
+ import { forwardRef } from "react";
6
+
7
+ export interface ContainerProps extends MantineContainerProps {}
8
+
9
+ const Container = forwardRef<HTMLDivElement, ContainerProps>((props, ref) => {
10
+ return <MantineContainer ref={ref} {...props} />;
11
+ });
12
+
13
+ Container.displayName = "Container";
14
+
15
+ export default Container;
@@ -1,3 +1,4 @@
1
+ import { alephaSidebarAtom, Flex } from "@alepha/ui";
1
2
  import {
2
3
  AppShell,
3
4
  type AppShellFooterProps,
@@ -5,26 +6,14 @@ import {
5
6
  type AppShellMainProps,
6
7
  type AppShellNavbarProps,
7
8
  type AppShellProps,
8
- Container,
9
9
  type ContainerProps,
10
- Flex,
11
10
  } from "@mantine/core";
12
11
  import { useEvents, useStore } from "alepha/react";
13
12
  import { NestedView, useRouter } from "alepha/react/router";
14
- import {
15
- type ReactNode,
16
- useCallback,
17
- useEffect,
18
- useRef,
19
- useState,
20
- } from "react";
21
- import { alephaSidebarAtom } from "../../atoms/alephaSidebarAtom.ts";
13
+ import type { ReactNode } from "react";
14
+ import { useState } from "react";
22
15
  import AppBar, { type AppBarProps } from "./AppBar.tsx";
23
- import {
24
- Sidebar,
25
- type SidebarMenuItem,
26
- type SidebarProps,
27
- } from "./Sidebar.tsx";
16
+ import { Sidebar, type SidebarProps } from "./Sidebar.tsx";
28
17
 
29
18
  export interface DashboardShellProps {
30
19
  appShellProps?: Partial<AppShellProps>;
@@ -67,12 +56,6 @@ export interface DashboardShellProps {
67
56
  */
68
57
  footerHeight?: number;
69
58
 
70
- /**
71
- * Enable drag-to-resize for the sidebar.
72
- * Width and constraints are configured in alephaSidebarAtom.
73
- */
74
- sidebarResizable?: boolean;
75
-
76
59
  noSidebarWhen?: {
77
60
  /**
78
61
  * Paths where the sidebar should be hidden.
@@ -90,138 +73,12 @@ export interface DashboardShellProps {
90
73
  const DashboardShell = (props: DashboardShellProps) => {
91
74
  const router = useRouter();
92
75
  const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
93
- const { opened } = sidebar;
94
76
  const collapsed =
95
77
  props.sidebarProps?.collapsed !== undefined
96
78
  ? props.sidebarProps.collapsed
97
79
  : sidebar.collapsed;
98
80
 
99
- // Resize state
100
- const [isResizing, setIsResizing] = useState(false);
101
- const [isHovering, setIsHovering] = useState(false);
102
- const [collapseEffect, setCollapseEffect] = useState({
103
- offset: 0,
104
- opacity: 1,
105
- });
106
- const resizeRef = useRef<{ startX: number; startWidth: number } | null>(null);
107
-
108
- // Use atom values for constraints
109
- const {
110
- collapsedWidth,
111
- collapseThreshold,
112
- maxWidth,
113
- hoverDelay,
114
- defaultWidth,
115
- } = sidebar;
116
-
117
- const handleResizeStart = useCallback(
118
- (e: React.MouseEvent) => {
119
- if (!props.sidebarResizable) return;
120
- e.preventDefault();
121
-
122
- // If collapsed and hovering, un-collapse first and start from defaultWidth
123
- if (collapsed) {
124
- setSidebar({ ...sidebar, collapsed: false, width: defaultWidth });
125
- setIsResizing(true);
126
- resizeRef.current = {
127
- startX: e.clientX,
128
- startWidth: defaultWidth,
129
- };
130
- } else {
131
- setIsResizing(true);
132
- resizeRef.current = {
133
- startX: e.clientX,
134
- startWidth: sidebar.width,
135
- };
136
- }
137
- },
138
- [props.sidebarResizable, collapsed, sidebar, setSidebar, defaultWidth],
139
- );
140
-
141
- useEffect(() => {
142
- if (!isResizing) return;
143
-
144
- const handleMouseMove = (e: MouseEvent) => {
145
- if (!resizeRef.current) return;
146
- const delta = e.clientX - resizeRef.current.startX;
147
- const rawWidth = resizeRef.current.startWidth + delta;
148
- const newWidth = Math.min(Math.max(rawWidth, collapsedWidth), maxWidth);
149
-
150
- // Visual effect when below collapse threshold
151
- if (rawWidth < collapseThreshold) {
152
- const progress = Math.max(
153
- 0,
154
- (collapseThreshold - rawWidth) / collapseThreshold,
155
- );
156
- setCollapseEffect({
157
- offset: -progress * collapsedWidth,
158
- opacity: 1 - progress * 0.7,
159
- });
160
- setSidebar({ ...sidebar, width: collapseThreshold, collapsed: false });
161
- } else {
162
- setCollapseEffect({ offset: 0, opacity: 1 });
163
- setSidebar({ ...sidebar, width: newWidth, collapsed: false });
164
- }
165
- };
166
-
167
- const handleMouseUp = () => {
168
- // If we released while in collapse zone, actually collapse
169
- if (collapseEffect.offset < 0) {
170
- setSidebar({ ...sidebar, collapsed: true });
171
- }
172
- setCollapseEffect({ offset: 0, opacity: 1 });
173
- setIsResizing(false);
174
- resizeRef.current = null;
175
- };
176
-
177
- document.addEventListener("mousemove", handleMouseMove);
178
- document.addEventListener("mouseup", handleMouseUp);
179
-
180
- return () => {
181
- document.removeEventListener("mousemove", handleMouseMove);
182
- document.removeEventListener("mouseup", handleMouseUp);
183
- };
184
- }, [
185
- isResizing,
186
- sidebar,
187
- setSidebar,
188
- collapsedWidth,
189
- maxWidth,
190
- collapseThreshold,
191
- collapseEffect.offset,
192
- ]);
193
-
194
- // Hover to expand when collapsed (with delay)
195
- const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
196
-
197
- const expandOnHover = props.sidebarProps?.expandOnHover !== false;
198
-
199
- const handleNavbarMouseEnter = useCallback(() => {
200
- if (collapsed && expandOnHover) {
201
- hoverTimeoutRef.current = setTimeout(() => {
202
- setIsHovering(true);
203
- }, hoverDelay);
204
- }
205
- }, [collapsed, expandOnHover, hoverDelay]);
206
-
207
- const handleNavbarMouseLeave = useCallback(() => {
208
- if (hoverTimeoutRef.current) {
209
- clearTimeout(hoverTimeoutRef.current);
210
- hoverTimeoutRef.current = null;
211
- }
212
- setIsHovering(false);
213
- }, []);
214
-
215
- // Reset hover state when collapsed changes (e.g., when toggle button is clicked)
216
- useEffect(() => {
217
- if (collapsed) {
218
- setIsHovering(false);
219
- if (hoverTimeoutRef.current) {
220
- clearTimeout(hoverTimeoutRef.current);
221
- hoverTimeoutRef.current = null;
222
- }
223
- }
224
- }, [collapsed]);
81
+ const { collapsedWidth, expandedWidth } = sidebar;
225
82
 
226
83
  const shouldShowSidebar = () => {
227
84
  if (props.noSidebarWhen?.paths) {
@@ -246,7 +103,7 @@ const DashboardShell = (props: DashboardShellProps) => {
246
103
  setShowSidebar(shouldShowSidebar());
247
104
  },
248
105
  "react:transition:begin": () => {
249
- setSidebar({ ...sidebar, opened: false });
106
+ setSidebar({ ...sidebar, closed: true });
250
107
  },
251
108
  },
252
109
  [sidebar],
@@ -264,55 +121,33 @@ const DashboardShell = (props: DashboardShellProps) => {
264
121
  const hasSidebar = showSidebar && props.sidebarProps !== undefined;
265
122
  const hasAppBar = props.appBarProps || props.header;
266
123
 
124
+ let footerElement = props.footer;
125
+ if (props.footerHeight) {
126
+ footerElement ??= <Flex h={props.footerHeight} />;
127
+ }
128
+
267
129
  const hHeight = props.headerHeight ?? 60;
268
130
  const fHeight = props.footerHeight ?? 24;
269
131
  const headerHeight = hasAppBar ? hHeight : 0;
270
- const footerHeight = props.footer ? fHeight : 0;
271
- const expandedWidth = Math.max(sidebar.width, collapsedWidth);
272
-
273
- // When collapsed but hovering, show defaultWidth (not current width)
274
- const isExpandedByHover = collapsed && isHovering;
275
- const effectiveCollapsed = collapsed && !isHovering;
276
-
277
- // Wrap onItemClick to collapse sidebar when clicking during hover-expansion
278
- const handleSidebarItemClick = useCallback(
279
- (item: SidebarMenuItem) => {
280
- if (isExpandedByHover) {
281
- setIsHovering(false);
282
- }
283
- props.sidebarProps?.onItemClick?.(item);
284
- },
285
- [isExpandedByHover, props.sidebarProps?.onItemClick],
286
- );
287
- const hoverWidth = Math.max(defaultWidth, collapsedWidth);
288
- // When hovering, keep main content at collapsed width (sidebar overlays)
289
- const sidebarWidth = hasSidebar
290
- ? effectiveCollapsed || isExpandedByHover
291
- ? collapsedWidth
292
- : expandedWidth
293
- : 0;
294
- const canResize = props.sidebarResizable && !collapsed;
132
+ const footerHeight = footerElement ? fHeight : 0;
133
+ const navbarWidth = collapsed ? collapsedWidth : expandedWidth;
295
134
 
296
135
  return (
297
136
  <AppShell
298
- layout={props.layout}
137
+ layout={"alt"}
299
138
  w={"100%"}
300
139
  flex={1}
301
140
  header={hasAppBar ? { height: hHeight } : undefined}
302
141
  navbar={
303
142
  hasSidebar
304
143
  ? {
305
- // When hovering, keep collapsed width to avoid pushing content
306
- width:
307
- effectiveCollapsed || isExpandedByHover
308
- ? { base: collapsedWidth }
309
- : { base: expandedWidth },
310
- breakpoint: "sm",
311
- collapsed: { mobile: !opened },
144
+ width: { base: navbarWidth },
145
+ breakpoint: "md",
146
+ collapsed: { mobile: sidebar.closed },
312
147
  }
313
148
  : undefined
314
149
  }
315
- footer={props.footer ? { height: fHeight } : undefined}
150
+ footer={footerElement ? { height: fHeight } : undefined}
316
151
  {...props.appShellProps}
317
152
  >
318
153
  {hasAppBar && (
@@ -326,22 +161,6 @@ const DashboardShell = (props: DashboardShellProps) => {
326
161
  {hasSidebar && (
327
162
  <AppShell.Navbar
328
163
  className="alepha-sidebar-navbar"
329
- data-resizing={isResizing}
330
- data-hover-expanded={isExpandedByHover}
331
- onMouseEnter={handleNavbarMouseEnter}
332
- onMouseLeave={handleNavbarMouseLeave}
333
- style={{
334
- transform: collapseEffect.offset
335
- ? `translateX(${collapseEffect.offset}px)`
336
- : undefined,
337
- opacity: collapseEffect.opacity,
338
- // When hovering, expand width visually as overlay
339
- ...(isExpandedByHover && {
340
- width: hoverWidth,
341
- zIndex: 200,
342
- boxShadow: "var(--mantine-shadow-xl)",
343
- }),
344
- }}
345
164
  {...props.appShellNavbarProps}
346
165
  >
347
166
  {props.navbarHeader ? (
@@ -354,11 +173,7 @@ const DashboardShell = (props: DashboardShellProps) => {
354
173
  {props.navbarHeader}
355
174
  </Flex>
356
175
  ) : null}
357
- <Sidebar
358
- {...(props.sidebarProps ?? {})}
359
- collapsed={effectiveCollapsed}
360
- onItemClick={handleSidebarItemClick}
361
- />
176
+ <Sidebar {...(props.sidebarProps ?? {})} collapsed={collapsed} />
362
177
  {props.navbarFooter ? (
363
178
  <Flex
364
179
  style={{
@@ -369,46 +184,16 @@ const DashboardShell = (props: DashboardShellProps) => {
369
184
  {props.navbarFooter}
370
185
  </Flex>
371
186
  ) : null}
372
- {(canResize || isExpandedByHover) && (
373
- <Flex
374
- pos="absolute"
375
- right={-6}
376
- top={0}
377
- bottom={0}
378
- w={12}
379
- style={{
380
- cursor: "col-resize",
381
- userSelect: "none",
382
- }}
383
- onMouseDown={handleResizeStart}
384
- />
385
- )}
386
187
  </AppShell.Navbar>
387
188
  )}
388
189
 
389
- <AppShell.Main
390
- className="alepha-sidebar-main"
391
- data-resizing={isResizing}
392
- {...props.appShellMainProps}
393
- >
394
- {props.container ? (
395
- <Container
396
- w={"100%"}
397
- flex={1}
398
- display="flex"
399
- style={{ flexDirection: "column" }}
400
- {...(typeof props.container === "boolean" ? {} : props.container)}
401
- >
402
- {props.children ?? <NestedView />}
403
- </Container>
404
- ) : (
405
- (props.children ?? <NestedView />)
406
- )}
190
+ <AppShell.Main pos={"relative"} {...props.appShellMainProps}>
191
+ {props.children ?? <NestedView />}
407
192
  </AppShell.Main>
408
193
 
409
- {props.footer && (
194
+ {footerElement && (
410
195
  <AppShell.Footer {...props.appShellFooterProps}>
411
- {props.footer}
196
+ {footerElement}
412
197
  </AppShell.Footer>
413
198
  )}
414
199
  </AppShell>