grafana/public/app/core/components/AppChrome/AppChrome.tsx
Ashley Harrison 10adebd7b3
Page: Add inline rename functionality (#68828)
* initial attempt at inline rename

* handle version correctly

* refactor

* minor tweaks

* add unit tests

* prettier...

* add to other tabs, remove settings tab when feature toggle is enabled

* fix truncation

* allow title to span full width of page

* fix h1 styling when no renderTitle/onEditTitle is present

* better layout

* use input from grafana/ui, fix imports

* fix unit test

* better error handling

* don't use autosavefield

* undo changes to AutoSaveField

* remove timeout

* remove maxWidth now we're not using AutoSaveField

* rename isEditInProgress to isLoading

* sync localValue with value

* better responsive css
2023-05-31 17:03:54 +01:00

133 lines
4.0 KiB
TypeScript

import { css, cx } from '@emotion/css';
import classNames from 'classnames';
import React, { PropsWithChildren } from 'react';
import { GrafanaTheme2, PageLayoutType } from '@grafana/data';
import { useStyles2, LinkButton } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { CommandPalette } from 'app/features/commandPalette/CommandPalette';
import { KioskMode } from 'app/types';
import { MegaMenu } from './MegaMenu/MegaMenu';
import { NavToolbar } from './NavToolbar/NavToolbar';
import { SectionNav } from './SectionNav/SectionNav';
import { TopSearchBar } from './TopBar/TopSearchBar';
import { TOP_BAR_LEVEL_HEIGHT } from './types';
export interface Props extends PropsWithChildren<{}> {}
export function AppChrome({ children }: Props) {
const styles = useStyles2(getStyles);
const { chrome } = useGrafana();
const state = chrome.useState();
const searchBarHidden = state.searchBarHidden || state.kioskMode === KioskMode.TV;
const contentClass = cx({
[styles.content]: true,
[styles.contentNoSearchBar]: searchBarHidden,
[styles.contentChromeless]: state.chromeless,
});
// Chromeless routes are without topNav, mega menu, search & command palette
// We check chromeless twice here instead of having a separate path so {children}
// doesn't get re-mounted when chromeless goes from true to false.
return (
<div className={classNames('main-view', searchBarHidden && 'main-view--search-bar-hidden')}>
{!state.chromeless && (
<>
<LinkButton className={styles.skipLink} href="#pageContent">
Skip to main content
</LinkButton>
<div className={cx(styles.topNav)}>
{!searchBarHidden && <TopSearchBar />}
<NavToolbar
searchBarHidden={searchBarHidden}
sectionNav={state.sectionNav.node}
pageNav={state.pageNav}
actions={state.actions}
onToggleSearchBar={chrome.onToggleSearchBar}
onToggleMegaMenu={chrome.onToggleMegaMenu}
onToggleKioskMode={chrome.onToggleKioskMode}
/>
</div>
</>
)}
<main className={contentClass} id="pageContent">
<div className={styles.panes}>
{state.layout === PageLayoutType.Standard && state.sectionNav && <SectionNav model={state.sectionNav} />}
<div className={styles.pageContainer}>{children}</div>
</div>
</main>
{!state.chromeless && (
<>
<MegaMenu searchBarHidden={searchBarHidden} onClose={() => chrome.setMegaMenu(false)} />
<CommandPalette />
</>
)}
</div>
);
}
const getStyles = (theme: GrafanaTheme2) => {
const shadow = theme.isDark
? `0 0.6px 1.5px rgb(0 0 0), 0 2px 4px rgb(0 0 0 / 40%), 0 5px 10px rgb(0 0 0 / 23%)`
: '0 4px 8px rgb(0 0 0 / 4%)';
return {
content: css({
display: 'flex',
flexDirection: 'column',
paddingTop: TOP_BAR_LEVEL_HEIGHT * 2,
flexGrow: 1,
height: '100%',
}),
contentNoSearchBar: css({
paddingTop: TOP_BAR_LEVEL_HEIGHT,
}),
contentChromeless: css({
paddingTop: 0,
}),
topNav: css({
display: 'flex',
position: 'fixed',
zIndex: theme.zIndex.navbarFixed,
left: 0,
right: 0,
boxShadow: shadow,
background: theme.colors.background.primary,
flexDirection: 'column',
borderBottom: `1px solid ${theme.colors.border.weak}`,
}),
panes: css({
label: 'page-panes',
display: 'flex',
height: '100%',
width: '100%',
flexGrow: 1,
minHeight: 0,
flexDirection: 'column',
[theme.breakpoints.up('md')]: {
flexDirection: 'row',
},
}),
pageContainer: css({
label: 'page-container',
flexGrow: 1,
minHeight: 0,
minWidth: 0,
}),
skipLink: css({
position: 'absolute',
top: -1000,
':focus': {
left: theme.spacing(1),
top: theme.spacing(1),
zIndex: theme.zIndex.portal,
},
}),
};
};