-
Notifications
You must be signed in to change notification settings - Fork 73
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
12bc0f9
commit 5fc96af
Showing
75 changed files
with
1,053 additions
and
958 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,88 @@ | ||
import { Box, BoxProps, Flex } from "fidesui"; | ||
import { isArray } from "lodash"; | ||
import { isValidElement, ReactElement } from "react"; | ||
import { AntFlex as Flex, Heading } from "fidesui"; | ||
import { ComponentProps, ReactNode } from "react"; | ||
|
||
import Breadcrumbs, { BreadcrumbsProps } from "~/features/common/Breadcrumbs"; | ||
import { NextBreadcrumb, NextBreadcrumbProps } from "./nav/v2/NextBreadcrumb"; | ||
|
||
interface PageHeaderProps extends BoxProps { | ||
breadcrumbs: BreadcrumbsProps["breadcrumbs"] | ReactElement | false; | ||
interface PageHeaderProps extends ComponentProps<"div"> { | ||
heading?: ReactNode; | ||
breadcrumbItems?: NextBreadcrumbProps["items"]; | ||
isSticky?: boolean; | ||
rightContent?: ReactElement; | ||
rightContent?: ReactNode; | ||
children?: ReactNode; | ||
} | ||
|
||
/** | ||
* A header component for pages. | ||
* | ||
* @param breadcrumbs - The breadcrumbs to display in the page header. | ||
* @param heading - The main heading to display in the page header. Can be a string or a React element. String will be rendered as an H1. | ||
* @param breadcrumbItems - Extends Ant Design Breadcrumb component `items` property. If an item has a `href` property, it will be wrapped in a Next.js link. | ||
* Can be an array of breadcrumb items (more information on Breadcrumbs component), a React element | ||
* if you want to render something else, or false to not show any breadcrumbs. | ||
* @param isSticky - Whether the page header should stick to the top of the page while scrolling. Defaults to true. | ||
* @param children - Additional content to display in the header at the bottom. | ||
* @param children - Additional content to display in the header below the heading and breadcrumb. | ||
* @param rightContent - Additional content to display in the header on the right side. Usually for displaying buttons. | ||
*/ | ||
const PageHeader = ({ | ||
breadcrumbs, | ||
heading, | ||
breadcrumbItems, | ||
isSticky = true, | ||
children, | ||
rightContent, | ||
...otherProps | ||
style, | ||
...props | ||
}: PageHeaderProps): JSX.Element => ( | ||
<Box | ||
bgColor="white" | ||
paddingY={5} | ||
{...(isSticky ? { position: "sticky", top: 0, left: 0, zIndex: 10 } : {})} | ||
{...otherProps} | ||
<div | ||
{...props} | ||
style={ | ||
isSticky | ||
? { | ||
position: "sticky", | ||
top: "-24px", | ||
paddingTop: "24px", | ||
paddingBottom: "24px", | ||
paddingLeft: "40px", | ||
marginLeft: "-40px", | ||
paddingRight: "40px", | ||
marginRight: "-40px", | ||
marginTop: "-24px", | ||
left: 0, | ||
zIndex: 20, // needs to be above Table header but below popovers, modals, drawers, etc. | ||
backgroundColor: "white", | ||
...style, | ||
} | ||
: { | ||
paddingBottom: "24px", | ||
...style, | ||
} | ||
} | ||
> | ||
<Flex alignItems="flex-start"> | ||
<Box flex={1}> | ||
{/* If breadcrumbs is an array, render the Breadcrumbs component. */} | ||
{isArray(breadcrumbs) && ( | ||
<Box marginBottom={children ? 4 : 0}> | ||
<Breadcrumbs breadcrumbs={breadcrumbs} /> | ||
</Box> | ||
)} | ||
{/* If breadcrumbs is a React element, render it. */} | ||
{isValidElement(breadcrumbs) && breadcrumbs} | ||
</Box> | ||
{rightContent && <Box>{rightContent}</Box>} | ||
<Flex justify="space-between"> | ||
{typeof heading === "string" ? ( | ||
<Heading | ||
className={!!breadcrumbItems || !!children ? "pb-4" : undefined} | ||
fontSize="2xl" | ||
data-testid="page-heading" | ||
> | ||
{heading} | ||
</Heading> | ||
) : ( | ||
heading | ||
)} | ||
{rightContent && ( | ||
<div data-testid="page-header-right-content">{rightContent}</div> | ||
)} | ||
</Flex> | ||
|
||
{!!breadcrumbItems && ( | ||
<NextBreadcrumb | ||
className={children ? "pb-4" : undefined} | ||
items={breadcrumbItems} | ||
data-testid="page-breadcrumb" | ||
/> | ||
)} | ||
|
||
{children} | ||
</Box> | ||
</div> | ||
); | ||
|
||
export default PageHeader; |
79 changes: 79 additions & 0 deletions
79
clients/admin-ui/src/features/common/nav/v2/NextBreadcrumb.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
/* eslint-disable tailwindcss/no-custom-classname */ | ||
import { | ||
AntBreadcrumb as Breadcrumb, | ||
AntBreadcrumbItemType as BreadcrumbItemType, | ||
AntBreadcrumbProps as BreadcrumbProps, | ||
AntTypography as Typography, | ||
} from "fidesui"; | ||
import { Url } from "next/dist/shared/lib/router/router"; | ||
import NextLink from "next/link"; | ||
import { ReactNode, useMemo } from "react"; | ||
|
||
const { Text } = Typography; | ||
|
||
// Too difficult to make `path` work with Next.js links so we'll just remove it from the type | ||
interface NextBreadcrumbItemType | ||
extends Omit<BreadcrumbItemType, "path" | "href"> { | ||
/** | ||
* becomes NextJS link href | ||
*/ | ||
href?: Url; | ||
icon?: ReactNode; | ||
} | ||
|
||
export interface NextBreadcrumbProps extends Omit<BreadcrumbProps, "items"> { | ||
items?: NextBreadcrumbItemType[]; | ||
} | ||
|
||
/** | ||
* Extends the Ant Design Breadcrumb component to allow for Next.js links. If an item has a `href` property, it will be wrapped in a Next.js link. | ||
* | ||
* Note: Since Next.js link is used to wrap the entire item, we cannot do these other customizations as an HOC in FidesUI due to the order of operations. HOC would be applied AFTER the Next.js link is applied, but we want the Next.js link to wrap the entire item after all other customizations. And, of course, we can't use Next.js links in FidesUI. | ||
*/ | ||
export const NextBreadcrumb = ({ items, ...props }: NextBreadcrumbProps) => { | ||
const formattedItems = useMemo( | ||
() => | ||
items?.map((item, i) => { | ||
const isCurrentPage = i === items.length - 1; | ||
const modifiedItem = { ...item }; | ||
if (typeof modifiedItem.title === "string") { | ||
// for everything except the current page, truncate the title if it's too long | ||
modifiedItem.title = ( | ||
<Text | ||
style={{ | ||
color: "inherit", | ||
maxWidth: !isCurrentPage ? 400 : undefined, | ||
}} | ||
ellipsis={!isCurrentPage} | ||
> | ||
{modifiedItem.title} | ||
</Text> | ||
); | ||
} | ||
if (modifiedItem.icon) { | ||
modifiedItem.title = ( | ||
<> | ||
<span className="anticon align-text-bottom"> | ||
{modifiedItem.icon} | ||
</span> | ||
{modifiedItem.title} | ||
</> | ||
); | ||
} | ||
if (modifiedItem.href && modifiedItem.title) { | ||
// repeat the ant breadcrumb link class to match the style and margin of the ant breadcrumb item | ||
modifiedItem.title = ( | ||
<NextLink href={modifiedItem.href} className="ant-breadcrumb-link"> | ||
{modifiedItem.title} | ||
</NextLink> | ||
); | ||
delete modifiedItem.href; | ||
} | ||
return modifiedItem; | ||
}), | ||
[items], | ||
); | ||
return ( | ||
<Breadcrumb items={formattedItems as BreadcrumbItemType[]} {...props} /> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.