@alepha/ui 0.15.1 → 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-DClGEVBj.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-C76r1_Xz.js → AdminFiles-Cu8GHgQ3.js} +3 -3
- package/dist/admin/AdminFiles-Cu8GHgQ3.js.map +1 -0
- package/dist/admin/{AdminNotifications-Bsalygm5.js → AdminNotifications-CgYkBuG_.js} +3 -3
- package/dist/admin/AdminNotifications-CgYkBuG_.js.map +1 -0
- package/dist/admin/AdminNotifications-DmfGPqHe.js +3 -0
- package/dist/admin/{AdminParameters-CpmAWwqN.js → AdminParameters-Cl-R0nXt.js} +1 -1
- package/dist/admin/{AdminParameters-Bmxtnpv-.js → AdminParameters-hjNG_KXb.js} +4 -4
- package/dist/admin/AdminParameters-hjNG_KXb.js.map +1 -0
- package/dist/admin/{AdminSessions-DmK3R6pP.js → AdminSessions-Bey9cuy1.js} +4 -4
- package/dist/admin/AdminSessions-Bey9cuy1.js.map +1 -0
- package/dist/admin/AdminSessions-Cn4_jB04.js +3 -0
- package/dist/admin/{AdminUserAudits-BPMP1Qd2.js → AdminUserAudits-C7AN9jx7.js} +4 -4
- package/dist/admin/AdminUserAudits-C7AN9jx7.js.map +1 -0
- package/dist/admin/{AdminUserAudits-Brcenss9.js → AdminUserAudits-Cp_ERd2g.js} +1 -1
- package/dist/admin/{AdminUserCreate-Cx8bkYC2.js → AdminUserCreate-Chr-7hLk.js} +1 -1
- package/dist/admin/{AdminUserCreate-CZjB6NKc.js → AdminUserCreate-DiXi1EWB.js} +4 -4
- package/dist/admin/AdminUserCreate-DiXi1EWB.js.map +1 -0
- package/dist/admin/{AdminUserDetails-8TYsqQBy.js → AdminUserDetails-Dcn3OwMC.js} +1 -1
- package/dist/admin/{AdminUserDetails-DuqCOBJK.js → AdminUserDetails-yM4x8JE6.js} +5 -5
- package/dist/admin/AdminUserDetails-yM4x8JE6.js.map +1 -0
- package/dist/admin/{AdminUserLayout-Bz2u_zQ4.js → AdminUserLayout-CfeQHH6e.js} +1 -1
- package/dist/admin/{AdminUserLayout-Dgk8s7Cd.js → AdminUserLayout-D9bqGt6T.js} +3 -3
- package/dist/admin/AdminUserLayout-D9bqGt6T.js.map +1 -0
- package/dist/admin/{AdminUserSessions-DCpe8_T6.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-qxDfowqh.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-ZlPsDz0T.js → AdminUsers-CYkcUWCg.js} +4 -4
- 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 +44 -29
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{AuthLayout-CWzQ8rCe.js → AuthLayout-Dj5K4SIN.js} +2 -2
- package/dist/auth/AuthLayout-Dj5K4SIN.js.map +1 -0
- package/dist/auth/{Login-CyvKwy5e.js → Login-BAFVcX_J.js} +5 -5
- package/dist/auth/Login-BAFVcX_J.js.map +1 -0
- package/dist/auth/Login-C5PUsp8I.js +4 -0
- package/dist/auth/{Register-C7Zp09Ks.js → Register-CZRXEcWy.js} +6 -6
- 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-DYJSUC6B.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-CNXFIwWW.js → VerifyEmail-DolENWGn.js} +4 -4
- package/dist/auth/VerifyEmail-DolENWGn.js.map +1 -0
- package/dist/auth/index.d.ts +30 -19
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +24 -13
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +115 -52
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +302 -87
- package/dist/core/index.js.map +1 -1
- package/dist/demo/{DemoDataTable-DYbDYbs5.js → DemoDataTable-CguplbR7.js} +2 -2
- package/dist/demo/{DemoDataTable-DYbDYbs5.js.map → DemoDataTable-CguplbR7.js.map} +1 -1
- package/dist/demo/DemoJsonViewer-DIssGVlJ.js +4 -0
- package/dist/demo/{DemoJsonViewer-D_Hff1Q2.js → DemoJsonViewer-Dgdk3Txb.js} +3 -3
- package/dist/demo/{DemoJsonViewer-D_Hff1Q2.js.map → DemoJsonViewer-Dgdk3Txb.js.map} +1 -1
- package/dist/demo/{DemoLayout-DjIDm93B.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-BA_HiIRZ.js → DemoLogin-mtkN6340.js} +6 -6
- package/dist/demo/DemoLogin-mtkN6340.js.map +1 -0
- package/dist/demo/{DemoRegister-B6syaxP9.js → DemoRegister-C0MW7anp.js} +7 -7
- package/dist/demo/DemoRegister-C0MW7anp.js.map +1 -0
- package/dist/demo/{DemoResetPassword-BOcLG4GF.js → DemoResetPassword-CPTy88iK.js} +6 -6
- package/dist/demo/DemoResetPassword-CPTy88iK.js.map +1 -0
- package/dist/demo/{DemoSidebar-DpZXf7GO.js → DemoSidebar-MVmQKfMt.js} +2 -2
- package/dist/demo/{DemoSidebar-DpZXf7GO.js.map → DemoSidebar-MVmQKfMt.js.map} +1 -1
- package/dist/demo/{DemoTypeForm-BlLAcQqZ.js → DemoTypeForm-w-qtfRlC.js} +3 -3
- package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +1 -0
- package/dist/demo/{DemoVerifyEmail-C-J7bXUQ.js → DemoVerifyEmail-C8FFJT5A.js} +5 -5
- package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +1 -0
- package/dist/demo/{Showcase-HchhcsHV.js → Showcase-CQrMWars.js} +2 -2
- package/dist/demo/Showcase-CQrMWars.js.map +1 -0
- package/dist/demo/index.d.ts +25 -15
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +24 -14
- package/dist/demo/index.js.map +1 -1
- package/package.json +5 -6
- 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-ColpiP4T.js +0 -3
- package/dist/admin/AdminAudits-DClGEVBj.js.map +0 -1
- package/dist/admin/AdminFiles-C5pqXN5B.js +0 -3
- package/dist/admin/AdminFiles-C76r1_Xz.js.map +0 -1
- package/dist/admin/AdminNotifications-BXixCBu9.js +0 -3
- package/dist/admin/AdminNotifications-Bsalygm5.js.map +0 -1
- package/dist/admin/AdminParameters-Bmxtnpv-.js.map +0 -1
- package/dist/admin/AdminSessions-CrkRvey3.js +0 -3
- package/dist/admin/AdminSessions-DmK3R6pP.js.map +0 -1
- package/dist/admin/AdminUserAudits-BPMP1Qd2.js.map +0 -1
- package/dist/admin/AdminUserCreate-CZjB6NKc.js.map +0 -1
- package/dist/admin/AdminUserDetails-DuqCOBJK.js.map +0 -1
- package/dist/admin/AdminUserLayout-Dgk8s7Cd.js.map +0 -1
- package/dist/admin/AdminUserSessions-DCpe8_T6.js.map +0 -1
- package/dist/admin/AdminUserSessions-beiJqY2D.js +0 -3
- package/dist/admin/AdminUserSettings-CxlInVnu.js +0 -3
- package/dist/admin/AdminUserSettings-qxDfowqh.js.map +0 -1
- package/dist/admin/AdminUsers-Bd0wMP8v.js +0 -3
- package/dist/admin/AdminUsers-ZlPsDz0T.js.map +0 -1
- package/dist/auth/AuthLayout-CWzQ8rCe.js.map +0 -1
- package/dist/auth/Login-CxOPyNFP.js +0 -4
- package/dist/auth/Login-CyvKwy5e.js.map +0 -1
- package/dist/auth/Register-C7Zp09Ks.js.map +0 -1
- package/dist/auth/Register-Cacr7YbA.js +0 -4
- package/dist/auth/ResetPassword-CMkx8Ibf.js +0 -3
- package/dist/auth/ResetPassword-DYJSUC6B.js.map +0 -1
- package/dist/auth/VerifyEmail-CNXFIwWW.js.map +0 -1
- package/dist/auth/VerifyEmail-DKyDlz96.js +0 -3
- package/dist/demo/DemoJsonViewer-DbWVDdz_.js +0 -4
- package/dist/demo/DemoLayout-DjIDm93B.js.map +0 -1
- package/dist/demo/DemoLayout-nNMajP_9.js +0 -3
- package/dist/demo/DemoLogin-BA_HiIRZ.js.map +0 -1
- package/dist/demo/DemoRegister-B6syaxP9.js.map +0 -1
- package/dist/demo/DemoResetPassword-BOcLG4GF.js.map +0 -1
- package/dist/demo/DemoTypeForm-BlLAcQqZ.js.map +0 -1
- package/dist/demo/DemoVerifyEmail-C-J7bXUQ.js.map +0 -1
- package/dist/demo/Showcase-HchhcsHV.js.map +0 -1
|
@@ -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";
|
package/src/core/index.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { $context, $module, type Static } from "alepha";
|
|
2
|
+
import { AlephaReactForm } from "alepha/react/form";
|
|
3
|
+
import { AlephaReactHead } from "alepha/react/head";
|
|
4
|
+
import { AlephaReactI18n } from "alepha/react/i18n";
|
|
5
5
|
import type { ComponentType, ReactNode } from "react";
|
|
6
|
+
import { alephaSidebarAtom } from "./atoms/alephaSidebarAtom.ts";
|
|
6
7
|
import { alephaThemeAtom } from "./atoms/alephaThemeAtom.ts";
|
|
7
8
|
import type { ControlProps } from "./components/form/Control.tsx";
|
|
8
9
|
import { ThemeProvider } from "./providers/ThemeProvider.ts";
|
|
@@ -13,6 +14,7 @@ import { ToastService } from "./services/ToastService.tsx";
|
|
|
13
14
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
14
15
|
|
|
15
16
|
export { Flex, Text } from "@mantine/core";
|
|
17
|
+
export * from "./atoms/alephaSidebarAtom.ts";
|
|
16
18
|
export * from "./atoms/alephaThemeAtom.ts";
|
|
17
19
|
export * from "./atoms/alephaThemeListAtom.ts";
|
|
18
20
|
export * from "./atoms/themes/default.ts";
|
|
@@ -35,6 +37,7 @@ export { default as LanguageButton } from "./components/buttons/LanguageButton.t
|
|
|
35
37
|
export { default as OmnibarButton } from "./components/buttons/OmnibarButton.tsx";
|
|
36
38
|
export type { ThemeButtonProps } from "./components/buttons/ThemeButton.tsx";
|
|
37
39
|
export { default as ThemeButton } from "./components/buttons/ThemeButton.tsx";
|
|
40
|
+
export { default as ToggleSidebarButton } from "./components/buttons/ToggleSidebarButton.tsx";
|
|
38
41
|
export { default as AlertDialog } from "./components/dialogs/AlertDialog.tsx";
|
|
39
42
|
export { default as ConfirmDialog } from "./components/dialogs/ConfirmDialog.tsx";
|
|
40
43
|
export { default as PromptDialog } from "./components/dialogs/PromptDialog.tsx";
|
|
@@ -121,11 +124,12 @@ declare module "typebox" {
|
|
|
121
124
|
|
|
122
125
|
declare module "alepha" {
|
|
123
126
|
interface State {
|
|
127
|
+
[alephaSidebarAtom.key]?: Static<typeof alephaSidebarAtom.schema>;
|
|
124
128
|
[alephaThemeAtom.key]?: Static<typeof alephaThemeAtom.schema>;
|
|
125
129
|
}
|
|
126
130
|
}
|
|
127
131
|
|
|
128
|
-
declare module "
|
|
132
|
+
declare module "alepha/react/router" {
|
|
129
133
|
interface PagePrimitiveOptions {
|
|
130
134
|
/**
|
|
131
135
|
* Human-readable title for the page.
|
|
@@ -152,7 +156,25 @@ declare module "@alepha/react/router" {
|
|
|
152
156
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
153
157
|
|
|
154
158
|
/**
|
|
155
|
-
*
|
|
159
|
+
* | type | quality | stability |
|
|
160
|
+
* |------|---------|-----------|
|
|
161
|
+
* | frontend | rare | experimental |
|
|
162
|
+
*
|
|
163
|
+
* Core UI components based on Mantine UI v8.
|
|
164
|
+
*
|
|
165
|
+
* **Features:**
|
|
166
|
+
* - Mantine integration with theme support
|
|
167
|
+
* - ActionButton, BurgerButton, ClipboardButton, DarkModeButton, LanguageButton, ThemeButton
|
|
168
|
+
* - AlertDialog, ConfirmDialog, PromptDialog
|
|
169
|
+
* - Form controls: Control, ControlArray, ControlDate, ControlNumber, ControlObject, ControlSelect, ControlQueryBuilder
|
|
170
|
+
* - TypeForm for automatic form generation from TypeBox schemas
|
|
171
|
+
* - AdminShell layout component
|
|
172
|
+
* - AppBar with configurable elements
|
|
173
|
+
* - Sidebar navigation with sections and menu items
|
|
174
|
+
* - Omnibar for command palette / search
|
|
175
|
+
* - DataTable with filtering, sorting, pagination
|
|
176
|
+
* - Toast notifications
|
|
177
|
+
* - Theme system with dark mode
|
|
156
178
|
*
|
|
157
179
|
* @module alepha.ui
|
|
158
180
|
*/
|
|
@@ -168,3 +190,32 @@ export const AlephaUI = $module({
|
|
|
168
190
|
alepha.with(ToastService);
|
|
169
191
|
},
|
|
170
192
|
});
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Register UI components and get the RootRouter instance.
|
|
196
|
+
*/
|
|
197
|
+
export const $ui = (
|
|
198
|
+
opts: {
|
|
199
|
+
// TODO:
|
|
200
|
+
// theme?: ThemeOptions;
|
|
201
|
+
// root?: string = "/";
|
|
202
|
+
} = {},
|
|
203
|
+
) => {
|
|
204
|
+
const { alepha } = $context();
|
|
205
|
+
|
|
206
|
+
// TODO: Register unique instance ? In order to have multiple ui apps in the same context ?
|
|
207
|
+
// app = $ui();
|
|
208
|
+
// admin = $ui({ root: "/admin", theme: adminTheme });
|
|
209
|
+
// auth = $ui({ root: "/auth", theme: authTheme });
|
|
210
|
+
// etc...
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* If multi ui, should we have N themes ? or one $atom theme but with change based on current ui app ?
|
|
214
|
+
*
|
|
215
|
+
* App (theme=T1) -> Admin (theme=T2) ?
|
|
216
|
+
*
|
|
217
|
+
* > It can be done with onLeave()/onEnter() of the RootRouter to set the theme atom.
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
return alepha.inject(RootRouter); // Inject as singleton ?
|
|
221
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { $head } from "@alepha/react/head";
|
|
2
1
|
import { $inject, Alepha, AlephaError } from "alepha";
|
|
2
|
+
import { $head } from "alepha/react/head";
|
|
3
3
|
import { $cookie } from "alepha/server/cookies";
|
|
4
4
|
import { alephaThemeAtom } from "../atoms/alephaThemeAtom.ts";
|
|
5
5
|
import { alephaThemeListAtom } from "../atoms/alephaThemeListAtom.ts";
|