import React, { useId } from 'react'; import Link from 'next/link'; import { Icon } from '@iconify/react'; import { cn, findMenuPath } from '@/lib/helper'; import { Size } from '@/types/theme'; import Button from '@/components/Button'; import { MAIN_DRAWER_LINKS } from '@/config/constant'; interface BreadcrumbItem { label: string; href?: string; icon?: React.ReactNode; isActive?: boolean; isDisabled?: boolean; } interface BreadcrumbsProps extends React.HTMLAttributes { items: BreadcrumbItem[]; size?: Size; maxVisibleItems?: number; showEllipsisDropdown?: boolean; } export function buildBreadcrumbs(pathname: string): BreadcrumbItem[] { const menuPath = findMenuPath(MAIN_DRAWER_LINKS, pathname); if (!menuPath) return []; return menuPath.map((menu, index) => { const isLast = index === menuPath.length - 1; return { label: menu.text, href: isLast ? menu.link : undefined, isActive: isLast, icon: menu.icon ? ( ) : undefined, }; }); } const EllipsisDropdown = ({ hiddenItems, }: { hiddenItems: BreadcrumbItem[]; }) => { const dropdownId = useId(); const anchorId = useId(); return (
  • {/* Ellipsis Button */} {/* Dropdown Menu using popover API */}
      {hiddenItems.map((item, index) => { const itemStyles = cn( '[&]:flex [&]:items-center [&]:justify-start py-1 text-sm', // Disabled state item.isDisabled && 'text-base-content/40 opacity-50', // Active/Last state (item.isActive || item.isDisabled) && 'text-primary', // Regular clickable state !item.isDisabled && 'text-base-content/50' ); const itemContent = (
      {item.icon && ( {item.icon} )} {item.label}
      ); return (
    • {item.href && !item.isDisabled ? ( e.stopPropagation()} > {itemContent} ) : (
      {itemContent}
      )}
    • ); })}
  • ); }; const Breadcrumb = ({ items, size = 'md', maxVisibleItems = 3, showEllipsisDropdown = true, className, ...props }: BreadcrumbsProps) => { const sizeClasses = { xs: 'text-xs', sm: 'text-sm', md: 'text-base', lg: 'text-lg', xl: 'text-xl', }; const getItemStyles = ( item: BreadcrumbItem, position: 'first' | 'middle' | 'last' = 'middle' ) => { const baseClasses = 'inline-flex items-center gap-2'; // Disabled state if (item.isDisabled) { return `${baseClasses} text-base-content/40 !cursor-default opacity-50 hover:!no-underline`; } // Active/Last state (no underline) if (item.isActive || position === 'last') { return `${baseClasses} text-primary !cursor-pointer hover:!no-underline`; } // Regular clickable state return `${baseClasses} text-base-content/60`; }; const renderItem = ( item: BreadcrumbItem, position: 'first' | 'middle' | 'last' = 'middle' ) => { const styles = getItemStyles(item, position); // Disabled items if (item.isDisabled) { return ( {item.icon && item.icon} {item.label} ); } // Active/Last items if (item.isActive || position === 'last') { if (item.href) { return ( {item.icon && ( {item.icon} )} {item.label} ); } return ( {item.icon && item.icon} {item.label} ); } // Regular items if (item.href) { return ( {item.icon && {item.icon}} {item.label} ); } return ( {item.icon && item.icon} {item.label} ); }; const renderBreadcrumbList = () => { // Show all items if within limit if (items.length <= maxVisibleItems) { return items.map((item, index) => { const position = index === 0 ? 'first' : index === items.length - 1 ? 'last' : 'middle'; return
  • {renderItem(item, position)}
  • ; }); } // Collapsed items indexing when exceeding limit const firstItem = items[0]; const lastItem = items[items.length - 1]; const visibleMiddleItems = items.slice(1, -1).slice(-(maxVisibleItems - 2)); const hiddenItems = items.slice(1, -1).slice(0, -(maxVisibleItems - 2)); const showEllipsis = showEllipsisDropdown && hiddenItems.length > 0; return ( <>
  • {renderItem(firstItem, 'first')}
  • {/* Ellipsis for hidden items with dropdown */} {showEllipsis && } {/* Middle items */} {visibleMiddleItems.map((item, index) => (
  • {renderItem(item, 'middle')}
  • ))}
  • {renderItem(lastItem, 'last')}
  • ); }; return ( ); }; export default Breadcrumb;