125 lines
2.8 KiB
TypeScript
125 lines
2.8 KiB
TypeScript
import type { FC, ReactNode } from "react";
|
|
|
|
import { AppShell as MantineAppShell, NavLink, Text } from "@mantine/core";
|
|
import {
|
|
BondsIcon,
|
|
CardsIcon,
|
|
PortfolioIcon,
|
|
SettingsIcon,
|
|
StocksIcon,
|
|
} from "@wealthledger/icons";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Outlet, NavLink as RouterNavLink, useLocation } from "react-router";
|
|
|
|
import classes from "./AppShell.module.css";
|
|
|
|
type AppShellProps = {
|
|
contentAboveOutlet?: ReactNode;
|
|
};
|
|
|
|
function getBottomNavItemClass({ isActive }: { isActive: boolean }) {
|
|
return isActive
|
|
? `${classes.bottomNavItem} ${classes.active}`
|
|
: classes.bottomNavItem;
|
|
}
|
|
|
|
const AppShell: FC<AppShellProps> = (props) => {
|
|
const { contentAboveOutlet } = props;
|
|
const { t } = useTranslation();
|
|
const { pathname } = useLocation();
|
|
|
|
const items = [
|
|
{
|
|
Icon: PortfolioIcon,
|
|
iconClassName: classes.portfolioIcon,
|
|
label: t("navigation.accounts"),
|
|
to: "/accounts",
|
|
},
|
|
{
|
|
Icon: CardsIcon,
|
|
iconClassName: classes.cardsIcon,
|
|
label: t("navigation.cards"),
|
|
to: "/cards",
|
|
},
|
|
{
|
|
Icon: StocksIcon,
|
|
iconClassName: classes.stocksIcon,
|
|
label: t("navigation.stocks"),
|
|
to: "/stocks",
|
|
},
|
|
{
|
|
Icon: BondsIcon,
|
|
iconClassName: classes.bondsIcon,
|
|
label: t("navigation.bonds"),
|
|
to: "/bonds",
|
|
},
|
|
{
|
|
Icon: SettingsIcon,
|
|
iconClassName: classes.settingsIcon,
|
|
label: t("navigation.settings"),
|
|
to: "/settings",
|
|
},
|
|
];
|
|
|
|
return (
|
|
<MantineAppShell
|
|
className={classes.root}
|
|
navbar={{ breakpoint: "sm", collapsed: { mobile: true }, width: 220 }}
|
|
padding="md"
|
|
>
|
|
<MantineAppShell.Navbar aria-label={t("navigation.primary")}>
|
|
<div className={classes.brand}>
|
|
<Text fw={700}>{t("appName")}</Text>
|
|
</div>
|
|
|
|
<div className={classes.navList}>
|
|
{items.map(item => (
|
|
<NavLink
|
|
active={pathname.startsWith(item.to)}
|
|
className={classes.navLink}
|
|
component={RouterNavLink}
|
|
key={item.to}
|
|
label={item.label}
|
|
leftSection={(
|
|
<span className={`${classes.navIcon} ${item.iconClassName}`}>
|
|
<item.Icon size={20} />
|
|
</span>
|
|
)}
|
|
to={item.to}
|
|
/>
|
|
))}
|
|
</div>
|
|
</MantineAppShell.Navbar>
|
|
|
|
<MantineAppShell.Main className={classes.main}>
|
|
<div className={classes.content}>
|
|
{contentAboveOutlet}
|
|
|
|
<Outlet />
|
|
</div>
|
|
</MantineAppShell.Main>
|
|
|
|
<nav
|
|
aria-label={t("navigation.primary")}
|
|
className={classes.bottomNav}
|
|
>
|
|
{items.map(item => (
|
|
<RouterNavLink
|
|
className={getBottomNavItemClass}
|
|
key={item.to}
|
|
to={item.to}
|
|
>
|
|
<span className={classes.iconPill}>
|
|
<item.Icon size={24} />
|
|
</span>
|
|
|
|
<span className={classes.bottomNavLabel}>{item.label}</span>
|
|
</RouterNavLink>
|
|
))}
|
|
</nav>
|
|
</MantineAppShell>
|
|
);
|
|
};
|
|
|
|
export { AppShell };
|