Skip to content

Commit

Permalink
frontend: Improve breadcrumbs UX
Browse files Browse the repository at this point in the history
  • Loading branch information
septum committed Nov 13, 2024
1 parent 2a2f4fe commit 6425d30
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 21 deletions.
2 changes: 1 addition & 1 deletion frontend/packages/core/src/AppProvider/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ const ClutchApp = ({
: workflow.displayName;

const workflowLayoutProps: LayoutProps = {
workflow,
workflowsInPath: workflows.filter(w => w.path === workflow.path),
title: heading,
subtitle: route.description,
variant:
Expand Down
16 changes: 6 additions & 10 deletions frontend/packages/core/src/WorkflowLayout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { matchPath, useParams } from "react-router-dom";
import { useParams } from "react-router-dom";
import type { Interpolation } from "@emotion/styled";
import type { CSSObject, Theme } from "@mui/material";
import { alpha } from "@mui/material";
Expand All @@ -14,7 +14,7 @@ import { generateBreadcrumbsEntries } from "../utils";
export type LayoutVariant = "standard" | "wizard";

export type LayoutProps = {
workflow: Workflow;
workflowsInPath: Array<Workflow>;
variant?: LayoutVariant | null;
title?: string | ((params: Record<string, string>) => string);
subtitle?: string;
Expand Down Expand Up @@ -88,7 +88,7 @@ const Subtitle = styled(Typography)(({ theme }: { theme: Theme }) => ({
}));

const WorkflowLayout = ({
workflow,
workflowsInPath,
variant = null,
title = null,
subtitle = null,
Expand All @@ -99,22 +99,18 @@ const WorkflowLayout = ({
const params = useParams();
const location = useLocation();

const entries = generateBreadcrumbsEntries(workflowsInPath, location);

if (variant === null) {
return <>{children}</>;
}

const workflowPaths = workflow.routes.map(({ path }) => `/${workflow.path}/${path}`);
const breadcrumbsEntries = generateBreadcrumbsEntries(
location,
url => !!workflowPaths.find(path => !!matchPath({ path }, url))
);

return (
<LayoutContainer $variant={variant}>
{!hideHeader && (
<PageHeader $variant={variant}>
<PageHeaderBreadcrumbsWrapper>
<Breadcrumbs entries={breadcrumbsEntries} />
<Breadcrumbs entries={entries} />
</PageHeaderBreadcrumbsWrapper>
{!breadcrumbsOnly && (title || subtitle) && (
<PageHeaderMainContainer>
Expand Down
36 changes: 26 additions & 10 deletions frontend/packages/core/src/utils/generateBreadcrumbsEntries.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
import type { Location } from "react-router-dom";
import { Location, matchPath } from "react-router-dom";

import type { Workflow } from "../AppProvider/workflow";
import type { BreadcrumbEntry } from "../Breadcrumbs";

const generateBreadcrumbsEntries = (location: Location, validateUrl: (url: string) => boolean) => {
const HOME_ENTRY = { label: "Home", url: "/" };

const generateBreadcrumbsEntries = (workflowsInPath: Array<Workflow>, location: Location) => {
const firstWorkflow = workflowsInPath[0];
const allRoutes = workflowsInPath.flatMap(w => w.routes);
const fullPaths = allRoutes.map(({ path }) => `/${firstWorkflow.path}/${path}`);

const labels = decodeURIComponent(location.pathname)
.split("/")
.slice(1, location.pathname.endsWith("/") ? -1 : undefined);

const entries: Array<BreadcrumbEntry> = [{ label: "Home", url: "/" }].concat(
labels.map((label, index) => {
let url = `/${labels.slice(0, index + 1).join("/")}`;
const entries: Array<BreadcrumbEntry> = [HOME_ENTRY].concat(
labels.map((defaultLabel, index) => {
const nextIndex = index + 1;
const url = `/${labels.slice(0, nextIndex).join("/")}`;

if (!validateUrl(url)) {
url = undefined;
}
const path = fullPaths.find(p => !!matchPath(p, url));
const route = path
? allRoutes.find(r =>
r.path.startsWith("/")
? r.path
: `/${r.path}` === `/${path.split("/").slice(2).join("/")}`
)
: null;

return {
label,
url,
label:
route?.displayName ||
(allRoutes.length === 1 && firstWorkflow.displayName) ||
defaultLabel,
url: !!path && labels.length !== nextIndex ? url : null,
};
})
);
Expand Down

0 comments on commit 6425d30

Please sign in to comment.