mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
104 lines
3.8 KiB
React
104 lines
3.8 KiB
React
import { useNavigate } from "react-router-dom";
|
|
import {
|
|
Breadcrumb,
|
|
BreadcrumbItem,
|
|
BreadcrumbLink,
|
|
BreadcrumbList,
|
|
BreadcrumbPage,
|
|
BreadcrumbSeparator,
|
|
} from "@/components/ui/breadcrumb";
|
|
|
|
/**
|
|
* AppBreadcrumb
|
|
*
|
|
* Generic breadcrumb driven entirely by the `items` prop.
|
|
* The last item is always rendered as the current page (non-clickable).
|
|
* All preceding items are rendered as clickable links.
|
|
*
|
|
* ─── Item definition shape ────────────────────────────────────────────────────
|
|
*
|
|
* @field {string} label Display text
|
|
* @field {ReactNode} [icon] Optional icon rendered before the label
|
|
* @field {string} [to] navigate() path — if omitted, item is non-navigable
|
|
* @field {Function} [onClick] Custom click handler (e, navigate) => void
|
|
* Overrides `to` when provided.
|
|
*
|
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
*
|
|
* @param {Array} items Ordered list of breadcrumb item definitions
|
|
*
|
|
* ─── Usage ───────────────────────────────────────────────────────────────────
|
|
*
|
|
* import { House, Users } from "lucide-react";
|
|
* import AppBreadcrumb from "@/components/generic/AppBreadcrumb";
|
|
*
|
|
* // Basic — just paths
|
|
* <AppBreadcrumb
|
|
* items={[
|
|
* { label: "Home", icon: <House className="size-4" />, to: `/admin/${adminId}/users` },
|
|
* { label: "Users" },
|
|
* ]}
|
|
* />
|
|
*
|
|
* // With custom click handler
|
|
* <AppBreadcrumb
|
|
* items={[
|
|
* { label: "Home", icon: <House className="size-4" />, onClick: (e, navigate) => navigate(-1) },
|
|
* { label: "Settings", to: `/admin/${adminId}/settings` },
|
|
* { label: "Profile" },
|
|
* ]}
|
|
* />
|
|
*
|
|
* ─────────────────────────────────────────────────────────────────────────────
|
|
*/
|
|
const AppBreadcrumb = ({ items = [] }) => {
|
|
const navigate = useNavigate();
|
|
|
|
if (!items.length) return null;
|
|
|
|
return (
|
|
<Breadcrumb>
|
|
<BreadcrumbList>
|
|
{items.map((item, index) => {
|
|
const isLast = index === items.length - 1;
|
|
|
|
return (
|
|
<span key={index} className="flex items-center gap-1.5">
|
|
<BreadcrumbItem>
|
|
{isLast ? (
|
|
// Current page — no interaction
|
|
<BreadcrumbPage className="flex items-center gap-2">
|
|
{item.icon}
|
|
{item.label}
|
|
</BreadcrumbPage>
|
|
) : (
|
|
// Clickable link
|
|
<BreadcrumbLink asChild>
|
|
<div
|
|
className="flex items-center gap-2 select-none cursor-pointer"
|
|
onClick={(e) => {
|
|
if (item.onClick) {
|
|
item.onClick(e, navigate);
|
|
} else if (item.to) {
|
|
e.preventDefault();
|
|
navigate(item.to);
|
|
}
|
|
}}
|
|
>
|
|
{item.icon}
|
|
<span>{item.label}</span>
|
|
</div>
|
|
</BreadcrumbLink>
|
|
)}
|
|
</BreadcrumbItem>
|
|
|
|
{!isLast && <BreadcrumbSeparator />}
|
|
</span>
|
|
);
|
|
})}
|
|
</BreadcrumbList>
|
|
</Breadcrumb>
|
|
);
|
|
};
|
|
|
|
export default AppBreadcrumb; |