Files
frontend/src/app/ui/AppShell/AppShell.tsx
T
codex-bot 1a92f023c1
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 12s
Frontend verify / verify (push) Failing after 7m7s
feat: remove top header and rework mobile bottom navigation (#109)
2026-10-25 18:25:10 +03:00

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 };