diff --git a/.eslintrc.js b/.eslintrc.js index cb9b9e50c..1d0db8d65 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { "@typescript-eslint/no-unsafe-argument": 0, "@typescript-eslint/no-non-null-assertion": 0, "@typescript-eslint/no-explicit-any": 0, + "react/prop-types": 0, }, settings: { react: { diff --git a/app/components/Breadcrumbs.tsx b/app/components/Breadcrumbs.tsx new file mode 100644 index 000000000..c17d627be --- /dev/null +++ b/app/components/Breadcrumbs.tsx @@ -0,0 +1,58 @@ +import { Link, useMatches } from "@remix-run/react"; +import { useMemo, Fragment } from "react"; +import { useTranslation } from "react-i18next"; +import { isDefined } from "~/utils/arrays"; +import { type SendouRouteHandle } from "~/utils/remix"; + +type Crumb = { + path: string; + name: string; +}; + +function useBreadcrumbs(): Crumb[] { + const matches = useMatches(); + const { t } = useTranslation("common"); + + return useMemo( + () => + matches + .map((match) => { + const handle = match.handle as undefined | SendouRouteHandle; + const name = handle?.breadcrumb?.({ match, t }); + return name ? { path: match.pathname, name } : undefined; + }) + .filter(isDefined), + [matches, t] + ); +} + +export function Breadcrumbs() { + const breadcrumbs = useBreadcrumbs(); + + const showBreadcrumbs = breadcrumbs.length > 0; + + if (!showBreadcrumbs) { + return null; + } + + return ( + + ); +} diff --git a/app/components/Label.tsx b/app/components/Label.tsx index 828456dc7..08e349d28 100644 --- a/app/components/Label.tsx +++ b/app/components/Label.tsx @@ -13,6 +13,7 @@ type LabelProps = Pick< }; required?: boolean; className?: string; + labelClassName?: string; }; export function Label({ @@ -21,10 +22,11 @@ export function Label({ children, htmlFor, className, + labelClassName, }: LabelProps) { return (
-