diff --git a/app/navigation/breadcrumbs.tsx b/app/navigation/breadcrumbs.tsx new file mode 100644 index 00000000..11cb6668 --- /dev/null +++ b/app/navigation/breadcrumbs.tsx @@ -0,0 +1,80 @@ +import * as React from 'react'; +import { + useLocation, + useMatches, + useSearchParams, + type UIMatch, +} from '@remix-run/react'; +import Nav from './nav'; +import NavLink from './nav-link'; +import NavDivider from './nav-divider'; +import type { SerializeFrom } from '@remix-run/node'; + +export default function Breadcrumbs() { + const matches = useMatches(); + const { pathname: currentPathname } = useLocation(); + const [searchParams] = useSearchParams(); + const q = searchParams.get('q'); + const isSearching = currentPathname === '/search' && q; + const matchesWithBreadcrumbData = matches.filter(hasHandleWithBreadcrumb); + + return ( + + ); +} + +export type BreadcrumbHandle = { + breadcrumb: (matches: ReturnType) => { + title: string | React.ReactElement; + }; +}; + +function hasHandleWithBreadcrumb( + match: UIMatch, +): match is UIMatch { + return ( + match.handle !== null && + typeof match.handle === 'object' && + 'breadcrumb' in match.handle && + typeof match.handle.breadcrumb === 'function' + ); +} + +/** + * Gets loader data for an ancestor route from a route id and the `matches` + * object returned from the `useMatches` function. + */ +export function getLoaderDataForHandle( + routeId: string, + matches: ReturnType, +) { + const match = matches.find((match) => match.id === routeId); + if (!match) throw new Error(`No match found for route id "${routeId}"`); + return match.data as SerializeFrom; +} diff --git a/app/navigation/nav-link.tsx b/app/navigation/nav-link.tsx index 66b6c8f2..f3c0a00d 100644 --- a/app/navigation/nav-link.tsx +++ b/app/navigation/nav-link.tsx @@ -2,15 +2,13 @@ import { Link, type LinkProps } from '@remix-run/react'; export default function NavLink({ children, to }: NavLinkProps) { return ( -
  • - - {children} - -
  • + + {children} + ); } diff --git a/app/navigation/nav.tsx b/app/navigation/nav.tsx index e091e9c2..1d3f5ae9 100644 --- a/app/navigation/nav.tsx +++ b/app/navigation/nav.tsx @@ -1,5 +1,3 @@ export default function Nav({ children }: { children: React.ReactNode }) { - return ( - - ); + return ; } diff --git a/app/root.tsx b/app/root.tsx index ff54cace..0b7b0d0c 100644 --- a/app/root.tsx +++ b/app/root.tsx @@ -1,4 +1,3 @@ -import * as React from 'react'; import { cssBundleHref } from '@remix-run/css-bundle'; import { json, type LinksFunction, type MetaFunction } from '@remix-run/node'; import { @@ -20,6 +19,8 @@ import { getEnvVars } from '~/utils/env.server'; import SkipNavLink from '~/core/skip-nav-link'; import Header from '~/core/header'; import Footer from '~/core/footer'; +import Breadcrumbs from '~/navigation/breadcrumbs'; +import type { AppRouteHandle } from './types'; export const loader = async () => { const { SITE_IMAGE_URL, SITE_IMAGE_ALT } = getEnvVars(); @@ -61,6 +62,10 @@ export const meta: MetaFunction = ({ data }) => { ]; }; +export const handle: AppRouteHandle = { + breadcrumb: () => ({ title: 'All Drinks' }), +}; + export const links: LinksFunction = () => [ ...(cssBundleHref ? [{ rel: 'stylesheet', href: cssBundleHref }] : []), { @@ -98,8 +103,11 @@ export default function App() {
    -
    - +
    + +
    + +