mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TopNav: Store collapse state for chrome top search bar in local storage (#52300)
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import { css, cx } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import React, { PropsWithChildren, useState } from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
import { useToggle } from 'react-use';
|
|
||||||
|
|
||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { config } from '@grafana/runtime';
|
import { config } from '@grafana/runtime';
|
||||||
@@ -17,8 +16,6 @@ export interface Props extends PropsWithChildren<{}> {}
|
|||||||
|
|
||||||
export function AppChrome({ children }: Props) {
|
export function AppChrome({ children }: Props) {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
const [searchBarHidden, toggleSearchBar] = useToggle(false); // repace with local storage
|
|
||||||
const [megaMenuOpen, setMegaMenuOpen] = useState(false);
|
|
||||||
const state = appChromeService.useState();
|
const state = appChromeService.useState();
|
||||||
|
|
||||||
if (state.chromeless || !config.featureToggles.topnav) {
|
if (state.chromeless || !config.featureToggles.topnav) {
|
||||||
@@ -28,18 +25,20 @@ export function AppChrome({ children }: Props) {
|
|||||||
return (
|
return (
|
||||||
<main className="main-view">
|
<main className="main-view">
|
||||||
<div className={styles.topNav}>
|
<div className={styles.topNav}>
|
||||||
{!searchBarHidden && <TopSearchBar />}
|
{!state.searchBarHidden && <TopSearchBar />}
|
||||||
<NavToolbar
|
<NavToolbar
|
||||||
searchBarHidden={searchBarHidden}
|
searchBarHidden={state.searchBarHidden}
|
||||||
sectionNav={state.sectionNav}
|
sectionNav={state.sectionNav}
|
||||||
pageNav={state.pageNav}
|
pageNav={state.pageNav}
|
||||||
actions={state.actions}
|
actions={state.actions}
|
||||||
onToggleSearchBar={toggleSearchBar}
|
onToggleSearchBar={appChromeService.toggleSearchBar}
|
||||||
onToggleMegaMenu={() => setMegaMenuOpen(!megaMenuOpen)}
|
onToggleMegaMenu={appChromeService.toggleMegaMenu}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(styles.content, searchBarHidden && styles.contentNoSearchBar)}>{children}</div>
|
<div className={cx(styles.content, state.searchBarHidden && styles.contentNoSearchBar)}>{children}</div>
|
||||||
{megaMenuOpen && <MegaMenu searchBarHidden={searchBarHidden} onClose={() => setMegaMenuOpen(false)} />}
|
{state.megaMenuOpen && (
|
||||||
|
<MegaMenu searchBarHidden={state.searchBarHidden} onClose={appChromeService.toggleMegaMenu} />
|
||||||
|
)}
|
||||||
</main>
|
</main>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { useObservable } from 'react-use';
|
|||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
import { NavModelItem } from '@grafana/data';
|
import { NavModelItem } from '@grafana/data';
|
||||||
|
import store from 'app/core/store';
|
||||||
import { isShallowEqual } from 'app/core/utils/isShallowEqual';
|
import { isShallowEqual } from 'app/core/utils/isShallowEqual';
|
||||||
|
|
||||||
import { RouteDescriptor } from '../../navigation/types';
|
import { RouteDescriptor } from '../../navigation/types';
|
||||||
@@ -11,14 +12,19 @@ export interface AppChromeState {
|
|||||||
sectionNav: NavModelItem;
|
sectionNav: NavModelItem;
|
||||||
pageNav?: NavModelItem;
|
pageNav?: NavModelItem;
|
||||||
actions?: React.ReactNode;
|
actions?: React.ReactNode;
|
||||||
|
searchBarHidden?: boolean;
|
||||||
|
megaMenuOpen?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultSection: NavModelItem = { text: 'Grafana' };
|
const defaultSection: NavModelItem = { text: 'Grafana' };
|
||||||
|
|
||||||
export class AppChromeService {
|
export class AppChromeService {
|
||||||
|
searchBarStorageKey = 'SearchBar_Hidden';
|
||||||
|
|
||||||
readonly state = new BehaviorSubject<AppChromeState>({
|
readonly state = new BehaviorSubject<AppChromeState>({
|
||||||
chromeless: true, // start out hidden to not flash it on pages without chrome
|
chromeless: true, // start out hidden to not flash it on pages without chrome
|
||||||
sectionNav: defaultSection,
|
sectionNav: defaultSection,
|
||||||
|
searchBarHidden: store.getBool(this.searchBarStorageKey, false),
|
||||||
});
|
});
|
||||||
|
|
||||||
routeMounted(route: RouteDescriptor) {
|
routeMounted(route: RouteDescriptor) {
|
||||||
@@ -42,6 +48,16 @@ export class AppChromeService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleMegaMenu = () => {
|
||||||
|
this.update({ megaMenuOpen: !this.state.getValue().megaMenuOpen });
|
||||||
|
};
|
||||||
|
|
||||||
|
toggleSearchBar = () => {
|
||||||
|
const searchBarHidden = !this.state.getValue().searchBarHidden;
|
||||||
|
store.set(this.searchBarStorageKey, searchBarHidden);
|
||||||
|
this.update({ searchBarHidden });
|
||||||
|
};
|
||||||
|
|
||||||
useState() {
|
useState() {
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
return useObservable(this.state, this.state.getValue());
|
return useObservable(this.state, this.state.getValue());
|
||||||
|
|||||||
Reference in New Issue
Block a user