@campxdev/react-blueprint 0.1.7 → 0.1.9

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.
@@ -22,7 +22,9 @@ const preview: Preview = {
22
22
  },
23
23
  },
24
24
  },
25
+
25
26
  decorators: [withThemeProvider],
27
+ tags: ["autodocs"]
26
28
  };
27
29
 
28
30
  export default preview;
package/package.json CHANGED
@@ -1,18 +1,19 @@
1
1
  {
2
2
  "name": "@campxdev/react-blueprint",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "main": "./export.ts",
5
5
  "private": false,
6
6
  "dependencies": {
7
7
  "@emotion/react": "^11.11.4",
8
8
  "@emotion/styled": "^11.11.5",
9
- "@mui/icons-material": "^5.15.18",
10
- "@mui/material": "^5.15.18",
9
+ "@mui/icons-material": "^5.14.11",
10
+ "@mui/material": "^5.14.11",
11
11
  "@testing-library/jest-dom": "^5.14.1",
12
12
  "@testing-library/react": "^13.0.0",
13
13
  "@testing-library/user-event": "^13.2.1",
14
14
  "@types/jest": "^27.0.1",
15
15
  "@types/node": "^16.7.13",
16
+ "react-error-boundary": "^3.1.4",
16
17
  "@types/react": "^18.0.0",
17
18
  "@types/react-dom": "^18.0.0",
18
19
  "axios": "^1.7.2",
@@ -30,6 +31,7 @@
30
31
  "build": "react-scripts build",
31
32
  "test": "react-scripts test",
32
33
  "eject": "react-scripts eject",
34
+ "push-package": "npm run build && npm publish",
33
35
  "storybook": "storybook dev -p 6006",
34
36
  "build-storybook": "storybook build"
35
37
  },
@@ -54,21 +56,21 @@
54
56
  },
55
57
  "devDependencies": {
56
58
  "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
57
- "@chromatic-com/storybook": "^1.4.0",
58
- "@storybook/addon-essentials": "^8.1.1",
59
- "@storybook/addon-interactions": "^8.1.1",
60
- "@storybook/addon-links": "^8.1.1",
61
- "@storybook/addon-mdx-gfm": "^8.1.1",
62
- "@storybook/addon-onboarding": "^8.1.1",
63
- "@storybook/blocks": "^8.1.1",
64
- "@storybook/preset-create-react-app": "^8.1.1",
65
- "@storybook/react": "^8.1.1",
66
- "@storybook/react-webpack5": "^8.1.1",
67
- "@storybook/test": "^8.1.1",
68
59
  "@types/js-cookie": "^3.0.5",
60
+ "@chromatic-com/storybook": "^1.4.0",
61
+ "@storybook/addon-essentials": "^8.1.4",
62
+ "@storybook/addon-interactions": "^8.1.4",
63
+ "@storybook/addon-links": "^8.1.4",
64
+ "@storybook/addon-mdx-gfm": "^8.1.4",
65
+ "@storybook/addon-onboarding": "^8.1.4",
66
+ "@storybook/blocks": "^8.1.4",
67
+ "@storybook/preset-create-react-app": "^8.1.4",
68
+ "@storybook/react": "^8.1.4",
69
+ "@storybook/react-webpack5": "^8.1.4",
70
+ "@storybook/test": "^8.1.4",
69
71
  "eslint-plugin-storybook": "^0.8.0",
70
72
  "prop-types": "^15.8.1",
71
- "storybook": "^8.1.1",
73
+ "storybook": "^8.1.4",
72
74
  "webpack": "^5.91.0"
73
75
  }
74
76
  }
package/src/App.tsx CHANGED
@@ -1,11 +1,17 @@
1
1
  import "./App.css";
2
+ import { AppHeader, AppsMenu } from "./components/export";
2
3
  import Providers from "./contexts/Providers";
3
4
 
4
5
  function App() {
5
6
  return (
6
7
  <Providers>
7
8
  {/* <AppHeader clientLogo={""} fullName={""} userBoxActions={[]} /> */}
8
- <></>
9
+ <AppHeader
10
+ appsMenu={<AppsMenu apps={[]} />}
11
+ clientLogo={""}
12
+ fullName={""}
13
+ userBoxActions={[]}
14
+ />
9
15
  </Providers>
10
16
  );
11
17
  }
@@ -191,3 +191,126 @@ export const ClogWheelIcon = () => {
191
191
  </svg>
192
192
  );
193
193
  };
194
+
195
+ export const RightIcon = () => (
196
+ <svg
197
+ xmlns="http://www.w3.org/2000/svg"
198
+ id="vuesax_linear_logout"
199
+ data-name="vuesax/linear/logout"
200
+ width="24"
201
+ height="24"
202
+ viewBox="0 0 24 24"
203
+ >
204
+ <g id="logout">
205
+ <g
206
+ id="Group_5120"
207
+ data-name="Group 5120"
208
+ transform="translate(3.614 9.381)"
209
+ >
210
+ <path
211
+ id="Vector"
212
+ d="M0,5.363,2.682,2.682,0,0"
213
+ transform="translate(8.045)"
214
+ fill="none"
215
+ stroke="#292d32"
216
+ stroke-linecap="round"
217
+ stroke-linejoin="round"
218
+ stroke-width="1.5"
219
+ />
220
+ <path
221
+ id="Vector-2"
222
+ data-name="Vector"
223
+ d="M0,0H10.653"
224
+ transform="translate(0 2.682)"
225
+ fill="none"
226
+ stroke="#292d32"
227
+ stroke-linecap="round"
228
+ stroke-linejoin="round"
229
+ stroke-width="1.5"
230
+ />
231
+ </g>
232
+ <path
233
+ id="Vector-3"
234
+ data-name="Vector"
235
+ d="M0,16.76A8.015,8.015,0,0,0,8.38,8.38,8.015,8.015,0,0,0,0,0"
236
+ transform="translate(12.246 3.62)"
237
+ fill="none"
238
+ stroke="#292d32"
239
+ stroke-linecap="round"
240
+ stroke-linejoin="round"
241
+ stroke-width="1.5"
242
+ />
243
+ <path
244
+ id="Vector-4"
245
+ data-name="Vector"
246
+ d="M0,24H24V0H0Z"
247
+ transform="translate(0 0)"
248
+ fill="none"
249
+ opacity="0"
250
+ />
251
+ </g>
252
+ </svg>
253
+ );
254
+ export const LeftIcon = () => (
255
+ <svg
256
+ xmlns="http://www.w3.org/2000/svg"
257
+ width="24"
258
+ height="24"
259
+ viewBox="0 0 24 24"
260
+ >
261
+ <g
262
+ id="vuesax_linear_logout"
263
+ data-name="vuesax/linear/logout"
264
+ transform="translate(-364 -444)"
265
+ >
266
+ <g id="logout">
267
+ <g
268
+ id="Group_5120"
269
+ data-name="Group 5120"
270
+ transform="translate(373.659 453.381)"
271
+ >
272
+ <path
273
+ id="Vector"
274
+ d="M2.682,5.363,0,2.682,2.682,0"
275
+ transform="translate(0)"
276
+ fill="none"
277
+ stroke="#292d32"
278
+ stroke-linecap="round"
279
+ stroke-linejoin="round"
280
+ stroke-width="1.5"
281
+ />
282
+ <path
283
+ id="Vector-2"
284
+ data-name="Vector"
285
+ d="M10.653,0H0"
286
+ transform="translate(0.073 2.682)"
287
+ fill="none"
288
+ stroke="#292d32"
289
+ stroke-linecap="round"
290
+ stroke-linejoin="round"
291
+ stroke-width="1.5"
292
+ />
293
+ </g>
294
+ <path
295
+ id="Vector-3"
296
+ data-name="Vector"
297
+ d="M8.38,16.76A8.015,8.015,0,0,1,0,8.38,8.015,8.015,0,0,1,8.38,0"
298
+ transform="translate(367.374 447.62)"
299
+ fill="none"
300
+ stroke="#292d32"
301
+ stroke-linecap="round"
302
+ stroke-linejoin="round"
303
+ stroke-width="1.5"
304
+ />
305
+ <path
306
+ id="Vector-4"
307
+ data-name="Vector"
308
+ d="M0,0H24V24H0Z"
309
+ transform="translate(388 468) rotate(180)"
310
+ fill="none"
311
+ opacity="0"
312
+ />
313
+ </g>
314
+ </g>
315
+ </svg>
316
+ );
@@ -5,6 +5,7 @@ import { StyledMenuItem } from "./styles";
5
5
  export type MenuItemButtonProps = {
6
6
  icon?: ReactNode;
7
7
  label: ReactNode;
8
+ sx?: any;
8
9
  onClick: () => void;
9
10
  };
10
11
 
@@ -12,14 +13,10 @@ export const MenuItemButton = ({
12
13
  icon,
13
14
  label,
14
15
  onClick,
15
- ...props
16
+ sx = {},
16
17
  }: MenuItemButtonProps) => {
17
18
  return (
18
- <StyledMenuItem
19
- sx={{ minWidth: "180px", width: "100%" }}
20
- onClick={onClick}
21
- {...props}
22
- >
19
+ <StyledMenuItem sx={sx} onClick={onClick}>
23
20
  {icon && <ListItemIcon>{icon}</ListItemIcon>}
24
21
  <Typography variant="subtitle3">{label}</Typography>
25
22
  </StyledMenuItem>
@@ -19,7 +19,7 @@ export const StyledIconButton = styled(IconButton, {
19
19
  export const StyledMenuItem = styled(MenuItem)(({}) => ({
20
20
  display: "flex",
21
21
  alignItems: "center",
22
- height: "50px",
22
+ padding: "10px 16px",
23
23
  gap: "5px",
24
24
  "& .MuiListItemIcon-root": {
25
25
  minWidth: "24px",
@@ -19,6 +19,10 @@ const meta: Meta<typeof AppHeader> = {
19
19
  control: "text",
20
20
  description: "The full name of the user.",
21
21
  },
22
+ designation: {
23
+ control: "text",
24
+ description: "The Designation of the user.",
25
+ },
22
26
  profileUrl: {
23
27
  control: "text",
24
28
  description: "The URL of the user's profile photo.",
@@ -60,6 +64,7 @@ export const Primary: Story = {
60
64
  args: {
61
65
  clientLogo: "https://via.placeholder.com/150",
62
66
  fullName: "John Doe",
67
+ designation: "Head of the Department",
63
68
  appsMenu: (
64
69
  <AppsMenu
65
70
  apps={[
@@ -78,9 +83,6 @@ export const Primary: Story = {
78
83
  { label: "Action 1", onClick: () => alert("Action 1 clicked") },
79
84
  { label: "Action 2", onClick: () => alert("Action 2 clicked") },
80
85
  ],
81
- headerSx: {
82
- position: "relative",
83
- },
84
86
  },
85
87
  };
86
88
 
@@ -90,14 +92,12 @@ export const WithNoAppsMenu: Story = {
90
92
  args: {
91
93
  clientLogo: "https://via.placeholder.com/150",
92
94
  fullName: "John Doe",
95
+ designation: "Head of the Department",
93
96
  appsMenu: <AppsMenu apps={[]} />,
94
97
  userBoxActions: [
95
98
  { label: "Action 1", onClick: () => alert("Action 1 clicked") },
96
99
  { label: "Action 2", onClick: () => alert("Action 2 clicked") },
97
100
  ],
98
- headerSx: {
99
- position: "relative",
100
- },
101
101
  },
102
102
  };
103
103
 
@@ -107,6 +107,7 @@ export const WithActions: Story = {
107
107
  args: {
108
108
  clientLogo: "https://via.placeholder.com/150",
109
109
  fullName: "John Doe",
110
+ designation: "Head of the Department",
110
111
  appsMenu: (
111
112
  <AppsMenu
112
113
  apps={[
@@ -133,9 +134,6 @@ export const WithActions: Story = {
133
134
  { label: "Action 1", onClick: () => alert("Action 1 clicked") },
134
135
  { label: "Action 2", onClick: () => alert("Action 2 clicked") },
135
136
  ],
136
- headerSx: {
137
- position: "relative",
138
- },
139
137
  },
140
138
  };
141
139
 
@@ -145,6 +143,7 @@ export const WithCustomHeaderActions: Story = {
145
143
  args: {
146
144
  clientLogo: "https://via.placeholder.com/150",
147
145
  fullName: "John Doe",
146
+ designation: "Head of the Department",
148
147
  appsMenu: (
149
148
  <AppsMenu
150
149
  apps={[
@@ -164,9 +163,6 @@ export const WithCustomHeaderActions: Story = {
164
163
  { label: "Action 1", onClick: () => alert("Action 1 clicked") },
165
164
  { label: "Action 2", onClick: () => alert("Action 2 clicked") },
166
165
  ],
167
- headerSx: {
168
- position: "relative",
169
- },
170
166
  },
171
167
  };
172
168
 
@@ -176,6 +172,7 @@ export const WithClogWheel: Story = {
176
172
  args: {
177
173
  clientLogo: "https://via.placeholder.com/150",
178
174
  fullName: "John Doe",
175
+ designation: "Head of the Department",
179
176
  appsMenu: (
180
177
  <AppsMenu
181
178
  apps={[
@@ -15,6 +15,7 @@ export interface AppHeaderProps {
15
15
  cogWheelMenu?: ReactNode[];
16
16
  customHeaderActions?: ReactNode;
17
17
  fullName: string;
18
+ designation?: string;
18
19
  profileUrl?: string;
19
20
  userBoxActions: {
20
21
  label: ReactNode;
@@ -31,6 +32,7 @@ export const AppHeader = ({
31
32
  actions = [],
32
33
  appsMenu,
33
34
  clientLogo,
35
+ designation,
34
36
  cogWheelMenu = [],
35
37
  customHeaderActions,
36
38
  fullName,
@@ -55,6 +57,7 @@ export const AppHeader = ({
55
57
  <HeaderActions
56
58
  cogWheelMenu={cogWheelMenu}
57
59
  fullName={fullName}
60
+ designation={designation}
58
61
  userBoxActions={userBoxActions}
59
62
  profileUrl={profileUrl}
60
63
  actions={actions}
@@ -8,12 +8,14 @@ import { DropDownMenu } from "../../../DropDownMenu/DropDownMenu";
8
8
  const CogWheelMenu = ({ menu }: { menu: ReactNode[] }) => {
9
9
  return (
10
10
  <>
11
- <Divider
12
- orientation="vertical"
13
- variant="middle"
14
- flexItem
15
- sx={{ height: "20px" }}
16
- />
11
+ <div>
12
+ <Divider
13
+ orientation="vertical"
14
+ variant="middle"
15
+ flexItem
16
+ sx={{ height: "20px" }}
17
+ />
18
+ </div>
17
19
 
18
20
  <DropDownMenu
19
21
  anchor={({ open }) => (
@@ -9,6 +9,7 @@ import UserBox from "./UserBox";
9
9
  export interface HeaderActionsProps {
10
10
  cogWheelMenu: ReactNode[];
11
11
  fullName: string;
12
+ designation?: string;
12
13
  userBoxActions: {
13
14
  label: ReactNode;
14
15
  icon?: ReactNode;
@@ -22,40 +23,42 @@ export interface HeaderActionsProps {
22
23
  const HeaderActions = ({
23
24
  cogWheelMenu,
24
25
  fullName,
26
+ designation,
25
27
  userBoxActions,
26
28
  profileUrl = "",
27
29
  actions = [],
28
30
  profileSx = {},
29
31
  }: HeaderActionsProps) => {
30
32
  return (
31
- <Stack direction="row" gap={6}>
32
- <Stack direction="row" gap={1}>
33
- <IconButton
34
- href={"https://campx.atlassian.net/servicedesk/customer/portal/2"}
35
- target="_blank"
36
- >
37
- <HelpIcon />
38
- </IconButton>
33
+ <Stack direction="row" gap={1} alignItems={"center"}>
34
+ <IconButton
35
+ href={"https://campx.atlassian.net/servicedesk/customer/portal/2"}
36
+ target="_blank"
37
+ >
38
+ <HelpIcon />
39
+ </IconButton>
39
40
 
40
- {actions.map((action, index) => (
41
- <>
41
+ {actions.map((action, index) => (
42
+ <>
43
+ <div>
42
44
  <Divider
43
45
  orientation="vertical"
44
46
  variant="middle"
45
47
  flexItem
46
- sx={{ height: "25px" }}
48
+ sx={{ height: "20px" }}
47
49
  />
48
- {action}
49
- </>
50
- ))}
51
- {cogWheelMenu?.length ? <CogWheelMenu menu={cogWheelMenu} /> : null}
52
- <UserBox
53
- fullName={fullName}
54
- actions={userBoxActions}
55
- profileUrl={profileUrl}
56
- profileSx={profileSx}
57
- />
58
- </Stack>
50
+ </div>
51
+ {action}
52
+ </>
53
+ ))}
54
+ {cogWheelMenu?.length ? <CogWheelMenu menu={cogWheelMenu} /> : null}
55
+ <UserBox
56
+ fullName={fullName}
57
+ designation={designation}
58
+ actions={userBoxActions}
59
+ profileUrl={profileUrl}
60
+ profileSx={profileSx}
61
+ />
59
62
  </Stack>
60
63
  );
61
64
  };
@@ -1,6 +1,8 @@
1
+ import { Stack, Typography } from "@mui/material";
1
2
  import { ReactNode } from "react";
2
3
  import { DropDownMenu } from "../../../DropDownMenu/DropDownMenu";
3
- import { StyledAvatar } from "../styles/styles";
4
+ import { MenuItemButton } from "../../../DropDownMenu/MenuItemButton";
5
+ import { StyledAvatar, StyledTypography } from "../styles/styles";
4
6
  // import {
5
7
  // activeDevices,
6
8
  // changePassword,
@@ -26,11 +28,13 @@ const getStartingLetters = (text: string) => {
26
28
 
27
29
  export default function UserBox({
28
30
  fullName,
31
+ designation = "",
29
32
  actions,
30
33
  profileUrl,
31
34
  profileSx = {},
32
35
  }: {
33
36
  fullName: string;
37
+ designation?: string;
34
38
  actions: {
35
39
  label: ReactNode;
36
40
  icon?: ReactNode;
@@ -47,71 +51,42 @@ export default function UserBox({
47
51
  {getStartingLetters(fullName)}
48
52
  </StyledAvatar>
49
53
  )}
50
- menu={[]} // menu={
51
- // customActions?.length
52
- // ? customActions
53
- // : [
54
- // ...actions,
55
- // {
56
- // label: "My Profile",
57
- // actionType: "dialog",
58
- // icon: (
59
- // <img style={{ marginRight: "10px" }} src={profile.default} />
60
- // ),
61
- // content: ({ close }) => <MyProfile close={close} />,
62
- // dialogProps: {
63
- // maxWidth: "xl",
64
- // PaperProps: {
65
- // sx: {
66
- // padding: 0,
67
- // },
68
- // },
69
- // },
70
- // },
71
- // {
72
- // label: "Active Devices",
73
- // actionType: "dialog",
74
- // icon: (
75
- // <img
76
- // style={{ marginRight: "10px" }}
77
- // src={activeDevices.default}
78
- // />
79
- // ),
80
- // content: ({ close }) => <ActiveDevices close={close} />,
81
- // contentTitle: "Active Devices",
82
- // dialogProps: {
83
- // maxWidth: "lg",
84
- // PaperProps: {
85
- // sx: {
86
- // padding: 0,
87
- // },
88
- // },
89
- // },
90
- // },
91
- // {
92
- // label: "Change Password",
93
- // actionType: "dialog",
94
- // icon: (
95
- // <img
96
- // style={{ marginRight: "10px" }}
97
- // src={changePassword.default}
98
- // />
99
- // ),
100
- // content: ({ close }) => <ChangePassword close={close} />,
101
- // contentTitle: "Change Password",
102
- // },
103
- // {
104
- // label: "Logout",
105
- // icon: (
106
- // <img
107
- // style={{ marginRight: "10px" }}
108
- // src={logoutIcon.default}
109
- // />
110
- // ),
111
- // onClick: logout,
112
- // },
113
- // ]
114
- // }
54
+ menu={[
55
+ <MenuItemButton
56
+ label={
57
+ <Stack gap={0.5}>
58
+ <StyledTypography variant="subtitle3">Account</StyledTypography>
59
+ <Stack direction={"row"} gap={1}>
60
+ <StyledAvatar src={profileUrl ?? ""} sx={profileSx}>
61
+ {getStartingLetters(fullName)}
62
+ </StyledAvatar>
63
+ <Stack>
64
+ <Typography variant="subtitle3">{fullName}</Typography>
65
+ <Typography variant="caption">{designation}</Typography>
66
+ </Stack>
67
+ </Stack>
68
+ </Stack>
69
+ }
70
+ onClick={function (): void {
71
+ throw new Error("Function not implemented.");
72
+ }}
73
+ />,
74
+ <MenuItemButton
75
+ label={
76
+ <Stack gap={0.5}>
77
+ <Typography variant="subtitle3">Account</Typography>
78
+ <Stack>
79
+ <StyledAvatar src={profileUrl ?? ""} sx={profileSx}>
80
+ {getStartingLetters(fullName)}
81
+ </StyledAvatar>
82
+ </Stack>
83
+ </Stack>
84
+ }
85
+ onClick={function (): void {
86
+ throw new Error("Function not implemented.");
87
+ }}
88
+ />,
89
+ ]}
115
90
  />
116
91
  );
117
92
  }
@@ -1,4 +1,4 @@
1
- import { Avatar, Box, styled } from "@mui/material";
1
+ import { Avatar, Box, Typography, styled } from "@mui/material";
2
2
  import { Link } from "react-router-dom";
3
3
 
4
4
  export const StyledContainer = styled(Box)(({ theme }) => ({
@@ -8,15 +8,7 @@ export const StyledContainer = styled(Box)(({ theme }) => ({
8
8
  justifyContent: "space-between",
9
9
  height: "60px",
10
10
  margin: "auto",
11
- "@media (min-width: 768px)": {
12
- width: "770px",
13
- },
14
- "@media (min-width: 1024px)": {
15
- width: "1025px",
16
- },
17
- "@media (min-width: 1200px)": {
18
- width: "1280px",
19
- },
11
+ width: "90%",
20
12
  }));
21
13
 
22
14
  export const StyledHeader = styled("header")(({ theme }) => ({
@@ -62,8 +54,16 @@ export const StyledImageWrapper = styled(Box)(() => ({
62
54
  }));
63
55
 
64
56
  export const StyledAvatar = styled(Avatar)(({ theme }) => ({
65
- // background: theme.palette.secondary.main,
66
- // cursor: "pointer",
67
- // height: "45px",
68
- // width: "45px",
57
+ background: theme.palette.background.default,
58
+ cursor: "pointer",
59
+ height: "42px",
60
+ width: "42px",
61
+ border: `1px solid ${theme.palette.primary.main}`,
62
+ fontSize: "1rem",
63
+ fontWeight: "600",
64
+ color: theme.palette.primary.main,
65
+ }));
66
+
67
+ export const StyledTypography = styled(Typography)(({ theme }) => ({
68
+ color: theme.palette.text.secondary,
69
69
  }));
@@ -0,0 +1,30 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { LayoutWrapper, LayoutWrapperProps } from "./LayoutWrapper";
3
+
4
+ // Define the default export with Meta type including the component type
5
+ const meta: Meta<typeof LayoutWrapper> = {
6
+ title: "Layout/LayoutWrapper",
7
+ component: LayoutWrapper,
8
+ tags: ["autodocs"],
9
+ // argTypes: {
10
+ // menu: {
11
+ // control: "object",
12
+ // description: "Menu items to be displayed in the side navigation.",
13
+ // },
14
+ // },
15
+ };
16
+
17
+ export default meta;
18
+ type Story = StoryObj<typeof LayoutWrapper>;
19
+
20
+ // Primary story
21
+ export const Primary: Story = {
22
+ render: (args: LayoutWrapperProps) => <LayoutWrapper {...args} />,
23
+ args: {
24
+ menu: [
25
+ { name: "Home", path: "/home" },
26
+ { name: "Item 2", path: "/item2" },
27
+ ],
28
+ children: <>hi</>,
29
+ },
30
+ };
@@ -0,0 +1,67 @@
1
+ import { Box, IconButton, Toolbar, Typography } from "@mui/material";
2
+
3
+ import MenuIcon from "@mui/icons-material/Menu";
4
+ import { useState } from "react";
5
+ import { LeftIcon, RightIcon } from "../../../assets/images/icons";
6
+ import { SideNavigation } from "../SideNavigation/SideNavigation";
7
+
8
+ export interface LayoutWrapperProps {
9
+ title?: string;
10
+ children: React.ReactNode;
11
+ showIcon?: boolean;
12
+ menu?: any;
13
+ }
14
+ export const LayoutWrapper = ({
15
+ children,
16
+ title,
17
+ showIcon = true,
18
+ menu,
19
+ }: LayoutWrapperProps) => {
20
+ const [open, setOpen] = useState<boolean>(
21
+ window.innerWidth > 1024 ? true : false
22
+ );
23
+ const [isHovered, setIsHovered] = useState<boolean>(false);
24
+
25
+ const [active, setActive] = useState(0);
26
+
27
+ const handleDrawer = () => {
28
+ setOpen(!open);
29
+ };
30
+
31
+ return (
32
+ <Box width={"100%"}>
33
+ <Toolbar sx={{ paddingLeft: "0px !important" }}>
34
+ {showIcon && (
35
+ <IconButton
36
+ color="inherit"
37
+ aria-label="open drawer"
38
+ onClick={handleDrawer}
39
+ edge="start"
40
+ sx={{ mr: 0.5 }}
41
+ onMouseEnter={() => setIsHovered(true)}
42
+ onMouseLeave={() => setIsHovered(false)}
43
+ >
44
+ {open && isHovered ? (
45
+ <LeftIcon />
46
+ ) : !open && isHovered ? (
47
+ <RightIcon />
48
+ ) : (
49
+ <MenuIcon />
50
+ )}
51
+ </IconButton>
52
+ )}
53
+ <Typography variant="subtitle1" noWrap>
54
+ {title ? title : menu[active].name}
55
+ </Typography>
56
+ </Toolbar>
57
+
58
+ <SideNavigation
59
+ menu={menu}
60
+ children={children}
61
+ open={open}
62
+ handleDrawer={handleDrawer}
63
+ setActive={setActive}
64
+ />
65
+ </Box>
66
+ );
67
+ };
@@ -0,0 +1,30 @@
1
+ import React from "react";
2
+ import { Meta, StoryObj } from "@storybook/react";
3
+ import { SideNavigation, SideNavigationProps } from "./SideNavigation";
4
+
5
+ // Define the default export with Meta type including the component type
6
+ const meta: Meta<typeof SideNavigation> = {
7
+ title: "Layout/SideNavigation",
8
+ component: SideNavigation,
9
+ tags: ["autodocs"],
10
+ argTypes: {
11
+ menu: {
12
+ control: "object",
13
+ description: "Menu items to be displayed in the side navigation.",
14
+ },
15
+ },
16
+ };
17
+
18
+ export default meta;
19
+ type Story = StoryObj<typeof SideNavigation>;
20
+
21
+ // Primary story
22
+ export const Primary: Story = {
23
+ render: (args: SideNavigationProps) => <SideNavigation {...args} />,
24
+ args: {
25
+ menu: [
26
+ { label: "Item 1", path: "/" },
27
+ { label: "Item 2", path: "/item2" },
28
+ ],
29
+ },
30
+ };
@@ -0,0 +1,112 @@
1
+ import { Box, ListItemIcon, ListItemText, Stack } from "@mui/material";
2
+ import { useMatch, useResolvedPath } from "react-router-dom";
3
+ import { Typography } from "../../Typography/Typography";
4
+ import {
5
+ Main,
6
+ StyledDrawer,
7
+ StyledLinkButton,
8
+ StyledList,
9
+ StyledListItem,
10
+ StyledListItemButton,
11
+ } from "./styles/styles";
12
+
13
+ export interface SideNavigationProps {
14
+ menu?: any;
15
+ children: React.ReactNode;
16
+ open?: any;
17
+ handleDrawer?: any;
18
+ setActive: any;
19
+ }
20
+
21
+ export interface MenuItemProps {
22
+ menuItem: {
23
+ name: string;
24
+ path: string;
25
+ icon: any;
26
+ permissionKey: string;
27
+ iconType: string;
28
+ };
29
+ index: number;
30
+ setActive: any;
31
+ }
32
+
33
+ export const SideNavigation = ({
34
+ menu,
35
+ children,
36
+ open,
37
+ handleDrawer,
38
+ setActive,
39
+ }: SideNavigationProps) => {
40
+ return (
41
+ <Stack gap="20px" direction={"row"}>
42
+ <StyledDrawer
43
+ variant={window.innerWidth > 1024 ? "persistent" : "temporary"}
44
+ anchor="left"
45
+ open={open}
46
+ onClose={handleDrawer}
47
+ >
48
+ <StyledList>
49
+ {menu?.map((item: any, index: number) => (
50
+ <MenuItem
51
+ menuItem={item}
52
+ index={index}
53
+ key={index}
54
+ setActive={setActive}
55
+ />
56
+ ))}
57
+ </StyledList>
58
+ </StyledDrawer>
59
+ <Main open={open}>{children}</Main>
60
+ </Stack>
61
+ );
62
+ };
63
+
64
+ const MenuItem = ({ menuItem, index, setActive }: MenuItemProps) => {
65
+ const { path, icon: Icon, name, permissionKey, iconType } = menuItem;
66
+
67
+ let resolved = useResolvedPath(path);
68
+ // const permissions = PermissionsStore.useState((s) => s).permissions
69
+ let match = useMatch({ path: resolved.pathname, end: false });
70
+
71
+ // const hasAccess = permissionKey ? permissions[permissionKey] : accessIfNoKey
72
+
73
+ // if (!hasAccess) return null
74
+
75
+ return (
76
+ <StyledListItem key={path} disablePadding match={match}>
77
+ <StyledLinkButton
78
+ to={path}
79
+ style={{ width: "100%" }}
80
+ onClick={() => setActive(index)}
81
+ >
82
+ <StyledListItemButton>
83
+ <ListItemIcon
84
+ sx={{
85
+ minWidth: "16px",
86
+ marginRight: "8px",
87
+ }}
88
+ >
89
+ <Box
90
+ sx={{
91
+ minWidth: "16px",
92
+ marginRight: "8px",
93
+ display: "flex",
94
+ alignItems: "center",
95
+ justifyContent: "center",
96
+ }}
97
+ >
98
+ {/* <GetSidenavIconByType
99
+ iconType={iconType}
100
+ color={match ? '#323167' : '#000'}
101
+ /> */}
102
+ {/* {getSidenavIconByType(iconType, 'red')} */}
103
+ </Box>
104
+ </ListItemIcon>
105
+ <ListItemText
106
+ primary={<Typography variant="subtitle3">{name}</Typography>}
107
+ />
108
+ </StyledListItemButton>
109
+ </StyledLinkButton>
110
+ </StyledListItem>
111
+ );
112
+ };
@@ -0,0 +1,84 @@
1
+ import { Drawer, List, ListItem, ListItemButton, styled } from "@mui/material";
2
+ import { Link } from "react-router-dom";
3
+ const drawerWidth: number = 240;
4
+
5
+ export const StyledDrawer = styled(Drawer)(() => ({
6
+ width: drawerWidth,
7
+ flexShrink: 0,
8
+ "& .MuiDrawer-paper": {
9
+ width: drawerWidth,
10
+ boxSizing: "border-box",
11
+ position: "unset",
12
+ transition: "none !important",
13
+ borderRight: "none !important",
14
+ borderRadius: "5px",
15
+ },
16
+ "@media (max-width: 1024px)": {
17
+ "& .MuiDrawer-paper": {
18
+ borderRadius: "0px",
19
+ },
20
+ },
21
+ }));
22
+
23
+ export const StyledList = styled(List)(({ theme }) => ({
24
+ backgroundColor: theme.palette.background.paper,
25
+ height: "calc(100vh - 120px)",
26
+ paddingTop: "20px",
27
+ }));
28
+
29
+ interface StyledListItemProps {
30
+ match: any;
31
+ }
32
+
33
+ export const StyledListItem = styled(ListItem)<StyledListItemProps>(
34
+ ({ theme, match }) => ({
35
+ backgroundColor: match ? theme.palette.secondary.main : "none",
36
+ })
37
+ );
38
+ export const StyledListItemButton = styled(ListItemButton)(() => ({
39
+ alignItems: "center",
40
+ display: "flex",
41
+ paddingBottom: "4px",
42
+ paddingTop: "4px",
43
+ }));
44
+
45
+ export const StyledLinkButton = styled(Link)({
46
+ textDecoration: "none",
47
+ });
48
+
49
+ export const Main = styled("main", {
50
+ shouldForwardProp: (prop) => prop !== "open",
51
+ })<{
52
+ open?: boolean;
53
+ }>(({ theme, open }) => ({
54
+ padding: "25px",
55
+ transition: theme.transitions.create("margin", {
56
+ easing: theme.transitions.easing.sharp,
57
+ duration: theme.transitions.duration.leavingScreen,
58
+ }),
59
+ marginLeft: `-${drawerWidth}px`,
60
+ ...(open && {
61
+ transition: theme.transitions.create("margin", {
62
+ easing: theme.transitions.easing.easeOut,
63
+ duration: theme.transitions.duration.enteringScreen,
64
+ }),
65
+ marginLeft: 0,
66
+ }),
67
+ width: "100%",
68
+ height: "calc(100vh - 120px)",
69
+ overflowY: "auto",
70
+ backgroundColor: theme.palette.background.paper,
71
+ borderRadius: "5px",
72
+ "&::-webkit-scrollbar": {
73
+ width: "0.4em",
74
+ height: "0.4em",
75
+ },
76
+
77
+ "&::-webkit-scrollbar-thumb": {
78
+ backgroundColor: "rgba(0, 0, 0, 0.2)",
79
+ borderRadius: "3px",
80
+ },
81
+ "@media (max-width: 1024px)": {
82
+ marginLeft: 0,
83
+ },
84
+ }));
@@ -1,4 +1,4 @@
1
- import { Box, Button } from "@mui/material";
1
+ import { Box, Button, Typography } from "@mui/material";
2
2
  import { Meta, StoryObj } from "@storybook/react/*";
3
3
  import DialogButton, { DialogButtonProps } from "./DialogButton";
4
4
 
@@ -94,12 +94,7 @@ export const WithMaxWidthMd: Story = {
94
94
  ),
95
95
  content: ({ close }: { close: (e: any) => void }) => (
96
96
  <>
97
- <Box
98
- sx={{
99
- height: "500px",
100
- width: "100px",
101
- }}
102
- ></Box>
97
+ <Typography> Hello</Typography>
103
98
  </>
104
99
  ),
105
100
  dialogProps: {
@@ -7,3 +7,4 @@ export * from "./Input/TextField/TextField";
7
7
  export * from "./Layout/Header/AppHeader";
8
8
  export * from "./Layout/Header/AppLogo";
9
9
  export * from "./Layout/Header/AppsMenu";
10
+ export * from "./Layout/LayoutWrapper/LayoutWrapper";
@@ -75,6 +75,7 @@ export const getCommonTheme = (mode: Theme) => {
75
75
  padding: 0,
76
76
  "& li": {
77
77
  borderBottom: "1212121A",
78
+ minHeight: "55px",
78
79
  ":hover": {
79
80
  backgroundColor: "rgba(0, 0, 0, 0.025)",
80
81
  },