69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
'use client';
|
|
|
|
import { usePathname } from 'next/navigation';
|
|
import type { MenuNode } from '@/lib/api/types/menu';
|
|
import {
|
|
isLayoutOverviewNode,
|
|
NavTreeItem,
|
|
layoutNavRootsFromApi,
|
|
} from '@/components/layout/nav-shared';
|
|
|
|
export function SidebarNav(props: {
|
|
items: MenuNode[];
|
|
loading: boolean;
|
|
error: string | null;
|
|
authed: boolean;
|
|
onInternalNavigate?: () => void;
|
|
onMenuNavigate?: (path: string, title: string) => void;
|
|
}) {
|
|
const pathname = usePathname() || '';
|
|
|
|
if (!props.authed) {
|
|
return <div className="px-3 py-4 text-sm text-neutral-500">登录后加载侧栏菜单</div>;
|
|
}
|
|
|
|
if (props.loading) {
|
|
return <div className="px-3 py-4 text-sm text-neutral-500">菜单加载中…</div>;
|
|
}
|
|
|
|
if (props.error) {
|
|
const roots = layoutNavRootsFromApi([]);
|
|
return (
|
|
<nav className="space-y-0.5 px-3 pb-4 py-1" aria-label="侧栏导航">
|
|
{roots.map((n) => (
|
|
<NavTreeItem
|
|
key={n.id}
|
|
node={n}
|
|
depth={0}
|
|
pathname={pathname}
|
|
onInternalNavigate={props.onInternalNavigate}
|
|
onMenuNavigate={props.onMenuNavigate}
|
|
/>
|
|
))}
|
|
<div className="px-2 py-2 text-sm text-red-600" title={props.error}>
|
|
菜单加载失败
|
|
</div>
|
|
</nav>
|
|
);
|
|
}
|
|
|
|
const roots = layoutNavRootsFromApi(props.items);
|
|
const onlyOverview = roots.length === 1 && isLayoutOverviewNode(roots[0]);
|
|
|
|
return (
|
|
<nav className="space-y-0.5 px-3 pb-4 py-1" aria-label="侧栏导航">
|
|
{roots.map((n) => (
|
|
<NavTreeItem
|
|
key={n.id}
|
|
node={n}
|
|
depth={0}
|
|
pathname={pathname}
|
|
onInternalNavigate={props.onInternalNavigate}
|
|
onMenuNavigate={props.onMenuNavigate}
|
|
/>
|
|
))}
|
|
{onlyOverview ? <div className="px-2 py-2 text-sm text-neutral-500">暂无业务菜单</div> : null}
|
|
</nav>
|
|
);
|
|
}
|