Files
please-pay-me/web/src/components/layout/AppShell.tsx
T
2026-09-21 04:06:43 +03:00

76 lines
2.2 KiB
TypeScript

import { NavLink } from "react-router-dom";
import type { ReactNode } from "react";
import { APP_NAME } from "../../brand";
import { SiteFooter } from "../../legal/SiteFooter";
import { AppAvatar, AppButton, AppText } from "../../ui";
import { PRIMARY_NAV } from "./nav";
type Props = {
brand?: string;
userLabel: string;
onLogout: () => void;
children: ReactNode;
};
function initials(label: string): string {
const parts = label.trim().split(/\s+/).filter(Boolean);
if (parts.length === 0) return "•";
if (parts.length === 1) return parts[0].slice(0, 1).toUpperCase();
return (parts[0][0] + parts[1][0]).toUpperCase();
}
export function AppShell({
brand = APP_NAME,
userLabel,
onLogout,
children,
}: Props) {
return (
<div className="app-shell">
<header className="app-shell__header">
<AppText variant="headline" tone="accent">
{brand}
</AppText>
<div className="app-shell__user">
<AppAvatar initials={initials(userLabel)} />
<span className="app-shell__chip" title={userLabel}>
{userLabel}
</span>
<AppButton buttonStyle="plain" size="small" expanded={false} onClick={onLogout}>
Выйти
</AppButton>
</div>
</header>
<nav className="app-shell__nav" aria-label="Основное меню">
<p className="app-section-header">Продукт</p>
<ul className="app-shell__nav-list">
{PRIMARY_NAV.map((item) => (
<li key={item.id}>
{item.soon ? (
<span className="app-shell__nav-link is-disabled" aria-disabled="true">
{item.label}
<span className="app-shell__badge">скоро</span>
</span>
) : (
<NavLink
to={item.to}
end={item.to === "/"}
className={({ isActive }) =>
`app-shell__nav-link${isActive ? " is-active" : ""}`
}
>
{item.label}
</NavLink>
)}
</li>
))}
</ul>
<SiteFooter />
</nav>
<div className="app-shell__main">{children}</div>
</div>
);
}