grafana/public/app/core/components/NavBar/NavBarItem.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

116 lines
3.9 KiB
TypeScript

import { css, cx } from '@emotion/css';
import { Item } from '@react-stately/collections';
import React from 'react';
import { GrafanaTheme2, locationUtil, NavMenuItemType, NavModelItem } from '@grafana/data';
import { locationService } from '@grafana/runtime';
import { toIconName, useTheme2 } from '@grafana/ui';
import { NavBarItemMenu } from './NavBarItemMenu';
import { NavBarItemMenuTrigger } from './NavBarItemMenuTrigger';
import { getNavBarItemWithoutMenuStyles } from './NavBarItemWithoutMenu';
import { NavBarMenuItem } from './NavBarMenuItem';
import { useNavBarContext } from './context';
import { getNavModelItemKey } from './utils';
export interface Props {
isActive?: boolean;
className?: string;
reverseMenuDirection?: boolean;
link: NavModelItem;
}
const NavBarItem = ({ isActive = false, className, reverseMenuDirection = false, link }: Props) => {
const theme = useTheme2();
const menuItems = link.children ?? [];
const { menuIdOpen } = useNavBarContext();
// Spreading `menuItems` here as otherwise we'd be mutating props
const menuItemsSorted = reverseMenuDirection ? [...menuItems].reverse() : menuItems;
const filteredItems = menuItemsSorted
.filter((item) => !item.hideFromMenu)
.map((i) => ({ ...i, menuItemType: NavMenuItemType.Item }));
const adjustHeightForBorder = filteredItems.length === 0;
const styles = getStyles(theme, adjustHeightForBorder, isActive);
const section: NavModelItem = {
...link,
children: filteredItems,
menuItemType: NavMenuItemType.Section,
};
const items: NavModelItem[] = [section].concat(filteredItems);
const onNavigate = (item: NavModelItem) => {
const { url, target, onClick } = item;
onClick?.();
if (url) {
if (!target && url.startsWith('/')) {
locationService.push(locationUtil.stripBaseFromUrl(url));
} else {
window.open(url, target);
}
}
};
return (
<li className={cx(styles.container, { [styles.containerHover]: section.id === menuIdOpen }, className)}>
<NavBarItemMenuTrigger
item={section}
isActive={isActive}
label={link.text}
reverseMenuDirection={reverseMenuDirection}
>
<NavBarItemMenu
items={items}
reverseMenuDirection={reverseMenuDirection}
adjustHeightForBorder={adjustHeightForBorder}
disabledKeys={['divider', 'subtitle']}
aria-label={section.text}
onNavigate={onNavigate}
>
{(item: NavModelItem) => {
const isSection = item.menuItemType === NavMenuItemType.Section;
const iconName = item.icon ? toIconName(item.icon) : undefined;
const icon = item.showIconInNavbar && !isSection ? iconName : undefined;
return (
<Item key={getNavModelItemKey(item)} textValue={item.text}>
<NavBarMenuItem
isDivider={!isSection && item.divider}
icon={icon}
target={item.target}
text={item.text}
url={item.url}
onClick={item.onClick}
styleOverrides={cx(styles.primaryText, { [styles.header]: isSection })}
/>
</Item>
);
}}
</NavBarItemMenu>
</NavBarItemMenuTrigger>
</li>
);
};
export default NavBarItem;
const getStyles = (theme: GrafanaTheme2, adjustHeightForBorder: boolean, isActive?: boolean) => ({
...getNavBarItemWithoutMenuStyles(theme, isActive),
containerHover: css({
backgroundColor: theme.colors.action.hover,
color: theme.colors.text.primary,
}),
primaryText: css({
color: theme.colors.text.primary,
}),
header: css({
height: `calc(${theme.spacing(6)} - ${adjustHeightForBorder ? 2 : 1}px)`,
fontSize: theme.typography.h4.fontSize,
fontWeight: theme.typography.h4.fontWeight,
padding: `${theme.spacing(1)} ${theme.spacing(2)}`,
whiteSpace: 'nowrap',
width: '100%',
}),
});