Page: Refactor out section nav state logic and move it to SectionNav component (#57036)

pull/57080/head
Torkel Ödegaard 3 years ago committed by GitHub
parent 3f26ffde94
commit 0f9e6dda2d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 49
      public/app/core/components/PageNew/Page.tsx
  2. 72
      public/app/core/components/PageNew/SectionNav.tsx

@ -1,10 +1,9 @@
// Libraries
import { css, cx } from '@emotion/css';
import React, { useEffect, useState } from 'react';
import { useLocalStorage } from 'react-use';
import React, { useEffect } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { CustomScrollbar, useStyles2, useTheme2 } from '@grafana/ui';
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { Footer } from '../Footer/Footer';
@ -16,7 +15,6 @@ import { PageContents } from './PageContents';
import { PageHeader } from './PageHeader';
import { PageTabs } from './PageTabs';
import { SectionNav } from './SectionNav';
import { SectionNavToggle } from './SectionNavToggle';
export const Page: PageType = ({
navId,
@ -31,29 +29,14 @@ export const Page: PageType = ({
scrollRef,
...otherProps
}) => {
const theme = useTheme2();
const styles = useStyles2(getStyles);
const navModel = usePageNav(navId, oldNavProp);
const { chrome } = useGrafana();
const isSmallScreen = window.matchMedia(`(max-width: ${theme.breakpoints.values.lg}px)`).matches;
const [navExpandedPreference, setNavExpandedPreference] = useLocalStorage<boolean>(
'grafana.sectionNav.expanded',
!isSmallScreen
);
const [isNavExpanded, setNavExpanded] = useState(!isSmallScreen && navExpandedPreference);
usePageTitle(navModel, pageNav);
const pageHeaderNav = pageNav ?? navModel?.node;
useEffect(() => {
const mediaQuery = window.matchMedia(`(max-width: ${theme.breakpoints.values.lg}px)`);
const onMediaQueryChange = (e: MediaQueryListEvent) => setNavExpanded(e.matches ? false : navExpandedPreference);
mediaQuery.addEventListener('change', onMediaQueryChange);
return () => mediaQuery.removeEventListener('change', onMediaQueryChange);
}, [navExpandedPreference, theme.breakpoints.values.lg]);
useEffect(() => {
if (navModel) {
chrome.update({
@ -63,25 +46,11 @@ export const Page: PageType = ({
}
}, [navModel, pageNav, chrome]);
const onToggleSectionNav = () => {
setNavExpandedPreference(!isNavExpanded);
setNavExpanded(!isNavExpanded);
};
return (
<div className={cx(styles.wrapper, className)} {...otherProps}>
{layout === PageLayoutType.Standard && (
<div className={styles.panes}>
{navModel && (
<>
<SectionNav model={navModel} isExpanded={Boolean(isNavExpanded)} />
<SectionNavToggle
className={styles.collapseIcon}
isExpanded={Boolean(isNavExpanded)}
onClick={onToggleSectionNav}
/>
</>
)}
{navModel && <SectionNav model={navModel} />}
<div className={styles.pageContainer}>
<CustomScrollbar autoHeightMin={'100%'} scrollTop={scrollTop} scrollRefCallback={scrollRef}>
<div className={styles.pageInner}>
@ -125,18 +94,6 @@ const getStyles = (theme: GrafanaTheme2) => {
: '0 0.6px 1.5px -1px rgb(0 0 0 / 8%),0 2px 4px rgb(0 0 0 / 6%),0 5px 10px -1px rgb(0 0 0 / 5%)';
return {
collapseIcon: css({
border: `1px solid ${theme.colors.border.weak}`,
transform: 'translateX(50%)',
top: theme.spacing(8),
right: theme.spacing(-1),
[theme.breakpoints.down('md')]: {
left: '50%',
transform: 'translate(-50%, 50%) rotate(90deg)',
top: theme.spacing(2),
},
}),
wrapper: css({
label: 'page-wrapper',
height: '100%',

@ -1,38 +1,68 @@
import { css, cx } from '@emotion/css';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { useLocalStorage } from 'react-use';
import { NavModel, GrafanaTheme2 } from '@grafana/data';
import { useStyles2, CustomScrollbar } from '@grafana/ui';
import { useStyles2, CustomScrollbar, useTheme2 } from '@grafana/ui';
import { SectionNavItem } from './SectionNavItem';
import { SectionNavToggle } from './SectionNavToggle';
export interface Props {
model: NavModel;
isExpanded: boolean;
}
export function SectionNav({ model, isExpanded }: Props) {
export function SectionNav({ model }: Props) {
const styles = useStyles2(getStyles);
const { isExpanded, onToggleSectionNav } = useSectionNavState();
if (!Boolean(model.main?.children?.length)) {
return null;
}
return (
<nav
className={cx(styles.nav, {
[styles.navExpanded]: isExpanded,
})}
>
<CustomScrollbar showScrollIndicators>
<div className={styles.items} role="tablist">
<SectionNavItem item={model.main} isSectionRoot />
</div>
</CustomScrollbar>
</nav>
<>
<nav
className={cx(styles.nav, {
[styles.navExpanded]: isExpanded,
})}
>
<CustomScrollbar showScrollIndicators>
<div className={styles.items} role="tablist">
<SectionNavItem item={model.main} isSectionRoot />
</div>
</CustomScrollbar>
</nav>
<SectionNavToggle className={styles.collapseIcon} isExpanded={Boolean(isExpanded)} onClick={onToggleSectionNav} />
</>
);
}
function useSectionNavState() {
const theme = useTheme2();
const isSmallScreen = window.matchMedia(`(max-width: ${theme.breakpoints.values.lg}px)`).matches;
const [navExpandedPreference, setNavExpandedPreference] = useLocalStorage<boolean>(
'grafana.sectionNav.expanded',
!isSmallScreen
);
const [isExpanded, setIsExpanded] = useState(!isSmallScreen && navExpandedPreference);
useEffect(() => {
const mediaQuery = window.matchMedia(`(max-width: ${theme.breakpoints.values.lg}px)`);
const onMediaQueryChange = (e: MediaQueryListEvent) => setIsExpanded(e.matches ? false : navExpandedPreference);
mediaQuery.addEventListener('change', onMediaQueryChange);
return () => mediaQuery.removeEventListener('change', onMediaQueryChange);
}, [navExpandedPreference, theme.breakpoints.values.lg]);
const onToggleSectionNav = () => {
setNavExpandedPreference(!isExpanded);
setIsExpanded(!isExpanded);
};
return { isExpanded, onToggleSectionNav };
}
const getStyles = (theme: GrafanaTheme2) => {
return {
nav: css({
@ -62,5 +92,17 @@ const getStyles = (theme: GrafanaTheme2) => {
padding: theme.spacing(4.5, 1, 2, 2),
minWidth: '250px',
}),
collapseIcon: css({
border: `1px solid ${theme.colors.border.weak}`,
transform: 'translateX(50%)',
top: theme.spacing(8),
right: theme.spacing(-1),
[theme.breakpoints.down('md')]: {
left: '50%',
transform: 'translate(-50%, 50%) rotate(90deg)',
top: theme.spacing(2),
},
}),
};
};

Loading…
Cancel
Save