@alepha/ui 0.18.2 → 0.18.3

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 (231) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Dy_k-4Vd.js} +2 -2
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Dy_k-4Vd.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-CKiFMSSU.js} +2 -2
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-CKiFMSSU.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-PhC_dZqo.js} +2 -2
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-PhC_dZqo.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-DFTjijGp.js} +2 -2
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-DFTjijGp.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D9E-CS-U.js} +2 -2
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D9E-CS-U.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-Ci9ue1zC.js} +2 -2
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-Ci9ue1zC.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-I6TlUMPc.js} +2 -2
  16. package/dist/admin/{AdminLayout-B1DXZHDn.js.map → AdminLayout-I6TlUMPc.js.map} +1 -1
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions-Bz5NRuoW.js} +2 -2
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions-Bz5NRuoW.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DuTUnjdG.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-CT_YDim0.js} +2 -2
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-CT_YDim0.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-D1UfGya9.js} +2 -2
  30. package/dist/admin/{AdminUsers-CR9z0g_5.js.map → AdminUsers-D1UfGya9.js.map} +1 -1
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/Login-xtNmQtGh.js +275 -0
  34. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  35. package/dist/admin/{Profile-B2EcIDB9.js → Profile-_AtPUwAP.js} +31 -27
  36. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  37. package/dist/admin/{Register-Z3fxRbUF.js → Register-JcCjHUUn.js} +198 -142
  38. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  39. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-CwGBPLJO.js} +7 -7
  40. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  41. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-hNxWejWf.js} +23 -8
  42. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  43. package/dist/admin/{core-BVO_TQxb.js → core-CYaRQ8O-.js} +709 -556
  44. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  45. package/dist/admin/index.d.ts +83 -44
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +58 -39
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-C161NeF6.js → AuthLayout-AvLlcLjS.js} +2 -2
  50. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  51. package/dist/auth/Login-BA1E8IZl.js +275 -0
  52. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  53. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-YcWdeuFz.js} +31 -27
  54. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  55. package/dist/auth/{Register-2gx8qll-.js → Register-CPhEO5MG.js} +198 -142
  56. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  57. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  58. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  59. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  60. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  61. package/dist/auth/{core-DyfeVr5c.js → core-D5jIAVF2.js} +386 -294
  62. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  63. package/dist/auth/index.d.ts +93 -48
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +28 -24
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +116 -61
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +873 -701
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-DN-ClJQk.js → AuthLayout-Brri4A-L.js} +2 -2
  72. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  73. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  74. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  75. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  76. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  77. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  78. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  79. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-CUWdLHim.js} +2 -2
  80. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  81. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-a8OhMMvq.js} +3 -3
  82. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  83. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C13OVDfS.js} +3 -3
  84. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  85. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-D_De3UiT.js} +2 -2
  86. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  87. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  88. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  89. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CHU8WTwO.js} +14 -5
  90. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  91. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-BBlrWpml.js} +49 -32
  92. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  93. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-BuNE3_-f.js} +49 -50
  94. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  95. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  96. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  97. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-Giy2HRBD.js} +3 -3
  98. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  99. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-ubcw-vog.js} +3 -3
  100. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-ubcw-vog.js.map} +1 -1
  101. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-9die_dYT.js} +2 -2
  102. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-9die_dYT.js.map} +1 -1
  103. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  104. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  105. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  106. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  107. package/dist/demo/Login-C12N4oGs.js +275 -0
  108. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  109. package/dist/demo/{Profile-BE_Y3co2.js → Profile-DS5q4vOh.js} +31 -27
  110. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  111. package/dist/demo/{Register-fXHmBpr3.js → Register-B4hLBeEv.js} +198 -142
  112. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  113. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  114. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  115. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D6Fxt4X4.js} +64 -65
  116. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  117. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  118. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  119. package/dist/demo/{auth-Djd7SKiw.js → auth-ByVTreDl.js} +8 -8
  120. package/dist/demo/{auth-Djd7SKiw.js.map → auth-ByVTreDl.js.map} +1 -1
  121. package/dist/demo/{core-B7LNjM78.js → core-DFgB3yU4.js} +741 -573
  122. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  123. package/dist/demo/index.d.ts +1 -0
  124. package/dist/demo/index.d.ts.map +1 -1
  125. package/dist/demo/index.js +24 -18
  126. package/dist/demo/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/admin/AdminRouter.tsx +24 -1
  129. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  130. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  131. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  132. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  133. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  134. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  135. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  136. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  137. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  138. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  139. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  140. package/src/auth/components/Login.tsx +188 -121
  141. package/src/auth/components/Profile.tsx +1 -22
  142. package/src/auth/components/ProfileField.tsx +39 -0
  143. package/src/auth/components/Register.tsx +215 -158
  144. package/src/auth/components/ResetPassword.tsx +7 -11
  145. package/src/auth/components/VerifyEmail.tsx +35 -10
  146. package/src/auth/components/buttons/UserButton.tsx +19 -21
  147. package/src/auth/index.ts +1 -0
  148. package/src/core/components/Flex.tsx +10 -0
  149. package/src/core/components/buttons/ActionButton.tsx +104 -78
  150. package/src/core/components/data/DetailDrawer.tsx +102 -96
  151. package/src/core/components/data/DetailList.tsx +2 -1
  152. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  153. package/src/core/components/layout/DashboardShell.tsx +18 -4
  154. package/src/core/components/layout/Sidebar.tsx +16 -241
  155. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  156. package/src/core/components/layout/SidebarItem.tsx +146 -0
  157. package/src/core/components/layout/index.ts +3 -1
  158. package/src/core/form/components/Control.tsx +31 -29
  159. package/src/core/form/components/ControlArray.tsx +13 -39
  160. package/src/core/form/components/ControlDate.tsx +10 -21
  161. package/src/core/form/components/ControlNumber.tsx +4 -33
  162. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  163. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  164. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  165. package/src/core/form/components/ControlSelect.tsx +294 -92
  166. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  167. package/src/core/form/components/TypeForm.tsx +5 -2
  168. package/src/core/form/index.ts +8 -1
  169. package/src/core/form/utils/parseInput.ts +7 -3
  170. package/src/core/index.ts +3 -1
  171. package/src/core/json/components/JsonViewer.tsx +103 -319
  172. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  173. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  174. package/src/core/json/components/JsonViewerShared.ts +76 -0
  175. package/src/core/styles.css +12 -2
  176. package/src/core/table/components/ColumnPicker.tsx +3 -3
  177. package/src/core/table/components/DataTable.tsx +89 -29
  178. package/src/core/table/components/DataTableFilters.tsx +6 -11
  179. package/src/core/table/components/DataTablePagination.tsx +9 -3
  180. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  181. package/src/core/table/components/FilterPicker.tsx +3 -3
  182. package/src/core/table/interfaces/types.ts +29 -0
  183. package/src/core/utils/icons.tsx +2 -2
  184. package/src/demo/DemoRouter.ts +8 -1
  185. package/src/demo/components/DemoLayout.tsx +12 -2
  186. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  187. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  188. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  189. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  190. package/src/demo/components/core/DemoButton.tsx +123 -103
  191. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  192. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  193. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  194. package/src/demo/components/shared/MacWindow.tsx +5 -11
  195. package/src/demo/components/shared/Showcase.tsx +28 -42
  196. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  197. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  198. package/dist/admin/Login-DHbYJKwg.js +0 -219
  199. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  200. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  201. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  202. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  203. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  204. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  205. package/dist/auth/Login-C7jIqf00.js +0 -219
  206. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  207. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  208. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  209. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  210. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  211. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  212. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  213. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  214. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  215. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  216. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  217. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  218. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  219. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  220. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  221. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  222. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  223. package/dist/demo/Login-CoYf_P_F.js +0 -219
  224. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  225. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  226. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  227. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  228. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  229. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  230. package/dist/demo/core-B7LNjM78.js.map +0 -1
  231. package/src/demo/styles.css +0 -0
@@ -1,6 +1,6 @@
1
1
  import { ActionButton, Control, capitalize } from "@alepha/ui";
2
2
  import { Card, Flex, Image, Text, Title } from "@mantine/core";
3
- import { IconLock, IconUser } from "@tabler/icons-react";
3
+ import { IconLock, IconPhoto, IconUser } from "@tabler/icons-react";
4
4
  import { AlephaError, t } from "alepha";
5
5
  import type { RealmConfig } from "alepha/api/users";
6
6
  import { useAuth } from "alepha/react/auth";
@@ -10,17 +10,20 @@ import { useRouter } from "alepha/react/router";
10
10
  import { HttpError } from "alepha/server";
11
11
  import { useMemo } from "react";
12
12
  import type { AuthI18n } from "../AuthI18n.ts";
13
- import type { AuthRouter } from "../AuthRouter.ts";
14
13
  import IconGithub from "./icons/IconGithub.tsx";
15
14
  import IconGoogle from "./icons/IconGoogle.tsx";
16
15
 
17
16
  export interface LoginProps {
18
17
  realmConfig: RealmConfig;
18
+ registerPath?: string;
19
+ resetPasswordPath?: string;
20
+ variant?: "card" | "split";
21
+ image?: string;
19
22
  }
20
23
 
21
24
  const Login = (props: LoginProps) => {
22
25
  const auth = useAuth();
23
- const router = useRouter<AuthRouter>();
26
+ const router = useRouter();
24
27
  const { tr } = useI18n<AuthI18n, "en">();
25
28
  const redirect = router.query.r || "/";
26
29
 
@@ -33,9 +36,9 @@ const Login = (props: LoginProps) => {
33
36
  // Determine what login methods are available
34
37
  const loginMethods = useMemo(() => {
35
38
  const methods = [];
36
- if (settings.usernameEnabled !== false) methods.push("username");
37
- if (settings.emailEnabled !== false) methods.push("email");
38
- if (settings.phoneEnabled === true) methods.push("phone");
39
+ if (settings.username !== "none") methods.push("username");
40
+ if (settings.email !== "none") methods.push("email");
41
+ if (settings.phoneNumber !== "none") methods.push("phone");
39
42
  return methods;
40
43
  }, [settings]);
41
44
 
@@ -113,129 +116,193 @@ const Login = (props: LoginProps) => {
113
116
 
114
117
  const showOrDivider = credentialsProvider && externalLoginMethods.length > 0;
115
118
 
116
- return (
117
- <Flex flex={1} justify={"center"} align={"center"}>
118
- <Flex direction="column" gap={"sm"} w={360}>
119
- <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
120
- <Flex direction="column" gap={"md"}>
121
- {/* Realm branding */}
122
- {(settings.logoUrl ||
123
- settings.displayName ||
124
- settings.description) && (
125
- <Flex direction="column" gap={"xs"} align="center" mb="xs">
126
- {settings.logoUrl && (
127
- <Image
128
- src={settings.logoUrl}
129
- alt={settings.displayName || props.realmConfig.realmName}
130
- h={48}
131
- w="auto"
132
- fit="contain"
133
- />
134
- )}
135
- {settings.displayName && (
136
- <Title order={4} ta="center">
137
- {settings.displayName}
138
- </Title>
139
- )}
140
- {settings.description && (
141
- <Text size="sm" c="dimmed" ta="center">
142
- {settings.description}
143
- </Text>
144
- )}
145
- </Flex>
146
- )}
119
+ const realmQuery = props.realmConfig.realmName
120
+ ? `?realm=${encodeURIComponent(props.realmConfig.realmName)}`
121
+ : "";
147
122
 
148
- {/* Credentials login form */}
149
- {credentialsProvider && (
150
- <>
151
- <form {...form.props}>
152
- <Flex direction="column" flex={1} gap={"md"}>
153
- <Control
154
- title={identifierTitle}
155
- input={form.input.identifier}
156
- icon={IconUser}
157
- text={{
158
- autoComplete: getAutoCompleteType(),
159
- }}
160
- />
161
- <Control
162
- title={tr("loginPassword")}
163
- input={form.input.password}
164
- icon={IconLock}
165
- password={{
166
- autoComplete: "current-password",
167
- }}
168
- />
169
- <ActionButton variant={"filled"} form={form}>
170
- {tr("loginSignIn")}
171
- </ActionButton>
172
- </Flex>
173
- </form>
174
- {settings.resetPasswordAllowed && (
175
- <Text size="sm" ta="center">
176
- <ActionButton
177
- href={router.path("resetPassword", {
178
- query: { realm: props.realmConfig.realmName },
179
- })}
180
- anchorProps={{ inherit: true }}
181
- >
182
- {tr("loginForgotPassword")}
183
- </ActionButton>
184
- </Text>
185
- )}
186
- </>
187
- )}
123
+ const formContent = (
124
+ <Flex direction="column" gap={"md"}>
125
+ {/* Realm branding */}
126
+ {(settings.logoUrl || settings.displayName || settings.description) && (
127
+ <Flex direction="column" gap={"xs"} align="center" mb="xs">
128
+ {settings.logoUrl && (
129
+ <Image
130
+ src={settings.logoUrl}
131
+ alt={settings.displayName || props.realmConfig.realmName}
132
+ h={48}
133
+ w="auto"
134
+ fit="contain"
135
+ />
136
+ )}
137
+ {settings.displayName && (
138
+ <Title order={4} ta="center">
139
+ {settings.displayName}
140
+ </Title>
141
+ )}
142
+ {settings.description && (
143
+ <Text size="sm" c="dimmed" ta="center">
144
+ {settings.description}
145
+ </Text>
146
+ )}
147
+ </Flex>
148
+ )}
188
149
 
189
- {/* OR divider - only when both credentials AND external methods exist */}
190
- {showOrDivider && (
191
- <Flex align="center" justify="center" gap={"md"}>
192
- <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
193
- <Text size="xs" c={"dimmed"}>
194
- {tr("loginOr")}
195
- </Text>
196
- <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
197
- </Flex>
198
- )}
150
+ {/* Credentials login form */}
151
+ {credentialsProvider && (
152
+ <>
153
+ <form {...form.props}>
154
+ <Flex direction="column" flex={1} gap={"md"}>
155
+ <Control
156
+ label={identifierTitle}
157
+ input={form.input.identifier}
158
+ icon={IconUser}
159
+ text={{
160
+ autoComplete: getAutoCompleteType(),
161
+ }}
162
+ />
163
+ <Control
164
+ label={tr("loginPassword")}
165
+ input={form.input.password}
166
+ icon={IconLock}
167
+ password={{
168
+ autoComplete: "current-password",
169
+ }}
170
+ />
171
+ <ActionButton variant={"filled"} form={form}>
172
+ {tr("loginSignIn")}
173
+ </ActionButton>
174
+ </Flex>
175
+ </form>
176
+ {settings.resetPasswordAllowed && (
177
+ <Text size="sm" ta="center">
178
+ <ActionButton
179
+ href={`${props.resetPasswordPath ?? "/auth/reset-password"}${realmQuery}`}
180
+ anchorProps={{ inherit: true }}
181
+ >
182
+ {tr("loginForgotPassword")}
183
+ </ActionButton>
184
+ </Text>
185
+ )}
186
+ </>
187
+ )}
199
188
 
200
- {/* External login methods */}
201
- {externalLoginMethods.length > 0 && (
202
- <Flex direction="column" gap={"sm"}>
203
- {externalLoginMethods.map((method) => (
204
- <ActionButton
205
- variant={"default"}
206
- key={method.type}
207
- leftSection={leftSection(method.name.toLowerCase())}
208
- onClick={() =>
209
- auth.login(method.name, {
210
- redirect,
211
- realm: props.realmConfig.realmName,
212
- })
213
- }
214
- >
215
- {tr("loginContinueWith", {
216
- args: [capitalize(method.name)],
217
- })}
218
- </ActionButton>
219
- ))}
220
- </Flex>
221
- )}
189
+ {/* OR divider - only when both credentials AND external methods exist */}
190
+ {showOrDivider && (
191
+ <Flex align="center" justify="center" gap={"md"}>
192
+ <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
193
+ <Text size="xs" c={"dimmed"}>
194
+ {tr("loginOr")}
195
+ </Text>
196
+ <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
197
+ </Flex>
198
+ )}
199
+
200
+ {/* External login methods */}
201
+ {externalLoginMethods.length > 0 && (
202
+ <Flex direction="column" gap={"sm"}>
203
+ {externalLoginMethods.map((method) => (
204
+ <ActionButton
205
+ variant={"default"}
206
+ key={method.type}
207
+ leftSection={leftSection(method.name.toLowerCase())}
208
+ onClick={() =>
209
+ auth.login(method.name, {
210
+ redirect,
211
+ realm: props.realmConfig.realmName,
212
+ })
213
+ }
214
+ >
215
+ {tr("loginContinueWith", {
216
+ args: [capitalize(method.name)],
217
+ })}
218
+ </ActionButton>
219
+ ))}
220
+ </Flex>
221
+ )}
222
222
 
223
- {/* Registration link */}
224
- {settings.registrationAllowed && (
225
- <Text size="sm" ta="center">
226
- {tr("loginNoAccount")}{" "}
227
- <ActionButton
228
- href={router.path("register", {
229
- query: { realm: props.realmConfig.realmName },
230
- })}
231
- anchorProps={{ inherit: true }}
223
+ {/* Registration link */}
224
+ {settings.registrationAllowed && (
225
+ <Text size="sm" ta="center">
226
+ {tr("loginNoAccount")}{" "}
227
+ <ActionButton
228
+ href={`${props.registerPath ?? "/auth/register"}${realmQuery}`}
229
+ anchorProps={{ inherit: true }}
230
+ >
231
+ {tr("loginSignUp")}
232
+ </ActionButton>
233
+ </Text>
234
+ )}
235
+ </Flex>
236
+ );
237
+
238
+ if (props.variant === "split") {
239
+ return (
240
+ <Flex flex={1} justify={"center"} align={"center"}>
241
+ <Card
242
+ withBorder
243
+ p={0}
244
+ w={720}
245
+ bg={"var(--alepha-elevated)"}
246
+ style={{ overflow: "hidden" }}
247
+ >
248
+ <Flex mih={480}>
249
+ {props.image ? (
250
+ <Flex
251
+ flex={1}
252
+ style={{
253
+ backgroundImage: `url(${props.image})`,
254
+ backgroundSize: "cover",
255
+ backgroundPosition: "center",
256
+ }}
257
+ />
258
+ ) : (
259
+ <Flex
260
+ flex={1}
261
+ justify="center"
262
+ align="center"
263
+ bg="var(--mantine-color-gray-light)"
264
+ style={{
265
+ borderRight: "1px solid var(--mantine-color-default-border)",
266
+ }}
267
+ >
268
+ <Flex
269
+ justify="center"
270
+ align="center"
271
+ w={120}
272
+ h={80}
273
+ style={{
274
+ border: "2px dashed var(--mantine-color-default-border)",
275
+ borderRadius: "var(--mantine-radius-sm)",
276
+ }}
232
277
  >
233
- {tr("loginSignUp")}
234
- </ActionButton>
235
- </Text>
278
+ <IconPhoto size={32} style={{ opacity: 0.3 }} />
279
+ </Flex>
280
+ </Flex>
236
281
  )}
282
+ <Flex
283
+ flex={1}
284
+ direction="column"
285
+ gap={"md"}
286
+ p={"xl"}
287
+ justify={"center"}
288
+ >
289
+ {formContent}
290
+ <ActionButton variant={"subtle"} href={"/"}>
291
+ {tr("loginCancel")}
292
+ </ActionButton>
293
+ </Flex>
237
294
  </Flex>
238
295
  </Card>
296
+ </Flex>
297
+ );
298
+ }
299
+
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
+ {formContent}
305
+ </Card>
239
306
  <ActionButton variant={"subtle"} href={"/"}>
240
307
  {tr("loginCancel")}
241
308
  </ActionButton>
@@ -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;