Breadcrumbs.tsx raw

   1  import { Fragment } from "react";
   2  import { Link, useMatches } from "react-router";
   3  import {
   4    Breadcrumb,
   5    BreadcrumbItem,
   6    BreadcrumbLink,
   7    BreadcrumbList,
   8    BreadcrumbSeparator,
   9  } from "src/components/ui/breadcrumb";
  10  
  11  type MatchWithCrumb = {
  12    pathname: string;
  13    handle?: {
  14      crumb?: () => React.ReactNode;
  15    };
  16  };
  17  
  18  function Breadcrumbs() {
  19    const matches = useMatches() as MatchWithCrumb[]; // Type-cast useMatches result to MatchWithCrumb array
  20  
  21    const crumbs = matches
  22      // First, get rid of any matches that don't have a handle or crumb
  23      .filter(
  24        (
  25          match
  26        ): match is MatchWithCrumb & {
  27          handle: { crumb: () => React.ReactNode };
  28        } => Boolean(match.handle?.crumb)
  29      );
  30  
  31    // Compare pathnames of index routes to remove duplicates
  32    const isIndexRoute =
  33      crumbs.length >= 2 && crumbs[crumbs.length - 1].pathname
  34        ? crumbs[crumbs.length - 1].pathname.slice(0, -1) ===
  35          crumbs[crumbs.length - 2].pathname
  36        : false;
  37  
  38    // Remove the last item if it's an index route to prevent e.g. Wallet > Wallet
  39    const filteredCrumbs = isIndexRoute ? crumbs.slice(0, -1) : crumbs;
  40  
  41    // Skip rendering for breadcrumbs consisting of 2 (or less) items
  42    if (filteredCrumbs.length < 3) {
  43      return null;
  44    }
  45  
  46    return (
  47      <>
  48        <Breadcrumb>
  49          <BreadcrumbList>
  50            {filteredCrumbs.map((crumb, index) => (
  51              <Fragment key={index}>
  52                <BreadcrumbItem>
  53                  {index + 1 < filteredCrumbs.length ? (
  54                    <BreadcrumbLink asChild>
  55                      <Link to={crumb.pathname}>{crumb.handle.crumb()}</Link>
  56                    </BreadcrumbLink>
  57                  ) : (
  58                    <>{crumb.handle.crumb()}</>
  59                  )}
  60                </BreadcrumbItem>
  61                {index + 1 < filteredCrumbs.length && <BreadcrumbSeparator />}
  62              </Fragment>
  63            ))}
  64          </BreadcrumbList>
  65        </Breadcrumb>
  66      </>
  67    );
  68  }
  69  
  70  export default Breadcrumbs;
  71