Navigation: Implement scrolling navbar + fix clickable area of grafana logo (#48045)

* Attach nav item menus to a portal that's a sibling of the chevron to prevent incorrect stacking

* add scrollbar to navbar

* Make clickable area of grafana logo full size

* hide vertical track as well

* prettier...
This commit is contained in:
Ashley Harrison 2022-04-22 11:04:04 +01:00 committed by GitHub
parent 3606527359
commit a34da3e248
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 46 additions and 23 deletions

View File

@ -391,7 +391,7 @@ const getCollapsibleStyles = (theme: GrafanaTheme2) => ({
position: 'relative',
display: 'grid',
gridAutoFlow: 'column',
gridTemplateColumns: '56px auto',
gridTemplateColumns: `${theme.spacing(7)} auto`,
}),
collapsibleMenuItem: css({
height: theme.spacing(6),

View File

@ -3,7 +3,7 @@ import { useLocation } from 'react-router-dom';
import { css, cx } from '@emotion/css';
import { cloneDeep } from 'lodash';
import { GrafanaTheme2, NavModelItem, NavSection } from '@grafana/data';
import { Icon, IconName, useTheme2 } from '@grafana/ui';
import { CustomScrollbar, Icon, IconName, useTheme2 } from '@grafana/ui';
import { config, locationService } from '@grafana/runtime';
import { getKioskMode } from 'app/core/navigation/kiosk';
import { KioskMode, StoreState } from 'app/types';
@ -13,10 +13,10 @@ import { NavBarMenu } from './NavBarMenu';
import NavBarItem from './NavBarItem';
import { useSelector } from 'react-redux';
import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu';
import { FocusScope } from '@react-aria/focus';
import { NavBarContext } from '../context';
import { NavBarToggle } from './NavBarToggle';
import { NavBarMenuPortalContainer } from './NavBarMenuPortalContainer';
import { FocusScope } from '@react-aria/focus';
const onOpenSearch = () => {
locationService.partial({ search: 'open' });
@ -90,6 +90,7 @@ export const NavBarNext = React.memo(() => {
<ul className={styles.itemList}>
<NavBarItemWithoutMenu
elClassName={styles.grafanaLogoInner}
isActive={isMatchOrChildMatch(homeItem, activeItem)}
label="Home"
className={styles.grafanaLogo}
@ -97,29 +98,36 @@ export const NavBarNext = React.memo(() => {
>
<Icon name="grafana" size="xl" />
</NavBarItemWithoutMenu>
<NavBarItem className={styles.search} isActive={activeItem === searchItem} link={searchItem}>
<Icon name="search" size="xl" />
</NavBarItem>
{coreItems.map((link, index) => (
<NavBarItem
key={`${link.id}-${index}`}
isActive={isMatchOrChildMatch(link, activeItem)}
link={{ ...link, subTitle: undefined, onClick: undefined }}
>
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
{link.img && <img src={link.img} alt={`${link.text} logo`} />}
<CustomScrollbar hideVerticalTrack hideHorizontalTrack>
<NavBarItem className={styles.search} isActive={activeItem === searchItem} link={searchItem}>
<Icon name="search" size="xl" />
</NavBarItem>
))}
{pluginItems.length > 0 &&
pluginItems.map((link, index) => (
<NavBarItem key={`${link.id}-${index}`} isActive={isMatchOrChildMatch(link, activeItem)} link={link}>
{coreItems.map((link, index) => (
<NavBarItem
key={`${link.id}-${index}`}
isActive={isMatchOrChildMatch(link, activeItem)}
link={{ ...link, subTitle: undefined, onClick: undefined }}
>
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
{link.img && <img src={link.img} alt={`${link.text} logo`} />}
</NavBarItem>
))}
{pluginItems.length > 0 &&
pluginItems.map((link, index) => (
<NavBarItem
key={`${link.id}-${index}`}
isActive={isMatchOrChildMatch(link, activeItem)}
link={link}
>
{link.icon && <Icon name={link.icon as IconName} size="xl" />}
{link.img && <img src={link.img} alt={`${link.text} logo`} />}
</NavBarItem>
))}
</CustomScrollbar>
{configItems.map((link, index) => (
<NavBarItem
key={`${link.id}-${index}`}
@ -171,7 +179,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
zIndex: theme.zIndex.sidemenu,
padding: `${theme.spacing(1)} 0`,
position: 'relative',
width: theme.spacing(7),
width: `calc(${theme.spacing(7)} + 1px)`,
borderRight: `1px solid ${theme.colors.border.weak}`,
[theme.breakpoints.down('md')]: {
@ -207,13 +215,22 @@ const getStyles = (theme: GrafanaTheme2) => ({
},
}),
grafanaLogo: css({
alignItems: 'stretch',
display: 'flex',
flexShrink: 0,
justifyContent: 'stretch',
}),
grafanaLogoInner: css({
alignItems: 'center',
display: 'flex',
img: {
height: theme.spacing(3),
width: theme.spacing(3),
},
height: '100%',
justifyContent: 'center',
width: '100%',
'> div': {
height: 'auto',
width: 'auto',
},
}),
search: css({
display: 'none',
@ -244,4 +261,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
right: '0px',
transform: `translateX(50%)`,
}),
menuPortalContainer: css({
zIndex: theme.zIndex.sidemenu,
}),
});

View File

@ -8,6 +8,9 @@ import { getFooterLinks } from '../Footer/Footer';
import { HelpModal } from '../help/HelpModal';
export const SEARCH_ITEM_ID = 'search';
export const NAV_MENU_PORTAL_CONTAINER_ID = 'navbar-menu-portal-container';
export const getNavMenuPortalContainer = () => document.getElementById(NAV_MENU_PORTAL_CONTAINER_ID) ?? document.body;
export const getForcedLoginUrl = (url: string) => {
const queryParams = new URLSearchParams(url.split('?')[1]);