diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index a8ce1451da..865e5e7e61 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -14,35 +14,44 @@ * limitations under the License. */ -import React, { useContext, PropsWithChildren } from 'react'; -import { Link, makeStyles } from '@material-ui/core'; -import HomeIcon from '@material-ui/icons/Home'; -import ExtensionIcon from '@material-ui/icons/Extension'; -import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; -import MapIcon from '@material-ui/icons/MyLocation'; -import LayersIcon from '@material-ui/icons/Layers'; -import LibraryBooks from '@material-ui/icons/LibraryBooks'; -import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; -import MoneyIcon from '@material-ui/icons/MonetizationOn'; -import LogoFull from './LogoFull'; -import LogoIcon from './LogoIcon'; -import { NavLink } from 'react-router-dom'; +import { + MobileSidebar, + sidebarConfig, + SidebarContext, + SidebarDivider, + SidebarGroup, + SidebarItem, + SidebarPage, + SidebarScrollWrapper, + SidebarSpace, +} from '@backstage/core-components'; import { GraphiQLIcon } from '@backstage/plugin-graphiql'; -import { Settings as SidebarSettings } from '@backstage/plugin-user-settings'; import { SidebarSearch } from '@backstage/plugin-search'; import { Shortcuts } from '@backstage/plugin-shortcuts'; import { - Sidebar, - SidebarPage, - sidebarConfig, - SidebarContext, - SidebarItem, - SidebarDivider, - SidebarSpace, - SidebarScrollWrapper, + Settings as SidebarSettings, + UserSettingsSignInAvatar, +} from '@backstage/plugin-user-settings'; +import { BottomNavigation, - SidebarGroup, -} from '@backstage/core-components'; + BottomNavigationAction, + Link, + makeStyles, +} from '@material-ui/core'; +import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; +import RuleIcon from '@material-ui/icons/AssignmentTurnedIn'; +import ExtensionIcon from '@material-ui/icons/Extension'; +import HomeIcon from '@material-ui/icons/Home'; +import LayersIcon from '@material-ui/icons/Layers'; +import LibraryBooks from '@material-ui/icons/LibraryBooks'; +import MenuIcon from '@material-ui/icons/Menu'; +import MoneyIcon from '@material-ui/icons/MonetizationOn'; +import MapIcon from '@material-ui/icons/MyLocation'; +import SearchIcon from '@material-ui/icons/Search'; +import React, { PropsWithChildren, useContext, useState } from 'react'; +import { NavLink } from 'react-router-dom'; +import LogoFull from './LogoFull'; +import LogoIcon from './LogoIcon'; const useSidebarLogoStyles = makeStyles({ root: { @@ -77,37 +86,52 @@ const SidebarLogo = () => { ); }; -export const Root = ({ children }: PropsWithChildren<{}>) => ( - - - - - - {/* Global nav, not org-specific */} - - - - - - {/* End global nav */} - - - - - - - - - - - - - - - - - - - {children} - -); +export const Root = ({ children }: PropsWithChildren<{}>) => { + return ( + + + + } to="/search"> + + + + {/* Global nav, not org-specific */} + }> + + + + + + {/* End global nav */} + + + + + + + + + + + + + } + to="/settings" + > + + + + {children} + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/BottomNavigation.tsx b/packages/core-components/src/layout/Sidebar/BottomNavigation.tsx deleted file mode 100644 index 2356cab249..0000000000 --- a/packages/core-components/src/layout/Sidebar/BottomNavigation.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright 2020 The Backstage Authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { - BottomNavigation as MUIBottomNavigation, - makeStyles, -} from '@material-ui/core'; -import React from 'react'; - -const useStyles = makeStyles({ - root: { - position: 'fixed', - bottom: 0, - left: 0, - right: 0, - }, -}); - -/** - * Filters for sidebar groups and reorders them to create a custom BottomNavigation - */ -export const BottomNavigation = ({ children }: React.PropsWithChildren<{}>) => { - const classes = useStyles(); - const [value, setValue] = React.useState('recents'); - - const handleChange = (event: React.ChangeEvent<{}>, newValue: string) => { - setValue(newValue); - }; - - return ( - - {children} - - ); -}; diff --git a/packages/core-components/src/layout/Sidebar/Group.tsx b/packages/core-components/src/layout/Sidebar/Group.tsx index f346daa9a1..2aabea69b8 100644 --- a/packages/core-components/src/layout/Sidebar/Group.tsx +++ b/packages/core-components/src/layout/Sidebar/Group.tsx @@ -14,15 +14,50 @@ * limitations under the License. */ -import { BottomNavigationAction } from '@material-ui/core'; -import MenuIcon from '@material-ui/icons/Menu'; +import { + BottomNavigationAction, + BottomNavigationActionProps, + makeStyles, +} from '@material-ui/core'; import React from 'react'; +import { NavLink, useLocation } from 'react-router-dom'; + +interface SidebarGroupProps extends BottomNavigationActionProps { + to?: string; + injectedSelected?: boolean; +} + +const useStyles = makeStyles({ + label: { + display: 'none', + }, +}); /** * If the page is mobile it should be BottomNavigationAction - otherwise just a fragment * Links to page, which will be displayed * - If 'to' Prop is not defined it will render a Menu page out of the children (if children given) */ -export const SidebarGroup = ({ children }: React.PropsWithChildren<{}>) => { - return } />; +export const SidebarGroup = ({ + to, + label, + icon, + onClick, + injectedSelected, +}: React.PropsWithChildren) => { + const classes = useStyles(); + const location = useLocation(); + + return ( + + ); }; diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx new file mode 100644 index 0000000000..4d846e3580 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -0,0 +1,96 @@ +/* + * Copyright 2020 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { BottomNavigation, Box, makeStyles } from '@material-ui/core'; +import React, { useState, useEffect } from 'react'; +import { useLocation } from 'react-router'; +import { SidebarGroup } from './Group'; + +const useStyles = makeStyles({ + root: { + position: 'fixed', + bottom: 0, + left: 0, + right: 0, + zIndex: 1000, + }, +}); + +const OverlayMenu = ({ children }: React.PropsWithChildren<{}>) => ( + + {children} + +); + +let currentLocation: string; + +/** + * Filters for sidebar groups and reorders them to create a custom BottomNavigation + */ +export const MobileSidebar = ({ children }: React.PropsWithChildren<{}>) => { + const classes = useStyles(); + const [value, setValue] = useState(); + const [menu, setMenu] = useState(); + const location = useLocation(); + + useEffect(() => { + if (menu && currentLocation !== location.pathname) { + setMenu(undefined); + setValue(undefined); + } + currentLocation = location.pathname; + }, [location, menu]); + + return ( + + {value && menu && } + + {React.Children.map(children, (child, index) => { + if ( + React.isValidElement(child) && + (child as React.ReactElement).type === SidebarGroup + ) { + if (index === value && !menu && !child.props.to) { + setMenu(child.props.children); + } + return React.cloneElement(child, { + injectedSelected: value + ? index === value + : location.pathname === child.props.to, + onClick: () => { + if (index === value && menu) { + setValue(undefined); + setMenu(undefined); + } else { + setValue(index); + } + }, + }); + } + return null; + })} + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index cc50c5af6b..d33564b5d4 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -25,19 +25,11 @@ import { sidebarConfig } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; -export type SidebarPageClassKey = 'root'; - -const useStyles = makeStyles( - { - root: { - width: '100%', - minHeight: '100%', - transition: 'padding-left 0.1s ease-out', - paddingLeft: ({ isPinned }) => - isPinned - ? sidebarConfig.drawerWidthOpen - : sidebarConfig.drawerWidthClosed, - }, +const useStyles = makeStyles({ + root: { + width: '100%', + minHeight: '100%', + transition: 'padding-left 0.1s ease-out', }, { name: 'BackstageSidebarPage' }, ); diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index d2a690e38f..bfff039492 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -45,5 +45,5 @@ export type SidebarContextType = { }; export const SidebarContext = createContext({ - isOpen: false, + isOpen: true, }); diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index cc1d127787..320625dc11 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -15,7 +15,7 @@ */ export { Sidebar } from './Bar'; -export { BottomNavigation } from './BottomNavigation'; +export { MobileSidebar } from './MobileSidebar'; export { SidebarGroup } from './Group'; export { SidebarPage, SidebarPinStateContext } from './Page'; export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page';