@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,17 @@
1
- import { Divider, Flex, type FlexProps } from "@mantine/core";
2
- import type { ReactNode } from "react";
1
+ import {
2
+ Anchor,
3
+ Container,
4
+ type ContainerProps,
5
+ Divider,
6
+ Flex,
7
+ type FlexProps,
8
+ Image,
9
+ Text,
10
+ } from "@mantine/core";
11
+ import { IconArrowLeft } from "@tabler/icons-react";
12
+ import { Link, useRouter } from "alepha/react/router";
13
+ import type { ComponentType, ReactNode } from "react";
14
+ import ActionButton from "../buttons/ActionButton.tsx";
3
15
  import BurgerButton from "../buttons/BurgerButton.tsx";
4
16
  import DarkModeButton, {
5
17
  type DarkModeButtonProps,
@@ -18,55 +30,146 @@ export type AppBarItem =
18
30
  | AppBarSearch
19
31
  | AppBarLang
20
32
  | AppBarSpacer
21
- | AppBarDivider;
33
+ | AppBarDivider
34
+ | AppBarLogo
35
+ | AppBarBack;
22
36
 
23
- export interface AppBarElement {
37
+ export interface AppBarAbstractItem {
24
38
  position: "left" | "center" | "right";
39
+
40
+ /**
41
+ * Visibility control: return true to show, false to hide.
42
+ */
43
+ can?: () => boolean;
44
+ }
45
+
46
+ export interface AppBarElement extends AppBarAbstractItem {
25
47
  element: ReactNode;
26
48
  }
27
49
 
28
- export interface AppBarBurger {
29
- position: "left" | "center" | "right";
50
+ export interface AppBarBurger extends AppBarAbstractItem {
30
51
  type: "burger";
31
52
  }
32
53
 
33
- export interface AppBarDark {
34
- position: "left" | "center" | "right";
54
+ export interface AppBarDark extends AppBarAbstractItem {
35
55
  type: "dark";
36
56
  props?: DarkModeButtonProps;
37
57
  }
38
58
 
39
- export interface AppBarSearch {
40
- position: "left" | "center" | "right";
59
+ export interface AppBarSearch extends AppBarAbstractItem {
41
60
  type: "search";
42
61
  props?: OmnibarButtonProps;
43
62
  }
44
63
 
45
- export interface AppBarLang {
46
- position: "left" | "center" | "right";
64
+ export interface AppBarLang extends AppBarAbstractItem {
47
65
  type: "lang";
48
66
  props?: LanguageButtonProps;
49
67
  }
50
68
 
51
- export interface AppBarSpacer {
52
- position: "left" | "center" | "right";
69
+ export interface AppBarSpacer extends AppBarAbstractItem {
53
70
  type: "spacer";
54
71
  }
55
72
 
56
- export interface AppBarDivider {
57
- position: "left" | "center" | "right";
73
+ export interface AppBarDivider extends AppBarAbstractItem {
58
74
  type: "divider";
59
75
  }
60
76
 
77
+ export interface AppBarLogo extends AppBarAbstractItem {
78
+ type: "logo";
79
+ props?: {
80
+ /**
81
+ * Logo image source URL.
82
+ */
83
+ src?: string;
84
+
85
+ /**
86
+ * Logo text (used if no src provided).
87
+ */
88
+ text?: string;
89
+
90
+ /**
91
+ * Icon component (used if no src or text provided).
92
+ */
93
+ icon?: ReactNode | ComponentType;
94
+
95
+ /**
96
+ * Link href when logo is clicked.
97
+ */
98
+ href?: string;
99
+
100
+ /**
101
+ * Logo image height in pixels.
102
+ * @default 32
103
+ */
104
+ height?: number;
105
+
106
+ /**
107
+ * Logo image width in pixels.
108
+ */
109
+ width?: number;
110
+
111
+ /**
112
+ * Font weight for text logo.
113
+ * @default 700
114
+ */
115
+ fontWeight?: number;
116
+
117
+ /**
118
+ * Font size for text logo.
119
+ * @default "lg"
120
+ */
121
+ fontSize?: string;
122
+ };
123
+ }
124
+
125
+ export interface AppBarBack extends AppBarAbstractItem {
126
+ type: "back";
127
+ props?: {
128
+ /**
129
+ * Custom label for back button.
130
+ * @default "Back"
131
+ */
132
+ label?: string;
133
+
134
+ /**
135
+ * Show only icon without label.
136
+ * @default true
137
+ */
138
+ iconOnly?: boolean;
139
+
140
+ /**
141
+ * Custom href to navigate to instead of history back.
142
+ */
143
+ href?: string;
144
+
145
+ /**
146
+ * Custom icon component.
147
+ */
148
+ icon?: ReactNode | ComponentType;
149
+ };
150
+ }
151
+
61
152
  export interface AppBarProps {
62
153
  flexProps?: FlexProps;
63
154
  items?: AppBarItem[];
155
+
156
+ /**
157
+ * Wrap the AppBar content in a Mantine Container.
158
+ * Pass `true` for default Container, or ContainerProps to customize.
159
+ */
160
+ container?: boolean | ContainerProps;
64
161
  }
65
162
 
66
163
  const AppBar = (props: AppBarProps) => {
67
164
  const { items = [] } = props;
165
+ const router = useRouter();
68
166
 
69
167
  const renderItem = (item: AppBarItem, index: number) => {
168
+ // Check visibility control
169
+ if (item.can && !item.can()) {
170
+ return null;
171
+ }
172
+
70
173
  if ("type" in item) {
71
174
  if (item.type === "burger") {
72
175
  return <BurgerButton key={index} />;
@@ -86,6 +189,12 @@ const AppBar = (props: AppBarProps) => {
86
189
  if (item.type === "divider") {
87
190
  return <Divider key={index} orientation="vertical" />;
88
191
  }
192
+ if (item.type === "logo") {
193
+ return renderLogo(item, index);
194
+ }
195
+ if (item.type === "back") {
196
+ return renderBack(item, index);
197
+ }
89
198
  }
90
199
  if ("element" in item) {
91
200
  return item.element;
@@ -93,15 +202,111 @@ const AppBar = (props: AppBarProps) => {
93
202
  return null;
94
203
  };
95
204
 
205
+ const renderLogo = (item: AppBarLogo, index: number) => {
206
+ const {
207
+ src,
208
+ text,
209
+ icon,
210
+ href,
211
+ height = 32,
212
+ width,
213
+ fontWeight = 700,
214
+ fontSize = "lg",
215
+ } = item.props ?? {};
216
+
217
+ const logoContent = src ? (
218
+ <Image src={src} h={height} w={width} fit="contain" />
219
+ ) : icon ? (
220
+ typeof icon === "function" ? (
221
+ (() => {
222
+ const IconComponent = icon;
223
+ return <IconComponent />;
224
+ })()
225
+ ) : (
226
+ icon
227
+ )
228
+ ) : text ? (
229
+ <Text fw={fontWeight} size={fontSize}>
230
+ {text}
231
+ </Text>
232
+ ) : null;
233
+
234
+ if (href) {
235
+ return (
236
+ <Anchor
237
+ component={Link}
238
+ key={index}
239
+ href={href}
240
+ underline="never"
241
+ c="inherit"
242
+ >
243
+ {logoContent}
244
+ </Anchor>
245
+ );
246
+ }
247
+
248
+ return <Flex key={index}>{logoContent}</Flex>;
249
+ };
250
+
251
+ const renderBack = (item: AppBarBack, index: number) => {
252
+ const { label = "Back", iconOnly = true, href, icon } = item.props ?? {};
253
+
254
+ const renderIcon = () => {
255
+ if (!icon) {
256
+ return <IconArrowLeft size={18} />;
257
+ }
258
+ if (typeof icon === "function") {
259
+ const IconComponent = icon as ComponentType<{ size?: number }>;
260
+ return <IconComponent size={18} />;
261
+ }
262
+ return icon;
263
+ };
264
+
265
+ const iconElement = renderIcon();
266
+
267
+ const handleClick = () => {
268
+ if (href) {
269
+ router.push(href);
270
+ } else {
271
+ router.back();
272
+ }
273
+ };
274
+
275
+ if (iconOnly) {
276
+ return (
277
+ <ActionButton
278
+ key={index}
279
+ icon={iconElement}
280
+ variant="subtle"
281
+ color="gray"
282
+ onClick={handleClick}
283
+ tooltip={{ label, position: "bottom" }}
284
+ />
285
+ );
286
+ }
287
+
288
+ return (
289
+ <ActionButton
290
+ key={index}
291
+ leftSection={iconElement}
292
+ variant="subtle"
293
+ color="gray"
294
+ onClick={handleClick}
295
+ >
296
+ {label}
297
+ </ActionButton>
298
+ );
299
+ };
300
+
96
301
  const leftItems = items.filter((item) => item.position === "left");
97
302
  const centerItems = items.filter((item) => item.position === "center");
98
303
  const rightItems = items.filter((item) => item.position === "right");
99
304
 
100
- return (
305
+ const content = (
101
306
  <Flex
102
307
  h="100%"
103
308
  align="center"
104
- px="md"
309
+ px={props.container ? 0 : "md"}
105
310
  justify="space-between"
106
311
  {...props.flexProps}
107
312
  >
@@ -128,6 +333,18 @@ const AppBar = (props: AppBarProps) => {
128
333
  </Flex>
129
334
  </Flex>
130
335
  );
336
+
337
+ if (props.container) {
338
+ const containerProps =
339
+ typeof props.container === "boolean" ? {} : props.container;
340
+ return (
341
+ <Container h="100%" {...containerProps}>
342
+ {content}
343
+ </Container>
344
+ );
345
+ }
346
+
347
+ return content;
131
348
  };
132
349
 
133
350
  export default AppBar;
@@ -1,7 +1,7 @@
1
- import { useStore } from "@alepha/react";
2
- import { useRouter } from "@alepha/react/router";
3
1
  import { Spotlight, type SpotlightActionData } from "@mantine/spotlight";
4
2
  import { IconSearch } from "@tabler/icons-react";
3
+ import { useStore } from "alepha/react";
4
+ import { useRouter } from "alepha/react/router";
5
5
  import { type ReactNode, useMemo } from "react";
6
6
  import { ui } from "../../constants/ui.ts";
7
7
  import { renderIcon } from "../../helpers/renderIcon.tsx";
@@ -35,9 +35,9 @@ const Omnibar = (props: OmnibarProps) => {
35
35
  description: page.description,
36
36
  onClick: () => {
37
37
  if (page.staticName) {
38
- return router.go(page.staticName, { params: page.params });
38
+ return router.push(page.staticName, { params: page.params });
39
39
  }
40
- return router.go(page.name);
40
+ return router.push(page.name);
41
41
  },
42
42
  leftSection: renderIcon(page.icon),
43
43
  })),
@@ -1,5 +1,3 @@
1
- import { useEvents } from "@alepha/react";
2
- import { useRouter } from "@alepha/react/router";
3
1
  import {
4
2
  Flex,
5
3
  type FlexProps,
@@ -11,6 +9,8 @@ import {
11
9
  IconChevronRight,
12
10
  IconSquareRounded,
13
11
  } from "@tabler/icons-react";
12
+ import { useEvents } from "alepha/react";
13
+ import { useRouter } from "alepha/react/router";
14
14
  import {
15
15
  type ComponentType,
16
16
  type ReactNode,
@@ -49,44 +49,51 @@ export const Sidebar = (props: SidebarProps) => {
49
49
  const router = useRouter();
50
50
  const { onItemClick } = props;
51
51
 
52
+ const divider = (key: string | number) => {
53
+ return (
54
+ <Flex
55
+ key={key}
56
+ h={1}
57
+ bg={"var(--alepha-border)"}
58
+ my={"xs"}
59
+ mx={props.collapsed ? 0 : "sm"}
60
+ />
61
+ );
62
+ };
63
+
52
64
  const renderNode = (item: SidebarNode, key: number) => {
53
65
  if ("type" in item) {
66
+ // Hide spacers when collapsed
54
67
  if (item.type === "spacer") {
68
+ if (props.collapsed) return null;
55
69
  return <Flex key={key} h={16} />;
56
70
  }
57
71
 
58
72
  if (item.type === "divider") {
59
- return (
60
- <Flex
61
- key={key}
62
- h={1}
63
- bg={"var(--alepha-border)"}
64
- my={"md"}
65
- mx={"sm"}
66
- />
67
- );
73
+ return divider(key);
68
74
  }
69
75
 
70
76
  if (item.type === "search") {
71
- return <OmnibarButton collapsed={props.collapsed} key={key} />;
77
+ return (
78
+ <Flex key={key} mb="xs">
79
+ <OmnibarButton collapsed={props.collapsed} />
80
+ </Flex>
81
+ );
72
82
  }
73
83
 
74
84
  if (item.type === "toggle") {
75
85
  return <ToggleSidebarButton key={key} />;
76
86
  }
77
87
 
88
+ // Replace sections with dividers when collapsed
78
89
  if (item.type === "section") {
79
- if (props.collapsed) return;
90
+ if (props.collapsed) {
91
+ return divider(key);
92
+ }
80
93
  return (
81
- <Flex key={key} mt={"md"} mb={"xs"} align={"center"} gap={"xs"}>
94
+ <Flex key={key} mt={"md"} align={"center"} gap={"xs"}>
82
95
  {renderIcon(item.icon)}
83
- <Text
84
- key={key}
85
- size={"xs"}
86
- c={"dimmed"}
87
- tt={"uppercase"}
88
- fw={"bold"}
89
- >
96
+ <Text size={"xs"} c={"dimmed"} tt={"uppercase"} fw={"bold"}>
90
97
  {item.label}
91
98
  </Text>
92
99
  </Flex>
@@ -150,15 +157,18 @@ export const Sidebar = (props: SidebarProps) => {
150
157
  };
151
158
 
152
159
  const padding = "md";
153
- const gap = props.items ? props.gap : "xs";
154
- const menu = useMemo(() => getSidebarNodes(), []);
160
+ const gap = props.items ? (props.gap ?? 2) : "xs";
161
+ const menu = useMemo(
162
+ () => getSidebarNodes(),
163
+ [props.items, props.autoPopulateMenu],
164
+ );
155
165
 
156
166
  return (
157
167
  <Flex
158
168
  flex={1}
159
169
  py={padding}
160
170
  direction={"column"}
161
- className={"overflow-auto"}
171
+ className="alepha-sidebar-scroll"
162
172
  {...props.flexProps}
163
173
  >
164
174
  <Flex gap={gap} px={padding} direction={"column"}>
@@ -171,7 +181,7 @@ export const Sidebar = (props: SidebarProps) => {
171
181
  px={padding}
172
182
  direction={"column"}
173
183
  flex={1}
174
- className={"overflow-auto"}
184
+ className="alepha-sidebar-scroll"
175
185
  >
176
186
  {menu
177
187
  .filter((it) => !it.position)
@@ -255,6 +265,7 @@ export const SidebarItem = (props: SidebarItemProps) => {
255
265
  props.theme.button?.size ??
256
266
  (level === 0 ? "sm" : "xs")
257
267
  }
268
+ tooltip={item.description}
258
269
  c={"var(--mantine-color-text)"}
259
270
  color={"gray"}
260
271
  variant={"subtle"}
@@ -266,11 +277,6 @@ export const SidebarItem = (props: SidebarItemProps) => {
266
277
  {renderIcon(item.icon)}
267
278
  <Flex direction={"column"}>
268
279
  <Flex>{item.label}</Flex>
269
- {item.description && (
270
- <Text size={"xs"} c={"dimmed"}>
271
- {item.description}
272
- </Text>
273
- )}
274
280
  </Flex>
275
281
  </Flex>
276
282
  }
@@ -332,34 +338,9 @@ export interface SidebarItemProps {
332
338
  const SidebarCollapsedItem = (props: SidebarItemProps) => {
333
339
  const { item, level } = props;
334
340
 
335
- const router = useRouter();
336
- const isActive = useCallback((item: SidebarMenuItem): boolean => {
337
- if (!item.children) return false;
338
- for (const child of item.children) {
339
- if (child.href) {
340
- if (router.isActive(child.href)) {
341
- return true;
342
- }
343
- }
344
- if (isActive(child)) {
345
- return true;
346
- }
347
- }
348
- return false;
349
- }, []);
350
-
351
- const [isOpen, setIsOpen] = useState<boolean>(isActive(item));
352
-
353
- const handleItemClick = (e: MouseEvent) => {
354
- if (!props.item.target) {
355
- e.preventDefault();
356
- }
357
- if (item.children && item.children.length > 0) {
358
- setIsOpen(!isOpen);
359
- } else {
360
- props.onItemClick?.(item);
361
- item.onClick?.();
362
- }
341
+ const handleItemClick = () => {
342
+ props.onItemClick?.(item);
343
+ item.onClick?.();
363
344
  };
364
345
 
365
346
  return (
@@ -371,35 +352,15 @@ const SidebarCollapsedItem = (props: SidebarItemProps) => {
371
352
  }
372
353
  variant={"subtle"}
373
354
  variantActive={"default"}
374
- tooltip={
375
- item.children
376
- ? undefined
377
- : {
378
- label: item.label,
379
- position: "right",
380
- }
381
- }
355
+ tooltip={{
356
+ label: item.label,
357
+ position: "right",
358
+ }}
382
359
  radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
383
360
  onClick={handleItemClick}
384
361
  icon={renderIcon(item.icon) ?? <IconSquareRounded />}
385
362
  href={props.item.href as any}
386
363
  target={props.item.target}
387
- menu={
388
- item.children
389
- ? ({
390
- position: "right",
391
- on: "hover",
392
- items: item.children
393
- .filter((child) => !child.can || child.can())
394
- .map((child) => ({
395
- label: child.label,
396
- href: child.href,
397
- icon: renderIcon(child.icon),
398
- children: child.children?.filter((c) => !c.can || c.can()),
399
- })),
400
- } as any)
401
- : undefined
402
- }
403
364
  {...props.item.actionProps}
404
365
  />
405
366
  );
@@ -1,5 +1,3 @@
1
- import { useInject } from "@alepha/react";
2
- import { type FormModel, useForm } from "@alepha/react/form";
3
1
  import { Checkbox, Flex, Table, Text, UnstyledButton } from "@mantine/core";
4
2
  import { useDebouncedCallback } from "@mantine/hooks";
5
3
  import {
@@ -9,6 +7,8 @@ import {
9
7
  } from "@tabler/icons-react";
10
8
  import { Alepha, type Static, type TObject, t } from "alepha";
11
9
  import { DateTimeProvider } from "alepha/datetime";
10
+ import { useInject } from "alepha/react";
11
+ import { type FormModel, useForm } from "alepha/react/form";
12
12
  import { useCallback, useEffect, useMemo, useState } from "react";
13
13
  import { ui } from "../../constants/ui.ts";
14
14
  import DataTableFilters, {
@@ -1,6 +1,6 @@
1
- import type { FormModel } from "@alepha/react/form";
2
1
  import { Flex } from "@mantine/core";
3
2
  import { type TObject, t } from "alepha";
3
+ import type { FormModel } from "alepha/react/form";
4
4
  import { useMemo } from "react";
5
5
  import { ui } from "../../constants/ui.ts";
6
6
  import TypeForm, { type TypeFormProps } from "../form/TypeForm.tsx";
@@ -1,4 +1,3 @@
1
- import type { FormModel } from "@alepha/react/form";
2
1
  import type { TableProps, TableTrProps } from "@mantine/core";
3
2
  import type {
4
3
  Alepha,
@@ -9,6 +8,7 @@ import type {
9
8
  TObject,
10
9
  } from "alepha";
11
10
  import type { DurationLike } from "alepha/datetime";
11
+ import type { FormModel } from "alepha/react/form";
12
12
  import type { ReactNode } from "react";
13
13
  import type { ActionProps } from "../buttons/ActionButton.tsx";
14
14
  import type { TypeFormProps } from "../form/TypeForm.tsx";
@@ -1,4 +1,4 @@
1
- import { useInject } from "@alepha/react";
1
+ import { useInject } from "alepha/react";
2
2
  import { DialogService } from "../services/DialogService.tsx";
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { useInject, useStore } from "@alepha/react";
1
+ import { useInject, useStore } from "alepha/react";
2
2
  import {
3
3
  alephaThemeAtom,
4
4
  type CurrentAlephaTheme,
@@ -1,4 +1,4 @@
1
- import { useInject } from "@alepha/react";
1
+ import { useInject } from "alepha/react";
2
2
  import { ToastService } from "../services/ToastService.tsx";
3
3
 
4
4
  /**