Files
leaudit-platform-frontend/app/components/layout/Breadcrumb.tsx
T

110 lines
3.0 KiB
TypeScript

import { Link, useMatches } from '@remix-run/react';
interface BreadcrumbItem {
title: string;
to?: string;
}
interface BreadcrumbProps {
items?: BreadcrumbItem[];
className?: string;
}
interface PreviousRouteData {
title: string;
to: string;
}
interface Handle {
breadcrumb: string | ((data: unknown) => string);
previousRoute?: PreviousRouteData | ((data: unknown) => PreviousRouteData | undefined);
breadcrumbClassName?: string;
}
interface Match {
handle?: Handle;
pathname: string;
data: unknown;
}
export function Breadcrumb({ items = [], className = '' }: BreadcrumbProps) {
const matches = useMatches() as Match[];
// 构建面包屑数据
const breadcrumbs = items.length > 0 ? items : matches
.filter(match => match.handle?.breadcrumb)
.map((match, index, array) => {
// 当前路由的面包屑
const current = {
title: typeof match.handle?.breadcrumb === 'function'
? match.handle.breadcrumb(match.data)
: match.handle?.breadcrumb as string,
to: match.pathname
};
// 如果当前路由有previousRoute属性且该路由是数组中的最后一个
if (match.handle?.previousRoute && index === array.length - 1) {
// 获取previousRoute数据,支持函数形式
const prevRouteData = typeof match.handle.previousRoute === 'function'
? match.handle.previousRoute(match.data)
: match.handle.previousRoute;
// 如果previousRoute存在,添加到面包屑中
if (prevRouteData) {
return [
{
title: prevRouteData.title,
to: prevRouteData.to
},
current
];
}
}
return [current];
})
.flat(); // 扁平化数组
// 获取自定义类名
const getCustomClassName = () => {
const lastMatch = matches[matches.length - 1];
return lastMatch?.handle?.breadcrumbClassName || '';
};
if (breadcrumbs.length === 0) {
return null;
}
// 应用自定义类名
const customClassName = getCustomClassName();
const finalClassName = `mb-4 ${className} ${customClassName}`.trim();
return (
<nav className={finalClassName} aria-label="面包屑导航">
<ol className="flex items-center space-x-2 text-sm text-gray-500">
<li>
<Link to="/" className="hover:text-primary-600 flex items-center">
<i className="ri-home-line mr-1" />
</Link>
</li>
{breadcrumbs.map((item, index) => (
<li key={index} className="flex items-center">
<i className="ri-arrow-right-s-line mx-1 text-gray-400" />
{index === breadcrumbs.length - 1 ? (
<span className="text-gray-900 font-medium">{item.title}</span>
) : (
<Link
to={item.to || '#'}
className="hover:text-primary-600"
>
{item.title}
</Link>
)}
</li>
))}
</ol>
</nav>
);
}