@alepha/ui 0.18.2 → 0.19.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 (257) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Bt1PjO6o.js} +3 -4
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Bt1PjO6o.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-C7c1CN4c.js} +3 -4
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-C7c1CN4c.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-C3RXpTp6.js} +3 -4
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-C3RXpTp6.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-31ivR6Wq.js} +3 -4
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-31ivR6Wq.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BABLe7hL.js} +73 -25
  10. package/dist/admin/AdminJobDashboard-BABLe7hL.js.map +1 -0
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D-G8RIlr.js} +3 -4
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D-G8RIlr.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-oIS3K9NX.js} +3 -4
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-oIS3K9NX.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-BmZ9mtXh.js} +8 -25
  16. package/dist/admin/AdminLayout-BmZ9mtXh.js.map +1 -0
  17. package/dist/admin/AdminNotifications-DHdzksww.js +541 -0
  18. package/dist/admin/AdminNotifications-DHdzksww.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CyZQSXnN.js} +118 -112
  20. package/dist/admin/AdminParameters-CyZQSXnN.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions--xwELDSO.js} +3 -4
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions--xwELDSO.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-DvBTG5gd.js} +82 -115
  24. package/dist/admin/AdminUserLayout-DvBTG5gd.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-CzsPBl6Z.js} +7 -6
  26. package/dist/admin/AdminUserProfile-CzsPBl6Z.js.map +1 -0
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-C-aUnhVN.js} +3 -4
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-C-aUnhVN.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-BYwei5sj.js} +4 -4
  30. package/dist/admin/AdminUsers-BYwei5sj.js.map +1 -0
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-CkPGLJku.js} +3 -4
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-CkPGLJku.js.map} +1 -1
  33. package/dist/{demo/IconGoogle-CSQLPYwX.js → admin/IconGoogle-8Nkx6yax.js} +2 -4
  34. package/dist/admin/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  35. package/dist/admin/Login-DSBqNsZc.js +274 -0
  36. package/dist/admin/Login-DSBqNsZc.js.map +1 -0
  37. package/dist/admin/{Profile-B2EcIDB9.js → Profile-CDRjJo0P.js} +31 -29
  38. package/dist/admin/Profile-CDRjJo0P.js.map +1 -0
  39. package/dist/admin/{Register-Z3fxRbUF.js → Register-4QGFOnfh.js} +201 -146
  40. package/dist/admin/Register-4QGFOnfh.js.map +1 -0
  41. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-Gxc9L_mY.js} +9 -10
  42. package/dist/admin/ResetPassword-Gxc9L_mY.js.map +1 -0
  43. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-D7G5NnaN.js} +25 -11
  44. package/dist/admin/VerifyEmail-D7G5NnaN.js.map +1 -0
  45. package/dist/admin/adminUserAtom-DCi4wf-v.js +11 -0
  46. package/dist/admin/adminUserAtom-DCi4wf-v.js.map +1 -0
  47. package/dist/admin/{core-BVO_TQxb.js → core-D1AbU50V.js} +662 -570
  48. package/dist/admin/core-D1AbU50V.js.map +1 -0
  49. package/dist/admin/index.d.ts +141 -53
  50. package/dist/admin/index.d.ts.map +1 -1
  51. package/dist/admin/index.js +67 -49
  52. package/dist/admin/index.js.map +1 -1
  53. package/dist/admin/rolldown-runtime-CiIaOW0V.js +13 -0
  54. package/dist/{demo/AuthLayout-DN-ClJQk.js → auth/AuthLayout-CfRKcTqP.js} +3 -4
  55. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-CfRKcTqP.js.map} +1 -1
  56. package/dist/{admin/IconGoogle-Ch1m3Uzl.js → auth/IconGoogle-8Nkx6yax.js} +2 -4
  57. package/dist/auth/{IconGoogle-Ch1m3Uzl.js.map → IconGoogle-8Nkx6yax.js.map} +1 -1
  58. package/dist/auth/Login-DJyweoPS.js +274 -0
  59. package/dist/auth/Login-DJyweoPS.js.map +1 -0
  60. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-Cy93pNTw.js} +31 -29
  61. package/dist/auth/Profile-Cy93pNTw.js.map +1 -0
  62. package/dist/auth/{Register-2gx8qll-.js → Register-CSqzzitW.js} +201 -146
  63. package/dist/auth/Register-CSqzzitW.js.map +1 -0
  64. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-B61QPlQi.js} +9 -10
  65. package/dist/auth/ResetPassword-B61QPlQi.js.map +1 -0
  66. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-CqBJ11id.js} +25 -11
  67. package/dist/auth/VerifyEmail-CqBJ11id.js.map +1 -0
  68. package/dist/auth/{core-DyfeVr5c.js → core-C6D3pazL.js} +403 -343
  69. package/dist/auth/core-C6D3pazL.js.map +1 -0
  70. package/dist/auth/index.d.ts +93 -54
  71. package/dist/auth/index.d.ts.map +1 -1
  72. package/dist/auth/index.js +30 -31
  73. package/dist/auth/index.js.map +1 -1
  74. package/dist/auth/rolldown-runtime-CiIaOW0V.js +13 -0
  75. package/dist/core/index.d.ts +123 -62
  76. package/dist/core/index.d.ts.map +1 -1
  77. package/dist/core/index.js +878 -776
  78. package/dist/core/index.js.map +1 -1
  79. package/dist/{auth/AuthLayout-C161NeF6.js → demo/AuthLayout-Dq5tSLSc.js} +3 -4
  80. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Dq5tSLSc.js.map} +1 -1
  81. package/dist/demo/DemoButton-_Ws2w-J0.js +181 -0
  82. package/dist/demo/DemoButton-_Ws2w-J0.js.map +1 -0
  83. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js +304 -0
  84. package/dist/demo/DemoControlSelect-ChP4ZOpQ.js.map +1 -0
  85. package/dist/demo/DemoDataTable-Hwf_UUni.js +361 -0
  86. package/dist/demo/DemoDataTable-Hwf_UUni.js.map +1 -0
  87. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-B01OMVRd.js} +3 -4
  88. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-B01OMVRd.js.map} +1 -1
  89. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-870PEl0V.js} +4 -5
  90. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-870PEl0V.js.map} +1 -1
  91. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C1YR27fz.js} +4 -5
  92. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C1YR27fz.js.map} +1 -1
  93. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-DRbL2eGf.js} +4 -5
  94. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-DRbL2eGf.js.map} +1 -1
  95. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-DoABiqBW.js} +4 -5
  96. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-DoABiqBW.js.map} +1 -1
  97. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CN_PDCX2.js} +16 -8
  98. package/dist/demo/DemoLayout-CN_PDCX2.js.map +1 -0
  99. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-B5x-ug3Q.js} +51 -35
  100. package/dist/demo/DemoLogin-B5x-ug3Q.js.map +1 -0
  101. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-Q6sg2xuV.js} +51 -53
  102. package/dist/demo/DemoRegister-Q6sg2xuV.js.map +1 -0
  103. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-DrqZfmEw.js} +14 -19
  104. package/dist/demo/DemoResetPassword-DrqZfmEw.js.map +1 -0
  105. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-CfKS6w1o.js} +4 -5
  106. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-CfKS6w1o.js.map} +1 -1
  107. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-pT6Gi5b5.js} +4 -5
  108. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-pT6Gi5b5.js.map} +1 -1
  109. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-I13NBzQQ.js} +3 -4
  110. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-I13NBzQQ.js.map} +1 -1
  111. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-BqzcrtvN.js} +9 -6
  112. package/dist/demo/DemoTypeForm-BqzcrtvN.js.map +1 -0
  113. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js +33 -0
  114. package/dist/demo/DemoVerifyEmail-HwD8xfQw.js.map +1 -0
  115. package/dist/{auth/IconGoogle-Ch1m3Uzl.js → demo/IconGoogle-CwQy4G9y.js} +2 -4
  116. package/dist/demo/{IconGoogle-CSQLPYwX.js.map → IconGoogle-CwQy4G9y.js.map} +1 -1
  117. package/dist/demo/Login-CqG1iJbn.js +274 -0
  118. package/dist/demo/Login-CqG1iJbn.js.map +1 -0
  119. package/dist/demo/{Profile-BE_Y3co2.js → Profile-C0ojJCaG.js} +31 -29
  120. package/dist/demo/Profile-C0ojJCaG.js.map +1 -0
  121. package/dist/demo/{Register-fXHmBpr3.js → Register-KKZwr_lL.js} +201 -146
  122. package/dist/demo/Register-KKZwr_lL.js.map +1 -0
  123. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-DMrLFEtr.js} +9 -10
  124. package/dist/demo/ResetPassword-DMrLFEtr.js.map +1 -0
  125. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D49Wud2v.js} +65 -68
  126. package/dist/demo/Showcase-D49Wud2v.js.map +1 -0
  127. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BFCAFz6T.js} +25 -11
  128. package/dist/demo/VerifyEmail-BFCAFz6T.js.map +1 -0
  129. package/dist/demo/{auth-Djd7SKiw.js → auth-D9qTZzCa.js} +18 -35
  130. package/dist/demo/{auth-Djd7SKiw.js.map → auth-D9qTZzCa.js.map} +1 -1
  131. package/dist/demo/{core-B7LNjM78.js → core-DRtQklr3.js} +752 -647
  132. package/dist/demo/core-DRtQklr3.js.map +1 -0
  133. package/dist/demo/index.d.ts +1 -0
  134. package/dist/demo/index.d.ts.map +1 -1
  135. package/dist/demo/index.js +25 -22
  136. package/dist/demo/index.js.map +1 -1
  137. package/dist/demo/rolldown-runtime-CiIaOW0V.js +13 -0
  138. package/package.json +19 -19
  139. package/src/admin/AdminRouter.tsx +42 -2
  140. package/src/admin/atoms/adminUserAtom.ts +7 -0
  141. package/src/admin/components/AdminLayout.tsx +2 -14
  142. package/src/admin/components/jobs/AdminJobDashboard.tsx +51 -20
  143. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  144. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  145. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  146. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  147. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  148. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  149. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  150. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  151. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  152. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  153. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  154. package/src/admin/components/users/AdminUserLayout.tsx +84 -127
  155. package/src/admin/components/users/AdminUserProfile.tsx +5 -2
  156. package/src/admin/components/users/AdminUsers.tsx +1 -1
  157. package/src/auth/components/Login.tsx +188 -121
  158. package/src/auth/components/Profile.tsx +1 -22
  159. package/src/auth/components/ProfileField.tsx +39 -0
  160. package/src/auth/components/Register.tsx +215 -158
  161. package/src/auth/components/ResetPassword.tsx +7 -11
  162. package/src/auth/components/VerifyEmail.tsx +35 -10
  163. package/src/auth/components/buttons/UserButton.tsx +19 -21
  164. package/src/auth/index.ts +1 -0
  165. package/src/core/components/Flex.tsx +34 -0
  166. package/src/core/components/buttons/ActionButton.tsx +105 -78
  167. package/src/core/components/data/DetailDrawer.tsx +102 -96
  168. package/src/core/components/data/DetailList.tsx +2 -1
  169. package/src/core/components/dialogs/PromptDialog.tsx +1 -1
  170. package/src/core/components/layout/Breadcrumb.tsx +4 -7
  171. package/src/core/components/layout/DashboardShell.tsx +18 -4
  172. package/src/core/components/layout/Sidebar.tsx +16 -241
  173. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  174. package/src/core/components/layout/SidebarItem.tsx +146 -0
  175. package/src/core/components/layout/index.ts +3 -1
  176. package/src/core/form/components/Control.tsx +31 -29
  177. package/src/core/form/components/ControlArray.tsx +13 -39
  178. package/src/core/form/components/ControlDate.tsx +10 -21
  179. package/src/core/form/components/ControlNumber.tsx +4 -33
  180. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  181. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  182. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  183. package/src/core/form/components/ControlSelect.tsx +294 -92
  184. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  185. package/src/core/form/components/TypeForm.tsx +5 -2
  186. package/src/core/form/index.ts +8 -1
  187. package/src/core/form/utils/parseInput.ts +7 -3
  188. package/src/core/index.ts +3 -1
  189. package/src/core/json/components/JsonViewer.tsx +103 -319
  190. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  191. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  192. package/src/core/json/components/JsonViewerShared.ts +76 -0
  193. package/src/core/services/DialogService.tsx +2 -2
  194. package/src/core/styles.css +13 -2
  195. package/src/core/table/components/ColumnPicker.tsx +3 -3
  196. package/src/core/table/components/DataTable.tsx +88 -29
  197. package/src/core/table/components/DataTableFilters.tsx +6 -11
  198. package/src/core/table/components/DataTablePagination.tsx +9 -3
  199. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  200. package/src/core/table/components/FilterPicker.tsx +3 -3
  201. package/src/core/table/interfaces/types.ts +29 -0
  202. package/src/core/utils/icons.tsx +2 -2
  203. package/src/demo/DemoRouter.ts +8 -1
  204. package/src/demo/components/DemoLayout.tsx +12 -2
  205. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  206. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  207. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  208. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  209. package/src/demo/components/core/DemoButton.tsx +123 -103
  210. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  211. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  212. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  213. package/src/demo/components/shared/MacWindow.tsx +5 -11
  214. package/src/demo/components/shared/Showcase.tsx +28 -42
  215. package/dist/admin/AdminJobDashboard-KIOkeMgE.js.map +0 -1
  216. package/dist/admin/AdminLayout-B1DXZHDn.js.map +0 -1
  217. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  218. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  219. package/dist/admin/AdminUserProfile-DuTUnjdG.js.map +0 -1
  220. package/dist/admin/AdminUsers-CR9z0g_5.js.map +0 -1
  221. package/dist/admin/Login-DHbYJKwg.js +0 -219
  222. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  223. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  224. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  225. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  226. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  227. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  228. package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
  229. package/dist/auth/Login-C7jIqf00.js +0 -219
  230. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  231. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  232. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  233. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  234. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  235. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  236. package/dist/auth/rolldown-runtime-CjeV3_4I.js +0 -18
  237. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  238. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  239. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  240. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  241. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  242. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  243. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  244. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  245. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  246. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  247. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  248. package/dist/demo/Login-CoYf_P_F.js +0 -219
  249. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  250. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  251. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  252. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  253. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  254. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  255. package/dist/demo/core-B7LNjM78.js.map +0 -1
  256. package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
  257. package/src/demo/styles.css +0 -0
@@ -10,6 +10,7 @@ import {
10
10
  import { useAuth } from "alepha/react/auth";
11
11
  import { useRouter } from "alepha/react/router";
12
12
  import type { AuthRouter } from "../AuthRouter.ts";
13
+ import ProfileField from "./ProfileField.tsx";
13
14
 
14
15
  const Profile = () => {
15
16
  const auth = useAuth();
@@ -123,26 +124,4 @@ const Profile = () => {
123
124
  );
124
125
  };
125
126
 
126
- interface ProfileFieldProps {
127
- icon: React.ReactNode;
128
- label: string;
129
- children: React.ReactNode;
130
- }
131
-
132
- const ProfileField = ({ icon, label, children }: ProfileFieldProps) => {
133
- return (
134
- <Flex gap="sm" align="flex-start">
135
- <Flex c="dimmed" mt={2}>
136
- {icon}
137
- </Flex>
138
- <Flex direction="column" gap={2} flex={1}>
139
- <Text size="xs" c="dimmed" tt="uppercase" fw={500}>
140
- {label}
141
- </Text>
142
- <Text size="sm">{children}</Text>
143
- </Flex>
144
- </Flex>
145
- );
146
- };
147
-
148
127
  export default Profile;
@@ -0,0 +1,39 @@
1
+ import { Flex, Text } from "@mantine/core";
2
+ import type { ReactNode } from "react";
3
+
4
+ export interface ProfileFieldProps {
5
+ /**
6
+ * Icon to display
7
+ */
8
+ icon: ReactNode;
9
+
10
+ /**
11
+ * Field label
12
+ */
13
+ label: string;
14
+
15
+ /**
16
+ * Field content
17
+ */
18
+ children: ReactNode;
19
+ }
20
+
21
+ const ProfileField = (props: ProfileFieldProps) => {
22
+ const { icon, label, children } = props;
23
+
24
+ return (
25
+ <Flex gap="sm" align="flex-start">
26
+ <Flex c="dimmed" mt={2}>
27
+ {icon}
28
+ </Flex>
29
+ <Flex direction="column" gap={2} flex={1}>
30
+ <Text size="xs" c="dimmed" tt="uppercase" fw={500}>
31
+ {label}
32
+ </Text>
33
+ <Text size="sm">{children}</Text>
34
+ </Flex>
35
+ </Flex>
36
+ );
37
+ };
38
+
39
+ export default ProfileField;
@@ -5,6 +5,7 @@ import {
5
5
  IconLock,
6
6
  IconMail,
7
7
  IconPhone,
8
+ IconPhoto,
8
9
  IconUser,
9
10
  } from "@tabler/icons-react";
10
11
  import { TypeBoxError, t } from "alepha";
@@ -20,12 +21,14 @@ import { useI18n } from "alepha/react/i18n";
20
21
  import { useRouter } from "alepha/react/router";
21
22
  import { useMemo, useState } from "react";
22
23
  import type { AuthI18n } from "../AuthI18n.ts";
23
- import type { AuthRouter } from "../AuthRouter.ts";
24
24
  import IconGithub from "./icons/IconGithub.tsx";
25
25
  import IconGoogle from "./icons/IconGoogle.tsx";
26
26
 
27
27
  export interface RegisterProps {
28
28
  realmConfig: RealmConfig;
29
+ loginPath?: string;
30
+ variant?: "card" | "split";
31
+ image?: string;
29
32
  }
30
33
 
31
34
  type RegistrationPhase = "form" | "verification";
@@ -42,7 +45,7 @@ interface RegistrationState {
42
45
  const Register = (props: RegisterProps) => {
43
46
  const auth = useAuth();
44
47
  const userCtrl = useClient<UserController>();
45
- const router = useRouter<AuthRouter>();
48
+ const router = useRouter();
46
49
  const { tr } = useI18n<AuthI18n, "en">();
47
50
  const redirect = router.query.r || "/";
48
51
 
@@ -81,9 +84,9 @@ const Register = (props: RegisterProps) => {
81
84
 
82
85
  const required = registerSchema.required as string[];
83
86
 
84
- if (settings.usernameRequired) required.push("username");
85
- if (settings.emailRequired) required.push("email");
86
- if (settings.phoneRequired) required.push("phoneNumber");
87
+ if (settings.username === "required") required.push("username");
88
+ if (settings.email === "required") required.push("email");
89
+ if (settings.phoneNumber === "required") required.push("phoneNumber");
87
90
 
88
91
  return registerSchema;
89
92
  }, []);
@@ -208,7 +211,7 @@ const Register = (props: RegisterProps) => {
208
211
  return true;
209
212
  };
210
213
 
211
- // Verification phase UI
214
+ // Verification phase UI (always card layout)
212
215
  if (registrationState.phase === "verification" && registrationState.intent) {
213
216
  return (
214
217
  <Flex flex={1} justify={"center"} align={"center"}>
@@ -296,171 +299,225 @@ const Register = (props: RegisterProps) => {
296
299
 
297
300
  const showOrDivider = credentialsProvider && externalMethods.length > 0;
298
301
 
299
- // Registration form phase UI
300
- return (
301
- <Flex flex={1} justify={"center"} align={"center"}>
302
- <Flex direction="column" gap={"sm"} w={360}>
303
- <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
304
- <Flex direction="column" gap={"md"}>
305
- {/* Realm branding */}
306
- {(settings.logoUrl ||
307
- settings.displayName ||
308
- settings.description) && (
309
- <Flex direction="column" gap={"xs"} align="center" mb="xs">
310
- {settings.logoUrl && (
311
- <Image
312
- src={settings.logoUrl}
313
- alt={settings.displayName || props.realmConfig.realmName}
314
- h={48}
315
- w="auto"
316
- fit="contain"
302
+ const realmQuery = props.realmConfig.realmName
303
+ ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`
304
+ : "";
305
+
306
+ const formContent = (
307
+ <Flex direction="column" gap={"md"}>
308
+ {/* Realm branding */}
309
+ {(settings.logoUrl || settings.displayName || settings.description) && (
310
+ <Flex direction="column" gap={"xs"} align="center" mb="xs">
311
+ {settings.logoUrl && (
312
+ <Image
313
+ src={settings.logoUrl}
314
+ alt={settings.displayName || props.realmConfig.realmName}
315
+ h={48}
316
+ w="auto"
317
+ fit="contain"
318
+ />
319
+ )}
320
+ {settings.displayName && (
321
+ <Title order={4} ta="center">
322
+ {settings.displayName}
323
+ </Title>
324
+ )}
325
+ {settings.description && (
326
+ <Text size="sm" c="dimmed" ta="center">
327
+ {settings.description}
328
+ </Text>
329
+ )}
330
+ </Flex>
331
+ )}
332
+
333
+ {!isRegistrationAllowed ? (
334
+ <>
335
+ <Alert variant="light" color="yellow" icon={<IconAlertCircle />}>
336
+ <Text size="sm">{tr("registerDisabled")}</Text>
337
+ </Alert>
338
+ <ActionButton
339
+ href={`${props.loginPath ?? "/auth/login"}${realmQuery}`}
340
+ >
341
+ {tr("registerBackToSignIn")}
342
+ </ActionButton>
343
+ </>
344
+ ) : (
345
+ <>
346
+ {/* Credentials registration form */}
347
+ {credentialsProvider && (
348
+ <form {...form.props}>
349
+ <Flex direction="column" flex={1} gap={"md"}>
350
+ {settings.username !== "none" && form.input.username && (
351
+ <Control
352
+ label={tr("registerUsername")}
353
+ input={form.input.username}
354
+ icon={<IconUser />}
355
+ text={{
356
+ autoComplete: "username",
357
+ }}
317
358
  />
318
359
  )}
319
- {settings.displayName && (
320
- <Title order={4} ta="center">
321
- {settings.displayName}
322
- </Title>
360
+ {settings.email !== "none" && form.input.email && (
361
+ <Control
362
+ label={tr("registerEmail")}
363
+ input={form.input.email}
364
+ icon={<IconMail />}
365
+ text={{
366
+ autoComplete: "email",
367
+ }}
368
+ />
323
369
  )}
324
- {settings.description && (
325
- <Text size="sm" c="dimmed" ta="center">
326
- {settings.description}
327
- </Text>
370
+ {settings.phoneNumber !== "none" && form.input.phoneNumber && (
371
+ <Control
372
+ label={tr("registerPhone")}
373
+ input={form.input.phoneNumber}
374
+ icon={<IconPhone />}
375
+ text={{
376
+ autoComplete: "tel",
377
+ }}
378
+ />
328
379
  )}
380
+ <Control
381
+ label={tr("registerPassword")}
382
+ input={form.input.password}
383
+ icon={<IconLock />}
384
+ password={{
385
+ autoComplete: "new-password",
386
+ }}
387
+ />
388
+ <Control
389
+ label={tr("registerConfirmPassword")}
390
+ input={form.input.confirmPassword}
391
+ icon={<IconLock />}
392
+ password={{
393
+ autoComplete: "new-password",
394
+ }}
395
+ />
396
+ <ActionButton form={form} color={"blue"} variant={"filled"}>
397
+ {tr("registerCreateAccount")}
398
+ </ActionButton>
329
399
  </Flex>
330
- )}
400
+ </form>
401
+ )}
402
+
403
+ {/* OR divider - only when both credentials AND external methods exist */}
404
+ {showOrDivider && (
405
+ <Flex align="center" justify="center" gap={"md"}>
406
+ <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
407
+ <Text size="xs" c="dimmed">
408
+ {tr("registerOr")}
409
+ </Text>
410
+ <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
411
+ </Flex>
412
+ )}
331
413
 
332
- {!isRegistrationAllowed ? (
333
- <>
334
- <Alert
335
- variant="light"
336
- color="yellow"
337
- icon={<IconAlertCircle />}
338
- >
339
- <Text size="sm">{tr("registerDisabled")}</Text>
340
- </Alert>
414
+ {/* External login methods */}
415
+ {externalMethods.length > 0 && (
416
+ <Flex direction="column" gap={"sm"}>
417
+ {externalMethods.map((method) => (
341
418
  <ActionButton
342
- href={router.path("login", {
343
- query: { realm: props.realmConfig.realmName },
344
- })}
419
+ variant={"default"}
420
+ key={method.type}
421
+ leftSection={leftSection(method.name.toLowerCase())}
422
+ onClick={() =>
423
+ auth.login(method.name, {
424
+ redirect,
425
+ realm: props.realmConfig.realmName,
426
+ })
427
+ }
345
428
  >
346
- {tr("registerBackToSignIn")}
429
+ {tr("registerContinueWith", {
430
+ args: [capitalize(method.name)],
431
+ })}
347
432
  </ActionButton>
348
- </>
349
- ) : (
350
- <>
351
- {/* Credentials registration form */}
352
- {credentialsProvider && (
353
- <form {...form.props}>
354
- <Flex direction="column" flex={1} gap={"md"}>
355
- {settings.usernameEnabled !== false &&
356
- form.input.username && (
357
- <Control
358
- title={tr("registerUsername")}
359
- input={form.input.username}
360
- icon={<IconUser />}
361
- text={{
362
- autoComplete: "username",
363
- }}
364
- />
365
- )}
366
- {settings.emailEnabled !== false && form.input.email && (
367
- <Control
368
- title={tr("registerEmail")}
369
- input={form.input.email}
370
- icon={<IconMail />}
371
- text={{
372
- autoComplete: "email",
373
- }}
374
- />
375
- )}
376
- {settings.phoneEnabled === true &&
377
- form.input.phoneNumber && (
378
- <Control
379
- title={tr("registerPhone")}
380
- input={form.input.phoneNumber}
381
- icon={<IconPhone />}
382
- text={{
383
- autoComplete: "tel",
384
- }}
385
- />
386
- )}
387
- <Control
388
- title={tr("registerPassword")}
389
- input={form.input.password}
390
- icon={<IconLock />}
391
- password={{
392
- autoComplete: "new-password",
393
- }}
394
- />
395
- <Control
396
- title={tr("registerConfirmPassword")}
397
- input={form.input.confirmPassword}
398
- icon={<IconLock />}
399
- password={{
400
- autoComplete: "new-password",
401
- }}
402
- />
403
- <ActionButton
404
- form={form}
405
- color={"blue"}
406
- variant={"filled"}
407
- >
408
- {tr("registerCreateAccount")}
409
- </ActionButton>
410
- </Flex>
411
- </form>
412
- )}
413
-
414
- {/* OR divider - only when both credentials AND external methods exist */}
415
- {showOrDivider && (
416
- <Flex align="center" justify="center" gap={"md"}>
417
- <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
418
- <Text size="xs" c="dimmed">
419
- {tr("registerOr")}
420
- </Text>
421
- <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
422
- </Flex>
423
- )}
424
-
425
- {/* External login methods */}
426
- {externalMethods.length > 0 && (
427
- <Flex direction="column" gap={"sm"}>
428
- {externalMethods.map((method) => (
429
- <ActionButton
430
- variant={"default"}
431
- key={method.type}
432
- leftSection={leftSection(method.name.toLowerCase())}
433
- onClick={() =>
434
- auth.login(method.name, {
435
- redirect,
436
- realm: props.realmConfig.realmName,
437
- })
438
- }
439
- >
440
- {tr("registerContinueWith", {
441
- args: [capitalize(method.name)],
442
- })}
443
- </ActionButton>
444
- ))}
445
- </Flex>
446
- )}
433
+ ))}
434
+ </Flex>
435
+ )}
436
+
437
+ {/* Sign in link */}
438
+ <Text size="sm" ta="center">
439
+ {tr("registerHaveAccount")}{" "}
440
+ <ActionButton
441
+ href={`${props.loginPath ?? "/auth/login"}${realmQuery}`}
442
+ anchorProps={{ inherit: true }}
443
+ >
444
+ {tr("registerSignIn")}
445
+ </ActionButton>
446
+ </Text>
447
+ </>
448
+ )}
449
+ </Flex>
450
+ );
447
451
 
448
- {/* Sign in link */}
449
- <Text size="sm" ta="center">
450
- {tr("registerHaveAccount")}{" "}
451
- <ActionButton
452
- href={router.path("login", {
453
- query: { realm: props.realmConfig.realmName },
454
- })}
455
- anchorProps={{ inherit: true }}
456
- >
457
- {tr("registerSignIn")}
458
- </ActionButton>
459
- </Text>
460
- </>
452
+ if (props.variant === "split") {
453
+ return (
454
+ <Flex flex={1} justify={"center"} align={"center"}>
455
+ <Card
456
+ withBorder
457
+ p={0}
458
+ w={720}
459
+ bg={"var(--alepha-elevated)"}
460
+ style={{ overflow: "hidden" }}
461
+ >
462
+ <Flex mih={480}>
463
+ {props.image ? (
464
+ <Flex
465
+ flex={1}
466
+ style={{
467
+ backgroundImage: `url(${props.image})`,
468
+ backgroundSize: "cover",
469
+ backgroundPosition: "center",
470
+ }}
471
+ />
472
+ ) : (
473
+ <Flex
474
+ flex={1}
475
+ justify="center"
476
+ align="center"
477
+ bg="var(--mantine-color-gray-light)"
478
+ style={{
479
+ borderRight: "1px solid var(--mantine-color-default-border)",
480
+ }}
481
+ >
482
+ <Flex
483
+ justify="center"
484
+ align="center"
485
+ w={120}
486
+ h={80}
487
+ style={{
488
+ border: "2px dashed var(--mantine-color-default-border)",
489
+ borderRadius: "var(--mantine-radius-sm)",
490
+ }}
491
+ >
492
+ <IconPhoto size={32} style={{ opacity: 0.3 }} />
493
+ </Flex>
494
+ </Flex>
461
495
  )}
496
+ <Flex
497
+ flex={1}
498
+ direction="column"
499
+ gap={"md"}
500
+ p={"xl"}
501
+ justify={"center"}
502
+ >
503
+ {formContent}
504
+ <ActionButton variant={"subtle"} href={redirect}>
505
+ {tr("registerCancel")}
506
+ </ActionButton>
507
+ </Flex>
462
508
  </Flex>
463
509
  </Card>
510
+ </Flex>
511
+ );
512
+ }
513
+
514
+ // Default card variant
515
+ return (
516
+ <Flex flex={1} justify={"center"} align={"center"}>
517
+ <Flex direction="column" gap={"sm"} w={360}>
518
+ <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
519
+ {formContent}
520
+ </Card>
464
521
  <ActionButton variant={"subtle"} href={redirect}>
465
522
  {tr("registerCancel")}
466
523
  </ActionButton>
@@ -20,10 +20,10 @@ import { useI18n } from "alepha/react/i18n";
20
20
  import { useRouter } from "alepha/react/router";
21
21
  import { useState } from "react";
22
22
  import type { AuthI18n } from "../AuthI18n.ts";
23
- import type { AuthRouter } from "../AuthRouter.ts";
24
23
 
25
24
  export interface ResetPasswordProps {
26
25
  realmConfig: RealmConfig;
26
+ loginPath?: string;
27
27
  }
28
28
 
29
29
  type Step = "email" | "code" | "password" | "success";
@@ -36,7 +36,7 @@ interface ResetState {
36
36
  }
37
37
 
38
38
  const ResetPassword = (props: ResetPasswordProps) => {
39
- const router = useRouter<AuthRouter>();
39
+ const router = useRouter();
40
40
  const userCtrl = useClient<UserController>();
41
41
  const { tr } = useI18n<AuthI18n, "en">();
42
42
  const [resetState, setResetState] = useState<ResetState>({ step: "email" });
@@ -176,9 +176,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
176
176
  <Text size="sm">{tr("resetPasswordDisabled")}</Text>
177
177
  </Alert>
178
178
  <ActionButton
179
- href={router.path("login", {
180
- query: { realm: props.realmConfig.realmName },
181
- })}
179
+ href={`${props.loginPath ?? "/auth/login"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : ""}`}
182
180
  >
183
181
  {tr("resetPasswordBackToSignIn")}
184
182
  </ActionButton>
@@ -193,7 +191,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
193
191
  {tr("resetPasswordEnterEmail")}
194
192
  </Text>
195
193
  <Control
196
- title={tr("resetPasswordEmail")}
194
+ label={tr("resetPasswordEmail")}
197
195
  input={emailForm.input.email}
198
196
  icon={<IconMail />}
199
197
  text={{
@@ -249,7 +247,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
249
247
  {tr("resetPasswordEnterNewPassword")}
250
248
  </Text>
251
249
  <Control
252
- title={tr("resetPasswordNewPassword")}
250
+ label={tr("resetPasswordNewPassword")}
253
251
  input={passwordForm.input.password}
254
252
  icon={<IconLock />}
255
253
  password={{
@@ -258,7 +256,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
258
256
  }}
259
257
  />
260
258
  <Control
261
- title={tr("resetPasswordConfirmPassword")}
259
+ label={tr("resetPasswordConfirmPassword")}
262
260
  input={passwordForm.input.confirmPassword}
263
261
  icon={<IconLock />}
264
262
  password={{
@@ -276,9 +274,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
276
274
  <Text size="sm">{tr("resetPasswordSuccess")}</Text>
277
275
  </Alert>
278
276
  <ActionButton
279
- href={router.path("login", {
280
- query: { realm: props.realmConfig.realmName },
281
- })}
277
+ href={`${props.loginPath ?? "/auth/login"}${props.realmConfig.realmName ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}` : ""}`}
282
278
  >
283
279
  {tr("resetPasswordBackToSignIn")}
284
280
  </ActionButton>
@@ -4,22 +4,23 @@ import { IconAlertCircle, IconCheck, IconMailCheck } from "@tabler/icons-react";
4
4
  import type { UserController } from "alepha/api/users";
5
5
  import { useClient } from "alepha/react";
6
6
  import { useI18n } from "alepha/react/i18n";
7
- import { useRouter, useRouterState } from "alepha/react/router";
7
+ import { useRouterState } from "alepha/react/router";
8
8
  import { useEffect, useState } from "react";
9
9
  import type { AuthI18n } from "../AuthI18n.ts";
10
- import type { AuthRouter } from "../AuthRouter.ts";
11
10
 
12
- export type VerifyEmailProps = {};
11
+ export type VerifyEmailStep = "verifying" | "success" | "error";
13
12
 
14
- type Step = "verifying" | "success" | "error";
13
+ export interface VerifyEmailProps {
14
+ loginPath?: string;
15
+ step?: VerifyEmailStep;
16
+ }
15
17
 
16
- const VerifyEmail = (_props: VerifyEmailProps) => {
17
- const router = useRouter<AuthRouter>();
18
+ const VerifyEmailStateful = (props: VerifyEmailProps) => {
18
19
  const state = useRouterState();
19
20
  const userCtrl = useClient<UserController>();
20
21
  const { tr } = useI18n<AuthI18n, "en">();
21
22
 
22
- const [step, setStep] = useState<Step>("verifying");
23
+ const [step, setStep] = useState<VerifyEmailStep>("verifying");
23
24
  const [error, setError] = useState<string | null>(null);
24
25
 
25
26
  const email = state.query.email as string | undefined;
@@ -47,6 +48,21 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
47
48
  verify();
48
49
  }, [email, token]);
49
50
 
51
+ return (
52
+ <VerifyEmailView step={step} error={error} loginPath={props.loginPath} />
53
+ );
54
+ };
55
+
56
+ interface VerifyEmailViewProps {
57
+ step: VerifyEmailStep;
58
+ error?: string | null;
59
+ loginPath?: string;
60
+ }
61
+
62
+ const VerifyEmailView = (props: VerifyEmailViewProps) => {
63
+ const { tr } = useI18n<AuthI18n, "en">();
64
+ const { step } = props;
65
+
50
66
  return (
51
67
  <Flex flex={1} justify="center" align="center">
52
68
  <Flex direction="column" gap="sm" w={400}>
@@ -73,7 +89,7 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
73
89
  <Alert variant="light" color="green" icon={<IconCheck />}>
74
90
  <Text size="sm">{tr("verifyEmailSuccess")}</Text>
75
91
  </Alert>
76
- <ActionButton href={router.path("login")} fullWidth>
92
+ <ActionButton href={props.loginPath ?? "/auth/login"} fullWidth>
77
93
  {tr("verifyEmailSignIn")}
78
94
  </ActionButton>
79
95
  </>
@@ -86,9 +102,11 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
86
102
  {tr("verifyEmailTitle")}
87
103
  </Text>
88
104
  <Alert variant="light" color="red" icon={<IconAlertCircle />}>
89
- <Text size="sm">{error || tr("verifyEmailFailed")}</Text>
105
+ <Text size="sm">
106
+ {props.error || tr("verifyEmailFailed")}
107
+ </Text>
90
108
  </Alert>
91
- <ActionButton href={router.path("login")} fullWidth>
109
+ <ActionButton href={props.loginPath ?? "/auth/login"} fullWidth>
92
110
  {tr("verifyEmailBackToSignIn")}
93
111
  </ActionButton>
94
112
  </>
@@ -100,4 +118,11 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
100
118
  );
101
119
  };
102
120
 
121
+ const VerifyEmail = (props: VerifyEmailProps) => {
122
+ if (props.step) {
123
+ return <VerifyEmailView step={props.step} loginPath={props.loginPath} />;
124
+ }
125
+ return <VerifyEmailStateful {...props} />;
126
+ };
127
+
103
128
  export default VerifyEmail;