mirror of
https://github.com/bluewave-labs/Checkmate.git
synced 2026-05-19 16:08:39 -05:00
Add collapse button and logo
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
import LeftArrow from "@/assets/icons/left-arrow.svg?react";
|
||||
import LeftArrowDouble from "@/assets/icons/left-arrow-double.svg?react";
|
||||
import LeftArrowLong from "@/assets/icons/left-arrow-long.svg?react";
|
||||
|
||||
export const ArrowLeft = ({
|
||||
type,
|
||||
color = "#667085",
|
||||
...props
|
||||
}: {
|
||||
type?: string;
|
||||
color?: string | undefined;
|
||||
[key: string]: any;
|
||||
}) => {
|
||||
if (type === "double") {
|
||||
return (
|
||||
<LeftArrowDouble
|
||||
style={{ color }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
} else if (type === "long") {
|
||||
return (
|
||||
<LeftArrowLong
|
||||
style={{ color }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<LeftArrow
|
||||
style={{ color }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,28 @@
|
||||
import RightArrow from "@/assets/icons/right-arrow.svg?react";
|
||||
import RightArrowDouble from "@/assets/icons/right-arrow-double.svg?react";
|
||||
|
||||
export const ArrowRight = ({
|
||||
type,
|
||||
color = "#667085",
|
||||
...props
|
||||
}: {
|
||||
type?: string;
|
||||
color?: string | undefined;
|
||||
[key: string]: any;
|
||||
}) => {
|
||||
if (type === "double") {
|
||||
return (
|
||||
<RightArrowDouble
|
||||
style={{ color }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<RightArrow
|
||||
style={{ color }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -1,39 +1,6 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
import { Outlet } from "react-router";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
|
||||
const COLLAPSED_WIDTH = 50;
|
||||
const EXPANDED_WIDTH = 250;
|
||||
|
||||
const SideBar = () => {
|
||||
const theme = useTheme();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
|
||||
|
||||
const [collapsed, setCollapsed] = useState(false);
|
||||
useEffect(() => {
|
||||
setCollapsed(isSmall);
|
||||
}, [isSmall]);
|
||||
return (
|
||||
<Stack
|
||||
border="1px solid red"
|
||||
width={collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH}
|
||||
sx={{
|
||||
transition: "width 0.3s ease",
|
||||
}}
|
||||
>
|
||||
<Box
|
||||
border="1px solid blue"
|
||||
onClick={() => setCollapsed(!collapsed)}
|
||||
>
|
||||
Sidebar Content
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
import { SideBar } from "@/Components/v2/Layouts/Sidebar";
|
||||
|
||||
const RootLayout = () => {
|
||||
return (
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import { ArrowRight } from "@/Components/v2/Arrows/ArrowRight";
|
||||
import { ArrowLeft } from "@/Components/v2/Arrows/ArrowLeft";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { toggleSidebar } from "../../../../Features/UI/uiSlice.js";
|
||||
|
||||
export const CollapseButton = ({ collapsed }: { collapsed: boolean }) => {
|
||||
const theme = useTheme();
|
||||
const dispatch = useDispatch();
|
||||
const arrowIcon = collapsed ? (
|
||||
<ArrowRight
|
||||
height={theme.spacing(8)}
|
||||
width={theme.spacing(8)}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
/>
|
||||
) : (
|
||||
<ArrowLeft
|
||||
height={theme.spacing(8)}
|
||||
width={theme.spacing(8)}
|
||||
color={theme.palette.primary.contrastTextSecondary}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<IconButton
|
||||
sx={{
|
||||
position: "absolute",
|
||||
/* TODO 60 is a magic number. if logo chnges size this might break */
|
||||
top: 60,
|
||||
right: 0,
|
||||
transform: `translate(50%, 0)`,
|
||||
backgroundColor: theme.palette.tertiary.main,
|
||||
border: `1px solid ${theme.palette.primary.lowContrast}`,
|
||||
p: theme.spacing(2.5),
|
||||
|
||||
"&:focus": { outline: "none" },
|
||||
"&:hover": {
|
||||
backgroundColor: theme.palette.primary.lowContrast,
|
||||
borderColor: theme.palette.primary.lowContrast,
|
||||
},
|
||||
}}
|
||||
onClick={() => {
|
||||
dispatch(toggleSidebar());
|
||||
}}
|
||||
>
|
||||
{arrowIcon}
|
||||
</IconButton>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,59 @@
|
||||
import Stack from "@mui/material/Stack";
|
||||
import Box from "@mui/material/Box";
|
||||
import Typography from "@mui/material/Typography";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
import { useNavigate } from "react-router";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
export const Logo = ({ collapsed }: { collapsed: boolean }) => {
|
||||
const { t } = useTranslation();
|
||||
const theme = useTheme();
|
||||
const navigate = useNavigate();
|
||||
|
||||
return (
|
||||
<Stack
|
||||
pt={theme.spacing(6)}
|
||||
pb={theme.spacing(12)}
|
||||
pl={theme.spacing(8)}
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
gap={theme.spacing(4)}
|
||||
onClick={() => navigate("/")}
|
||||
sx={{ cursor: "pointer" }}
|
||||
>
|
||||
<Typography
|
||||
pl={theme.spacing("1px")}
|
||||
minWidth={theme.spacing(16)}
|
||||
minHeight={theme.spacing(16)}
|
||||
display={"flex"}
|
||||
justifyContent={"center"}
|
||||
alignItems={"center"}
|
||||
bgcolor={theme.palette.accent.main}
|
||||
borderRadius={theme.shape.borderRadius}
|
||||
color={theme.palette.accent.contrastText}
|
||||
fontSize={18}
|
||||
>
|
||||
C
|
||||
</Typography>
|
||||
<Box
|
||||
overflow={"hidden"}
|
||||
sx={{
|
||||
transition: "opacity 900ms ease, width 900ms ease",
|
||||
opacity: collapsed ? 0 : 1,
|
||||
whiteSpace: "nowrap",
|
||||
width: collapsed ? 0 : "100%",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
<Typography
|
||||
lineHeight={1}
|
||||
mt={theme.spacing(2)}
|
||||
color={theme.palette.primary.contrastText}
|
||||
variant="h2"
|
||||
>
|
||||
{t("common.appName")}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,40 @@
|
||||
import { useEffect } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { setCollapsed } from "@/Features/UI/uiSlice";
|
||||
import useMediaQuery from "@mui/material/useMediaQuery";
|
||||
import { useTheme } from "@mui/material/styles";
|
||||
|
||||
import { CollapseButton } from "@/Components/v2/Layouts/Sidebar/CollapseButton";
|
||||
import Stack from "@mui/material/Stack";
|
||||
import { Logo } from "@/Components/v2/Layouts/Sidebar/Logo";
|
||||
|
||||
export const COLLAPSED_WIDTH = 64;
|
||||
export const EXPANDED_WIDTH = 250;
|
||||
|
||||
export const SideBar = () => {
|
||||
const theme = useTheme();
|
||||
const isSmall = useMediaQuery(theme.breakpoints.down("md"));
|
||||
const dispatch = useDispatch();
|
||||
const collapsed = useSelector((state: any) => state.ui.sidebar.collapsed);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setCollapsed({ collapsed: isSmall }));
|
||||
}, [isSmall]);
|
||||
|
||||
return (
|
||||
<Stack
|
||||
position="sticky"
|
||||
paddingTop={theme.spacing(6)}
|
||||
paddingBottom={theme.spacing(6)}
|
||||
gap={theme.spacing(6)}
|
||||
borderRight={`1px solid ${theme.palette.primary.lowContrast}`}
|
||||
width={collapsed ? COLLAPSED_WIDTH : EXPANDED_WIDTH}
|
||||
sx={{
|
||||
transition: "width 0.3s ease",
|
||||
}}
|
||||
>
|
||||
<CollapseButton collapsed={collapsed} />
|
||||
<Logo collapsed={collapsed} />
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -47,6 +47,10 @@ const uiSlice = createSlice({
|
||||
toggleSidebar: (state) => {
|
||||
state.sidebar.collapsed = !state.sidebar.collapsed;
|
||||
},
|
||||
setCollapsed: (state, action) => {
|
||||
const { collapsed } = action.payload;
|
||||
state.sidebar.collapsed = collapsed;
|
||||
},
|
||||
setMode: (state, action) => {
|
||||
state.mode = action.payload;
|
||||
},
|
||||
@@ -73,6 +77,7 @@ export default uiSlice.reducer;
|
||||
export const {
|
||||
setRowsPerPage,
|
||||
toggleSidebar,
|
||||
setCollapsed,
|
||||
setMode,
|
||||
setShowURL,
|
||||
setGreeting,
|
||||
|
||||
@@ -54,12 +54,17 @@ export const lightPalette = {
|
||||
main: colors.offWhite,
|
||||
contrastText: colors.blueGray800,
|
||||
contrastTextSecondary: colors.blueGray600,
|
||||
lowContrast: colors.gray250,
|
||||
},
|
||||
secondary: {
|
||||
main: colors.gray200,
|
||||
light: colors.lightBlueWave,
|
||||
contrastText: colors.blueGray600,
|
||||
},
|
||||
tertiary: {
|
||||
main: colors.gray100,
|
||||
contrastText: colors.blueGray800,
|
||||
},
|
||||
};
|
||||
|
||||
export const darkPalette = {
|
||||
@@ -73,10 +78,15 @@ export const darkPalette = {
|
||||
main: colors.offBlack,
|
||||
contrastText: colors.blueGray50,
|
||||
contrastTextSecondary: colors.gray200,
|
||||
lowContrast: colors.blueGray600,
|
||||
},
|
||||
secondary: {
|
||||
main: "#313131",
|
||||
light: colors.lightBlueWave,
|
||||
contrastText: colors.gray200,
|
||||
},
|
||||
tertiary: {
|
||||
main: colors.blueGray800,
|
||||
contrastText: colors.gray100,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -67,6 +67,9 @@ export const theme = (mode: string, palette: any) =>
|
||||
},
|
||||
},
|
||||
},
|
||||
shape: {
|
||||
borderRadius: 2,
|
||||
},
|
||||
});
|
||||
|
||||
export const lightTheme = createTheme(theme("light", lightPalette));
|
||||
|
||||
Vendored
+8
@@ -7,3 +7,11 @@ interface ImportMetaEnv {
|
||||
interface ImportMeta {
|
||||
readonly env: ImportMetaEnv;
|
||||
}
|
||||
|
||||
declare module "*.svg?react" {
|
||||
import * as React from "react";
|
||||
const ReactComponent: React.FunctionComponent<
|
||||
React.SVGProps<SVGSVGElement> & { title?: string }
|
||||
>;
|
||||
export default ReactComponent;
|
||||
}
|
||||
|
||||
Vendored
+3
@@ -3,13 +3,16 @@ import "@mui/material/Button";
|
||||
declare module "@mui/material/styles" {
|
||||
interface Palette {
|
||||
accent: Palette["primary"];
|
||||
tertiary: Palette["primary"];
|
||||
}
|
||||
interface PaletteOptions {
|
||||
accent?: PaletteOptions["primary"];
|
||||
tertiary?: PaletteOptions["primary"];
|
||||
}
|
||||
|
||||
interface PaletteColor {
|
||||
contrastTextSecondary?: string;
|
||||
lowContrast?: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user