-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Issue 704] Breadcrumbs #776
Changes from all commits
94b038b
9575429
362ee03
ef4f024
81f7805
7d81b36
536cac7
fd88d94
dd3b6f3
813db1e
a099d40
da4a48f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { | ||
Breadcrumb, | ||
BreadcrumbBar, | ||
BreadcrumbLink, | ||
GridContainer, | ||
} from "@trussworks/react-uswds"; | ||
|
||
export type Breadcrumb = { | ||
title: string; | ||
path: string; | ||
}; | ||
|
||
export type BreadcrumbList = Breadcrumb[]; | ||
|
||
type Props = { | ||
breadcrumbList: BreadcrumbList; | ||
}; | ||
|
||
const Breadcrumbs = ({ breadcrumbList }: Props) => { | ||
const rdfaMetadata = { | ||
ol: { | ||
vocab: "http://schema.org/", | ||
typeof: "BreadcrumbList", | ||
}, | ||
li: { | ||
property: "itemListElement", | ||
typeof: "ListItem", | ||
}, | ||
a: { | ||
property: "item", | ||
typeof: "WebPage", | ||
}, | ||
}; | ||
|
||
const breadcrumArray = breadcrumbList.map((breadcrumbInfo, i) => { | ||
return ( | ||
<Breadcrumb | ||
key={breadcrumbInfo.title + "-crumb"} | ||
current={i + 1 === breadcrumbList.length} | ||
{...rdfaMetadata.li} | ||
> | ||
{i + 1 !== breadcrumbList.length ? ( | ||
<BreadcrumbLink href={breadcrumbInfo.path} {...rdfaMetadata.a}> | ||
{} | ||
<span property="name">{breadcrumbInfo.title}</span> | ||
</BreadcrumbLink> | ||
) : ( | ||
<span property="name">{breadcrumbInfo.title}</span> | ||
)} | ||
<meta property="position" content={(i + 1).toString()} /> | ||
</Breadcrumb> | ||
); | ||
}); | ||
|
||
return ( | ||
<GridContainer | ||
className="padding-y-1 tablet:padding-y-3 desktop-lg:padding-y-6" | ||
data-testid="breadcrumb" | ||
> | ||
<BreadcrumbBar listProps={{ ...rdfaMetadata.ol }}> | ||
{breadcrumArray} | ||
</BreadcrumbBar> | ||
</GridContainer> | ||
); | ||
}; | ||
|
||
export default Breadcrumbs; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { Breadcrumb, BreadcrumbList } from "src/components/Breadcrumbs"; | ||
|
||
const HOME: Breadcrumb = { title: "Home", path: "/" }; | ||
const RESEARCH: Breadcrumb = { title: "Research", path: "research/" }; | ||
const PROCESS: Breadcrumb = { title: "Process", path: "process/" }; | ||
|
||
export const RESEARCH_CRUMBS: BreadcrumbList = [HOME, RESEARCH]; | ||
export const PROCESS_CRUMBS: BreadcrumbList = [HOME, PROCESS]; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import { Meta } from "@storybook/react"; | ||
import { PROCESS_CRUMBS, RESEARCH_CRUMBS } from "src/constants/breadcrumbs"; | ||
|
||
import Breadcrumbs from "src/components/Breadcrumbs"; | ||
|
||
const meta: Meta<typeof Breadcrumbs> = { | ||
title: "Components/Breadcrumbs", | ||
component: Breadcrumbs, | ||
}; | ||
export default meta; | ||
|
||
export const Home = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think we'd ever show breadcrumbs on root. Okay to show how it'd work if we did tho. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I wasn't sure what to use for the default story. I could change it to be either Research or Process 🤷, let me know if you have a preference There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably fine as-is. We can revisit in the future as our route/page requirements become more complex. |
||
parameters: { | ||
design: { | ||
type: "figma", | ||
url: "https://www.figma.com/file/lpKPdyTyLJB5JArxhGjJnE/beta.grants.gov?type=design&node-id=918%3A1698&mode=design&t=rKuHZ4QiepVfLvwq-1", | ||
}, | ||
}, | ||
args: { | ||
breadcrumbList: [{ title: "Home", path: "/" }], | ||
}, | ||
}; | ||
|
||
export const Research = { | ||
parameters: Home.parameters, | ||
args: { | ||
breadcrumbList: RESEARCH_CRUMBS, | ||
}, | ||
}; | ||
|
||
export const Process = { | ||
parameters: Home.parameters, | ||
args: { | ||
breadcrumbList: PROCESS_CRUMBS, | ||
}, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import { render, screen } from "@testing-library/react"; | ||
import { RESEARCH_CRUMBS } from "src/constants/breadcrumbs"; | ||
|
||
import Breadcrumbs from "src/components/Breadcrumbs"; | ||
|
||
describe("Breadcrumb", () => { | ||
it("Renders without errors", () => { | ||
render(<Breadcrumbs breadcrumbList={RESEARCH_CRUMBS} />); | ||
const bc = screen.getByTestId("breadcrumb"); | ||
expect(bc).toBeInTheDocument(); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we infer hierarchy from routes so we don't have to define the breadcrumb trail for each page? Might there be downsides for doing that? We'd still need a lookup for the title strings. 🤔 Just thinking out loud here. No change required, maybe just food for thought as we get into more complex info architecture and page/route structures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought about that too and was considering using https://nextjs.org/docs/app/api-reference/functions/use-pathname to get and and then break up the path. But realized as you mentioned we'd still need to look up the title strings based on the path, so doesn't really save us much and can be harder to track down if it breaks.