@alepha/ui 0.15.0 → 0.15.2
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.
- package/dist/admin/AdminAudits-BlGGKLof.js +3 -0
- package/dist/admin/{AdminAudits-DIrCCPk3.js → AdminAudits-C0DPYw0W.js} +4 -4
- package/dist/admin/AdminAudits-C0DPYw0W.js.map +1 -0
- package/dist/admin/AdminFiles-Bg9feLFH.js +3 -0
- package/dist/admin/{AdminFiles-RsL178Ta.js → AdminFiles-Cu8GHgQ3.js} +5 -5
- package/dist/admin/AdminFiles-Cu8GHgQ3.js.map +1 -0
- package/dist/admin/AdminLayout-BfeFXiul.js +3 -0
- package/dist/admin/{AdminLayout-XiSivwWH.js → AdminLayout-QJLIesuG.js} +1 -1
- package/dist/admin/{AdminLayout-XiSivwWH.js.map → AdminLayout-QJLIesuG.js.map} +1 -1
- package/dist/admin/{AdminNotifications-cIbywWKi.js → AdminNotifications-CgYkBuG_.js} +5 -5
- package/dist/admin/AdminNotifications-CgYkBuG_.js.map +1 -0
- package/dist/admin/AdminNotifications-DmfGPqHe.js +3 -0
- package/dist/admin/{AdminParameters-BKObzzpN.js → AdminParameters-Cl-R0nXt.js} +1 -1
- package/dist/admin/{AdminParameters-D-q3Qmhv.js → AdminParameters-hjNG_KXb.js} +4 -4
- package/dist/admin/AdminParameters-hjNG_KXb.js.map +1 -0
- package/dist/admin/{AdminSessions-vOgkrQ2U.js → AdminSessions-Bey9cuy1.js} +6 -6
- package/dist/admin/AdminSessions-Bey9cuy1.js.map +1 -0
- package/dist/admin/AdminSessions-Cn4_jB04.js +3 -0
- package/dist/admin/{AdminUserAudits-CSsN1fIC.js → AdminUserAudits-C7AN9jx7.js} +4 -4
- package/dist/admin/AdminUserAudits-C7AN9jx7.js.map +1 -0
- package/dist/admin/{AdminUserAudits-DmAnivo3.js → AdminUserAudits-Cp_ERd2g.js} +1 -1
- package/dist/admin/{AdminUserCreate-DpA13zwj.js → AdminUserCreate-Chr-7hLk.js} +1 -1
- package/dist/admin/{AdminUserCreate-B72nu-3W.js → AdminUserCreate-DiXi1EWB.js} +4 -4
- package/dist/admin/AdminUserCreate-DiXi1EWB.js.map +1 -0
- package/dist/admin/{AdminUserDetails-Zib_B6Al.js → AdminUserDetails-Dcn3OwMC.js} +1 -1
- package/dist/admin/{AdminUserDetails-CKM2IEMr.js → AdminUserDetails-yM4x8JE6.js} +5 -5
- package/dist/admin/AdminUserDetails-yM4x8JE6.js.map +1 -0
- package/dist/admin/{AdminUserLayout-BNBOEiAO.js → AdminUserLayout-CfeQHH6e.js} +1 -1
- package/dist/admin/{AdminUserLayout-D7En9UBq.js → AdminUserLayout-D9bqGt6T.js} +3 -3
- package/dist/admin/AdminUserLayout-D9bqGt6T.js.map +1 -0
- package/dist/admin/{AdminUserSessions-DEaGu6n6.js → AdminUserSessions-kmkXG-xf.js} +4 -4
- package/dist/admin/AdminUserSessions-kmkXG-xf.js.map +1 -0
- package/dist/admin/AdminUserSessions-rvA0ztxn.js +3 -0
- package/dist/admin/{AdminUserSettings-Di73D7g2.js → AdminUserSettings-BnzRAcqV.js} +4 -4
- package/dist/admin/AdminUserSettings-BnzRAcqV.js.map +1 -0
- package/dist/admin/AdminUserSettings-CXs-jtRv.js +3 -0
- package/dist/admin/{AdminUsers-BnGIRvmV.js → AdminUsers-CYkcUWCg.js} +6 -6
- package/dist/admin/AdminUsers-CYkcUWCg.js.map +1 -0
- package/dist/admin/AdminUsers-DdFXzrEn.js +3 -0
- package/dist/admin/index.d.ts +33 -18
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +48 -33
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{AuthLayout-B1sUB8fB.js → AuthLayout-Dj5K4SIN.js} +2 -2
- package/dist/auth/AuthLayout-Dj5K4SIN.js.map +1 -0
- package/dist/{demo/IconGoogle-DvmFiEDB.js → auth/IconGoogle-DpSlPZ1u.js} +1 -1
- package/dist/auth/{IconGoogle-Cm5d8J3f.js.map → IconGoogle-DpSlPZ1u.js.map} +1 -1
- package/dist/auth/{Login-Cjxv3EDi.js → Login-BAFVcX_J.js} +6 -6
- package/dist/auth/Login-BAFVcX_J.js.map +1 -0
- package/dist/auth/Login-C5PUsp8I.js +4 -0
- package/dist/auth/{Register-CGlbQ50l.js → Register-CZRXEcWy.js} +7 -7
- package/dist/auth/Register-CZRXEcWy.js.map +1 -0
- package/dist/auth/Register-DMTs5ep_.js +4 -0
- package/dist/auth/ResetPassword-D-mhMtmx.js +3 -0
- package/dist/auth/{ResetPassword-DvqD_1SJ.js → ResetPassword-DTYNsBIj.js} +5 -5
- package/dist/auth/ResetPassword-DTYNsBIj.js.map +1 -0
- package/dist/auth/VerifyEmail-BsrCmncc.js +3 -0
- package/dist/auth/{VerifyEmail-VaBruOnO.js → VerifyEmail-DolENWGn.js} +4 -4
- package/dist/auth/VerifyEmail-DolENWGn.js.map +1 -0
- package/dist/auth/index.d.ts +34 -23
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +25 -14
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +272 -209
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +314 -99
- package/dist/core/index.js.map +1 -1
- package/dist/demo/{DemoDataTable-2mzzf__a.js → DemoDataTable-CguplbR7.js} +2 -2
- package/dist/demo/{DemoDataTable-2mzzf__a.js.map → DemoDataTable-CguplbR7.js.map} +1 -1
- package/dist/demo/{DemoHome-CnuL5WV9.js → DemoHome-Cce2bWmg.js} +1 -1
- package/dist/demo/{DemoHome-CnuL5WV9.js.map → DemoHome-Cce2bWmg.js.map} +1 -1
- package/dist/demo/DemoHome-DC9qkMNe.js +3 -0
- package/dist/demo/DemoJsonViewer-DIssGVlJ.js +4 -0
- package/dist/demo/{DemoJsonViewer-NUGst5wW.js → DemoJsonViewer-Dgdk3Txb.js} +3 -3
- package/dist/demo/{DemoJsonViewer-NUGst5wW.js.map → DemoJsonViewer-Dgdk3Txb.js.map} +1 -1
- package/dist/demo/{DemoLayout-dvbeuBBf.js → DemoLayout-B20TEuhV.js} +2 -2
- package/dist/demo/DemoLayout-B20TEuhV.js.map +1 -0
- package/dist/demo/DemoLayout-DSRyf4qJ.js +3 -0
- package/dist/demo/{DemoLogin-DvltFTER.js → DemoLogin-mtkN6340.js} +7 -7
- package/dist/demo/DemoLogin-mtkN6340.js.map +1 -0
- package/dist/demo/{DemoRegister-Vu6ZPWib.js → DemoRegister-C0MW7anp.js} +8 -8
- package/dist/demo/DemoRegister-C0MW7anp.js.map +1 -0
- package/dist/demo/{DemoResetPassword-BFwmqwec.js → DemoResetPassword-CPTy88iK.js} +6 -6
- package/dist/demo/DemoResetPassword-CPTy88iK.js.map +1 -0
- package/dist/demo/{DemoSidebar-DWnjYHoP.js → DemoSidebar-MVmQKfMt.js} +2 -2
- package/dist/demo/{DemoSidebar-DWnjYHoP.js.map → DemoSidebar-MVmQKfMt.js.map} +1 -1
- package/dist/demo/{DemoTypeForm-P5_VInW2.js → DemoTypeForm-w-qtfRlC.js} +3 -3
- package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +1 -0
- package/dist/demo/{DemoVerifyEmail-C_ooC5u8.js → DemoVerifyEmail-C8FFJT5A.js} +5 -5
- package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +1 -0
- package/dist/{auth/IconGoogle-Cm5d8J3f.js → demo/IconGoogle-CbBF8Hqq.js} +1 -1
- package/dist/demo/{IconGoogle-DvmFiEDB.js.map → IconGoogle-CbBF8Hqq.js.map} +1 -1
- package/dist/demo/{Showcase-vemLuO2t.js → Showcase-CQrMWars.js} +4 -4
- package/dist/demo/Showcase-CQrMWars.js.map +1 -0
- package/dist/demo/index.d.ts +37 -27
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +26 -16
- package/dist/demo/index.js.map +1 -1
- package/dist/json/index.d.ts +17 -17
- package/dist/json/index.d.ts.map +1 -1
- package/package.json +13 -14
- package/src/admin/AdminRouter.ts +2 -2
- package/src/admin/MainRouter.ts +1 -1
- package/src/admin/components/audits/AdminAudits.tsx +3 -3
- package/src/admin/components/files/AdminFiles.tsx +2 -2
- package/src/admin/components/jobs/AdminJobs.tsx +2 -2
- package/src/admin/components/notifications/AdminNotifications.tsx +2 -2
- package/src/admin/components/parameters/AdminParameters.tsx +1 -1
- package/src/admin/components/parameters/ParameterDetails.tsx +2 -2
- package/src/admin/components/parameters/ParameterHistory.tsx +1 -1
- package/src/admin/components/parameters/types.ts +9 -3
- package/src/admin/components/sessions/AdminSessions.tsx +3 -3
- package/src/admin/components/shared/AdminResourceHeader.tsx +1 -1
- package/src/admin/components/shared/AdminResourceTabs.tsx +1 -1
- package/src/admin/components/users/AdminUserAudits.tsx +3 -3
- package/src/admin/components/users/AdminUserCreate.tsx +3 -3
- package/src/admin/components/users/AdminUserDetails.tsx +4 -4
- package/src/admin/components/users/AdminUserLayout.tsx +2 -2
- package/src/admin/components/users/AdminUserSessions.tsx +3 -3
- package/src/admin/components/users/AdminUserSettings.tsx +3 -3
- package/src/admin/components/users/AdminUsers.tsx +3 -3
- package/src/admin/index.ts +16 -1
- package/src/auth/AuthI18n.ts +1 -1
- package/src/auth/AuthRouter.ts +2 -2
- package/src/auth/components/AuthLayout.tsx +1 -1
- package/src/auth/components/Login.tsx +4 -4
- package/src/auth/components/Register.tsx +5 -5
- package/src/auth/components/ResetPassword.tsx +4 -4
- package/src/auth/components/VerifyEmail.tsx +3 -3
- package/src/auth/components/buttons/UserButton.tsx +2 -2
- package/src/auth/index.ts +14 -3
- package/src/core/RootRouter.ts +1 -1
- package/src/core/atoms/alephaSidebarAtom.ts +57 -0
- package/src/core/components/buttons/ActionButton.tsx +9 -9
- package/src/core/components/buttons/BurgerButton.tsx +5 -4
- package/src/core/components/buttons/LanguageButton.tsx +1 -1
- package/src/core/components/buttons/OmnibarButton.tsx +20 -1
- package/src/core/components/buttons/ThemeButton.tsx +1 -1
- package/src/core/components/buttons/ToggleSidebarButton.tsx +33 -23
- package/src/core/components/form/Control.tsx +1 -1
- package/src/core/components/form/ControlArray.tsx +2 -2
- package/src/core/components/form/ControlDate.tsx +1 -1
- package/src/core/components/form/ControlNumber.tsx +2 -2
- package/src/core/components/form/ControlObject.tsx +1 -1
- package/src/core/components/form/ControlQueryBuilder.tsx +1 -1
- package/src/core/components/form/ControlSelect.tsx +1 -1
- package/src/core/components/form/TypeForm.tsx +2 -2
- package/src/core/components/layout/AdminShell.tsx +205 -27
- package/src/core/components/layout/AlephaMantineProvider.tsx +3 -3
- package/src/core/components/layout/Omnibar.tsx +2 -2
- package/src/core/components/layout/Sidebar.tsx +42 -77
- package/src/core/components/table/DataTable.tsx +2 -2
- package/src/core/components/table/DataTableFilters.tsx +1 -1
- package/src/core/components/table/types.ts +1 -1
- package/src/core/hooks/useDialog.ts +1 -1
- package/src/core/hooks/useTheme.ts +1 -1
- package/src/core/hooks/useToast.ts +1 -1
- package/src/core/index.ts +57 -6
- package/src/core/providers/ThemeProvider.ts +1 -1
- package/src/core/styles.css +58 -0
- package/src/core/utils/parseInput.ts +1 -1
- package/src/demo/DemoRouter.ts +1 -1
- package/src/demo/components/DemoLayout.tsx +1 -1
- package/src/demo/components/core/DemoTypeForm.tsx +1 -1
- package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
- package/src/demo/components/shared/Showcase.tsx +1 -1
- package/src/demo/index.ts +11 -1
- package/src/json/index.ts +13 -0
- package/dist/admin/AdminAudits-B3EhKhN7.js +0 -3
- package/dist/admin/AdminAudits-DIrCCPk3.js.map +0 -1
- package/dist/admin/AdminFiles-C8OG4dtD.js +0 -3
- package/dist/admin/AdminFiles-RsL178Ta.js.map +0 -1
- package/dist/admin/AdminLayout-BnSmtA4x.js +0 -3
- package/dist/admin/AdminNotifications-BSL4B2fQ.js +0 -3
- package/dist/admin/AdminNotifications-cIbywWKi.js.map +0 -1
- package/dist/admin/AdminParameters-D-q3Qmhv.js.map +0 -1
- package/dist/admin/AdminSessions-DHG9zPfr.js +0 -3
- package/dist/admin/AdminSessions-vOgkrQ2U.js.map +0 -1
- package/dist/admin/AdminUserAudits-CSsN1fIC.js.map +0 -1
- package/dist/admin/AdminUserCreate-B72nu-3W.js.map +0 -1
- package/dist/admin/AdminUserDetails-CKM2IEMr.js.map +0 -1
- package/dist/admin/AdminUserLayout-D7En9UBq.js.map +0 -1
- package/dist/admin/AdminUserSessions-D9X2_HMA.js +0 -3
- package/dist/admin/AdminUserSessions-DEaGu6n6.js.map +0 -1
- package/dist/admin/AdminUserSettings-Di73D7g2.js.map +0 -1
- package/dist/admin/AdminUserSettings-yI-JECf5.js +0 -3
- package/dist/admin/AdminUsers-BnGIRvmV.js.map +0 -1
- package/dist/admin/AdminUsers-CG9-2Z8W.js +0 -3
- package/dist/auth/AuthLayout-B1sUB8fB.js.map +0 -1
- package/dist/auth/Login-BWi-pPbO.js +0 -4
- package/dist/auth/Login-Cjxv3EDi.js.map +0 -1
- package/dist/auth/Register-CGlbQ50l.js.map +0 -1
- package/dist/auth/Register-CWdkXWkc.js +0 -4
- package/dist/auth/ResetPassword-BUdM7T_R.js +0 -3
- package/dist/auth/ResetPassword-DvqD_1SJ.js.map +0 -1
- package/dist/auth/VerifyEmail-BYmtnkEl.js +0 -3
- package/dist/auth/VerifyEmail-VaBruOnO.js.map +0 -1
- package/dist/demo/DemoHome-D6Z7EE4V.js +0 -3
- package/dist/demo/DemoJsonViewer-CYUggLop.js +0 -4
- package/dist/demo/DemoLayout-ZFDzyvY3.js +0 -3
- package/dist/demo/DemoLayout-dvbeuBBf.js.map +0 -1
- package/dist/demo/DemoLogin-DvltFTER.js.map +0 -1
- package/dist/demo/DemoRegister-Vu6ZPWib.js.map +0 -1
- package/dist/demo/DemoResetPassword-BFwmqwec.js.map +0 -1
- package/dist/demo/DemoTypeForm-P5_VInW2.js.map +0 -1
- package/dist/demo/DemoVerifyEmail-C_ooC5u8.js.map +0 -1
- package/dist/demo/Showcase-vemLuO2t.js.map +0 -1
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useEvents } from "@alepha/react";
|
|
2
1
|
import {
|
|
3
2
|
ActionIcon,
|
|
4
3
|
Badge,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
import { IconFilter, IconInfoTriangle, IconX } from "@tabler/icons-react";
|
|
15
14
|
import type { TObject } from "alepha";
|
|
16
15
|
import { parseQueryString } from "alepha/orm";
|
|
16
|
+
import { useEvents } from "alepha/react";
|
|
17
17
|
import { useRef, useState } from "react";
|
|
18
18
|
import { ui } from "../../constants/ui.ts";
|
|
19
19
|
import {
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useFormState } from "@alepha/react/form";
|
|
2
1
|
import {
|
|
3
2
|
Autocomplete,
|
|
4
3
|
type AutocompleteProps,
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
TagsInput,
|
|
14
13
|
type TagsInputProps,
|
|
15
14
|
} from "@mantine/core";
|
|
15
|
+
import { useFormState } from "alepha/react/form";
|
|
16
16
|
import { useEffect, useState } from "react";
|
|
17
17
|
import {
|
|
18
18
|
type GenericControlProps,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { FormModel } from "@alepha/react/form";
|
|
2
1
|
import { Card, Flex, type FlexProps, Grid } from "@mantine/core";
|
|
3
2
|
import type { TObject } from "alepha";
|
|
3
|
+
import type { FormModel } from "alepha/react/form";
|
|
4
4
|
import type { ReactNode } from "react";
|
|
5
5
|
import ActionButton, {
|
|
6
6
|
type ActionSubmitButtonProps,
|
|
@@ -55,7 +55,7 @@ export interface TypeFormProps<T extends TObject> {
|
|
|
55
55
|
* @example
|
|
56
56
|
* ```tsx
|
|
57
57
|
* import { t } from "alepha";
|
|
58
|
-
* import { useForm } from "
|
|
58
|
+
* import { useForm } from "alepha/react/form";
|
|
59
59
|
* import { TypeForm } from "@alepha/ui";
|
|
60
60
|
*
|
|
61
61
|
* const form = useForm({
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { useEvents, useStore } from "@alepha/react";
|
|
2
|
-
import { NestedView, useRouter } from "@alepha/react/router";
|
|
3
1
|
import {
|
|
4
2
|
AppShell,
|
|
5
3
|
type AppShellFooterProps,
|
|
@@ -7,8 +5,18 @@ import {
|
|
|
7
5
|
type AppShellMainProps,
|
|
8
6
|
type AppShellNavbarProps,
|
|
9
7
|
type AppShellProps,
|
|
8
|
+
Flex,
|
|
10
9
|
} from "@mantine/core";
|
|
11
|
-
import {
|
|
10
|
+
import { useEvents, useStore } from "alepha/react";
|
|
11
|
+
import { NestedView, useRouter } from "alepha/react/router";
|
|
12
|
+
import {
|
|
13
|
+
type ReactNode,
|
|
14
|
+
useCallback,
|
|
15
|
+
useEffect,
|
|
16
|
+
useRef,
|
|
17
|
+
useState,
|
|
18
|
+
} from "react";
|
|
19
|
+
import { alephaSidebarAtom } from "../../atoms/alephaSidebarAtom.ts";
|
|
12
20
|
import { ui } from "../../constants/ui.ts";
|
|
13
21
|
import AppBar, { type AppBarProps } from "./AppBar.tsx";
|
|
14
22
|
import { Sidebar, type SidebarProps } from "./Sidebar.tsx";
|
|
@@ -25,6 +33,12 @@ export interface AdminShellProps {
|
|
|
25
33
|
footer?: ReactNode;
|
|
26
34
|
children?: ReactNode;
|
|
27
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Enable drag-to-resize for the sidebar.
|
|
38
|
+
* Width and constraints are configured in alephaSidebarAtom.
|
|
39
|
+
*/
|
|
40
|
+
resizable?: boolean;
|
|
41
|
+
|
|
28
42
|
noSidebarWhen?: {
|
|
29
43
|
/**
|
|
30
44
|
* Paths where the sidebar should be hidden.
|
|
@@ -33,28 +47,143 @@ export interface AdminShellProps {
|
|
|
33
47
|
};
|
|
34
48
|
}
|
|
35
49
|
|
|
36
|
-
declare module "alepha" {
|
|
37
|
-
interface State {
|
|
38
|
-
/**
|
|
39
|
-
* Whether the sidebar is opened or closed.
|
|
40
|
-
*/
|
|
41
|
-
"alepha.ui.sidebar.opened"?: boolean;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Whether the sidebar is collapsed (narrow) or expanded (wide).
|
|
45
|
-
*/
|
|
46
|
-
"alepha.ui.sidebar.collapsed"?: boolean;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
50
|
const AdminShell = (props: AdminShellProps) => {
|
|
51
51
|
const router = useRouter();
|
|
52
|
-
const [
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
|
|
53
|
+
const { opened, collapsed } = sidebar;
|
|
54
|
+
|
|
55
|
+
// Initialize collapsed state from props on mount
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
if (props.sidebarProps?.collapsed !== undefined) {
|
|
58
|
+
setSidebar({ ...sidebar, collapsed: props.sidebarProps.collapsed });
|
|
59
|
+
}
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
// Resize state
|
|
63
|
+
const [isResizing, setIsResizing] = useState(false);
|
|
64
|
+
const [isHovering, setIsHovering] = useState(false);
|
|
65
|
+
const [collapseEffect, setCollapseEffect] = useState({
|
|
66
|
+
offset: 0,
|
|
67
|
+
opacity: 1,
|
|
68
|
+
});
|
|
69
|
+
const resizeRef = useRef<{ startX: number; startWidth: number } | null>(null);
|
|
70
|
+
|
|
71
|
+
// Use atom values for constraints
|
|
72
|
+
const {
|
|
73
|
+
collapsedWidth,
|
|
74
|
+
collapseThreshold,
|
|
75
|
+
maxWidth,
|
|
76
|
+
hoverDelay,
|
|
77
|
+
defaultWidth,
|
|
78
|
+
} = sidebar;
|
|
79
|
+
|
|
80
|
+
const handleResizeStart = useCallback(
|
|
81
|
+
(e: React.MouseEvent) => {
|
|
82
|
+
if (!props.resizable) return;
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
|
|
85
|
+
// If collapsed and hovering, un-collapse first and start from defaultWidth
|
|
86
|
+
if (collapsed) {
|
|
87
|
+
setSidebar({ ...sidebar, collapsed: false, width: defaultWidth });
|
|
88
|
+
setIsResizing(true);
|
|
89
|
+
resizeRef.current = {
|
|
90
|
+
startX: e.clientX,
|
|
91
|
+
startWidth: defaultWidth,
|
|
92
|
+
};
|
|
93
|
+
} else {
|
|
94
|
+
setIsResizing(true);
|
|
95
|
+
resizeRef.current = {
|
|
96
|
+
startX: e.clientX,
|
|
97
|
+
startWidth: sidebar.width,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
[props.resizable, collapsed, sidebar, setSidebar, defaultWidth],
|
|
56
102
|
);
|
|
57
103
|
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!isResizing) return;
|
|
106
|
+
|
|
107
|
+
const handleMouseMove = (e: MouseEvent) => {
|
|
108
|
+
if (!resizeRef.current) return;
|
|
109
|
+
const delta = e.clientX - resizeRef.current.startX;
|
|
110
|
+
const rawWidth = resizeRef.current.startWidth + delta;
|
|
111
|
+
const newWidth = Math.min(Math.max(rawWidth, collapsedWidth), maxWidth);
|
|
112
|
+
|
|
113
|
+
// Visual effect when below collapse threshold
|
|
114
|
+
if (rawWidth < collapseThreshold) {
|
|
115
|
+
const progress = Math.max(
|
|
116
|
+
0,
|
|
117
|
+
(collapseThreshold - rawWidth) / collapseThreshold,
|
|
118
|
+
);
|
|
119
|
+
setCollapseEffect({
|
|
120
|
+
offset: -progress * collapsedWidth,
|
|
121
|
+
opacity: 1 - progress * 0.7,
|
|
122
|
+
});
|
|
123
|
+
setSidebar({ ...sidebar, width: collapseThreshold, collapsed: false });
|
|
124
|
+
} else {
|
|
125
|
+
setCollapseEffect({ offset: 0, opacity: 1 });
|
|
126
|
+
setSidebar({ ...sidebar, width: newWidth, collapsed: false });
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
const handleMouseUp = () => {
|
|
131
|
+
// If we released while in collapse zone, actually collapse
|
|
132
|
+
if (collapseEffect.offset < 0) {
|
|
133
|
+
setSidebar({ ...sidebar, collapsed: true });
|
|
134
|
+
}
|
|
135
|
+
setCollapseEffect({ offset: 0, opacity: 1 });
|
|
136
|
+
setIsResizing(false);
|
|
137
|
+
resizeRef.current = null;
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
document.addEventListener("mousemove", handleMouseMove);
|
|
141
|
+
document.addEventListener("mouseup", handleMouseUp);
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
document.removeEventListener("mousemove", handleMouseMove);
|
|
145
|
+
document.removeEventListener("mouseup", handleMouseUp);
|
|
146
|
+
};
|
|
147
|
+
}, [
|
|
148
|
+
isResizing,
|
|
149
|
+
sidebar,
|
|
150
|
+
setSidebar,
|
|
151
|
+
collapsedWidth,
|
|
152
|
+
maxWidth,
|
|
153
|
+
collapseThreshold,
|
|
154
|
+
collapseEffect.offset,
|
|
155
|
+
]);
|
|
156
|
+
|
|
157
|
+
// Hover to expand when collapsed (with delay)
|
|
158
|
+
const hoverTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
159
|
+
|
|
160
|
+
const handleNavbarMouseEnter = useCallback(() => {
|
|
161
|
+
if (collapsed) {
|
|
162
|
+
hoverTimeoutRef.current = setTimeout(() => {
|
|
163
|
+
setIsHovering(true);
|
|
164
|
+
}, hoverDelay);
|
|
165
|
+
}
|
|
166
|
+
}, [collapsed, hoverDelay]);
|
|
167
|
+
|
|
168
|
+
const handleNavbarMouseLeave = useCallback(() => {
|
|
169
|
+
if (hoverTimeoutRef.current) {
|
|
170
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
171
|
+
hoverTimeoutRef.current = null;
|
|
172
|
+
}
|
|
173
|
+
setIsHovering(false);
|
|
174
|
+
}, []);
|
|
175
|
+
|
|
176
|
+
// Reset hover state when collapsed changes (e.g., when toggle button is clicked)
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
if (collapsed) {
|
|
179
|
+
setIsHovering(false);
|
|
180
|
+
if (hoverTimeoutRef.current) {
|
|
181
|
+
clearTimeout(hoverTimeoutRef.current);
|
|
182
|
+
hoverTimeoutRef.current = null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}, [collapsed]);
|
|
186
|
+
|
|
58
187
|
const shouldShowSidebar = () => {
|
|
59
188
|
if (props.noSidebarWhen?.paths) {
|
|
60
189
|
for (const path of props.noSidebarWhen.paths) {
|
|
@@ -78,10 +207,10 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
78
207
|
setShowSidebar(shouldShowSidebar());
|
|
79
208
|
},
|
|
80
209
|
"react:transition:begin": () => {
|
|
81
|
-
|
|
210
|
+
setSidebar({ ...sidebar, opened: false });
|
|
82
211
|
},
|
|
83
212
|
},
|
|
84
|
-
[],
|
|
213
|
+
[sidebar],
|
|
85
214
|
);
|
|
86
215
|
|
|
87
216
|
// Default AppBar items with burger button on the left
|
|
@@ -94,7 +223,20 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
94
223
|
|
|
95
224
|
const headerHeight = hasAppBar ? 60 : 0;
|
|
96
225
|
const footerHeight = props.footer ? 24 : 0;
|
|
97
|
-
const
|
|
226
|
+
const expandedWidth = Math.max(sidebar.width, collapsedWidth);
|
|
227
|
+
|
|
228
|
+
// When collapsed but hovering, show defaultWidth (not current width)
|
|
229
|
+
const isExpandedByHover = collapsed && isHovering;
|
|
230
|
+
const effectiveCollapsed = collapsed && !isHovering;
|
|
231
|
+
const hoverWidth = Math.max(defaultWidth, collapsedWidth);
|
|
232
|
+
const sidebarWidth = hasSidebar
|
|
233
|
+
? effectiveCollapsed
|
|
234
|
+
? collapsedWidth
|
|
235
|
+
: isExpandedByHover
|
|
236
|
+
? hoverWidth
|
|
237
|
+
: expandedWidth
|
|
238
|
+
: 0;
|
|
239
|
+
const canResize = props.resizable && !collapsed;
|
|
98
240
|
|
|
99
241
|
return (
|
|
100
242
|
<AppShell
|
|
@@ -105,7 +247,11 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
105
247
|
navbar={
|
|
106
248
|
hasSidebar
|
|
107
249
|
? {
|
|
108
|
-
width:
|
|
250
|
+
width: effectiveCollapsed
|
|
251
|
+
? { base: collapsedWidth }
|
|
252
|
+
: isExpandedByHover
|
|
253
|
+
? { base: hoverWidth }
|
|
254
|
+
: { base: expandedWidth },
|
|
109
255
|
breakpoint: "sm",
|
|
110
256
|
collapsed: { mobile: !opened },
|
|
111
257
|
}
|
|
@@ -121,8 +267,38 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
121
267
|
</AppShell.Header>
|
|
122
268
|
|
|
123
269
|
{hasSidebar && (
|
|
124
|
-
<AppShell.Navbar
|
|
125
|
-
|
|
270
|
+
<AppShell.Navbar
|
|
271
|
+
bg={ui.colors.surface}
|
|
272
|
+
className="alepha-sidebar-navbar"
|
|
273
|
+
data-resizing={isResizing}
|
|
274
|
+
onMouseEnter={handleNavbarMouseEnter}
|
|
275
|
+
onMouseLeave={handleNavbarMouseLeave}
|
|
276
|
+
style={{
|
|
277
|
+
transform: collapseEffect.offset
|
|
278
|
+
? `translateX(${collapseEffect.offset}px)`
|
|
279
|
+
: undefined,
|
|
280
|
+
opacity: collapseEffect.opacity,
|
|
281
|
+
}}
|
|
282
|
+
{...props.appShellNavbarProps}
|
|
283
|
+
>
|
|
284
|
+
<Sidebar
|
|
285
|
+
{...(props.sidebarProps ?? {})}
|
|
286
|
+
collapsed={effectiveCollapsed}
|
|
287
|
+
/>
|
|
288
|
+
{(canResize || isExpandedByHover) && (
|
|
289
|
+
<Flex
|
|
290
|
+
pos="absolute"
|
|
291
|
+
right={-2}
|
|
292
|
+
top={0}
|
|
293
|
+
bottom={0}
|
|
294
|
+
w={4}
|
|
295
|
+
style={{
|
|
296
|
+
cursor: "col-resize",
|
|
297
|
+
userSelect: "none",
|
|
298
|
+
}}
|
|
299
|
+
onMouseDown={handleResizeStart}
|
|
300
|
+
/>
|
|
301
|
+
)}
|
|
126
302
|
</AppShell.Navbar>
|
|
127
303
|
)}
|
|
128
304
|
|
|
@@ -134,6 +310,8 @@ const AdminShell = (props: AdminShellProps) => {
|
|
|
134
310
|
display={"flex"}
|
|
135
311
|
flex={1}
|
|
136
312
|
style={{ flexDirection: "column" }}
|
|
313
|
+
className="alepha-sidebar-main"
|
|
314
|
+
data-resizing={isResizing}
|
|
137
315
|
{...props.appShellMainProps}
|
|
138
316
|
>
|
|
139
317
|
{props.children ?? <NestedView />}
|
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { useEvents } from "@alepha/react";
|
|
2
|
-
import { FormValidationError } from "@alepha/react/form";
|
|
3
|
-
import { NestedView } from "@alepha/react/router";
|
|
4
1
|
import {
|
|
5
2
|
ColorSchemeScript,
|
|
6
3
|
type ColorSchemeScriptProps,
|
|
@@ -12,6 +9,9 @@ import { Notifications, type NotificationsProps } from "@mantine/notifications";
|
|
|
12
9
|
import type { NavigationProgressProps } from "@mantine/nprogress";
|
|
13
10
|
import { NavigationProgress, nprogress } from "@mantine/nprogress";
|
|
14
11
|
import { TypeBoxError } from "alepha";
|
|
12
|
+
import { useEvents } from "alepha/react";
|
|
13
|
+
import { FormValidationError } from "alepha/react/form";
|
|
14
|
+
import { NestedView } from "alepha/react/router";
|
|
15
15
|
import type { ReactNode } from "react";
|
|
16
16
|
import { useTheme } from "../../hooks/useTheme.ts";
|
|
17
17
|
import { useToast } from "../../hooks/useToast.ts";
|
|
@@ -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";
|
|
@@ -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
|
|
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)
|
|
90
|
+
if (props.collapsed) {
|
|
91
|
+
return divider(key);
|
|
92
|
+
}
|
|
80
93
|
return (
|
|
81
|
-
<Flex key={key} mt={"md"}
|
|
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(
|
|
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=
|
|
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=
|
|
184
|
+
className="alepha-sidebar-scroll"
|
|
175
185
|
>
|
|
176
186
|
{menu
|
|
177
187
|
.filter((it) => !it.position)
|
|
@@ -332,34 +342,9 @@ export interface SidebarItemProps {
|
|
|
332
342
|
const SidebarCollapsedItem = (props: SidebarItemProps) => {
|
|
333
343
|
const { item, level } = props;
|
|
334
344
|
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
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
|
-
}
|
|
345
|
+
const handleItemClick = () => {
|
|
346
|
+
props.onItemClick?.(item);
|
|
347
|
+
item.onClick?.();
|
|
363
348
|
};
|
|
364
349
|
|
|
365
350
|
return (
|
|
@@ -371,35 +356,15 @@ const SidebarCollapsedItem = (props: SidebarItemProps) => {
|
|
|
371
356
|
}
|
|
372
357
|
variant={"subtle"}
|
|
373
358
|
variantActive={"default"}
|
|
374
|
-
tooltip={
|
|
375
|
-
item.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
label: item.label,
|
|
379
|
-
position: "right",
|
|
380
|
-
}
|
|
381
|
-
}
|
|
359
|
+
tooltip={{
|
|
360
|
+
label: item.label,
|
|
361
|
+
position: "right",
|
|
362
|
+
}}
|
|
382
363
|
radius={props.item.theme?.radius ?? props.theme.button?.radius ?? "md"}
|
|
383
364
|
onClick={handleItemClick}
|
|
384
365
|
icon={renderIcon(item.icon) ?? <IconSquareRounded />}
|
|
385
366
|
href={props.item.href as any}
|
|
386
367
|
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
368
|
{...props.item.actionProps}
|
|
404
369
|
/>
|
|
405
370
|
);
|
|
@@ -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";
|