@campxdev/react-blueprint 1.1.2 → 1.1.4

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.
@@ -1,3 +1,3 @@
1
1
  {
2
- "cSpell.words": ["autodocs"]
2
+ "cSpell.words": ["autodocs", "Campx"]
3
3
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@campxdev/react-blueprint",
3
- "version": "1.1.2",
3
+ "version": "1.1.4",
4
4
  "main": "./export.ts",
5
5
  "private": false,
6
6
  "dependencies": {
package/src/App.tsx CHANGED
@@ -1,5 +1,10 @@
1
1
  import "./App.css";
2
- import { AppHeader, Button, UnAuthorized } from "./components/export";
2
+ import {
3
+ AppHeader,
4
+ Button,
5
+ SearchBar,
6
+ UnAuthorized,
7
+ } from "./components/export";
3
8
  import Providers from "./contexts/Providers";
4
9
 
5
10
  function App() {
@@ -19,6 +24,7 @@ function App() {
19
24
  </Button>
20
25
  }
21
26
  />
27
+ <SearchBar onSearch={() => {}} value={""} placeholder="Search by Name" />
22
28
  </Providers>
23
29
  );
24
30
  }
@@ -0,0 +1,22 @@
1
+ import { useTheme } from "@mui/material";
2
+
3
+ export const ArrowBackIcon = ({ size = 16 }) => {
4
+ const theme = useTheme();
5
+ const color = theme.palette.text.primary;
6
+
7
+ return (
8
+ <svg
9
+ width={size}
10
+ height={size}
11
+ viewBox="0 0 16 17"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ >
14
+ <path
15
+ d="M1.06696 7.4994L1.06698 7.50248C1.06829 7.68471 1.13715 7.85967 1.25971 7.99374L1.26442 8.00159L1.28182 8.01899L7.14849 13.8857L7.14851 13.8857C7.28603 14.0232 7.47252 14.1004 7.66698 14.1004C7.86143 14.1004 8.04792 14.0232 8.18544 13.8857L8.18549 13.8856C8.32296 13.7481 8.4002 13.5616 8.4002 13.3672C8.4002 13.1727 8.32296 12.9862 8.18549 12.8487L8.18546 12.8487L2.83782 7.50104L8.18492 2.15447L8.18495 2.15444C8.32243 2.01692 8.39966 1.83043 8.39966 1.63597C8.39966 1.44152 8.32243 1.25502 8.18495 1.1175L8.18491 1.11746C8.04739 0.979983 7.8609 0.902753 7.66644 0.902753C7.47199 0.902753 7.2855 0.979983 7.14798 1.11746L7.14795 1.11748L1.28129 6.98415L1.25834 7.0071L1.25355 7.01668C1.13502 7.14927 1.06844 7.32079 1.06696 7.4994Z"
16
+ stroke="#121212"
17
+ stroke-width="0.4"
18
+ fill={color}
19
+ />
20
+ </svg>
21
+ );
22
+ };
@@ -0,0 +1,22 @@
1
+ import { useTheme } from "@mui/material";
2
+
3
+ export const CollapseIcon = ({ size = 16 }) => {
4
+ const theme = useTheme();
5
+ const color = theme.palette.text.primary;
6
+
7
+ return (
8
+ <svg
9
+ width={size}
10
+ height={size}
11
+ viewBox="0 0 16 16"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ >
14
+ <path
15
+ d="M2.38873 7.31504L2.38918 7.31504L13.6116 7.31504H13.612V7.31504C13.7938 7.31586 13.9678 7.38842 14.0963 7.51693C14.2249 7.64545 14.2974 7.81951 14.2982 8.00125L14.2982 8.00216C14.2974 8.1839 14.2249 8.35796 14.0963 8.48648C13.9678 8.61499 13.7938 8.68755 13.612 8.68837L13.6116 8.68837L2.38758 8.68837H2.38685C2.20544 8.68706 2.03185 8.61428 1.90374 8.48582M2.38873 7.31504L1.90374 8.48582M2.38873 7.31504C2.20698 7.31586 2.03292 7.38842 1.9044 7.51693C1.77589 7.64545 1.70333 7.81951 1.70251 8.00125L1.70251 8.00216M2.38873 7.31504L1.70251 8.00216M1.90374 8.48582C1.77563 8.35736 1.70333 8.18358 1.70251 8.00216M1.90374 8.48582L1.70251 8.00216"
16
+ fill={color}
17
+ stroke="#121212"
18
+ stroke-width="0.2"
19
+ />
20
+ </svg>
21
+ );
22
+ };
@@ -0,0 +1,28 @@
1
+ import { useTheme } from "@mui/material";
2
+
3
+ export const ExpandIcon = ({ size = 16 }) => {
4
+ const theme = useTheme();
5
+ const color = theme.palette.text.primary;
6
+
7
+ return (
8
+ <svg
9
+ width={size}
10
+ height={size}
11
+ viewBox="0 0 16 16"
12
+ xmlns="http://www.w3.org/2000/svg"
13
+ >
14
+ <path
15
+ d="M7.31406 13.6108L7.31406 13.6113C7.31488 13.793 7.38744 13.9671 7.51596 14.0956C7.64447 14.2241 7.81854 14.2967 8.00028 14.2975L8.00118 14.2975C8.1826 14.2967 8.35638 14.2244 8.48484 14.0963C8.6133 13.9682 8.68608 13.7946 8.6874 13.6131V13.6124L8.6874 2.38842L8.68739 2.38797C8.68657 2.20623 8.61401 2.03217 8.4855 1.90365C8.35699 1.77514 8.18292 1.70258 8.00118 1.70175L8.00028 1.70176C7.81854 1.70258 7.64447 1.77514 7.51596 1.90365C7.38744 2.03217 7.31488 2.20623 7.31406 2.38797H7.31406V2.38842L7.31406 13.6108Z"
16
+ fill={color}
17
+ stroke="#121212"
18
+ stroke-width="0.2"
19
+ />
20
+ <path
21
+ d="M2.38873 7.31504L2.38918 7.31504L13.6116 7.31504H13.612V7.31504C13.7938 7.31586 13.9678 7.38842 14.0963 7.51693C14.2249 7.64545 14.2974 7.81951 14.2982 8.00125L14.2982 8.00216C14.2974 8.1839 14.2249 8.35796 14.0963 8.48648C13.9678 8.61499 13.7938 8.68755 13.612 8.68837L13.6116 8.68837L2.38758 8.68837H2.38685C2.20544 8.68706 2.03185 8.61428 1.90374 8.48582M2.38873 7.31504L1.90374 8.48582M2.38873 7.31504C2.20698 7.31586 2.03292 7.38842 1.9044 7.51693C1.77589 7.64545 1.70333 7.81951 1.70251 8.00125L1.70251 8.00216M2.38873 7.31504L1.70251 8.00216M1.90374 8.48582C1.77563 8.35736 1.70333 8.18358 1.70251 8.00216M1.90374 8.48582L1.70251 8.00216"
22
+ fill={color}
23
+ stroke="#121212"
24
+ stroke-width="0.2"
25
+ />
26
+ </svg>
27
+ );
28
+ };
@@ -0,0 +1,29 @@
1
+ import { useTheme } from "@mui/material";
2
+
3
+ export const RedoIcon = ({ size = 16 }) => {
4
+ const theme = useTheme();
5
+ const color = theme.palette.text.primary;
6
+
7
+ return (
8
+ <svg
9
+ width={size}
10
+ height={size}
11
+ viewBox={`0 0 20 20`}
12
+ fill="none"
13
+ xmlns="http://www.w3.org/2000/svg"
14
+ >
15
+ <path
16
+ d="M12.612 4.01719H5.94531C5.75303 4.01719 5.56862 4.09357 5.43266 4.22954C5.2967 4.3655 5.22031 4.54991 5.22031 4.74219C5.22031 4.93447 5.2967 5.11888 5.43266 5.25484C5.56862 5.3908 5.75303 5.46719 5.94531 5.46719H12.612C13.5248 5.46719 14.4002 5.82979 15.0456 6.47523C15.691 7.12067 16.0536 7.99607 16.0536 8.90885C16.0536 9.82164 15.691 10.697 15.0456 11.3425C14.4002 11.9879 13.5248 12.3505 12.612 12.3505H3.44531C3.25303 12.3505 3.06862 12.4269 2.93266 12.5629C2.7967 12.6988 2.72031 12.8832 2.72031 13.0755C2.72031 13.2678 2.7967 13.4522 2.93266 13.5882C3.06862 13.7241 3.25303 13.8005 3.44531 13.8005H12.612C13.9093 13.8005 15.1535 13.2851 16.0709 12.3678C16.9883 11.4504 17.5036 10.2062 17.5036 8.90885C17.5036 7.6115 16.9883 6.36729 16.0709 5.44992C15.1535 4.53256 13.9093 4.01719 12.612 4.01719Z"
17
+ fill={color}
18
+ stroke="#323167"
19
+ stroke-width="0.2"
20
+ />
21
+ <path
22
+ d="M5.35888 10.2672C5.26348 10.2668 5.16895 10.2854 5.08082 10.3219C4.99263 10.3584 4.91261 10.4122 4.84543 10.48C4.84537 10.4801 4.84531 10.4801 4.84524 10.4802L2.71227 12.6131L2.71185 12.6136C2.57712 12.7499 2.50156 12.9339 2.50156 13.1255C2.50156 13.3172 2.57712 13.5012 2.71185 13.6375L2.71227 13.6379L4.845 15.7706C4.91172 15.8396 4.99146 15.8946 5.07961 15.9325C5.16804 15.9706 5.26317 15.9906 5.35943 15.9915C5.4557 15.9924 5.55117 15.9741 5.64029 15.9377C5.7294 15.9013 5.81038 15.8475 5.87848 15.7794C5.94659 15.7114 6.00046 15.6305 6.03695 15.5414C6.07345 15.4523 6.09184 15.3569 6.09105 15.2606C6.09026 15.1643 6.0703 15.0692 6.03235 14.9807C5.99451 14.8925 5.93953 14.8127 5.87061 14.7459L4.25024 13.1255L5.87119 11.5046L5.87161 11.5042C6.00634 11.3678 6.0819 11.1839 6.0819 10.9922C6.0819 10.8005 6.00634 10.6166 5.87161 10.4802L5.87155 10.4802C5.80445 10.4124 5.72452 10.3586 5.63643 10.3221C5.54846 10.2856 5.45412 10.2669 5.35888 10.2672ZM5.35888 10.2672C5.35902 10.2672 5.35916 10.2672 5.35931 10.2672L5.35881 10.3672L5.35846 10.2672C5.3586 10.2672 5.35874 10.2672 5.35888 10.2672Z"
23
+ fill={color}
24
+ stroke="#323167"
25
+ stroke-width="0.2"
26
+ />
27
+ </svg>
28
+ );
29
+ };
@@ -0,0 +1,27 @@
1
+ import { useTheme } from "@mui/material";
2
+
3
+ export const SearchIcon = ({ size = 16 }) => {
4
+ const theme = useTheme();
5
+ const color = theme.palette.text.primary;
6
+ return (
7
+ <svg
8
+ width={size}
9
+ height={size}
10
+ viewBox="0 0 16 16"
11
+ fill="none"
12
+ style={{
13
+ stroke: color,
14
+ }}
15
+ xmlns="http://www.w3.org/2000/svg"
16
+ >
17
+ <path
18
+ d="M7.67007 14.5031C6.31847 14.5032 4.99719 14.1025 3.87333 13.3517C2.74947 12.6008 1.8735 11.5336 1.35622 10.2849C0.838934 9.03619 0.703561 7.66214 0.96722 6.3365C1.23088 5.01086 1.88173 3.79318 2.83746 2.83746C3.79318 1.88173 5.01086 1.23088 6.3365 0.96722C7.66214 0.703561 9.03619 0.838934 10.2849 1.35622C11.5336 1.8735 12.6008 2.74947 13.3517 3.87333C14.1025 4.99719 14.5032 6.31847 14.5031 7.67007C14.5006 9.48154 13.7799 11.2181 12.499 12.499C11.2181 13.7799 9.48154 14.5006 7.67007 14.5031ZM7.67007 1.83647C6.51643 1.83647 5.38868 2.17856 4.42945 2.81949C3.47022 3.46041 2.72258 4.37138 2.28107 5.4372C1.83957 6.50302 1.72402 7.67583 1.94905 8.80732C2.17408 9.93881 2.72957 10.9782 3.54528 11.794C4.361 12.6097 5.4003 13.1653 6.53177 13.3905C7.66324 13.6156 8.83606 13.5002 9.90192 13.0587C10.9678 12.6173 11.8788 11.8698 12.5198 10.9106C13.1608 9.95144 13.503 8.82372 13.5031 7.67007C13.5014 6.12352 12.8864 4.64079 11.7928 3.54716C10.6993 2.45353 9.21663 1.83831 7.67007 1.83647Z"
19
+ fill="#121212"
20
+ />
21
+ <path
22
+ d="M14.6635 15.1637C14.5978 15.1641 14.5327 15.1513 14.472 15.1263C14.4112 15.1012 14.3561 15.0642 14.3099 15.0176L11.8325 12.5392C11.7396 12.4451 11.6875 12.3181 11.6875 12.1859C11.6875 12.0536 11.7396 11.9267 11.8325 11.8325C11.9267 11.7396 12.0536 11.6875 12.1859 11.6875C12.3181 11.6875 12.4451 11.7396 12.5392 11.8325L15.0171 14.3104C15.11 14.4045 15.1621 14.5315 15.1621 14.6637C15.1621 14.796 15.11 14.9229 15.0171 15.0171C14.9708 15.0638 14.9157 15.1008 14.855 15.126C14.7943 15.1512 14.7292 15.164 14.6635 15.1637Z"
23
+ fill="#121212"
24
+ />
25
+ </svg>
26
+ );
27
+ };
@@ -31,14 +31,19 @@ import { PayxIcon } from "./IconComponents/PayxIcon";
31
31
 
32
32
  import { AdminIcon } from "./IconComponents/AdminIcon";
33
33
  import { ErrorFilledIcon } from "./IconComponents/AlertFilledIcon";
34
+ import { ArrowBackIcon } from "./IconComponents/ArrowBackIcon";
34
35
  import { CampxFullLogoIcon } from "./IconComponents/CampxFullLogoIcon";
36
+ import { CollapseIcon } from "./IconComponents/CollapseIcon";
35
37
  import { CrossIcon2 } from "./IconComponents/CrossIcon2";
38
+ import { ExpandIcon } from "./IconComponents/ExpandIcon";
36
39
  import { InfoFilledIcon } from "./IconComponents/InfoFilledIcon";
37
40
  import { PeoplexIcon } from "./IconComponents/PeoplexIcon";
38
41
  import { ProductFeaturesIcon } from "./IconComponents/ProductFeaturesIcon";
39
42
  import { ProfileIcon } from "./IconComponents/ProfileIcon";
43
+ import { RedoIcon } from "./IconComponents/RedoIcon";
40
44
  import { RightIcon } from "./IconComponents/RightIcon";
41
45
  import { SaveIcon } from "./IconComponents/SaveIcon";
46
+ import { SearchIcon } from "./IconComponents/SearchIcon";
42
47
  import { ShareIcon } from "./IconComponents/ShareIcon";
43
48
  import { SuccessFilledIcon } from "./IconComponents/SuccessFilledIcon";
44
49
  import { TicketsIcon } from "./IconComponents/TicketsIcon";
@@ -48,6 +53,10 @@ import { UnCheckedRadioIcon } from "./IconComponents/UncheckedRadioIcon";
48
53
  import { WarningFilledIcon } from "./IconComponents/WarningFilledIcon";
49
54
 
50
55
  export const Icons = {
56
+ RedoIcon,
57
+ ArrowBackIcon,
58
+ CollapseIcon,
59
+ ExpandIcon,
51
60
  AppsIcon,
52
61
  CareerIcon,
53
62
  ClogWheelIcon,
@@ -95,4 +104,5 @@ export const Icons = {
95
104
  AdminIcon,
96
105
  ShareIcon,
97
106
  SaveIcon,
107
+ SearchIcon,
98
108
  };
@@ -5,6 +5,14 @@ import {
5
5
 
6
6
  export type TypographyProps = {} & MuiTypographyProps;
7
7
 
8
- export const Typography = ({ variant, children }: TypographyProps) => {
9
- return <MuiTypography variant={variant}>{children}</MuiTypography>;
8
+ export const Typography = ({
9
+ variant,
10
+ children,
11
+ ...props
12
+ }: TypographyProps) => {
13
+ return (
14
+ <MuiTypography variant={variant} {...props}>
15
+ {children}
16
+ </MuiTypography>
17
+ );
10
18
  };
@@ -1,8 +1,12 @@
1
- import { Search } from "@mui/icons-material";
2
- import { InputAdornment } from "@mui/material";
1
+ import {
2
+ InputAdornment,
3
+ TextField,
4
+ TextFieldProps,
5
+ styled,
6
+ } from "@mui/material";
3
7
  import { debounce } from "lodash";
4
8
  import { ReactNode, useMemo, useState } from "react";
5
- import { TextField, TextFieldProps } from "../TextField/TextField";
9
+ import { SearchIcon } from "../../Assets/Icons/IconComponents/SearchIcon";
6
10
 
7
11
  export type SearchBarProps = {
8
12
  placeholder?: string;
@@ -12,7 +16,7 @@ export type SearchBarProps = {
12
16
  } & TextFieldProps;
13
17
 
14
18
  export const SearchBar = ({
15
- placeholder = "Search",
19
+ placeholder = "Search by Name",
16
20
  label,
17
21
  value = "",
18
22
  onSearch,
@@ -30,14 +34,14 @@ export const SearchBar = ({
30
34
  };
31
35
 
32
36
  return (
33
- <TextField
37
+ <StyledTextField
34
38
  placeholder={placeholder}
35
39
  label={label}
36
40
  value={search}
37
41
  InputProps={{
38
42
  endAdornment: (
39
43
  <InputAdornment position="end">
40
- <Search />
44
+ <SearchIcon />
41
45
  </InputAdornment>
42
46
  ),
43
47
  }}
@@ -46,3 +50,33 @@ export const SearchBar = ({
46
50
  />
47
51
  );
48
52
  };
53
+
54
+ const StyledTextField = styled(TextField)(({ theme }) => ({
55
+ margin: 0,
56
+ height: 40,
57
+ backgroundColor: theme.palette.surface.grey,
58
+ ".MuiFormControl-root": {
59
+ margin: 0,
60
+ height: "100%",
61
+ },
62
+ ".MuiOutlinedInput-root": {
63
+ height: "100%",
64
+ padding: "5px, 10px",
65
+ display: "flex",
66
+ alignItems: "center",
67
+ },
68
+ ".MuiInputBase-input": {
69
+ height: "100%",
70
+ fontSize: "14px",
71
+ "&::placeholder": {
72
+ color: theme.palette.text.tertiary,
73
+ fontSize: "14px",
74
+ opacity: 1,
75
+ },
76
+ },
77
+ ".MuiOutlinedInput-notchedOutline": {
78
+ height: "100%",
79
+ top: 0,
80
+ borderColor: theme.palette.border.primary,
81
+ },
82
+ }));
@@ -0,0 +1,34 @@
1
+ import { useMatch, useResolvedPath } from "react-router-dom";
2
+ import { Typography } from "../../export";
3
+ import { DropdownMenuItem } from "./interfaces";
4
+ import { createSidebarStyles } from "./styles";
5
+
6
+ export const SidebarDropdownItem = ({
7
+ dropdownItem,
8
+ collapsed,
9
+ index,
10
+ }: {
11
+ dropdownItem: DropdownMenuItem;
12
+ collapsed: boolean;
13
+ index: number;
14
+ }) => {
15
+ const { name, path, permissionKey } = dropdownItem;
16
+
17
+ let resolved = useResolvedPath(path);
18
+ let match = useMatch({ path: resolved.pathname, end: false });
19
+
20
+ const { StyledListItem, StyledLinkButton, StyledListItemButton } =
21
+ createSidebarStyles(collapsed);
22
+
23
+ return (
24
+ <StyledListItem key={index} disablePadding className="listItem">
25
+ <StyledLinkButton to={path} match={match}>
26
+ {!collapsed && (
27
+ <StyledListItemButton collapsed={collapsed}>
28
+ <Typography variant="button1">{name}</Typography>
29
+ </StyledListItemButton>
30
+ )}
31
+ </StyledLinkButton>
32
+ </StyledListItem>
33
+ );
34
+ };
@@ -0,0 +1,150 @@
1
+ import { Box, Stack } from "@mui/material";
2
+ import { motion } from "framer-motion";
3
+ import { useState } from "react";
4
+ import { useMatch, useResolvedPath } from "react-router-dom";
5
+ import { Icons, Tooltip, Typography } from "../../export";
6
+ import { SidebarDropdownItem } from "./DropdownItem";
7
+ import { MenuItemProps } from "./interfaces";
8
+ import { createSidebarStyles } from "./styles";
9
+
10
+ export const SideBarMenuItem = ({
11
+ menuItem,
12
+ index,
13
+ collapsed,
14
+ newMenuClickHandler,
15
+ }: {
16
+ menuItem: MenuItemProps;
17
+ index: number;
18
+ collapsed: boolean;
19
+ newMenuClickHandler: (newMenu: MenuItemProps[], newMenuTitle: string) => void;
20
+ }) => {
21
+ const {
22
+ StyledListItem,
23
+ StyledLinkButton,
24
+ StyledListItemButton,
25
+ StyledListItemIcon,
26
+ StyledDropdownButton,
27
+ HoverIcon,
28
+ } = createSidebarStyles(collapsed);
29
+
30
+ const { name, path, icon: Icon, menu: newMenu, dropdownMenu } = menuItem;
31
+
32
+ let resolved = useResolvedPath(path);
33
+ let match = useMatch({ path: resolved.pathname, end: false });
34
+
35
+ let [expanded, setExpanded] = useState(false);
36
+ const dropdownMenuClickHandler = () => {
37
+ setExpanded(!expanded);
38
+ };
39
+
40
+ const DrawerCollapsedTile = () => {
41
+ return (
42
+ <Tooltip title={<Typography variant="label2">{name}</Typography>}>
43
+ {Icon}
44
+ </Tooltip>
45
+ );
46
+ };
47
+
48
+ const NewMenuTile = () => {
49
+ return (
50
+ <StyledListItemButton collapsed={collapsed}>
51
+ <Stack
52
+ width={"100%"}
53
+ direction="row"
54
+ alignItems={"center"}
55
+ justifyContent={"space-between"}
56
+ >
57
+ <Stack direction="row" alignItems={"center"}>
58
+ <StyledListItemIcon collapsed={collapsed}>
59
+ {Icon ? Icon : <Icons.HomeIcon />}
60
+ </StyledListItemIcon>
61
+ <Typography variant="button1">{name}</Typography>
62
+ </Stack>
63
+ <HoverIcon display={"flex"} className="hoverIcon">
64
+ <Icons.RedoIcon size={18} />
65
+ </HoverIcon>
66
+ </Stack>
67
+ </StyledListItemButton>
68
+ );
69
+ };
70
+
71
+ const DropdownMenuTile = () => {
72
+ return (
73
+ <StyledListItemButton collapsed={collapsed}>
74
+ <Stack
75
+ width={"100%"}
76
+ direction="row"
77
+ alignItems={"center"}
78
+ justifyContent={"space-between"}
79
+ >
80
+ <Stack direction="row" alignItems={"center"}>
81
+ <StyledListItemIcon collapsed={collapsed}>
82
+ {Icon ? Icon : <Icons.HomeIcon />}
83
+ </StyledListItemIcon>
84
+ <Typography variant="button1">{name}</Typography>
85
+ </Stack>
86
+ <Box display={"flex"}>
87
+ {expanded ? <Icons.CollapseIcon /> : <Icons.ExpandIcon />}
88
+ </Box>
89
+ </Stack>
90
+ </StyledListItemButton>
91
+ );
92
+ };
93
+
94
+ const DefaultTile = () => {
95
+ return (
96
+ <StyledListItemButton collapsed={collapsed}>
97
+ <StyledListItemIcon collapsed={collapsed}>{Icon}</StyledListItemIcon>
98
+ <Typography variant="button1">{name}</Typography>
99
+ </StyledListItemButton>
100
+ );
101
+ };
102
+
103
+ return (
104
+ <motion.div
105
+ key="collapsed"
106
+ initial={{ opacity: 0 }}
107
+ animate={{ opacity: 1 }}
108
+ transition={{ duration: 1 }}
109
+ >
110
+ {newMenu && (
111
+ <StyledListItem key={index} disablePadding className="listItem">
112
+ <StyledDropdownButton
113
+ match={match}
114
+ onClick={() => newMenuClickHandler(newMenu, name)}
115
+ >
116
+ {collapsed ? <DrawerCollapsedTile /> : <NewMenuTile />}
117
+ </StyledDropdownButton>
118
+ </StyledListItem>
119
+ )}
120
+ {dropdownMenu && dropdownMenu.length > 0 && (
121
+ <StyledListItem key={index} disablePadding className="listItem">
122
+ <StyledDropdownButton
123
+ match={match}
124
+ onClick={() => dropdownMenuClickHandler()}
125
+ >
126
+ {collapsed ? <DrawerCollapsedTile /> : <DropdownMenuTile />}
127
+ </StyledDropdownButton>
128
+ </StyledListItem>
129
+ )}
130
+ {expanded && dropdownMenu && dropdownMenu.length > 0 && (
131
+ <Stack>
132
+ {dropdownMenu?.map((item: any, index: number) => (
133
+ <SidebarDropdownItem
134
+ dropdownItem={item}
135
+ collapsed={collapsed}
136
+ index={index}
137
+ />
138
+ ))}
139
+ </Stack>
140
+ )}
141
+ {!newMenu && !dropdownMenu && (
142
+ <StyledListItem key={path} disablePadding className="listItem">
143
+ <StyledLinkButton to={path} match={match}>
144
+ {collapsed ? <DrawerCollapsedTile /> : <DefaultTile />}
145
+ </StyledLinkButton>
146
+ </StyledListItem>
147
+ )}
148
+ </motion.div>
149
+ );
150
+ };
@@ -1,21 +1,15 @@
1
- import { IconButton } from "@mui/material";
2
- import { useMatch, useResolvedPath } from "react-router-dom";
1
+ import { motion } from "framer-motion";
2
+ import { useMemo, useState } from "react";
3
3
  import { CampxFullLogoIcon } from "../../Assets/Icons/IconComponents/CampxFullLogoIcon";
4
4
  import { CampxIcon } from "../../Assets/Icons/IconComponents/CampxIcon";
5
5
  import { LeftIcon } from "../../Assets/Icons/IconComponents/LeftIcon";
6
6
  import { RightIcon } from "../../Assets/Icons/IconComponents/RightIcon";
7
7
  import { Typography } from "../../DataDisplay/Typography/Typography";
8
- import { Icons, Tooltip } from "../../export";
8
+ import { Icons } from "../../export";
9
+ import { SideBarMenuItem } from "./MenuItem";
10
+ import { MenuHistory, MenuItemProps } from "./interfaces";
9
11
  import { createSidebarStyles } from "./styles";
10
12
 
11
- export interface MenuItemProps {
12
- name: string;
13
- path: string;
14
- icon?: any;
15
- permissionKey?: string;
16
- iconType?: string;
17
- }
18
-
19
13
  export const Sidebar = ({
20
14
  menu,
21
15
  collapsed,
@@ -25,86 +19,119 @@ export const Sidebar = ({
25
19
  collapsed: boolean;
26
20
  setCollapsed: any;
27
21
  }) => {
28
- const {
29
- StyledSidebarContainer,
30
- StyledLogoArea,
31
- StyledMenuBar,
32
- StyledCollapsibleSection,
33
- StyledListItem,
34
- StyledLinkButton,
35
- StyledListItemButton,
36
- StyledListItemIcon,
37
- } = createSidebarStyles(collapsed);
22
+ const [history, setHistory] = useState<MenuHistory[]>([]);
23
+ const [currentMenu, setCurrentMenu] = useState<MenuItemProps[] | null>(menu);
24
+ const [currentMenuTitle, setCurrentMenuTitle] = useState<string | null>(null);
25
+ const [menuPosition, setMenuPosition] = useState(0);
26
+
27
+ const newMenuClickHandler = (
28
+ newMenu: MenuItemProps[],
29
+ newMenuTitle: string
30
+ ) => {
31
+ if (newMenu) {
32
+ setHistory((prev) => [
33
+ ...prev,
34
+ { menu: currentMenu, menuTitle: currentMenuTitle },
35
+ ]);
36
+
37
+ setCurrentMenu(newMenu);
38
+ setMenuPosition(collapsed ? 60 : 250);
39
+ setCurrentMenuTitle(newMenuTitle);
40
+ }
41
+ };
42
+
43
+ const backClickHandler = () => {
44
+ const prev = history && history.length > 0 && history.pop();
45
+
46
+ if (prev) {
47
+ setCurrentMenu(prev.menu);
48
+ setCurrentMenuTitle(prev.menuTitle);
49
+ setHistory([...history]);
50
+ setMenuPosition(collapsed ? -60 : -250);
51
+ }
52
+ };
38
53
 
39
54
  const toggleSidebar = () => {
55
+ setMenuPosition(0);
40
56
  setCollapsed(!collapsed);
41
57
  };
42
58
 
43
- const MenuItem = ({
44
- menuItem,
45
- index,
46
- }: {
47
- menuItem: MenuItemProps;
48
- index: number;
49
- }) => {
50
- const { path, icon: Icon, name } = menuItem;
51
- let resolved = useResolvedPath(path);
52
- let match = useMatch({ path: resolved.pathname, end: false });
53
- return (
54
- <StyledListItem key={path} disablePadding className="listItem">
55
- <StyledLinkButton to={path} match={match}>
56
- {!collapsed && (
57
- <StyledListItemButton collapsed={collapsed}>
58
- <StyledListItemIcon collapsed={collapsed}>
59
- {Icon ? Icon : <Icons.HomeIcon />}
60
- </StyledListItemIcon>
61
- <Typography variant="subtitle2">{name}</Typography>
62
- </StyledListItemButton>
63
- )}
64
- {collapsed && (
65
- <>
66
- {Icon ? (
67
- <Tooltip
68
- title={<Typography variant="label2">{name}</Typography>}
69
- >
70
- {Icon}
71
- </Tooltip>
72
- ) : (
73
- <Tooltip
74
- title={<Typography variant="label2">{name}</Typography>}
75
- >
76
- <Icons.HomeIcon />
77
- </Tooltip>
78
- )}
79
- </>
80
- )}
81
- </StyledLinkButton>
82
- </StyledListItem>
83
- );
84
- };
59
+ const {
60
+ StyledSidebarContainer,
61
+ StyledLogoArea,
62
+ StyledMenuBar,
63
+ StyledCollapsibleSection,
64
+ StyledMenuHeaderButton,
65
+ } = useMemo(() => createSidebarStyles(collapsed), [collapsed]);
85
66
 
86
67
  return (
87
- <StyledSidebarContainer
88
- direction="column"
89
- spacing="12px"
90
- className="sidebarContainer"
68
+ <motion.div
69
+ animate={{ width: collapsed ? "60px" : "250px" }}
70
+ transition={{ duration: 0.3, ease: "circOut" }}
71
+ style={{
72
+ margin: "12px",
73
+ height: "calc(100vh - 24px)",
74
+ }}
91
75
  >
92
- <StyledLogoArea collapsed={collapsed}>
93
- {collapsed ? <CampxIcon size={32} /> : <CampxFullLogoIcon />}
94
- </StyledLogoArea>
95
- <StyledMenuBar>
96
- {menu &&
97
- menu.length > 0 &&
98
- menu?.map((item: any, index: number) => (
99
- <MenuItem menuItem={item} index={index} key={index} />
100
- ))}
101
- </StyledMenuBar>
102
- <StyledCollapsibleSection className="collapsibleSection">
103
- <IconButton onClick={toggleSidebar}>
76
+ <StyledSidebarContainer
77
+ spacing="12px"
78
+ direction="column"
79
+ className="sidebarContainer"
80
+ >
81
+ <motion.div
82
+ key="collapsed"
83
+ initial={{ opacity: 0 }}
84
+ animate={{ opacity: 1 }}
85
+ transition={{ duration: 0.5 }}
86
+ >
87
+ <StyledLogoArea collapsed={collapsed}>
88
+ {collapsed ? <CampxIcon size={32} /> : <CampxFullLogoIcon />}
89
+ </StyledLogoArea>
90
+ </motion.div>
91
+
92
+ <motion.div
93
+ initial={{ x: menuPosition }}
94
+ animate={{ x: 0 }}
95
+ transition={{
96
+ duration: 0.3,
97
+ ease: menuPosition ? "circOut" : "circIn",
98
+ }}
99
+ style={{
100
+ height: "100%",
101
+ }}
102
+ >
103
+ <StyledMenuBar>
104
+ {!collapsed && currentMenuTitle && (
105
+ <StyledMenuHeaderButton
106
+ direction="row"
107
+ onClick={() => backClickHandler()}
108
+ >
109
+ <Icons.ArrowBackIcon size={20} />
110
+
111
+ <Typography variant="button1">{currentMenuTitle}</Typography>
112
+ </StyledMenuHeaderButton>
113
+ )}
114
+ {currentMenu &&
115
+ currentMenu.length > 0 &&
116
+ currentMenu?.map((item: any, index: number) => (
117
+ <SideBarMenuItem
118
+ menuItem={item}
119
+ index={index}
120
+ key={index}
121
+ collapsed={collapsed}
122
+ newMenuClickHandler={newMenuClickHandler}
123
+ />
124
+ ))}
125
+ </StyledMenuBar>
126
+ </motion.div>
127
+ <StyledCollapsibleSection
128
+ className="collapsibleSection"
129
+ onClick={toggleSidebar}
130
+ >
104
131
  {collapsed ? <RightIcon size={32} /> : <LeftIcon size={32} />}
105
- </IconButton>
106
- </StyledCollapsibleSection>
107
- </StyledSidebarContainer>
132
+ </StyledCollapsibleSection>
133
+ </StyledSidebarContainer>
134
+ </motion.div>
108
135
  );
109
136
  };
110
137
 
@@ -0,0 +1,21 @@
1
+ import { ReactElement } from "react";
2
+
3
+ export interface MenuItemProps {
4
+ name: string;
5
+ path: string;
6
+ icon: ReactElement;
7
+ permissionKey?: string;
8
+ menu?: MenuItemProps[];
9
+ dropdownMenu?: DropdownMenuItem[];
10
+ }
11
+
12
+ export interface DropdownMenuItem {
13
+ name: string;
14
+ path: string;
15
+ permissionKey?: string;
16
+ }
17
+
18
+ export interface MenuHistory {
19
+ menu: MenuItemProps[] | null;
20
+ menuTitle: string | null;
21
+ }
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  Box,
3
+ Button,
4
+ IconButton,
3
5
  ListItem,
4
6
  ListItemButton,
5
7
  ListItemIcon,
@@ -11,10 +13,10 @@ import { Link } from "react-router-dom";
11
13
  export const createSidebarStyles = (collapsed: boolean) => {
12
14
  const StyledSidebarContainer = styled(Stack)(({ theme }) => {
13
15
  return {
14
- height: "calc(100vh - 24px)",
15
- width: collapsed ? "60px" : "240px",
16
- margin: "12px",
17
16
  backgroundColor: theme.palette.surface.defaultBackground,
17
+ height: "100%",
18
+ justifyContent: "space-between",
19
+ overflow: "hidden",
18
20
  };
19
21
  });
20
22
 
@@ -31,12 +33,12 @@ export const createSidebarStyles = (collapsed: boolean) => {
31
33
  );
32
34
 
33
35
  const StyledMenuBar = styled(Box)(({ theme }) => ({
34
- flexGrow: 1,
36
+ height: "100%",
35
37
  borderRadius: "8px",
36
38
  backgroundColor: theme.palette.surface.paperBackground,
37
39
  }));
38
40
 
39
- const StyledCollapsibleSection = styled(Box)(({ theme }) => ({
41
+ const StyledCollapsibleSection = styled(IconButton)(({ theme }) => ({
40
42
  display: "flex",
41
43
  alignItems: "center",
42
44
  justifyContent: "center",
@@ -73,6 +75,15 @@ export const createSidebarStyles = (collapsed: boolean) => {
73
75
  })
74
76
  );
75
77
 
78
+ const StyledListItemIcon = styled(ListItemIcon)(
79
+ ({ collapsed }: { collapsed: boolean }) => ({
80
+ display: "flex",
81
+ justifyContent: "center",
82
+ minWidth: "0px",
83
+ marginRight: "10px",
84
+ })
85
+ );
86
+
76
87
  interface StyledListItemButtonProps {
77
88
  collapsed: boolean;
78
89
  }
@@ -87,16 +98,40 @@ export const createSidebarStyles = (collapsed: boolean) => {
87
98
  paddingTop: "5px",
88
99
  width: "100%",
89
100
  borderRadius: "5px",
101
+ "&:hover .hoverIcon": {
102
+ display: "flex",
103
+ },
90
104
  }));
91
105
 
92
- const StyledListItemIcon = styled(ListItemIcon)(
93
- ({ collapsed }: { collapsed: boolean }) => ({
106
+ const HoverIcon = styled(Box)(({ theme }) => ({
107
+ display: "none",
108
+ }));
109
+
110
+ const StyledDropdownButton = styled(Button)<StyledLinkButtonProps>(
111
+ ({ theme, match }) => ({
112
+ width: collapsed ? "auto" : "100%",
113
+ textDecoration: "none",
94
114
  display: "flex",
115
+ margin: collapsed ? "5px 0px 0px 0px" : "5px 8px",
116
+ backgroundColor: match ? theme.palette.secondary.main : "none",
95
117
  justifyContent: "center",
96
- minWidth: "48px",
118
+ "&:hover": {
119
+ color: "unset",
120
+ },
121
+ borderRadius: "4px",
97
122
  })
98
123
  );
99
124
 
125
+ const StyledMenuHeaderButton = styled(Stack)(({ theme }) => ({
126
+ alignItems: "end",
127
+ height: "50px",
128
+ width: "100%",
129
+ padding: "12px 16px",
130
+ backgroundColor: theme.palette.surface.grey,
131
+ cursor: "pointer",
132
+ borderRadius: "8px 8px 0px 0px",
133
+ }));
134
+
100
135
  return {
101
136
  StyledSidebarContainer,
102
137
  StyledLogoArea,
@@ -106,5 +141,8 @@ export const createSidebarStyles = (collapsed: boolean) => {
106
141
  StyledLinkButton,
107
142
  StyledListItemButton,
108
143
  StyledListItemIcon,
144
+ StyledDropdownButton,
145
+ StyledMenuHeaderButton,
146
+ HoverIcon,
109
147
  };
110
148
  };
@@ -17,7 +17,7 @@ interface StepperProps {
17
17
 
18
18
  interface StepItem {
19
19
  label: string;
20
- description: string;
20
+ description?: string;
21
21
  }
22
22
 
23
23
  export const Stepper = ({
@@ -43,7 +43,7 @@ export const TypographyStyles = () => (
43
43
  />
44
44
  <TypographyDisplay
45
45
  variant="subtitle2"
46
- fontInfo={{ family: "Poppins", weight: "600", size: "16px" }}
46
+ fontInfo={{ family: "Poppins", weight: "500", size: "16px" }}
47
47
  text="Subtitle 2 (subtitle2) - Lorem ipsum dolor sit."
48
48
  />
49
49
  <TypographyDisplay
@@ -68,13 +68,18 @@ export const TypographyStyles = () => (
68
68
  />
69
69
  <TypographyDisplay
70
70
  variant={"label1" as any}
71
- fontInfo={{ family: "Heebo", weight: "300", size: "14px" }}
71
+ fontInfo={{ family: "Heebo", weight: "400", size: "14px" }}
72
72
  text="Label 1 (label1) - Lorem ipsum dolor sit."
73
73
  />
74
74
  <TypographyDisplay
75
75
  variant={"label2" as any}
76
- fontInfo={{ family: "Poppins", weight: "300", size: "14px" }}
76
+ fontInfo={{ family: "Poppins", weight: "400", size: "12px" }}
77
77
  text="Label 2 (label2) - Lorem ipsum dolor sit."
78
78
  />
79
+ <TypographyDisplay
80
+ variant={"button1" as any}
81
+ fontInfo={{ family: "Poppins", weight: "600", size: "14px" }}
82
+ text="Button 1 (button1) - Lorem ipsum dolor sit."
83
+ />
79
84
  </Stack>
80
85
  );
@@ -30,40 +30,38 @@ const meta: Meta<typeof Sidebar> = {
30
30
  export default meta;
31
31
  type Story = StoryObj<typeof Sidebar>;
32
32
 
33
+ const mainMenu = [
34
+ { name: "Admin", path: "/admin", icon: <Icons.AdminIcon size={20} /> },
35
+ { name: "UMS", path: "/ums", icon: <Icons.UmsIcon size={20} /> },
36
+ {
37
+ name: "Payments",
38
+ path: "/payments",
39
+ icon: <Icons.PayxIcon size={20} />,
40
+ },
41
+ { name: "Exams", path: "/exams", icon: <Icons.ExamxIcon size={20} /> },
42
+ { name: "HRMS", path: "/hrms", icon: <Icons.PeoplexIcon size={20} /> },
43
+ {
44
+ name: "Enroll",
45
+ path: "/enroll",
46
+ icon: <Icons.EnrollxIcon size={20} />,
47
+ },
48
+ {
49
+ name: "Commute",
50
+ path: "/commute",
51
+ icon: <Icons.CommutexIcon size={20} />,
52
+ },
53
+ {
54
+ name: "Hostels",
55
+ path: "/hostels",
56
+ icon: <Icons.HostelxIcon size={20} />,
57
+ },
58
+ ];
59
+
33
60
  // Primary story
34
61
  export const Primary: Story = {
35
62
  render: (args) => <Sidebar {...args} />,
36
63
  args: {
37
- menu: [
38
- { name: "Admin", path: "/admin", icon: <Icons.AdminIcon size={20} /> },
39
- { name: "UMS", path: "/ums", icon: <Icons.UmsIcon size={20} /> },
40
- {
41
- name: "Payments",
42
- path: "/payments",
43
- icon: <Icons.PayxIcon size={20} />,
44
- },
45
- { name: "Exams", path: "/exams", icon: <Icons.ExamxIcon size={20} /> },
46
- { name: "HRMS", path: "/hrms", icon: <Icons.PeoplexIcon size={20} /> },
47
- {
48
- name: "Enroll",
49
- path: "/enroll",
50
- icon: <Icons.EnrollxIcon size={20} />,
51
- },
52
- {
53
- name: "Commute",
54
- path: "/commute",
55
- icon: <Icons.CommutexIcon size={20} />,
56
- },
57
- {
58
- name: "Hostels",
59
- path: "/hostels",
60
- icon: <Icons.HostelxIcon size={20} />,
61
- },
62
- {
63
- name: "Evaluator",
64
- path: "/evaluator",
65
- },
66
- ],
64
+ menu: mainMenu,
67
65
  },
68
66
  };
69
67
 
@@ -11,41 +11,61 @@ export default meta;
11
11
 
12
12
  type Story = StoryObj<typeof Stepper>;
13
13
 
14
+ const steps = [
15
+ {
16
+ label: "Semester Configuration",
17
+ description:
18
+ "Configure Credits, Tuition Fee Requirements, Registration Dates",
19
+ },
20
+ {
21
+ label: "Semester Calender",
22
+ description:
23
+ "Manage the timeline of the semester. Add new or edit the following events as per the semester needs",
24
+ },
25
+ {
26
+ label: "Students and Sections",
27
+ description: "Add or move students to their respective sections",
28
+ },
29
+ {
30
+ label: "Courses",
31
+ description:
32
+ "Verify the courses that are going to be taught in this semester",
33
+ },
34
+ {
35
+ label: "Assign Faculty",
36
+ description: "Assign Faculty to the available subjects",
37
+ },
38
+ ];
39
+
14
40
  export const VerticalStepper: Story = {
15
41
  args: {
16
42
  orientation: "vertical",
17
- steps: [
18
- {
19
- label: "Semester Configuration",
20
- description:
21
- "Configure Credits, Tuition Fee Requirements, Registration Dates",
22
- },
23
- {
24
- label: "Semester Calender",
25
- description:
26
- "Manage the timeline of the semester. Add new or edit the following events as per the semester needs",
27
- },
28
- {
29
- label: "Students and Sections",
30
- description: "Add or move students to their respective sections",
31
- },
32
- {
33
- label: "Courses",
34
- description:
35
- "Verify the courses that are going to be taught in this semester",
36
- },
37
- {
38
- label: "Assign Faculty",
39
- description: "Assign Faculty to the available subjects",
40
- },
41
- ],
43
+ steps,
42
44
  activeStep: 2,
43
45
  },
44
46
  };
45
47
 
48
+ export const VerticalStepperWithNoDescription: Story = {
49
+ args: {
50
+ ...VerticalStepper.args,
51
+ steps: steps.map((step) => ({
52
+ label: step.label,
53
+ })),
54
+ },
55
+ };
56
+
46
57
  export const HorizontalStepper: Story = {
47
58
  args: {
48
59
  ...VerticalStepper.args,
49
60
  orientation: "horizontal",
50
61
  },
51
62
  };
63
+
64
+ export const HorizontalStepperWithNoDescription: Story = {
65
+ args: {
66
+ ...HorizontalStepper.args,
67
+ steps: steps.map((step) => ({
68
+ label: step.label,
69
+ })),
70
+ },
71
+ };
@@ -483,6 +483,12 @@ export const getCommonTheme = (mode: Theme) => {
483
483
  fontFamily: "Poppins",
484
484
  color: ColorTokens.text.secondary,
485
485
  },
486
+ button1: {
487
+ fontSize: "14px",
488
+ fontWeight: 600,
489
+ fontFamily: "Poppins",
490
+ color: ColorTokens.text.primary,
491
+ },
486
492
  } as TypographyOptions,
487
493
  },
488
494
  MuiCssBaseline: {
package/types/theme.d.ts CHANGED
@@ -54,5 +54,6 @@ declare module "@mui/material/Typography" {
54
54
  label1: true;
55
55
  label2: true;
56
56
  subtitle3: true;
57
+ button1: true;
57
58
  }
58
59
  }