@campxdev/react-blueprint 2.3.8 → 2.3.10
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/cjs/index.js +1 -1
- package/dist/cjs/types/src/components/Layout/AppLayout/components/AppBar.d.ts +6 -3
- package/dist/cjs/types/src/components/Layout/AppLayout/components/Sidebar/Sidebar.d.ts +8 -1
- package/dist/cjs/types/src/components/Layout/AppLayout/components/Sidebar/interfaces.d.ts +4 -0
- package/dist/cjs/types/src/components/Layout/AppLayout/components/UserProfilePopup.d.ts +5 -4
- package/dist/cjs/types/src/components/Layout/AppLayout/types.d.ts +9 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/types/src/components/Layout/AppLayout/components/AppBar.d.ts +6 -3
- package/dist/esm/types/src/components/Layout/AppLayout/components/Sidebar/Sidebar.d.ts +8 -1
- package/dist/esm/types/src/components/Layout/AppLayout/components/Sidebar/interfaces.d.ts +4 -0
- package/dist/esm/types/src/components/Layout/AppLayout/components/UserProfilePopup.d.ts +5 -4
- package/dist/esm/types/src/components/Layout/AppLayout/types.d.ts +9 -0
- package/dist/index.d.ts +50 -40
- package/package.json +1 -1
- package/src/App.tsx +9 -37
- package/src/components/DataDisplay/SidePanel/styles.tsx +1 -1
- package/src/components/Layout/AppLayout/AppLayout.tsx +63 -20
- package/src/components/Layout/AppLayout/components/AppBar.tsx +40 -49
- package/src/components/Layout/AppLayout/components/Sidebar/MenuBar.tsx +13 -5
- package/src/components/Layout/AppLayout/components/Sidebar/MenuItem.tsx +129 -47
- package/src/components/Layout/AppLayout/components/Sidebar/Sidebar.tsx +165 -45
- package/src/components/Layout/AppLayout/components/Sidebar/interfaces.ts +4 -0
- package/src/components/Layout/AppLayout/components/Sidebar/styles.ts +0 -2
- package/src/components/Layout/AppLayout/components/UserProfilePopup.tsx +46 -16
- package/src/components/Layout/AppLayout/types.ts +12 -0
- package/src/components/Layout/PageHeader/components/Views/Views.tsx +3 -2
- package/src/components/Navigation/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/src/components/Navigation/Sidebar/SidebarV2.tsx +1 -1
- package/src/themes/colorTokens/darkColorTokens.tsx +1 -1
- package/src/themes/colorTokens/lightColorTokens.ts +1 -1
- package/src/themes/commonTheme.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Stack, Typography } from '@mui/material';
|
|
1
|
+
import { Stack, Tooltip, Typography } from '@mui/material';
|
|
2
2
|
import { motion } from 'framer-motion';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { useMatch, useResolvedPath } from 'react-router-dom';
|
|
@@ -21,6 +21,8 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
21
21
|
currentMenuPath,
|
|
22
22
|
internalMenuClickHandler,
|
|
23
23
|
onClose,
|
|
24
|
+
collapsed,
|
|
25
|
+
setCollapsed,
|
|
24
26
|
}) => {
|
|
25
27
|
const { name, path, icon, menu: internalMenu, subMenu } = menuItem;
|
|
26
28
|
const newPath = currentMenuPath ? `${currentMenuPath}${path}` : path;
|
|
@@ -29,9 +31,13 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
29
31
|
const match = useMatch({ path: resolved.pathname, end: false });
|
|
30
32
|
const [expanded, setExpanded] = useState(!!match);
|
|
31
33
|
|
|
32
|
-
const handleSubMenuToggle = () =>
|
|
34
|
+
const handleSubMenuToggle = () => {
|
|
35
|
+
setCollapsed(false);
|
|
36
|
+
setExpanded(!expanded);
|
|
37
|
+
};
|
|
33
38
|
|
|
34
39
|
const handleInternalMenuClick = () => {
|
|
40
|
+
setCollapsed(false);
|
|
35
41
|
internalMenuClickHandler({
|
|
36
42
|
menuTitle: name,
|
|
37
43
|
menuPath: newPath,
|
|
@@ -41,9 +47,6 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
41
47
|
|
|
42
48
|
// Smart drawer closing logic
|
|
43
49
|
const shouldCloseDrawer = (item: typeof menuItem) => {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
50
|
// For desktop, only close if it's a leaf node (no children)
|
|
48
51
|
return !item.menu && !item.subMenu;
|
|
49
52
|
};
|
|
@@ -56,16 +59,22 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
56
59
|
|
|
57
60
|
// Internal menu item (has nested menu)
|
|
58
61
|
if (internalMenu && internalMenu.length > 0) {
|
|
59
|
-
|
|
60
|
-
<
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
62
|
+
const content = (
|
|
63
|
+
<MenuItemContainer disablePadding>
|
|
64
|
+
<SubMenuContainer
|
|
65
|
+
match={!!match}
|
|
66
|
+
onClick={handleInternalMenuClick}
|
|
67
|
+
sx={{ width: collapsed ? 'max-content' : '100%' }}
|
|
68
|
+
>
|
|
69
|
+
<MenuItemButton
|
|
70
|
+
sx={{
|
|
71
|
+
justifyContent: collapsed ? 'center' : 'flex-start',
|
|
72
|
+
padding: collapsed ? '8px' : '5px 8px',
|
|
73
|
+
}}
|
|
74
|
+
>
|
|
75
|
+
{collapsed ? (
|
|
76
|
+
<MenuItemIcon sx={{ margin: 0 }}>{icon}</MenuItemIcon>
|
|
77
|
+
) : (
|
|
69
78
|
<Stack direction="row" alignItems="center" width="100%">
|
|
70
79
|
<Stack direction="row" alignItems="center" flex={1}>
|
|
71
80
|
<MenuItemIcon>{icon}</MenuItemIcon>
|
|
@@ -75,15 +84,12 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
75
84
|
<Icons.RedoIcon size={18} />
|
|
76
85
|
</HoverIcon>
|
|
77
86
|
</Stack>
|
|
78
|
-
|
|
79
|
-
</
|
|
80
|
-
</
|
|
81
|
-
</
|
|
87
|
+
)}
|
|
88
|
+
</MenuItemButton>
|
|
89
|
+
</SubMenuContainer>
|
|
90
|
+
</MenuItemContainer>
|
|
82
91
|
);
|
|
83
|
-
}
|
|
84
92
|
|
|
85
|
-
// Sub menu item (has expandable sub items)
|
|
86
|
-
if (subMenu && subMenu.length > 0) {
|
|
87
93
|
return (
|
|
88
94
|
<motion.div
|
|
89
95
|
key={`submenu-${index}`}
|
|
@@ -91,28 +97,56 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
91
97
|
animate={{ opacity: 1 }}
|
|
92
98
|
transition={{ duration: 1 }}
|
|
93
99
|
>
|
|
100
|
+
{collapsed ? (
|
|
101
|
+
<Tooltip title={name} placement="right">
|
|
102
|
+
{content}
|
|
103
|
+
</Tooltip>
|
|
104
|
+
) : (
|
|
105
|
+
content
|
|
106
|
+
)}
|
|
107
|
+
</motion.div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Sub menu item (has expandable sub items)
|
|
112
|
+
if (subMenu && subMenu.length > 0) {
|
|
113
|
+
const content = (
|
|
114
|
+
<>
|
|
94
115
|
<MenuItemContainer disablePadding>
|
|
95
|
-
<SubMenuContainer
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
<
|
|
108
|
-
|
|
116
|
+
<SubMenuContainer
|
|
117
|
+
match={!!match}
|
|
118
|
+
onClick={handleSubMenuToggle}
|
|
119
|
+
sx={{ width: collapsed ? 'max-content' : '100%' }}
|
|
120
|
+
>
|
|
121
|
+
<MenuItemButton
|
|
122
|
+
sx={{
|
|
123
|
+
justifyContent: collapsed ? 'center' : 'flex-start',
|
|
124
|
+
padding: collapsed ? '8px' : '5px 8px',
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
{collapsed ? (
|
|
128
|
+
<MenuItemIcon sx={{ margin: 0 }}>{icon}</MenuItemIcon>
|
|
129
|
+
) : (
|
|
130
|
+
<Stack
|
|
131
|
+
direction="row"
|
|
132
|
+
alignItems="center"
|
|
133
|
+
width="100%"
|
|
134
|
+
justifyContent="space-between"
|
|
135
|
+
>
|
|
136
|
+
<Stack direction="row" alignItems="center">
|
|
137
|
+
<MenuItemIcon>{icon}</MenuItemIcon>
|
|
138
|
+
<Typography variant="button1">{name}</Typography>
|
|
139
|
+
</Stack>
|
|
140
|
+
<Stack>
|
|
141
|
+
{expanded ? <Icons.CollapseIcon /> : <Icons.ExpandIcon />}
|
|
142
|
+
</Stack>
|
|
109
143
|
</Stack>
|
|
110
|
-
|
|
144
|
+
)}
|
|
111
145
|
</MenuItemButton>
|
|
112
146
|
</SubMenuContainer>
|
|
113
147
|
</MenuItemContainer>
|
|
114
148
|
|
|
115
|
-
{expanded && (
|
|
149
|
+
{expanded && !collapsed && (
|
|
116
150
|
<motion.div
|
|
117
151
|
initial={{ height: 0, opacity: 0 }}
|
|
118
152
|
animate={{ height: 'auto', opacity: 1 }}
|
|
@@ -132,11 +166,55 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
132
166
|
</SubMenuItemContainer>
|
|
133
167
|
</motion.div>
|
|
134
168
|
)}
|
|
169
|
+
</>
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
return (
|
|
173
|
+
<motion.div
|
|
174
|
+
key={`submenu-${index}`}
|
|
175
|
+
initial={{ opacity: 0 }}
|
|
176
|
+
animate={{ opacity: 1 }}
|
|
177
|
+
transition={{ duration: 1 }}
|
|
178
|
+
>
|
|
179
|
+
{collapsed ? (
|
|
180
|
+
<Tooltip title={name} placement="right">
|
|
181
|
+
<div>{content}</div>
|
|
182
|
+
</Tooltip>
|
|
183
|
+
) : (
|
|
184
|
+
content
|
|
185
|
+
)}
|
|
135
186
|
</motion.div>
|
|
136
187
|
);
|
|
137
188
|
}
|
|
138
189
|
|
|
139
190
|
// Regular menu item (direct link)
|
|
191
|
+
const regularContent = (
|
|
192
|
+
<MenuItemContainer disablePadding>
|
|
193
|
+
<MenuLink
|
|
194
|
+
to={newPath}
|
|
195
|
+
match={match}
|
|
196
|
+
onClick={handleNavigationClick}
|
|
197
|
+
sx={{ width: collapsed ? 'max-content' : '100%' }}
|
|
198
|
+
>
|
|
199
|
+
<MenuItemButton
|
|
200
|
+
sx={{
|
|
201
|
+
justifyContent: collapsed ? 'center' : 'flex-start',
|
|
202
|
+
padding: collapsed ? '8px' : '5px 8px',
|
|
203
|
+
}}
|
|
204
|
+
>
|
|
205
|
+
{collapsed ? (
|
|
206
|
+
<MenuItemIcon sx={{ margin: 0 }}>{icon}</MenuItemIcon>
|
|
207
|
+
) : (
|
|
208
|
+
<>
|
|
209
|
+
<MenuItemIcon>{icon}</MenuItemIcon>
|
|
210
|
+
<Typography variant="button1">{name}</Typography>
|
|
211
|
+
</>
|
|
212
|
+
)}
|
|
213
|
+
</MenuItemButton>
|
|
214
|
+
</MenuLink>
|
|
215
|
+
</MenuItemContainer>
|
|
216
|
+
);
|
|
217
|
+
|
|
140
218
|
return (
|
|
141
219
|
<motion.div
|
|
142
220
|
key={`regular-${index}`}
|
|
@@ -144,14 +222,13 @@ export const MenuItem: React.FC<MenuItemProps> = ({
|
|
|
144
222
|
animate={{ opacity: 1 }}
|
|
145
223
|
transition={{ duration: 1 }}
|
|
146
224
|
>
|
|
147
|
-
|
|
148
|
-
<
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
</MenuItemContainer>
|
|
225
|
+
{collapsed ? (
|
|
226
|
+
<Tooltip title={name} placement="right">
|
|
227
|
+
{regularContent}
|
|
228
|
+
</Tooltip>
|
|
229
|
+
) : (
|
|
230
|
+
regularContent
|
|
231
|
+
)}
|
|
155
232
|
</motion.div>
|
|
156
233
|
);
|
|
157
234
|
};
|
|
@@ -178,7 +255,12 @@ const SubMenuItem: React.FC<{
|
|
|
178
255
|
|
|
179
256
|
return (
|
|
180
257
|
<MenuItemContainer key={index} disablePadding>
|
|
181
|
-
<MenuLink
|
|
258
|
+
<MenuLink
|
|
259
|
+
to={newPath}
|
|
260
|
+
match={match}
|
|
261
|
+
sx={{ margin: '5px 8px 5px 16px' }}
|
|
262
|
+
onClick={handleSubMenuNavigationClick}
|
|
263
|
+
>
|
|
182
264
|
<MenuItemButton>
|
|
183
265
|
<Typography variant="button1">{name}</Typography>
|
|
184
266
|
</MenuItemButton>
|
|
@@ -1,62 +1,182 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import {
|
|
2
|
+
Box,
|
|
3
|
+
IconButton,
|
|
4
|
+
Stack,
|
|
5
|
+
styled,
|
|
6
|
+
useMediaQuery,
|
|
7
|
+
useTheme,
|
|
8
|
+
} from '@mui/material';
|
|
9
|
+
import { AnimatePresence, motion } from 'framer-motion';
|
|
10
|
+
import React, { useState } from 'react';
|
|
11
|
+
import { CampxFullLogoIconV2 } from '../../../../Assets/Icons/IconComponents/CampxFullLogoIconV2';
|
|
12
|
+
import { CampxIconV2 } from '../../../../Assets/Icons/IconComponents/CampxIconV2';
|
|
13
|
+
import { Icons } from '../../../../export';
|
|
14
|
+
import { UserProfilePopup, UserProfilePopupProps } from '../UserProfilePopup';
|
|
5
15
|
import { SideMenuItemProps } from './interfaces';
|
|
6
16
|
import { MenuBar } from './MenuBar';
|
|
7
|
-
import { SidebarContainer } from './styles';
|
|
8
17
|
import { useSidebarNavigation } from './useSidebarNavigation';
|
|
9
18
|
|
|
10
19
|
interface SidebarProps {
|
|
20
|
+
/** Menu items for navigation */
|
|
11
21
|
menu: SideMenuItemProps[];
|
|
12
|
-
|
|
22
|
+
/**User profile Params */
|
|
23
|
+
userProfileParams: UserProfilePopupProps;
|
|
24
|
+
/** Whether the sidebar is collapsed */
|
|
25
|
+
collapsed: boolean;
|
|
26
|
+
/** Function to toggle sidebar collapse state */
|
|
27
|
+
setCollapsed: any;
|
|
13
28
|
}
|
|
14
29
|
|
|
15
|
-
export const Sidebar: React.FC<SidebarProps> = ({
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
export const Sidebar: React.FC<SidebarProps> = ({
|
|
31
|
+
menu,
|
|
32
|
+
userProfileParams,
|
|
33
|
+
collapsed,
|
|
34
|
+
setCollapsed,
|
|
35
|
+
}) => {
|
|
36
|
+
const theme = useTheme();
|
|
37
|
+
const isSmallScreen = useMediaQuery(theme.breakpoints.down('md'));
|
|
38
|
+
const [hovered, setHovered] = useState(false);
|
|
39
|
+
// Use the navigation hook
|
|
40
|
+
const navigation = useSidebarNavigation(menu);
|
|
41
|
+
|
|
42
|
+
const onToggle = () => {
|
|
43
|
+
setCollapsed(!collapsed);
|
|
44
|
+
};
|
|
22
45
|
|
|
23
46
|
return (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
47
|
+
<>
|
|
48
|
+
{/* Mobile overlay backdrop */}
|
|
49
|
+
<AnimatePresence>
|
|
50
|
+
{!collapsed && isSmallScreen && (
|
|
51
|
+
<motion.div
|
|
52
|
+
initial={{ opacity: 0 }}
|
|
53
|
+
animate={{ opacity: 1 }}
|
|
54
|
+
exit={{ opacity: 0 }}
|
|
55
|
+
transition={{ duration: 0.2 }}
|
|
56
|
+
style={{
|
|
57
|
+
position: 'fixed',
|
|
58
|
+
top: 0,
|
|
59
|
+
left: 0,
|
|
60
|
+
right: 0,
|
|
61
|
+
bottom: 0,
|
|
62
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
63
|
+
zIndex: 1299,
|
|
64
|
+
}}
|
|
65
|
+
onClick={onToggle}
|
|
41
66
|
/>
|
|
42
|
-
|
|
43
|
-
</
|
|
44
|
-
|
|
67
|
+
)}
|
|
68
|
+
</AnimatePresence>
|
|
69
|
+
|
|
70
|
+
{/* Persistent Sidebar */}
|
|
71
|
+
<motion.div
|
|
72
|
+
animate={{
|
|
73
|
+
width: collapsed ? '64px' : '250px',
|
|
74
|
+
x: isSmallScreen && collapsed ? '-100%' : '0%',
|
|
75
|
+
}}
|
|
76
|
+
transition={{ duration: 0.3, ease: [0.32, 0.72, 0, 1] }}
|
|
77
|
+
style={{
|
|
78
|
+
position: isSmallScreen ? 'fixed' : 'relative',
|
|
79
|
+
zIndex: isSmallScreen ? 1300 : 1,
|
|
80
|
+
height: '100vh',
|
|
81
|
+
flexShrink: 0,
|
|
82
|
+
}}
|
|
83
|
+
>
|
|
84
|
+
<SidebarContainer>
|
|
85
|
+
{/* Sidebar Header */}
|
|
86
|
+
<Stack
|
|
87
|
+
direction="row"
|
|
88
|
+
justifyContent="space-between"
|
|
89
|
+
alignItems="center"
|
|
90
|
+
sx={{
|
|
91
|
+
height: '64px',
|
|
92
|
+
padding: collapsed ? '0' : '0 16px',
|
|
93
|
+
[theme.breakpoints.down('md')]: {
|
|
94
|
+
height: '54px',
|
|
95
|
+
},
|
|
96
|
+
}}
|
|
97
|
+
>
|
|
98
|
+
{/* Logo - Show icon when collapsed, full logo when expanded */}
|
|
99
|
+
{collapsed ? (
|
|
100
|
+
<IconButton
|
|
101
|
+
onClick={() => {
|
|
102
|
+
setHovered(false);
|
|
103
|
+
onToggle();
|
|
104
|
+
}}
|
|
105
|
+
onMouseEnter={() => setHovered(true)}
|
|
106
|
+
onMouseLeave={() => setHovered(false)}
|
|
107
|
+
sx={{
|
|
108
|
+
width: '64px',
|
|
109
|
+
height: '64px',
|
|
110
|
+
borderRadius: 0,
|
|
111
|
+
[theme.breakpoints.down('md')]: {
|
|
112
|
+
height: '54px',
|
|
113
|
+
width: '54px',
|
|
114
|
+
},
|
|
115
|
+
':hover': { cursor: 'e-resize' },
|
|
116
|
+
}}
|
|
117
|
+
>
|
|
118
|
+
{hovered ? <Icons.RightIcon size={24} /> : <CampxIconV2 />}
|
|
119
|
+
</IconButton>
|
|
120
|
+
) : (
|
|
121
|
+
<>
|
|
122
|
+
<CampxFullLogoIconV2 />
|
|
123
|
+
<IconButton
|
|
124
|
+
onClick={onToggle}
|
|
125
|
+
sx={{
|
|
126
|
+
':hover': { cursor: 'e-resize' },
|
|
127
|
+
}}
|
|
128
|
+
>
|
|
129
|
+
<Icons.LeftIcon size={20} />
|
|
130
|
+
</IconButton>
|
|
131
|
+
</>
|
|
132
|
+
)}
|
|
133
|
+
</Stack>
|
|
134
|
+
|
|
135
|
+
{/* Menu Content */}
|
|
136
|
+
<motion.div
|
|
137
|
+
key={`sidebar-${navigation.currentMenuState.title || 'main'}`}
|
|
138
|
+
initial={{ x: navigation.menuPosition }}
|
|
139
|
+
animate={{ x: 0 }}
|
|
140
|
+
transition={{
|
|
141
|
+
duration: 0.3,
|
|
142
|
+
ease: navigation.menuPosition ? 'circOut' : 'circIn',
|
|
143
|
+
}}
|
|
144
|
+
style={{
|
|
145
|
+
height: `calc(100% - 116px)`,
|
|
146
|
+
width: '100%',
|
|
147
|
+
}}
|
|
148
|
+
onClick={() => setCollapsed(false)}
|
|
149
|
+
>
|
|
150
|
+
<MenuBar
|
|
151
|
+
currentMenuState={navigation.currentMenuState}
|
|
152
|
+
menuPosition={navigation.menuPosition}
|
|
153
|
+
internalMenuClickHandler={navigation.internalMenuClickHandler}
|
|
154
|
+
previousMenuClickHandler={navigation.previousMenuClickHandler}
|
|
155
|
+
onClose={isSmallScreen ? onToggle : undefined}
|
|
156
|
+
collapsed={collapsed}
|
|
157
|
+
setCollapsed={setCollapsed}
|
|
158
|
+
/>
|
|
159
|
+
</motion.div>
|
|
160
|
+
<Box sx={{ position: 'fixed', bottom: 0, left: 0 }}>
|
|
161
|
+
<UserProfilePopup
|
|
162
|
+
userFullName={userProfileParams?.userFullName}
|
|
163
|
+
email={userProfileParams?.email}
|
|
164
|
+
onLogout={userProfileParams?.onLogout}
|
|
165
|
+
onAccountClick={userProfileParams?.onAccountClick}
|
|
166
|
+
profileActions={userProfileParams?.profileActions}
|
|
167
|
+
collapsed={collapsed}
|
|
168
|
+
/>
|
|
169
|
+
</Box>
|
|
170
|
+
</SidebarContainer>
|
|
171
|
+
</motion.div>
|
|
172
|
+
</>
|
|
45
173
|
);
|
|
46
174
|
};
|
|
47
175
|
|
|
48
|
-
const
|
|
49
|
-
width: `${width}px`,
|
|
176
|
+
const SidebarContainer = styled(Stack)(({ theme }: { theme?: any }) => ({
|
|
50
177
|
height: '100%',
|
|
51
|
-
|
|
52
|
-
backgroundColor: theme.palette.background.paper,
|
|
53
|
-
borderRadius: '8px',
|
|
54
|
-
border: `1px solid ${theme.palette.divider}`,
|
|
55
|
-
overflow: 'hidden',
|
|
56
|
-
display: 'flex',
|
|
178
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
57
179
|
flexDirection: 'column',
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
display: 'none',
|
|
61
|
-
},
|
|
180
|
+
overflow: 'hidden',
|
|
181
|
+
borderRight: `1px solid ${theme.palette.divider}`,
|
|
62
182
|
}));
|
|
@@ -48,6 +48,8 @@ export interface MenuItemProps {
|
|
|
48
48
|
currentMenuPath: string | null;
|
|
49
49
|
internalMenuClickHandler: (params: InternalMenuClickHandlerProps) => void;
|
|
50
50
|
onClose?: () => void; // Optional callback to close the drawer
|
|
51
|
+
collapsed?: boolean; // Whether sidebar is collapsed
|
|
52
|
+
setCollapsed?: any;
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
export interface SubMenuItemProps {
|
|
@@ -62,4 +64,6 @@ export interface MenuBarProps {
|
|
|
62
64
|
internalMenuClickHandler: (params: InternalMenuClickHandlerProps) => void;
|
|
63
65
|
previousMenuClickHandler: () => void;
|
|
64
66
|
onClose?: () => void; // Optional callback to close the drawer
|
|
67
|
+
collapsed?: boolean; // Whether sidebar is collapsed
|
|
68
|
+
setCollapsed?: any;
|
|
65
69
|
}
|
|
@@ -30,7 +30,6 @@ export const SidebarContainer = styled(Stack)(({ theme }) => ({
|
|
|
30
30
|
export const MenuBarContainer = styled(Box)(({ theme }) => ({
|
|
31
31
|
flex: 1,
|
|
32
32
|
height: '100%',
|
|
33
|
-
borderRadius: '8px',
|
|
34
33
|
backgroundColor: theme.palette.surface.paperBackground,
|
|
35
34
|
overflowY: 'auto',
|
|
36
35
|
overflowX: 'hidden',
|
|
@@ -64,7 +63,6 @@ export const MenuHeaderContainer = styled(Stack)(({ theme }) => ({
|
|
|
64
63
|
padding: '12px 16px',
|
|
65
64
|
backgroundColor: theme.palette.surface.grey,
|
|
66
65
|
cursor: 'pointer',
|
|
67
|
-
borderRadius: '8px 8px 0px 0px',
|
|
68
66
|
}));
|
|
69
67
|
|
|
70
68
|
// Menu item containers
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Avatar, Stack, Typography, useTheme } from '@mui/material';
|
|
1
|
+
import { Avatar, Box, Stack, Typography, useTheme } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Icons } from '../../../Assets/Icons/Icons';
|
|
4
4
|
import { DropdownMenu } from '../../../Navigation/DropDownMenu/DropDownMenu';
|
|
5
5
|
import { DropdownMenuItem } from '../../../Navigation/DropDownMenu/DropdownMenuItem';
|
|
6
6
|
|
|
7
|
-
interface UserProfilePopupProps {
|
|
7
|
+
export interface UserProfilePopupProps {
|
|
8
8
|
/** User's full name */
|
|
9
9
|
userFullName: string;
|
|
10
|
-
/** User's
|
|
11
|
-
|
|
10
|
+
/** User's email */
|
|
11
|
+
email?: string;
|
|
12
12
|
/** Profile dropdown actions (custom menu items) */
|
|
13
13
|
profileActions?: React.ReactNode[];
|
|
14
14
|
/** Logout click handler */
|
|
@@ -23,6 +23,8 @@ interface UserProfilePopupProps {
|
|
|
23
23
|
onActiveDevicesClick?: () => void;
|
|
24
24
|
/** Account section click handler */
|
|
25
25
|
onAccountClick?: () => void;
|
|
26
|
+
/**Persistant Side bar collapsed - boolean */
|
|
27
|
+
collapsed?: boolean;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const getStartingLetters = (text: string) => {
|
|
@@ -52,8 +54,9 @@ const getStartingLetters = (text: string) => {
|
|
|
52
54
|
* />
|
|
53
55
|
*/
|
|
54
56
|
export const UserProfilePopup: React.FC<UserProfilePopupProps> = ({
|
|
57
|
+
collapsed,
|
|
55
58
|
userFullName,
|
|
56
|
-
|
|
59
|
+
email = '',
|
|
57
60
|
profileActions = [],
|
|
58
61
|
onLogout,
|
|
59
62
|
profileUrl,
|
|
@@ -89,19 +92,46 @@ export const UserProfilePopup: React.FC<UserProfilePopupProps> = ({
|
|
|
89
92
|
return (
|
|
90
93
|
<DropdownMenu
|
|
91
94
|
anchor={({ open }) => (
|
|
92
|
-
<
|
|
93
|
-
src={profileUrl ?? ''}
|
|
94
|
-
onClick={open}
|
|
95
|
+
<Box
|
|
95
96
|
sx={{
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
97
|
+
display: 'flex',
|
|
98
|
+
justifyContent: collapsed ? 'center' : 'space-between',
|
|
99
|
+
borderTop: `1px solid ${theme.palette.border.primary}`,
|
|
100
|
+
padding: 1,
|
|
101
|
+
alignItems: 'center',
|
|
102
|
+
width: collapsed ? '64px' : '250px',
|
|
103
|
+
':hover': {
|
|
104
|
+
background: theme.palette.surface.grey,
|
|
105
|
+
cursor: 'pointer',
|
|
106
|
+
},
|
|
101
107
|
}}
|
|
108
|
+
onClick={open}
|
|
102
109
|
>
|
|
103
|
-
|
|
104
|
-
|
|
110
|
+
<Stack
|
|
111
|
+
direction={'row'}
|
|
112
|
+
gap={1}
|
|
113
|
+
sx={{
|
|
114
|
+
alignItems: 'center',
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
<Avatar
|
|
118
|
+
src={profileUrl ?? ''}
|
|
119
|
+
sx={{
|
|
120
|
+
cursor: 'pointer',
|
|
121
|
+
width: 35,
|
|
122
|
+
height: 35,
|
|
123
|
+
fontSize: '12px',
|
|
124
|
+
background: 'transparent',
|
|
125
|
+
...avatarSx,
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
{getStartingLetters(userFullName)}
|
|
129
|
+
</Avatar>
|
|
130
|
+
{!collapsed && (
|
|
131
|
+
<Typography variant="subtitle3">{userFullName}</Typography>
|
|
132
|
+
)}
|
|
133
|
+
</Stack>
|
|
134
|
+
</Box>
|
|
105
135
|
)}
|
|
106
136
|
menuListProps={{
|
|
107
137
|
sx: {
|
|
@@ -135,7 +165,7 @@ export const UserProfilePopup: React.FC<UserProfilePopupProps> = ({
|
|
|
135
165
|
</Avatar>
|
|
136
166
|
<Stack>
|
|
137
167
|
<Typography variant="subtitle3">{userFullName}</Typography>
|
|
138
|
-
<Typography variant="caption">{
|
|
168
|
+
<Typography variant="caption">{email}</Typography>
|
|
139
169
|
</Stack>
|
|
140
170
|
</Stack>
|
|
141
171
|
<Icons.NavigationIcon />
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { SideMenuItemProps } from './components/Sidebar/interfaces';
|
|
3
|
+
import { UserProfilePopupProps } from './components/UserProfilePopup';
|
|
3
4
|
|
|
4
5
|
export interface HelpDocsAction {
|
|
5
6
|
name: string;
|
|
@@ -20,6 +21,12 @@ export interface AppLayoutProps {
|
|
|
20
21
|
/** Navigation menu items */
|
|
21
22
|
menu: SideMenuItemProps[];
|
|
22
23
|
|
|
24
|
+
/**User profile parameters */
|
|
25
|
+
userProfileParams: UserProfilePopupProps;
|
|
26
|
+
|
|
27
|
+
/** AppBar customization - Primary approach */
|
|
28
|
+
leftSection?: ReactNode;
|
|
29
|
+
|
|
23
30
|
/** AppBar customization - Primary approach */
|
|
24
31
|
rightSection?: ReactNode;
|
|
25
32
|
|
|
@@ -31,4 +38,9 @@ export interface AppLayoutProps {
|
|
|
31
38
|
|
|
32
39
|
/** Help documentation configuration for route-based contextual help */
|
|
33
40
|
helpDocsConfig?: HelpDocsConfig;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Initial collapsed state for persistent sidebar
|
|
44
|
+
*/
|
|
45
|
+
initialCollapsed?: boolean;
|
|
34
46
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
resetStateForUniqueId,
|
|
10
10
|
setViewForUniqueId,
|
|
11
11
|
} from '../../../../../redux/slices/pageHeaderSlice';
|
|
12
|
-
import {
|
|
12
|
+
import { Spinner, Typography } from '../../../../export';
|
|
13
13
|
|
|
14
14
|
export type ViewsProps = {
|
|
15
15
|
type: string;
|
|
@@ -37,7 +37,8 @@ export const ViewTab = ({
|
|
|
37
37
|
return (
|
|
38
38
|
<Stack onClick={onClick} sx={{ cursor: 'pointer' }} minWidth="80px">
|
|
39
39
|
<Stack direction="row" gap={1} alignItems="center" padding="8px 0px">
|
|
40
|
-
|
|
40
|
+
{/* There is not specifix use for this icon & it is repeated for all the views */}
|
|
41
|
+
{/* <Icons.ViewsIcon /> */}
|
|
41
42
|
<Typography variant="subtitle3">{title}</Typography>
|
|
42
43
|
</Stack>
|
|
43
44
|
|
|
@@ -68,7 +68,7 @@ const BreadcrumbContainer = styled(Stack)(({ theme }) => ({
|
|
|
68
68
|
justifyContent: 'space-between',
|
|
69
69
|
height: '52px',
|
|
70
70
|
paddingLeft: '12px',
|
|
71
|
-
backgroundColor: theme.palette.surface.
|
|
71
|
+
backgroundColor: theme.palette.surface.paperBackground,
|
|
72
72
|
[theme.breakpoints.down('md')]: {
|
|
73
73
|
paddingLeft: '0px',
|
|
74
74
|
},
|