grafana/public/app/core/components/PageNew/SectionNavItem.tsx
Josh Hunt 504eabbe80
Navigation: Ensure command palette is correctly translated (#61103)
* Navigation: Translate nav tree in store

* Remove usage of getNavTitle

* properly translate children

* add pubdash translation

* remove extraneous calls to translation in PageHeader

* empty commit

* correctly allow subtitle to be overrwitten (thank you tests!)

---------

Co-authored-by: Ashley Harrison <ashley.harrison@grafana.com>
2023-02-08 13:15:37 +00:00

124 lines
3.3 KiB
TypeScript

import { css, cx } from '@emotion/css';
import React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { reportInteraction } from '@grafana/runtime';
import { useStyles2, Icon } from '@grafana/ui';
export interface Props {
item: NavModelItem;
isSectionRoot?: boolean;
}
export function SectionNavItem({ item, isSectionRoot = false }: Props) {
const styles = useStyles2(getStyles);
const children = item.children?.filter((x) => !x.hideFromTabs);
// If first root child is a section skip the bottom margin (as sections have top margin already)
const noRootMargin = isSectionRoot && Boolean(item.children![0].children?.length);
const linkClass = cx({
[styles.link]: true,
[styles.activeStyle]: item.active,
[styles.isSection]: Boolean(children?.length) || item.isSection,
[styles.isSectionRoot]: isSectionRoot,
[styles.noRootMargin]: noRootMargin,
});
let icon: React.ReactNode | null = null;
if (item.img) {
icon = <img data-testid="section-image" className={styles.sectionImg} src={item.img} alt="" />;
} else if (item.icon) {
icon = <Icon data-testid="section-icon" name={item.icon} />;
}
const onItemClicked = () => {
reportInteraction('grafana_navigation_item_clicked', {
path: item.url ?? item.id,
sectionNav: true,
});
};
return (
<>
<a
onClick={onItemClicked}
href={item.url}
className={linkClass}
aria-label={selectors.components.Tab.title(item.text)}
role="tab"
aria-selected={item.active}
>
{isSectionRoot && icon}
{item.text}
{item.tabSuffix && <item.tabSuffix className={styles.suffix} />}
</a>
{children?.map((child, index) => (
<SectionNavItem item={child} key={index} />
))}
</>
);
}
const getStyles = (theme: GrafanaTheme2) => {
return {
link: css`
padding: ${theme.spacing(1, 0, 1, 1.5)};
display: flex;
align-items: center;
border-radius: ${theme.shape.borderRadius(2)};
gap: ${theme.spacing(1)};
height: 100%;
position: relative;
color: ${theme.colors.text.secondary};
&:hover,
&:focus {
text-decoration: underline;
z-index: 1;
}
`,
activeStyle: css`
label: activeTabStyle;
color: ${theme.colors.text.primary};
background: ${theme.colors.emphasize(theme.colors.background.canvas, 0.03)};
&::before {
display: block;
content: ' ';
position: absolute;
left: 0;
width: 4px;
bottom: 2px;
top: 2px;
border-radius: 2px;
background-image: ${theme.colors.gradients.brandVertical};
}
`,
suffix: css`
margin-left: ${theme.spacing(1)};
`,
sectionImg: css({
height: 18,
}),
isSectionRoot: css({
fontSize: theme.typography.h4.fontSize,
marginTop: 0,
marginBottom: theme.spacing(2),
fontWeight: theme.typography.fontWeightMedium,
}),
isSection: css({
color: theme.colors.text.primary,
fontSize: theme.typography.h5.fontSize,
marginTop: theme.spacing(2),
fontWeight: theme.typography.fontWeightMedium,
}),
noRootMargin: css({
marginBottom: 0,
}),
};
};