forked from baron/baron-sso
106 lines
2.9 KiB
TypeScript
106 lines
2.9 KiB
TypeScript
import { Menu, SquareMenu } from "lucide-react";
|
|
import type { ComponentType, ReactNode } from "react";
|
|
import { shellLayoutClasses } from "./layout";
|
|
|
|
export type ShellSidebarNavItem = {
|
|
labelKey: string;
|
|
labelFallback: string;
|
|
to: string;
|
|
icon: ComponentType<{ size?: number | string }>;
|
|
isExternal?: boolean;
|
|
end?: boolean;
|
|
isActive?: boolean;
|
|
};
|
|
|
|
type ShellSidebarProps = {
|
|
brandLabel: string;
|
|
brandTitle: string;
|
|
brandIcon?: ReactNode;
|
|
navContent: ReactNode;
|
|
footerContent: ReactNode;
|
|
collapsed?: boolean;
|
|
onToggleCollapsed?: () => void;
|
|
collapseLabel?: string;
|
|
expandLabel?: string;
|
|
};
|
|
|
|
export function AppSidebar({
|
|
brandLabel,
|
|
brandTitle,
|
|
brandIcon,
|
|
navContent,
|
|
footerContent,
|
|
collapsed = false,
|
|
onToggleCollapsed,
|
|
collapseLabel = "Collapse sidebar",
|
|
expandLabel = "Expand sidebar",
|
|
}: ShellSidebarProps) {
|
|
return (
|
|
<aside
|
|
className={
|
|
collapsed ? shellLayoutClasses.asideCollapsed : shellLayoutClasses.aside
|
|
}
|
|
>
|
|
<div>
|
|
<div
|
|
className={
|
|
collapsed
|
|
? shellLayoutClasses.brandSectionCollapsed
|
|
: shellLayoutClasses.brandSection
|
|
}
|
|
>
|
|
<div
|
|
className={
|
|
collapsed
|
|
? shellLayoutClasses.brandWrapCollapsed
|
|
: shellLayoutClasses.brandWrap
|
|
}
|
|
>
|
|
{onToggleCollapsed ? (
|
|
<button
|
|
type="button"
|
|
onClick={onToggleCollapsed}
|
|
className="grid h-11 w-11 place-items-center rounded-xl border border-border bg-primary/15 text-primary shadow-[0_12px_30px_rgba(54,211,153,0.22)] transition hover:bg-primary/20"
|
|
aria-label={collapsed ? expandLabel : collapseLabel}
|
|
title={collapsed ? expandLabel : collapseLabel}
|
|
>
|
|
<span className="sr-only">
|
|
{collapsed ? expandLabel : collapseLabel}
|
|
</span>
|
|
{collapsed ? <Menu size={20} /> : <SquareMenu size={20} />}
|
|
</button>
|
|
) : (
|
|
<div
|
|
className={
|
|
collapsed
|
|
? shellLayoutClasses.brandIconCollapsed
|
|
: shellLayoutClasses.brandIcon
|
|
}
|
|
>
|
|
{brandIcon}
|
|
</div>
|
|
)}
|
|
<div className={collapsed ? "hidden" : "block"}>
|
|
<p className="text-xs uppercase tracking-[0.18em] text-muted-foreground">
|
|
{brandLabel}
|
|
</p>
|
|
<h1 className="text-lg font-semibold">{brandTitle}</h1>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<nav
|
|
className={
|
|
collapsed
|
|
? shellLayoutClasses.navWrapCollapsed
|
|
: shellLayoutClasses.navWrap
|
|
}
|
|
>
|
|
{navContent}
|
|
</nav>
|
|
</div>
|
|
|
|
<div>{footerContent}</div>
|
|
</aside>
|
|
);
|
|
}
|