diff --git a/packages/core/src/layout/Header/Header.test.tsx b/packages/core/src/layout/Header/Header.test.tsx index 5d28c6633f..320592c218 100644 --- a/packages/core/src/layout/Header/Header.test.tsx +++ b/packages/core/src/layout/Header/Header.test.tsx @@ -58,4 +58,11 @@ describe('
', () => { ); rendered.getByText('tool'); }); + + it('should have breadcrumb rendered', () => { + const rendered = render( + wrapInTestApp(
), + ); + rendered.getAllByText('Title'); + }); }); diff --git a/packages/core/src/layout/Header/Header.tsx b/packages/core/src/layout/Header/Header.tsx index 6b9ea05245..3bd95d0ef3 100644 --- a/packages/core/src/layout/Header/Header.tsx +++ b/packages/core/src/layout/Header/Header.tsx @@ -16,9 +16,15 @@ import React, { ReactNode, CSSProperties, FC, useContext } from 'react'; import { Helmet } from 'react-helmet'; -import { Typography, Tooltip, makeStyles } from '@material-ui/core'; +import { + Link, + Typography, + Tooltip, + makeStyles, + Breadcrumbs, +} from '@material-ui/core'; +import ChevronRightIcon from '@material-ui/icons/ChevronRight'; import { BackstageTheme } from '@backstage/theme'; - import { PageThemeContext } from '../Page/Page'; const useStyles = makeStyles( @@ -69,6 +75,21 @@ const useStyles = makeStyles( marginBottom: theme.spacing(1), color: theme.palette.bursts.fontColor, }, + breadcrumb: { + fontSize: 'calc(15px + 1 * ((100vw - 320px) / 680))', + color: theme.palette.bursts.fontColor, + }, + breadcrumbType: { + fontSize: 'inherit', + opacity: 0.7, + marginRight: -theme.spacing(0.3), + marginBottom: theme.spacing(0.3), + }, + breadcrumbTitle: { + fontSize: 'inherit', + marginLeft: -theme.spacing(0.3), + marginBottom: theme.spacing(0.3), + }, }), ); @@ -87,7 +108,8 @@ type Props = { type TypeFragmentProps = { classes: HeaderStyles; - type?: Props['title']; + pageTitle: string | ReactNode; + type?: Props['type']; typeLink?: Props['typeLink']; }; @@ -102,17 +124,32 @@ type SubtitleFragmentProps = { subtitle?: Props['subtitle']; }; -const TypeFragment: FC = ({ type, typeLink, classes }) => { +const TypeFragment: FC = ({ + type, + typeLink, + classes, + pageTitle, +}) => { if (!type) { return null; } if (!typeLink) { - // TODO: Add breadcrumbs. return {type}; } - return {type}; + return ( + } + className={classes.breadcrumb} + > + + {type} + + {pageTitle} + + ); }; const TitleFragment: FC = ({ @@ -175,7 +212,12 @@ export const Header: FC = ({
- + ', () => { ), ); expect(rendered.container.innerHTML).toContain('header'); - expect(rendered.getByText('test-site-name')).toBeDefined(); + expect(rendered.getAllByText('test-site-name')).toHaveLength(2); expect(rendered.getByText('test-site-desc')).toBeDefined(); }); }); diff --git a/plugins/techdocs/src/reader/components/TechDocsPageHeader.tsx b/plugins/techdocs/src/reader/components/TechDocsPageHeader.tsx index 8084378ca1..c59cce2b11 100644 --- a/plugins/techdocs/src/reader/components/TechDocsPageHeader.tsx +++ b/plugins/techdocs/src/reader/components/TechDocsPageHeader.tsx @@ -48,12 +48,14 @@ export const TechDocsPageHeader = ({ spec: { owner, lifecycle }, } = entityMetadataValues || { spec: {} }; + const componentLink = `/catalog/${kind}/${name}`; + const labels = ( <> + {name} } @@ -85,6 +87,8 @@ export const TechDocsPageHeader = ({ subtitle={ siteDescription && siteDescription !== 'None' ? siteDescription : '' } + type={name} + typeLink={componentLink} > {labels}