@alepha/ui 0.15.1 → 0.15.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 (199) hide show
  1. package/dist/admin/AdminAudits-BU-p1g7A.js +3 -0
  2. package/dist/admin/{AdminAudits-DClGEVBj.js → AdminAudits-Oh7iAfQa.js} +5 -5
  3. package/dist/admin/AdminAudits-Oh7iAfQa.js.map +1 -0
  4. package/dist/admin/AdminFiles-Bg9feLFH.js +3 -0
  5. package/dist/admin/{AdminFiles-C76r1_Xz.js → AdminFiles-Cu8GHgQ3.js} +3 -3
  6. package/dist/admin/AdminFiles-Cu8GHgQ3.js.map +1 -0
  7. package/dist/admin/{AdminNotifications-Bsalygm5.js → AdminNotifications-CgYkBuG_.js} +3 -3
  8. package/dist/admin/AdminNotifications-CgYkBuG_.js.map +1 -0
  9. package/dist/admin/AdminNotifications-DmfGPqHe.js +3 -0
  10. package/dist/admin/{AdminParameters-CpmAWwqN.js → AdminParameters-Cl-R0nXt.js} +1 -1
  11. package/dist/admin/{AdminParameters-Bmxtnpv-.js → AdminParameters-hjNG_KXb.js} +4 -4
  12. package/dist/admin/AdminParameters-hjNG_KXb.js.map +1 -0
  13. package/dist/admin/{AdminSessions-DmK3R6pP.js → AdminSessions-Bey9cuy1.js} +4 -4
  14. package/dist/admin/AdminSessions-Bey9cuy1.js.map +1 -0
  15. package/dist/admin/AdminSessions-Cn4_jB04.js +3 -0
  16. package/dist/admin/{AdminUserAudits-BPMP1Qd2.js → AdminUserAudits-C7AN9jx7.js} +4 -4
  17. package/dist/admin/AdminUserAudits-C7AN9jx7.js.map +1 -0
  18. package/dist/admin/{AdminUserAudits-Brcenss9.js → AdminUserAudits-Cp_ERd2g.js} +1 -1
  19. package/dist/admin/{AdminUserCreate-CZjB6NKc.js → AdminUserCreate-BVIm4JdN.js} +5 -5
  20. package/dist/admin/AdminUserCreate-BVIm4JdN.js.map +1 -0
  21. package/dist/admin/{AdminUserCreate-Cx8bkYC2.js → AdminUserCreate-C1aInRDk.js} +1 -1
  22. package/dist/admin/{AdminUserDetails-8TYsqQBy.js → AdminUserDetails-Dcn3OwMC.js} +1 -1
  23. package/dist/admin/{AdminUserDetails-DuqCOBJK.js → AdminUserDetails-yM4x8JE6.js} +5 -5
  24. package/dist/admin/AdminUserDetails-yM4x8JE6.js.map +1 -0
  25. package/dist/admin/{AdminUserLayout-Dgk8s7Cd.js → AdminUserLayout-BnfBC1gD.js} +4 -4
  26. package/dist/admin/AdminUserLayout-BnfBC1gD.js.map +1 -0
  27. package/dist/admin/{AdminUserLayout-Bz2u_zQ4.js → AdminUserLayout-gb-nbggz.js} +1 -1
  28. package/dist/admin/{AdminUserSessions-DCpe8_T6.js → AdminUserSessions-kmkXG-xf.js} +4 -4
  29. package/dist/admin/AdminUserSessions-kmkXG-xf.js.map +1 -0
  30. package/dist/admin/AdminUserSessions-rvA0ztxn.js +3 -0
  31. package/dist/admin/{AdminUserSettings-qxDfowqh.js → AdminUserSettings-DZ9iWhJW.js} +5 -5
  32. package/dist/admin/AdminUserSettings-DZ9iWhJW.js.map +1 -0
  33. package/dist/admin/AdminUserSettings-Dg-wTRzN.js +3 -0
  34. package/dist/admin/{AdminUsers-ZlPsDz0T.js → AdminUsers-D6Y5K8Am.js} +5 -5
  35. package/dist/admin/AdminUsers-D6Y5K8Am.js.map +1 -0
  36. package/dist/admin/AdminUsers-RCaxccEW.js +3 -0
  37. package/dist/admin/index.d.ts +55 -36
  38. package/dist/admin/index.d.ts.map +1 -1
  39. package/dist/admin/index.js +54 -32
  40. package/dist/admin/index.js.map +1 -1
  41. package/dist/auth/{AuthLayout-CWzQ8rCe.js → AuthLayout-Dj5K4SIN.js} +2 -2
  42. package/dist/auth/AuthLayout-Dj5K4SIN.js.map +1 -0
  43. package/dist/auth/{Login-CyvKwy5e.js → Login-BBqTosqZ.js} +6 -6
  44. package/dist/auth/Login-BBqTosqZ.js.map +1 -0
  45. package/dist/auth/Login-CoU63mMR.js +4 -0
  46. package/dist/auth/Profile-Bxj8Nwom.js +150 -0
  47. package/dist/auth/Profile-Bxj8Nwom.js.map +1 -0
  48. package/dist/auth/Register-BV_oa_AK.js +4 -0
  49. package/dist/auth/{Register-C7Zp09Ks.js → Register-Ce675Crg.js} +8 -8
  50. package/dist/auth/Register-Ce675Crg.js.map +1 -0
  51. package/dist/auth/ResetPassword-D5wC8GAA.js +3 -0
  52. package/dist/auth/{ResetPassword-DYJSUC6B.js → ResetPassword-DWdt7c40.js} +5 -5
  53. package/dist/auth/ResetPassword-DWdt7c40.js.map +1 -0
  54. package/dist/auth/{VerifyEmail-CNXFIwWW.js → VerifyEmail-CI4JwByV.js} +4 -4
  55. package/dist/auth/VerifyEmail-CI4JwByV.js.map +1 -0
  56. package/dist/auth/VerifyEmail-DAfqVm5s.js +3 -0
  57. package/dist/auth/index.d.ts +36 -20
  58. package/dist/auth/index.d.ts.map +1 -1
  59. package/dist/auth/index.js +62 -17
  60. package/dist/auth/index.js.map +1 -1
  61. package/dist/core/index.d.ts +216 -71
  62. package/dist/core/index.d.ts.map +1 -1
  63. package/dist/core/index.js +733 -445
  64. package/dist/core/index.js.map +1 -1
  65. package/dist/demo/{DemoDataTable-DYbDYbs5.js → DemoDataTable-CguplbR7.js} +2 -2
  66. package/dist/demo/{DemoDataTable-DYbDYbs5.js.map → DemoDataTable-CguplbR7.js.map} +1 -1
  67. package/dist/demo/DemoJsonViewer-DIssGVlJ.js +4 -0
  68. package/dist/demo/{DemoJsonViewer-D_Hff1Q2.js → DemoJsonViewer-Dgdk3Txb.js} +3 -3
  69. package/dist/demo/{DemoJsonViewer-D_Hff1Q2.js.map → DemoJsonViewer-Dgdk3Txb.js.map} +1 -1
  70. package/dist/demo/{DemoLayout-DjIDm93B.js → DemoLayout-B20TEuhV.js} +2 -2
  71. package/dist/demo/DemoLayout-B20TEuhV.js.map +1 -0
  72. package/dist/demo/DemoLayout-DSRyf4qJ.js +3 -0
  73. package/dist/demo/{DemoLogin-BA_HiIRZ.js → DemoLogin-S-b15cmE.js} +7 -7
  74. package/dist/demo/DemoLogin-S-b15cmE.js.map +1 -0
  75. package/dist/demo/{DemoRegister-B6syaxP9.js → DemoRegister-B29MdAaZ.js} +9 -9
  76. package/dist/demo/DemoRegister-B29MdAaZ.js.map +1 -0
  77. package/dist/demo/{DemoResetPassword-BOcLG4GF.js → DemoResetPassword-CPTy88iK.js} +6 -6
  78. package/dist/demo/DemoResetPassword-CPTy88iK.js.map +1 -0
  79. package/dist/demo/{DemoSidebar-DpZXf7GO.js → DemoSidebar-MVmQKfMt.js} +2 -2
  80. package/dist/demo/{DemoSidebar-DpZXf7GO.js.map → DemoSidebar-MVmQKfMt.js.map} +1 -1
  81. package/dist/demo/{DemoTypeForm-BlLAcQqZ.js → DemoTypeForm-w-qtfRlC.js} +3 -3
  82. package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +1 -0
  83. package/dist/demo/{DemoVerifyEmail-C-J7bXUQ.js → DemoVerifyEmail-C8FFJT5A.js} +5 -5
  84. package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +1 -0
  85. package/dist/demo/{Showcase-HchhcsHV.js → Showcase-CQrMWars.js} +2 -2
  86. package/dist/demo/Showcase-CQrMWars.js.map +1 -0
  87. package/dist/demo/index.d.ts +25 -15
  88. package/dist/demo/index.d.ts.map +1 -1
  89. package/dist/demo/index.js +24 -14
  90. package/dist/demo/index.js.map +1 -1
  91. package/package.json +6 -6
  92. package/src/admin/AdminRouter.ts +4 -4
  93. package/src/admin/MainRouter.ts +1 -1
  94. package/src/admin/components/audits/AdminAudits.tsx +4 -4
  95. package/src/admin/components/files/AdminFiles.tsx +2 -2
  96. package/src/admin/components/jobs/AdminJobs.tsx +2 -2
  97. package/src/admin/components/notifications/AdminNotifications.tsx +2 -2
  98. package/src/admin/components/parameters/AdminParameters.tsx +1 -1
  99. package/src/admin/components/parameters/ParameterDetails.tsx +2 -2
  100. package/src/admin/components/parameters/ParameterHistory.tsx +1 -1
  101. package/src/admin/components/parameters/types.ts +9 -3
  102. package/src/admin/components/sessions/AdminSessions.tsx +3 -3
  103. package/src/admin/components/shared/AdminResourceHeader.tsx +1 -1
  104. package/src/admin/components/shared/AdminResourceTabs.tsx +1 -1
  105. package/src/admin/components/users/AdminUserAudits.tsx +3 -3
  106. package/src/admin/components/users/AdminUserCreate.tsx +4 -4
  107. package/src/admin/components/users/AdminUserDetails.tsx +4 -4
  108. package/src/admin/components/users/AdminUserLayout.tsx +3 -3
  109. package/src/admin/components/users/AdminUserSessions.tsx +3 -3
  110. package/src/admin/components/users/AdminUserSettings.tsx +4 -4
  111. package/src/admin/components/users/AdminUsers.tsx +4 -4
  112. package/src/admin/index.ts +27 -2
  113. package/src/auth/AuthI18n.ts +1 -1
  114. package/src/auth/AuthRouter.ts +14 -2
  115. package/src/auth/components/AuthLayout.tsx +1 -1
  116. package/src/auth/components/Login.tsx +5 -5
  117. package/src/auth/components/Profile.tsx +157 -0
  118. package/src/auth/components/Register.tsx +7 -7
  119. package/src/auth/components/ResetPassword.tsx +4 -4
  120. package/src/auth/components/VerifyEmail.tsx +3 -3
  121. package/src/auth/components/buttons/UserButton.tsx +35 -3
  122. package/src/auth/index.ts +25 -4
  123. package/src/core/UiRouter.ts +15 -0
  124. package/src/core/atoms/alephaSidebarAtom.ts +57 -0
  125. package/src/core/atoms/alephaThemeListAtom.ts +3 -1
  126. package/src/core/components/buttons/ActionButton.tsx +10 -10
  127. package/src/core/components/buttons/BurgerButton.tsx +5 -4
  128. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  129. package/src/core/components/buttons/OmnibarButton.tsx +20 -1
  130. package/src/core/components/buttons/ThemeButton.tsx +1 -1
  131. package/src/core/components/buttons/ToggleSidebarButton.tsx +33 -23
  132. package/src/core/components/form/Control.tsx +1 -1
  133. package/src/core/components/form/ControlArray.tsx +2 -2
  134. package/src/core/components/form/ControlDate.tsx +1 -1
  135. package/src/core/components/form/ControlNumber.tsx +2 -2
  136. package/src/core/components/form/ControlObject.tsx +1 -1
  137. package/src/core/components/form/ControlQueryBuilder.tsx +1 -1
  138. package/src/core/components/form/ControlSelect.tsx +1 -1
  139. package/src/core/components/form/TypeForm.tsx +2 -2
  140. package/src/core/components/layout/AdminShell.tsx +236 -30
  141. package/src/core/components/layout/AlephaMantineProvider.tsx +3 -3
  142. package/src/core/components/layout/AppBar.tsx +235 -18
  143. package/src/core/components/layout/Omnibar.tsx +4 -4
  144. package/src/core/components/layout/Sidebar.tsx +43 -82
  145. package/src/core/components/table/DataTable.tsx +2 -2
  146. package/src/core/components/table/DataTableFilters.tsx +1 -1
  147. package/src/core/components/table/types.ts +1 -1
  148. package/src/core/hooks/useDialog.ts +1 -1
  149. package/src/core/hooks/useTheme.ts +1 -1
  150. package/src/core/hooks/useToast.ts +1 -1
  151. package/src/core/index.ts +46 -9
  152. package/src/core/providers/ThemeProvider.ts +1 -1
  153. package/src/core/styles.css +58 -0
  154. package/src/core/utils/parseInput.ts +1 -1
  155. package/src/demo/DemoRouter.ts +1 -1
  156. package/src/demo/components/DemoLayout.tsx +1 -1
  157. package/src/demo/components/core/DemoTypeForm.tsx +1 -1
  158. package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
  159. package/src/demo/components/shared/Showcase.tsx +1 -1
  160. package/src/demo/index.ts +11 -1
  161. package/src/json/index.ts +13 -0
  162. package/dist/admin/AdminAudits-ColpiP4T.js +0 -3
  163. package/dist/admin/AdminAudits-DClGEVBj.js.map +0 -1
  164. package/dist/admin/AdminFiles-C5pqXN5B.js +0 -3
  165. package/dist/admin/AdminFiles-C76r1_Xz.js.map +0 -1
  166. package/dist/admin/AdminNotifications-BXixCBu9.js +0 -3
  167. package/dist/admin/AdminNotifications-Bsalygm5.js.map +0 -1
  168. package/dist/admin/AdminParameters-Bmxtnpv-.js.map +0 -1
  169. package/dist/admin/AdminSessions-CrkRvey3.js +0 -3
  170. package/dist/admin/AdminSessions-DmK3R6pP.js.map +0 -1
  171. package/dist/admin/AdminUserAudits-BPMP1Qd2.js.map +0 -1
  172. package/dist/admin/AdminUserCreate-CZjB6NKc.js.map +0 -1
  173. package/dist/admin/AdminUserDetails-DuqCOBJK.js.map +0 -1
  174. package/dist/admin/AdminUserLayout-Dgk8s7Cd.js.map +0 -1
  175. package/dist/admin/AdminUserSessions-DCpe8_T6.js.map +0 -1
  176. package/dist/admin/AdminUserSessions-beiJqY2D.js +0 -3
  177. package/dist/admin/AdminUserSettings-CxlInVnu.js +0 -3
  178. package/dist/admin/AdminUserSettings-qxDfowqh.js.map +0 -1
  179. package/dist/admin/AdminUsers-Bd0wMP8v.js +0 -3
  180. package/dist/admin/AdminUsers-ZlPsDz0T.js.map +0 -1
  181. package/dist/auth/AuthLayout-CWzQ8rCe.js.map +0 -1
  182. package/dist/auth/Login-CxOPyNFP.js +0 -4
  183. package/dist/auth/Login-CyvKwy5e.js.map +0 -1
  184. package/dist/auth/Register-C7Zp09Ks.js.map +0 -1
  185. package/dist/auth/Register-Cacr7YbA.js +0 -4
  186. package/dist/auth/ResetPassword-CMkx8Ibf.js +0 -3
  187. package/dist/auth/ResetPassword-DYJSUC6B.js.map +0 -1
  188. package/dist/auth/VerifyEmail-CNXFIwWW.js.map +0 -1
  189. package/dist/auth/VerifyEmail-DKyDlz96.js +0 -3
  190. package/dist/demo/DemoJsonViewer-DbWVDdz_.js +0 -4
  191. package/dist/demo/DemoLayout-DjIDm93B.js.map +0 -1
  192. package/dist/demo/DemoLayout-nNMajP_9.js +0 -3
  193. package/dist/demo/DemoLogin-BA_HiIRZ.js.map +0 -1
  194. package/dist/demo/DemoRegister-B6syaxP9.js.map +0 -1
  195. package/dist/demo/DemoResetPassword-BOcLG4GF.js.map +0 -1
  196. package/dist/demo/DemoTypeForm-BlLAcQqZ.js.map +0 -1
  197. package/dist/demo/DemoVerifyEmail-C-J7bXUQ.js.map +0 -1
  198. package/dist/demo/Showcase-HchhcsHV.js.map +0 -1
  199. package/src/core/RootRouter.ts +0 -9
@@ -1,5 +1,3 @@
1
- import { useClient } from "@alepha/react";
2
- import { useRouter, useRouterState } from "@alepha/react/router";
3
1
  import { ActionButton, Flex, Text } from "@alepha/ui";
4
2
  import { Alert, Card, Group, Loader, Stack } from "@mantine/core";
5
3
  import {
@@ -13,6 +11,8 @@ import type {
13
11
  UserController,
14
12
  UserEntity,
15
13
  } from "alepha/api/users";
14
+ import { useClient } from "alepha/react";
15
+ import { useRouter, useRouterState } from "alepha/react/router";
16
16
  import { useEffect, useState } from "react";
17
17
  import type { AdminRouter } from "../../AdminRouter.ts";
18
18
 
@@ -60,7 +60,7 @@ const AdminUserSettings = (props: AdminUserSettingsProps) => {
60
60
  params: { id: userId },
61
61
  query: { userRealmName: props.userRealmName },
62
62
  });
63
- await router.go("adminUsers");
63
+ await router.push("adminUsers");
64
64
  } finally {
65
65
  setDeleteLoading(false);
66
66
  }
@@ -76,7 +76,7 @@ const AdminUserSettings = (props: AdminUserSettingsProps) => {
76
76
  query: {
77
77
  userRealmName: props.userRealmName,
78
78
  method: "link",
79
- verifyUrl: `${window.location.origin}/verify-email`,
79
+ verifyUrl: `${window.location.origin}/auth/verify-email`,
80
80
  },
81
81
  body: { email: user.email },
82
82
  });
@@ -1,6 +1,3 @@
1
- import { useClient } from "@alepha/react";
2
- import { useI18n } from "@alepha/react/i18n";
3
- import { useRouter } from "@alepha/react/router";
4
1
  import { DataTable, Text } from "@alepha/ui";
5
2
  import { Badge, Flex, Group } from "@mantine/core";
6
3
  import { IconCheck, IconUsersPlus, IconX } from "@tabler/icons-react";
@@ -10,6 +7,9 @@ import {
10
7
  type UserEntity,
11
8
  users,
12
9
  } from "alepha/api/users";
10
+ import { useClient } from "alepha/react";
11
+ import { useI18n } from "alepha/react/i18n";
12
+ import { useRouter } from "alepha/react/router";
13
13
  import type { AdminRouter } from "../../AdminRouter.ts";
14
14
 
15
15
  export interface AdminUsersProps {
@@ -63,7 +63,7 @@ const AdminUsers = (props: AdminUsersProps) => {
63
63
  const baseProps: Record<string, any> = {
64
64
  style: { cursor: "pointer" },
65
65
  onClick: () =>
66
- router.go("adminUserDetails", {
66
+ router.push("adminUserDetails", {
67
67
  params: { userId: item.id },
68
68
  }),
69
69
  };
@@ -1,6 +1,6 @@
1
1
  import { AlephaUI } from "@alepha/ui";
2
2
  import { AlephaUIAuth } from "@alepha/ui/auth";
3
- import { $module } from "alepha";
3
+ import { $context, $module } from "alepha";
4
4
  import { AdminRouter } from "./AdminRouter.ts";
5
5
  import { MainRouter } from "./MainRouter.ts";
6
6
 
@@ -36,7 +36,22 @@ export { MainRouter } from "./MainRouter.ts";
36
36
  // ---------------------------------------------------------------------------------------------------------------------
37
37
 
38
38
  /**
39
- * Admin panel UI Module
39
+ * | type | quality | stability |
40
+ * |------|---------|-----------|
41
+ * | frontend | rare | experimental |
42
+ *
43
+ * Admin panel UI components.
44
+ *
45
+ * **Features:**
46
+ * - AdminLayout for admin pages
47
+ * - AdminUsers with user list, create, details, settings, sessions, audits
48
+ * - AdminFiles for file management
49
+ * - AdminJobs for job monitoring
50
+ * - AdminNotifications for notification management
51
+ * - AdminParameters for configuration management
52
+ * - AdminSessions for session management
53
+ * - AdminAudits for audit log viewing
54
+ * - AdminVerifications for verification management
40
55
  *
41
56
  * @module alepha.ui.admin
42
57
  */
@@ -47,3 +62,13 @@ export const AlephaUIAdmin = $module({
47
62
  alepha.with(AdminRouter);
48
63
  },
49
64
  });
65
+
66
+ // ---------------------------------------------------------------------------------------------------------------------
67
+
68
+ /**
69
+ * Register Admin UI components and get the AdminRouter instance.
70
+ */
71
+ export const $uiAdmin = () => {
72
+ const { alepha } = $context();
73
+ return alepha.inject(AdminRouter);
74
+ };
@@ -1,4 +1,4 @@
1
- import { $dictionary } from "@alepha/react/i18n";
1
+ import { $dictionary } from "alepha/react/i18n";
2
2
 
3
3
  export class AuthI18n {
4
4
  en = $dictionary({
@@ -1,14 +1,15 @@
1
- import { ReactAuth } from "@alepha/react/auth";
2
- import { $page } from "@alepha/react/router";
3
1
  import {
4
2
  IconLogin2,
5
3
  IconLogout2,
6
4
  IconMailCheck,
7
5
  IconPasswordUser,
6
+ IconUser,
8
7
  IconUserPlus,
9
8
  } from "@tabler/icons-react";
10
9
  import { $inject, AlephaError, t } from "alepha";
11
10
  import type { RealmController } from "alepha/api/users";
11
+ import { ReactAuth } from "alepha/react/auth";
12
+ import { $page } from "alepha/react/router";
12
13
  import { $client } from "alepha/server/links";
13
14
 
14
15
  /**
@@ -34,6 +35,7 @@ export class AuthRouter {
34
35
  this.register,
35
36
  this.resetPassword,
36
37
  this.verifyEmail,
38
+ this.profile,
37
39
  ],
38
40
  });
39
41
 
@@ -115,6 +117,16 @@ export class AuthRouter {
115
117
  },
116
118
  });
117
119
 
120
+ profile = $page({
121
+ name: "userProfile",
122
+ icon: IconUser,
123
+ label: "Profile",
124
+ description: "View your profile",
125
+ path: "/profile",
126
+ can: () => !!this.auth.user,
127
+ lazy: () => import("./components/Profile.tsx"),
128
+ });
129
+
118
130
  protected async loadRealmConfig(realmName?: string) {
119
131
  try {
120
132
  return await this.realmClient.getRealmConfig({
@@ -1,6 +1,6 @@
1
- import { NestedView } from "@alepha/react/router";
2
1
  import { AlephaMantineProvider } from "@alepha/ui";
3
2
  import { Flex } from "@mantine/core";
3
+ import { NestedView } from "alepha/react/router";
4
4
 
5
5
  const AuthLayout = () => {
6
6
  return (
@@ -1,12 +1,12 @@
1
- import { useAuth } from "@alepha/react/auth";
2
- import { FormValidationError, useForm } from "@alepha/react/form";
3
- import { useI18n } from "@alepha/react/i18n";
4
- import { useRouter } from "@alepha/react/router";
5
1
  import { ActionButton, Control, capitalize } from "@alepha/ui";
6
2
  import { Card, Flex, Group, Image, Stack, Text, Title } from "@mantine/core";
7
3
  import { IconLock, IconUser } from "@tabler/icons-react";
8
4
  import { AlephaError, t } from "alepha";
9
5
  import type { RealmConfig } from "alepha/api/users";
6
+ import { useAuth } from "alepha/react/auth";
7
+ import { FormValidationError, useForm } from "alepha/react/form";
8
+ import { useI18n } from "alepha/react/i18n";
9
+ 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";
@@ -78,7 +78,7 @@ const Login = (props: LoginProps) => {
78
78
  password: data.password,
79
79
  realm: props.realmConfig.realmName,
80
80
  });
81
- await router.go(router.query.r || "/");
81
+ await router.push(router.query.r || "/");
82
82
  } catch (error) {
83
83
  if (
84
84
  error instanceof HttpError &&
@@ -0,0 +1,157 @@
1
+ import { ActionButton } from "@alepha/ui";
2
+ import {
3
+ Avatar,
4
+ Badge,
5
+ Card,
6
+ Flex,
7
+ Group,
8
+ Stack,
9
+ Text,
10
+ Title,
11
+ } from "@mantine/core";
12
+ import {
13
+ IconAt,
14
+ IconCalendar,
15
+ IconId,
16
+ IconShield,
17
+ IconUser,
18
+ } from "@tabler/icons-react";
19
+ import { useAuth } from "alepha/react/auth";
20
+ import { useRouter } from "alepha/react/router";
21
+ import type { AuthRouter } from "../AuthRouter.ts";
22
+
23
+ const Profile = () => {
24
+ const auth = useAuth();
25
+ const router = useRouter<AuthRouter>();
26
+
27
+ if (!auth.user) {
28
+ return null;
29
+ }
30
+
31
+ const { id, name, email, username, picture, roles, organizations } =
32
+ auth.user;
33
+
34
+ const displayName = name || username || email || "User";
35
+
36
+ return (
37
+ <Flex flex={1} justify="center" align="center">
38
+ <Stack gap="md" w={400}>
39
+ <Card withBorder p="xl" bg="var(--alepha-elevated)">
40
+ <Stack gap="lg">
41
+ {/* Avatar and name */}
42
+ <Flex direction="column" align="center" gap="md">
43
+ <Avatar
44
+ src={picture ? `/api/files/${picture}` : undefined}
45
+ size={96}
46
+ radius="xl"
47
+ color="blue"
48
+ >
49
+ {!picture && <IconUser size={48} />}
50
+ </Avatar>
51
+ <Stack gap={4} align="center">
52
+ <Title order={3}>{displayName}</Title>
53
+ {email && username && (
54
+ <Text size="sm" c="dimmed">
55
+ @{username}
56
+ </Text>
57
+ )}
58
+ </Stack>
59
+ </Flex>
60
+
61
+ {/* User details */}
62
+ <Stack gap="sm">
63
+ {email && (
64
+ <ProfileField icon={<IconAt size={18} />} label="Email">
65
+ {email}
66
+ </ProfileField>
67
+ )}
68
+
69
+ {username && (
70
+ <ProfileField icon={<IconUser size={18} />} label="Username">
71
+ {username}
72
+ </ProfileField>
73
+ )}
74
+
75
+ {id && (
76
+ <ProfileField icon={<IconId size={18} />} label="User ID">
77
+ <Text size="xs" c="dimmed" ff="monospace">
78
+ {id}
79
+ </Text>
80
+ </ProfileField>
81
+ )}
82
+
83
+ {/* Roles */}
84
+ {roles && roles.length > 0 && (
85
+ <ProfileField icon={<IconShield size={18} />} label="Roles">
86
+ <Group gap="xs">
87
+ {roles.map((role) => (
88
+ <Badge key={role} size="sm" variant="light">
89
+ {role}
90
+ </Badge>
91
+ ))}
92
+ </Group>
93
+ </ProfileField>
94
+ )}
95
+
96
+ {/* Organizations */}
97
+ {organizations && organizations.length > 0 && (
98
+ <ProfileField
99
+ icon={<IconCalendar size={18} />}
100
+ label="Organizations"
101
+ >
102
+ <Group gap="xs">
103
+ {organizations.map((org) => (
104
+ <Badge key={org} size="sm" variant="outline">
105
+ {org}
106
+ </Badge>
107
+ ))}
108
+ </Group>
109
+ </ProfileField>
110
+ )}
111
+ </Stack>
112
+
113
+ {/* Actions */}
114
+ <Stack gap="sm" mt="md">
115
+ <ActionButton
116
+ variant="light"
117
+ color="red"
118
+ onClick={() => auth.logout()}
119
+ fullWidth
120
+ >
121
+ Sign out
122
+ </ActionButton>
123
+ </Stack>
124
+ </Stack>
125
+ </Card>
126
+
127
+ <ActionButton variant="subtle" href="/">
128
+ Back to home
129
+ </ActionButton>
130
+ </Stack>
131
+ </Flex>
132
+ );
133
+ };
134
+
135
+ interface ProfileFieldProps {
136
+ icon: React.ReactNode;
137
+ label: string;
138
+ children: React.ReactNode;
139
+ }
140
+
141
+ const ProfileField = ({ icon, label, children }: ProfileFieldProps) => {
142
+ return (
143
+ <Flex gap="sm" align="flex-start">
144
+ <Flex c="dimmed" mt={2}>
145
+ {icon}
146
+ </Flex>
147
+ <Stack gap={2} flex={1}>
148
+ <Text size="xs" c="dimmed" tt="uppercase" fw={500}>
149
+ {label}
150
+ </Text>
151
+ <Text size="sm">{children}</Text>
152
+ </Stack>
153
+ </Flex>
154
+ );
155
+ };
156
+
157
+ export default Profile;
@@ -1,8 +1,3 @@
1
- import { useClient } from "@alepha/react";
2
- import { useAuth } from "@alepha/react/auth";
3
- import { useForm } from "@alepha/react/form";
4
- import { useI18n } from "@alepha/react/i18n";
5
- import { useRouter } from "@alepha/react/router";
6
1
  import { ActionButton, Control, capitalize } from "@alepha/ui";
7
2
  import {
8
3
  Alert,
@@ -28,6 +23,11 @@ import type {
28
23
  RegistrationIntentResponse,
29
24
  UserController,
30
25
  } from "alepha/api/users";
26
+ import { useClient } from "alepha/react";
27
+ import { useAuth } from "alepha/react/auth";
28
+ import { useForm } from "alepha/react/form";
29
+ import { useI18n } from "alepha/react/i18n";
30
+ import { useRouter } from "alepha/react/router";
31
31
  import { useMemo, useState } from "react";
32
32
  import type { AuthI18n } from "../AuthI18n.ts";
33
33
  import type { AuthRouter } from "../AuthRouter.ts";
@@ -155,7 +155,7 @@ const Register = (props: RegisterProps) => {
155
155
  });
156
156
  }
157
157
 
158
- await router.go(router.query.r || "/");
158
+ await router.push(router.query.r || "/");
159
159
  },
160
160
  });
161
161
 
@@ -188,7 +188,7 @@ const Register = (props: RegisterProps) => {
188
188
  });
189
189
  }
190
190
 
191
- await router.go(router.query.r || "/");
191
+ await router.push(router.query.r || "/");
192
192
  } catch (error) {
193
193
  setVerificationError(
194
194
  error instanceof Error ? error.message : "Verification failed",
@@ -1,7 +1,3 @@
1
- import { useClient } from "@alepha/react";
2
- import { useForm } from "@alepha/react/form";
3
- import { useI18n } from "@alepha/react/i18n";
4
- import { useRouter } from "@alepha/react/router";
5
1
  import { ActionButton, Control } from "@alepha/ui";
6
2
  import {
7
3
  Alert,
@@ -27,6 +23,10 @@ import type {
27
23
  UserController,
28
24
  } from "alepha/api/users";
29
25
  import { resetPasswordRequestSchema } from "alepha/api/users";
26
+ import { useClient } from "alepha/react";
27
+ import { useForm } from "alepha/react/form";
28
+ import { useI18n } from "alepha/react/i18n";
29
+ import { useRouter } from "alepha/react/router";
30
30
  import { useState } from "react";
31
31
  import type { AuthI18n } from "../AuthI18n.ts";
32
32
  import type { AuthRouter } from "../AuthRouter.ts";
@@ -1,10 +1,10 @@
1
- import { useClient } from "@alepha/react";
2
- import { useI18n } from "@alepha/react/i18n";
3
- import { useRouter, useRouterState } from "@alepha/react/router";
4
1
  import { ActionButton } from "@alepha/ui";
5
2
  import { Alert, Card, Flex, Loader, Stack, Text } from "@mantine/core";
6
3
  import { IconAlertCircle, IconCheck, IconMailCheck } from "@tabler/icons-react";
7
4
  import type { UserController } from "alepha/api/users";
5
+ import { useClient } from "alepha/react";
6
+ import { useI18n } from "alepha/react/i18n";
7
+ import { useRouter, useRouterState } from "alepha/react/router";
8
8
  import { useEffect, useState } from "react";
9
9
  import type { AuthI18n } from "../AuthI18n.ts";
10
10
  import type { AuthRouter } from "../AuthRouter.ts";
@@ -1,5 +1,3 @@
1
- import { useAuth } from "@alepha/react/auth";
2
- import { useRouter } from "@alepha/react/router";
3
1
  import {
4
2
  ActionButton,
5
3
  type ActionMenuConfig,
@@ -8,7 +6,16 @@ import {
8
6
  ui,
9
7
  } from "@alepha/ui";
10
8
  import { Avatar } from "@mantine/core";
11
- import { IconLogin2, IconLogout, IconUser } from "@tabler/icons-react";
9
+ import {
10
+ IconLogin2,
11
+ IconLogout,
12
+ IconSettings,
13
+ IconUser,
14
+ } from "@tabler/icons-react";
15
+ import type { AdminUserController } from "alepha/api/users";
16
+ import { useClient, useInject } from "alepha/react";
17
+ import { useAuth } from "alepha/react/auth";
18
+ import { ReactPageProvider, useRouter } from "alepha/react/router";
12
19
  import type { ReactNode } from "react";
13
20
  import type { AuthRouter } from "../../AuthRouter.ts";
14
21
 
@@ -53,12 +60,19 @@ const UserButton = (props: UserButtonProps) => {
53
60
 
54
61
  buttonProps.variant ??= "subtle";
55
62
 
63
+ const adminUserCtrl = useClient<AdminUserController>();
64
+ const pages = useInject(ReactPageProvider);
65
+
56
66
  const auth = useAuth<{
57
67
  username?: string;
58
68
  email?: string;
59
69
  picture?: string;
60
70
  }>();
61
71
 
72
+ const isConnected = !!auth.user;
73
+ const isAdmin = isConnected && adminUserCtrl.findUsers.can();
74
+ const userPage = pages.getPages().find((it) => it.name === "userProfile");
75
+ const adminPage = pages.getPages().find((it) => it.name === "adminLayout");
62
76
  const authRouter = useRouter<AuthRouter>();
63
77
 
64
78
  if (!auth.user) {
@@ -83,6 +97,24 @@ const UserButton = (props: UserButtonProps) => {
83
97
  });
84
98
  }
85
99
 
100
+ // Add profile page link if available
101
+ if (userPage && isConnected) {
102
+ items.push({
103
+ label: "Profile",
104
+ icon: <IconUser size={ui.sizes.icon.md} />,
105
+ href: authRouter.path("userProfile"),
106
+ });
107
+ }
108
+
109
+ // Add admin page link if available and user is admin
110
+ if (adminPage && isAdmin) {
111
+ items.push({
112
+ label: "Admin",
113
+ icon: <IconSettings size={ui.sizes.icon.md} />,
114
+ href: authRouter.path("adminLayout"),
115
+ });
116
+ }
117
+
86
118
  // Add custom menu items
87
119
  items.push(...menuItems);
88
120
 
package/src/auth/index.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { AlephaReactAuth } from "@alepha/react/auth";
2
- import { AlephaReactI18n } from "@alepha/react/i18n";
3
1
  import { AlephaUI } from "@alepha/ui";
4
- import { $module } from "alepha";
2
+ import { $context, $module } from "alepha";
3
+ import { AlephaReactAuth } from "alepha/react/auth";
4
+ import { AlephaReactI18n } from "alepha/react/i18n";
5
5
  import { AuthI18n } from "./AuthI18n.ts";
6
6
  import { AuthRouter } from "./AuthRouter.ts";
7
7
 
@@ -18,7 +18,18 @@ export { default as VerifyEmail } from "./components/VerifyEmail.tsx";
18
18
  // ---------------------------------------------------------------------------------------------------------------------
19
19
 
20
20
  /**
21
- * Login UI Module
21
+ * | type | quality | stability |
22
+ * |------|---------|-----------|
23
+ * | frontend | rare | experimental |
24
+ *
25
+ * Authentication UI components.
26
+ *
27
+ * **Features:**
28
+ * - Login page component
29
+ * - Register page component
30
+ * - Reset password page component
31
+ * - Email verification page component
32
+ * - UserButton for user menu
22
33
  *
23
34
  * @module alepha.ui.auth
24
35
  */
@@ -26,3 +37,13 @@ export const AlephaUIAuth = $module({
26
37
  name: "alepha.ui.auth",
27
38
  services: [AlephaUI, AlephaReactAuth, AlephaReactI18n, AuthRouter, AuthI18n],
28
39
  });
40
+
41
+ // ---------------------------------------------------------------------------------------------------------------------
42
+
43
+ /**
44
+ * Register Auth UI components and get the AuthRouter instance.
45
+ */
46
+ export const $uiAuth = () => {
47
+ const { alepha } = $context();
48
+ return alepha.inject(AuthRouter);
49
+ };
@@ -0,0 +1,15 @@
1
+ import { $page } from "alepha/react/router";
2
+ import AlephaMantineProvider from "./components/layout/AlephaMantineProvider.tsx";
3
+
4
+ /**
5
+ * UI Router defining the root page with AlephaMantineProvider.
6
+ *
7
+ * - Use UiRouter when you need Alepha's Mantine-based UI components and theming.
8
+ * - Prefer to use $ui() for convenience. (Custom Factory of UiRouter)
9
+ */
10
+ export class UiRouter {
11
+ public readonly root = $page({
12
+ path: "/",
13
+ component: AlephaMantineProvider,
14
+ });
15
+ }
@@ -0,0 +1,57 @@
1
+ import { $atom, type Static, t } from "alepha";
2
+
3
+ export const alephaSidebarAtom = $atom({
4
+ name: "alepha.ui.sidebar",
5
+ schema: t.object({
6
+ /**
7
+ * Whether the sidebar is opened or closed (mobile).
8
+ */
9
+ opened: t.boolean(),
10
+ /**
11
+ * Whether the sidebar is collapsed (narrow) or expanded (wide).
12
+ */
13
+ collapsed: t.boolean(),
14
+ /**
15
+ * Current width of the sidebar when expanded (can be changed by resizing).
16
+ * @default 300
17
+ */
18
+ width: t.number(),
19
+ /**
20
+ * Default width used when expanding from collapsed state or on hover.
21
+ * @default 300
22
+ */
23
+ defaultWidth: t.number(),
24
+ /**
25
+ * Width of the sidebar when collapsed.
26
+ * @default 78
27
+ */
28
+ collapsedWidth: t.number(),
29
+ /**
30
+ * Maximum width when resizing.
31
+ * @default 500
32
+ */
33
+ maxWidth: t.number(),
34
+ /**
35
+ * Minimum width before auto-collapse triggers.
36
+ * @default 150
37
+ */
38
+ collapseThreshold: t.number(),
39
+ /**
40
+ * Delay in ms before sidebar expands on hover when collapsed.
41
+ * @default 300
42
+ */
43
+ hoverDelay: t.number(),
44
+ }),
45
+ default: {
46
+ opened: false,
47
+ collapsed: false,
48
+ width: 300,
49
+ defaultWidth: 300,
50
+ collapsedWidth: 78,
51
+ maxWidth: 500,
52
+ collapseThreshold: 240,
53
+ hoverDelay: 300,
54
+ },
55
+ });
56
+
57
+ export type AlephaSidebarState = Static<typeof alephaSidebarAtom.schema>;
@@ -1,4 +1,4 @@
1
- import { $atom, t } from "alepha";
1
+ import { $atom, type Static, t } from "alepha";
2
2
  import type { AlephaTheme } from "../interfaces/AlephaTheme.ts";
3
3
  import { defaultTheme } from "./themes/default.ts";
4
4
  import { midnightTheme } from "./themes/midnight.ts";
@@ -8,3 +8,5 @@ export const alephaThemeListAtom = $atom({
8
8
  schema: t.array(t.json<AlephaTheme>()), // TODO: translate to proper schema
9
9
  default: [defaultTheme, midnightTheme],
10
10
  });
11
+
12
+ export type AlephaThemeListAtom = Static<typeof alephaThemeListAtom.schema>;
@@ -1,11 +1,3 @@
1
- import { type UseActionReturn, useAction } from "@alepha/react";
2
- import { type FormModel, useFormState } from "@alepha/react/form";
3
- import {
4
- type RouterGoOptions,
5
- type UseActiveOptions,
6
- useActive,
7
- useRouter,
8
- } from "@alepha/react/router";
9
1
  import {
10
2
  Anchor,
11
3
  type AnchorProps,
@@ -23,6 +15,14 @@ import {
23
15
  useMantineTheme,
24
16
  } from "@mantine/core";
25
17
  import { IconCheck, IconChevronRight } from "@tabler/icons-react";
18
+ import { type UseActionReturn, useAction } from "alepha/react";
19
+ import { type FormModel, useFormState } from "alepha/react/form";
20
+ import {
21
+ type RouterPushOptions,
22
+ type UseActiveOptions,
23
+ useActive,
24
+ useRouter,
25
+ } from "alepha/react/router";
26
26
  import {
27
27
  type ButtonHTMLAttributes,
28
28
  Children,
@@ -287,7 +287,7 @@ const ActionButton = (_props: ActionProps) => {
287
287
 
288
288
  if (!props.children) {
289
289
  restProps.children = Children.only(icon);
290
- restProps.px ??= "xs";
290
+ restProps.px ??= "xs"; // TODO: change based on props.size ?
291
291
  } else {
292
292
  restProps.leftSection = icon;
293
293
  }
@@ -551,7 +551,7 @@ const ActionClickButton = (props: ActionClickButtonProps) => {
551
551
  export interface ActionNavigationButtonProps extends ButtonProps {
552
552
  href: string;
553
553
  active?: Partial<UseActiveOptions> | false;
554
- routerGoOptions?: RouterGoOptions;
554
+ routerGoOptions?: RouterPushOptions;
555
555
  classNameActive?: string;
556
556
  variantActive?: ButtonProps["variant"];
557
557
  target?: string;