mirror of
https://github.com/grafana/grafana.git
synced 2025-02-20 11:48:34 -06:00
* 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>
124 lines
3.3 KiB
TypeScript
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,
|
|
}),
|
|
};
|
|
};
|