From ea0f921cd3008e59dd33c1fc1d370af515b3cb5c Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 8 Oct 2021 17:08:03 +0100 Subject: [PATCH 01/39] Implement Expedias new Scalable Side Nav design - items with submenus and expand on click Signed-off-by: hiba-aldalaty --- packages/app/src/components/Root/Root.tsx | 2 + .../src/layout/Sidebar/Bar.tsx | 130 +++++++------- .../src/layout/Sidebar/Items.tsx | 167 ++++++++++++++++- .../src/layout/Sidebar/Sidebar.stories.tsx | 40 ++++- .../src/layout/Sidebar/Submenu.tsx | 97 ++++++++++ .../src/layout/Sidebar/SubmenuItem.tsx | 170 ++++++++++++++++++ .../src/layout/Sidebar/config.ts | 33 +++- .../src/layout/Sidebar/icons/APIsIcon.tsx | 33 ++++ .../Sidebar/icons/CatalogSidebarLogo.tsx | 40 +++++ .../layout/Sidebar/icons/DoubleArrowLeft.tsx | 50 ++++++ .../layout/Sidebar/icons/DoubleArrowRight.tsx | 50 ++++++ .../src/layout/Sidebar/icons/MiscIcon.tsx | 33 ++++ .../src/layout/Sidebar/icons/ServicesIcon.tsx | 33 ++++ .../src/layout/Sidebar/index.ts | 3 +- packages/theme/src/themes.ts | 18 ++ packages/theme/src/types.ts | 9 + 16 files changed, 834 insertions(+), 74 deletions(-) create mode 100644 packages/core-components/src/layout/Sidebar/Submenu.tsx create mode 100644 packages/core-components/src/layout/Sidebar/SubmenuItem.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/APIsIcon.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx create mode 100644 packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx diff --git a/packages/app/src/components/Root/Root.tsx b/packages/app/src/components/Root/Root.tsx index 7a666a020a..b0318cdaf8 100644 --- a/packages/app/src/components/Root/Root.tsx +++ b/packages/app/src/components/Root/Root.tsx @@ -40,6 +40,7 @@ import { SidebarDivider, SidebarSpace, SidebarScrollWrapper, + SidebarExpandButton, } from '@backstage/core-components'; const useSidebarLogoStyles = makeStyles({ @@ -98,6 +99,7 @@ export const Root = ({ children }: PropsWithChildren<{}>) => ( + diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 750ec6bbdc..ad73b52435 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -16,10 +16,17 @@ import { makeStyles, useMediaQuery } from '@material-ui/core'; import clsx from 'clsx'; -import React, { useRef, useState, useContext, PropsWithChildren } from 'react'; +import React, { + useState, + useContext, + PropsWithChildren, + useEffect, +} from 'react'; import { sidebarConfig, SidebarContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext } from './Page'; +import DoubleArrowRight from './icons/DoubleArrowRight'; +import DoubleArrowLeft from './icons/DoubleArrowLeft'; export type SidebarClassKey = 'root' | 'drawer' | 'drawerOpen'; @@ -45,7 +52,6 @@ const useStyles = makeStyles( msOverflowStyle: 'none', scrollbarWidth: 'none', width: sidebarConfig.drawerWidthClosed, - borderRight: `1px solid #383838`, transition: theme.transitions.create('width', { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.shortest, @@ -57,6 +63,19 @@ const useStyles = makeStyles( display: 'none', }, }, + expandButton: { + background: 'none', + border: 'none', + color: theme.palette.navigation.color, + width: '100%', + cursor: 'pointer', + position: 'relative', + height: 48, + }, + arrows: { + position: 'absolute', + right: 10, + }, drawerOpen: { width: sidebarConfig.drawerWidthOpen, transition: theme.transitions.create('width', { @@ -68,81 +87,24 @@ const useStyles = makeStyles( { name: 'BackstageSidebar' }, ); -enum State { - Closed, - Idle, - Open, -} - -type Props = { - openDelayMs?: number; - closeDelayMs?: number; -}; - -export function Sidebar(props: PropsWithChildren) { - const { - openDelayMs = sidebarConfig.defaultOpenDelayMs, - closeDelayMs = sidebarConfig.defaultCloseDelayMs, - children, - } = props; +export function Sidebar({ children }: PropsWithChildren<{}>) { const classes = useStyles(); - const isSmallScreen = useMediaQuery(theme => - theme.breakpoints.down('md'), - ); - const [state, setState] = useState(State.Closed); - const hoverTimerRef = useRef(); + const { isPinned } = useContext(SidebarPinStateContext); + const [isOpen, setIsOpen] = useState(isPinned); - const handleOpen = () => { + useEffect(() => { if (isPinned) { - return; + setIsOpen(true); } - if (hoverTimerRef.current) { - clearTimeout(hoverTimerRef.current); - hoverTimerRef.current = undefined; - } - if (state !== State.Open && !isSmallScreen) { - hoverTimerRef.current = window.setTimeout(() => { - hoverTimerRef.current = undefined; - setState(State.Open); - }, openDelayMs); - - setState(State.Idle); - } - }; - - const handleClose = () => { - if (isPinned) { - return; - } - if (hoverTimerRef.current) { - clearTimeout(hoverTimerRef.current); - hoverTimerRef.current = undefined; - } - if (state === State.Idle) { - setState(State.Closed); - } else if (state === State.Open) { - hoverTimerRef.current = window.setTimeout(() => { - hoverTimerRef.current = undefined; - setState(State.Closed); - }, closeDelayMs); - } - }; - - const isOpen = (state === State.Open && !isSmallScreen) || isPinned; + }, [isPinned]); return ( -
+
) {
); } + +export const SidebarExpandButton = () => { + const classes = useStyles(); + const isSmallScreen = useMediaQuery(theme => + theme.breakpoints.down('md'), + ); + const { isPinned } = useContext(SidebarPinStateContext); + const { isOpen, setIsOpen } = useContext(SidebarContext); + + const openDelayMs = sidebarConfig.defaultOpenDelayMs; + const closeDelayMs = sidebarConfig.defaultCloseDelayMs; + + const handleClick = () => { + if (isPinned || isSmallScreen) { + return; + } + const delayMs = isOpen ? openDelayMs : closeDelayMs; + setTimeout(async () => { + setIsOpen(!isOpen); + }, delayMs); + }; + + if (isSmallScreen || isPinned) { + return null; + } + + return ( + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 8bd80b6825..e735468e95 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -25,11 +25,14 @@ import { Typography, } from '@material-ui/core'; import { CreateCSSProperties } from '@material-ui/core/styles/withStyles'; +import ArrowRightIcon from '@material-ui/icons/ArrowRight'; import SearchIcon from '@material-ui/icons/Search'; import clsx from 'clsx'; import React, { + Children, forwardRef, KeyboardEventHandler, + PropsWithChildren, ReactNode, useContext, useState, @@ -37,10 +40,16 @@ import React, { import { Link, NavLinkProps, + resolvePath, useLocation, useResolvedPath, } from 'react-router-dom'; -import { sidebarConfig, SidebarContext } from './config'; +import { + sidebarConfig, + SidebarContext, + ItemWithSubmenuContext, +} from './config'; +import { Submenu } from './Submenu'; export type SidebarItemClassKey = | 'root' @@ -89,6 +98,14 @@ const useStyles = makeStyles( open: { width: drawerWidthOpen, }, + highlightable: { + '&:hover': { + background: theme.palette.navigation.navItem.hoverBackground, // TODO: consider + }, + }, + highlighted: { + background: theme.palette.navigation.navItem.hoverBackground, // TODO: consider + }, label: { // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs fontWeight: 'bold', @@ -127,13 +144,24 @@ const useStyles = makeStyles( textAlign: 'center', marginRight: theme.spacing(1), }, + closedItemIcon: { + width: '100%', + justifyContent: 'center', + }, + submenuArrow: { + position: 'absolute', + right: 0, + }, selected: { '&$root': { borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, color: theme.palette.navigation.selectedColor, }, '&$closed': { - width: drawerWidthClosed - selectedIndicatorWidth, + width: drawerWidthClosed, + }, + '& $closedItemIcon': { + paddingRight: selectedIndicatorWidth, }, '& $iconContainer': { marginLeft: -selectedIndicatorWidth, @@ -144,10 +172,117 @@ const useStyles = makeStyles( { name: 'BackstageSidebarItem' }, ); +type ItemWithSubmenuProps = { + label?: string; + title?: string; + hasNotifications?: boolean; + icon: IconComponent; + children: ReactNode; +}; +const ItemWithSubmenu = ({ + label, + title, + hasNotifications = false, + icon: Icon, + children, +}: PropsWithChildren) => { + const classes = useStyles(); + const [isHoveredOn, setIsHoveredOn] = useState(false); + const toPathnames: string[] = []; + + let isActive; + const { pathname: locationPathname } = useLocation(); + + // Menu item is active if any of its children have active paths + Children.forEach(children, element => { + if (!React.isValidElement(element)) return; + if (element.props.hasDropDown && element.props.dropdownItems) { + element.props.dropdownItems.map((item: { to: string }) => + toPathnames.push(item.to), + ); + } else if (element.props.to) { + toPathnames.push(element.props.to); + } + }); + toPathnames.some(to => { + const toPathname = resolvePath(to); + isActive = locationPathname === toPathname.pathname; + return isActive; + }); + + const handleMouseEnter = () => { + setIsHoveredOn(true); + }; + const handleMouseLeave = () => { + setIsHoveredOn(false); + }; + + const { isOpen } = useContext(SidebarContext); + const itemIcon = ( + + + + ); + const openContent = ( + <> +
+ {itemIcon} +
+ {label && ( + + {label} + + )} +
{}
+ + ); + const closedContent = itemIcon; + + return ( + +
+
+ {isOpen ? openContent : closedContent} + {!isHoveredOn && ( + + )} +
+ {isHoveredOn && {children}} +
+
+ ); +}; + type SidebarItemBaseProps = { icon: IconComponent; text?: string; hasNotifications?: boolean; + hasSubMenu?: boolean; + submenuTitle?: string; + disableHighlight?: boolean; children?: ReactNode; className?: string; }; @@ -222,6 +357,9 @@ export const SidebarItem = forwardRef((props, ref) => { icon: Icon, text, hasNotifications = false, + hasSubMenu = false, + submenuTitle, + disableHighlight = false, onClick, children, className, @@ -239,6 +377,7 @@ export const SidebarItem = forwardRef((props, ref) => { variant="dot" overlap="circular" invisible={!hasNotifications} + className={clsx(isOpen ? undefined : classes.closedItemIcon)} > @@ -248,7 +387,7 @@ export const SidebarItem = forwardRef((props, ref) => { const openContent = ( <> -
+
{itemIcon}
{text && ( @@ -269,9 +408,24 @@ export const SidebarItem = forwardRef((props, ref) => { classes.root, isOpen ? classes.open : classes.closed, isButtonItem(props) && classes.buttonItem, + disableHighlight ? undefined : classes.highlightable, ), }; + // If submenu prop is true, return ItemWithSubmenu + if (hasSubMenu) { + return ( + + {children} + + ); + } + if (isButtonItem(props)) { return ( + {hasDropDown && showDropDown && ( +
+ {dropdownItems.map((object, key) => ( + + {object.title} + + ))} +
+ )} +
+ ); + } + + return ( +
+ + + + {title} + + +
+ ); +}; diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index d2a690e38f..e7a9e26e1d 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { createContext } from 'react'; +import { createContext, Dispatch, SetStateAction } from 'react'; const drawerWidthClosed = 72; const iconPadding = 24; @@ -37,13 +37,44 @@ export const sidebarConfig = { userBadgeDiameter: drawerWidthClosed - userBadgePadding * 2, }; +export const submenuConfig = { + drawerWidthClosed: 0, + drawerWidthOpen: 202, + // As per NN/g's guidance on timing for exposing hidden content + // See https://www.nngroup.com/articles/timing-exposing-content/ + defaultOpenDelayMs: 100, + defaultCloseDelayMs: 0, + defaultFadeDuration: 200, + logoHeight: 32, + iconContainerWidth: drawerWidthClosed, + iconSize: drawerWidthClosed - iconPadding * 2, + iconPadding, + selectedIndicatorWidth: 3, + userBadgePadding, + userBadgeDiameter: drawerWidthClosed - userBadgePadding * 2, +}; + export const SIDEBAR_INTRO_LOCAL_STORAGE = '@backstage/core/sidebar-intro-dismissed'; export type SidebarContextType = { isOpen: boolean; + setIsOpen: Dispatch>; }; export const SidebarContext = createContext({ isOpen: false, + setIsOpen: () => {}, }); + +export type ItemWithSubmenuContextType = { + isHoveredOn: boolean; + setIsHoveredOn: Dispatch>; +}; + +export const ItemWithSubmenuContext = createContext( + { + isHoveredOn: false, + setIsHoveredOn: () => {}, + }, +); diff --git a/packages/core-components/src/layout/Sidebar/icons/APIsIcon.tsx b/packages/core-components/src/layout/Sidebar/icons/APIsIcon.tsx new file mode 100644 index 0000000000..a185ab346d --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/APIsIcon.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2021 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 React from 'react'; + +export const APIsIcon = () => { + return ( + + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx b/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx new file mode 100644 index 0000000000..d42a3ea957 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx @@ -0,0 +1,40 @@ +/* + * Copyright 2021 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 { SvgIcon } from '@material-ui/core'; +import React from 'react'; + +export const CatalogSidebarLogo = () => { + return ( + + + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx new file mode 100644 index 0000000000..ec1dbcdd31 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx @@ -0,0 +1,50 @@ +/* + * 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 React from 'react'; +import { makeStyles } from '@material-ui/core'; + +const useStyles = makeStyles({ + svg: { + width: 'auto', + height: 15, + }, + path: { + fill: '#7df3e1', + }, +}); +const DoubleArrowRight = () => { + const classes = useStyles(); + + return ( + + + + + ); +}; + +export default DoubleArrowRight; diff --git a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx new file mode 100644 index 0000000000..00d595175d --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx @@ -0,0 +1,50 @@ +/* + * 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 React from 'react'; +import { makeStyles } from '@material-ui/core'; + +const useStyles = makeStyles({ + svg: { + width: 'auto', + height: 15, + }, + path: { + fill: '#7df3e1', + }, +}); +const DoubleArrowRight = () => { + const classes = useStyles(); + + return ( + + + + + ); +}; + +export default DoubleArrowRight; diff --git a/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx b/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx new file mode 100644 index 0000000000..67010baeb5 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2021 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 React from 'react'; + +export const MiscIcon = () => { + return ( + + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx b/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx new file mode 100644 index 0000000000..49a619d422 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx @@ -0,0 +1,33 @@ +/* + * Copyright 2021 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 React from 'react'; + +export const ServicesIcon = () => { + return ( + + + + ); +}; diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 067a9bf2eb..f25f7355f7 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -14,7 +14,8 @@ * limitations under the License. */ -export { Sidebar } from './Bar'; +export { Sidebar, SidebarExpandButton } from './Bar'; +export { SubmenuItem } from './SubmenuItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page'; diff --git a/packages/theme/src/themes.ts b/packages/theme/src/themes.ts index d7a4a6d785..da5925b237 100644 --- a/packages/theme/src/themes.ts +++ b/packages/theme/src/themes.ts @@ -70,6 +70,15 @@ export const lightTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', + navItem: { + hoverBackground: '#404040', + }, + submenu: { + background: '#404040', + indicator: '#9BF0E1', + color: '#b5b5b5', + selectedColor: '#FFF', + }, }, pinSidebarButton: { icon: '#181818', @@ -139,6 +148,15 @@ export const darkTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', + navItem: { + hoverBackground: '#404040', + }, + submenu: { + background: '#404040', + indicator: '#9BF0E1', + color: '#b5b5b5', + selectedColor: '#FFF', + }, }, pinSidebarButton: { icon: '#404040', diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index 76a1b7eb5c..0b1217f00f 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -48,6 +48,15 @@ type PaletteAdditions = { indicator: string; color: string; selectedColor: string; + navItem: { + hoverBackground: string; + }; + submenu: { + background: string; + indicator: string; + color: string; + selectedColor: string; + }; }; tabbar: { indicator: string; From 582a7964b7849681adb5bf8b4e0357d84a075a31 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Thu, 28 Oct 2021 10:02:09 +0100 Subject: [PATCH 02/39] Add tests for scalable sidebar Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Bar.test.tsx | 104 ++++++++++++++++++ .../src/layout/Sidebar/Bar.tsx | 7 +- .../src/layout/Sidebar/Items.tsx | 1 + .../src/layout/Sidebar/Submenu.tsx | 3 +- .../src/layout/Sidebar/SubmenuItem.tsx | 4 +- 5 files changed, 116 insertions(+), 3 deletions(-) create mode 100644 packages/core-components/src/layout/Sidebar/Bar.test.tsx diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx new file mode 100644 index 0000000000..8a28d69e27 --- /dev/null +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -0,0 +1,104 @@ +/* + * 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 React from 'react'; +import { renderInTestApp } from '@backstage/test-utils'; +import { createEvent, fireEvent, screen, within } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import BuildRoundedIcon from '@material-ui/icons/BuildRounded'; +import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; +import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; +import { MiscIcon } from './icons/MiscIcon'; +import { Sidebar, SidebarExpandButton } from './Bar'; +import { SidebarItem, SidebarSearchField } from './Items'; +import { hexToRgb } from '@material-ui/core/styles'; +import { SubmenuItem } from './SubmenuItem'; + +async function renderScalableSidebar() { + await renderInTestApp( + + {}} to="/search" /> + {}} + text="Catalog" + hasSubMenu + submenuTitle="Catalog" + > + + + + + + , + ); +} + +describe('Sidebar', () => { + beforeEach(async () => { + await renderScalableSidebar(); + }); + + describe('Click to Expand', () => { + it('Sidebar should show expanded items when expand button is clicked', async () => { + userEvent.click(screen.getByTestId('sidebar-expand-button')); + expect(await screen.findByText('Create...')).toBeInTheDocument(); + }); + }); + describe('Submenu Items', () => { + it('Extended sidebar with submenu content hidden by default', async () => { + expect(await screen.queryByText('Tools')).not.toBeInTheDocument(); + expect(await screen.queryByText('Misc')).not.toBeInTheDocument(); + }); + + it('Extended sidebar with submenu content visible when hover over submenu items', async () => { + userEvent.hover(screen.getByTestId('item-with-submenu')); + expect(await screen.findByText('Tools')).toBeInTheDocument(); + expect(await screen.findByText('Misc')).toBeInTheDocument(); + }); + + it('Multicategory item in submenu shows drop down on click', async () => { + userEvent.hover(screen.getByTestId('item-with-submenu')); + userEvent.click(screen.getByText('Misc')); + expect(await screen.getByText('dropdown item 1')).toBeInTheDocument(); + expect(await screen.getByText('dropdown item 2')).toBeInTheDocument(); + }); + + it('Dropdown item in submenu renders a link when `to` value is provided', async () => { + userEvent.hover(screen.getByTestId('item-with-submenu')); + userEvent.click(screen.getByText('Misc')); + expect(screen.getByText('dropdown item 1').closest('a')).toHaveAttribute( + 'href', + '/dropdownitemlink', + ); + }); + }); +}); diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 6fc2ac1cdb..23a4ae1286 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -146,7 +146,12 @@ export const SidebarExpandButton = () => { } return ( - - {hasDropDown && showDropDown && ( + {dropdownItems && showDropDown && (
{dropdownItems.map((object, key) => ( Date: Fri, 19 Nov 2021 15:00:11 +0000 Subject: [PATCH 20/39] Change SubmenuItem to SidebarSubItem Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 32 +++++++++---------- .../src/layout/Sidebar/Bar.test.tsx | 6 ++-- .../src/layout/Sidebar/Sidebar.stories.tsx | 18 +++++++---- .../{SubmenuItem.tsx => SidebarSubItem.tsx} | 6 ++-- .../src/layout/Sidebar/index.ts | 4 +-- 5 files changed, 35 insertions(+), 31 deletions(-) rename packages/core-components/src/layout/Sidebar/{SubmenuItem.tsx => SidebarSubItem.tsx} (98%) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 628d0d9a63..4cfab11374 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1988,6 +1988,22 @@ export const SidebarSpacer: React_2.ComponentType< } >; +// @public +export const SidebarSubItem: ({ + title, + to, + icon: Icon, + dropdownItems, +}: SidebarSubItemProps) => JSX.Element; + +// @public +export type SidebarSubItemProps = { + title: string; + to: string; + icon: IconComponent; + dropdownItems?: DropDownItem[]; +}; + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "SignInPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2093,22 +2109,6 @@ export type StructuredMetadataTableListClassKey = 'root'; // @public (undocumented) export type StructuredMetadataTableNestedListClassKey = 'root'; -// @public -export const SubmenuItem: ({ - title, - to, - icon: Icon, - dropdownItems, -}: SubmenuItemProps) => JSX.Element; - -// @public -export type SubmenuItemProps = { - title: string; - to: string; - icon: IconComponent; - dropdownItems?: DropDownItem[]; -}; - // Warning: (ae-forgotten-export) The symbol "SubvalueCellProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "SubvalueCell" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 32f286e22a..56815305fb 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -24,7 +24,7 @@ import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; import { MiscIcon } from './icons/MiscIcon'; import { Sidebar, SidebarExpandButton } from './Bar'; import { SidebarItem, SidebarSearchField } from './Items'; -import { SubmenuItem } from './SubmenuItem'; +import { SidebarSubItem } from './SidebarSubItem'; async function renderScalableSidebar() { await renderInTestApp( @@ -37,8 +37,8 @@ async function renderScalableSidebar() { hasSubMenu submenuTitle="Catalog" > - - + ( hasSubMenu submenuTitle="Catalog" > - - - - - - + + + + + { +}: SidebarSubItemProps) => { const classes = useStyles(); const { pathname: locationPathname } = useLocation(); const { pathname: toPathname } = useResolvedPath(to); diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index e572315cf2..f816b8f7f4 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -15,8 +15,8 @@ */ export { Sidebar, SidebarExpandButton } from './Bar'; -export { SubmenuItem } from './SubmenuItem'; -export type { SubmenuItemProps, DropDownItem } from './SubmenuItem'; +export { SidebarSubItem } from './SidebarSubItem'; +export type { SidebarSubItemProps, DropDownItem } from './SidebarSubItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page'; From 18b089cdccaeeeea015080de5889e3892bc5d192 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 22 Nov 2021 13:50:32 +0000 Subject: [PATCH 21/39] Refactor: remove hasSubmenu prop and move submenuTitle prop to submenu component Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Bar.test.tsx | 43 +++++++------- .../src/layout/Sidebar/Items.tsx | 49 ++++++++------- .../src/layout/Sidebar/Sidebar.stories.tsx | 59 +++++++++---------- 3 files changed, 77 insertions(+), 74 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 56815305fb..68b05fc393 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -25,34 +25,31 @@ import { MiscIcon } from './icons/MiscIcon'; import { Sidebar, SidebarExpandButton } from './Bar'; import { SidebarItem, SidebarSearchField } from './Items'; import { SidebarSubItem } from './SidebarSubItem'; +import { Submenu } from './Submenu'; async function renderScalableSidebar() { await renderInTestApp( {}} to="/search" /> - {}} - text="Catalog" - hasSubMenu - submenuTitle="Catalog" - > - - + {}} text="Catalog"> + + + + diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 3c4fc6ffd0..f1b51e497f 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -28,7 +28,6 @@ import React, { Children, forwardRef, KeyboardEventHandler, - PropsWithChildren, ReactNode, useContext, useState, @@ -170,27 +169,30 @@ const useStyles = makeStyles( type ItemWithSubmenuProps = { label?: string; - title?: string; hasNotifications?: boolean; icon: IconComponent; - children: ReactNode; + submenu: ReactNode; }; const ItemWithSubmenu = ({ label, - title, hasNotifications = false, icon: Icon, - children, -}: PropsWithChildren) => { + submenu, +}: ItemWithSubmenuProps) => { const classes = useStyles(); const [isHoveredOn, setIsHoveredOn] = useState(false); - const toPathnames: string[] = []; + let submenuItems: ReactNode; + Children.forEach(submenu, element => { + if (!React.isValidElement(element)) return; + submenuItems = element.props.children; + }); + const toPathnames: string[] = []; let isActive; const { pathname: locationPathname } = useLocation(); - // Menu item is active if any of its children have active paths - Children.forEach(children, element => { + // SidebarItem is active if any of submenu items have active paths + Children.forEach(submenuItems, element => { if (!React.isValidElement(element)) return; if (element.props.dropdownItems) { element.props.dropdownItems.map((item: { to: string }) => @@ -267,7 +269,7 @@ const ItemWithSubmenu = ({ )}
- {isHoveredOn && {children}} + {isHoveredOn && submenu}
); @@ -277,8 +279,6 @@ type SidebarItemBaseProps = { icon: IconComponent; text?: string; hasNotifications?: boolean; - hasSubMenu?: boolean; - submenuTitle?: string; disableHighlight?: boolean; children?: ReactNode; className?: string; @@ -354,8 +354,6 @@ export const SidebarItem = forwardRef((props, ref) => { icon: Icon, text, hasNotifications = false, - hasSubMenu = false, - submenuTitle, disableHighlight = false, onClick, children, @@ -409,17 +407,28 @@ export const SidebarItem = forwardRef((props, ref) => { ), }; - // If submenu prop is true, return ItemWithSubmenu - if (hasSubMenu) { + let hasSubmenu = false; + let submenu: any; + const componentType = ( + + <> + + ).type; + Children.forEach(children, element => { + if (!React.isValidElement(element)) return; + if (element.type === componentType) { + submenu = element; + hasSubmenu = true; + } + }); + if (hasSubmenu) { return ( - {children} - + submenu={submenu} + /> ); } diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index 0a41f421a2..e25693cc81 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -35,6 +35,7 @@ import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; import { APIsIcon } from './icons/APIsIcon'; import { ServicesIcon } from './icons/ServicesIcon'; import { MiscIcon } from './icons/MiscIcon'; +import { Submenu } from './Submenu'; export default { title: 'Layout/Sidebar', @@ -67,37 +68,33 @@ export const SampleScalableSidebar = () => ( - {}} - text="Catalog" - hasSubMenu - submenuTitle="Catalog" - > - - - - - - + {}} text="Catalog"> + + + + + + + + From 305901cbe6ce412d1349381fd58ce082c3cd710a Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 22 Nov 2021 14:43:18 +0000 Subject: [PATCH 22/39] Modify SidebarContextType to reduce api surface + update api-report Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 15 +++++++++++++-- .../src/layout/Sidebar/Bar.tsx | 19 +++++++++++-------- .../src/layout/Sidebar/Submenu.tsx | 14 +++++++++++++- .../src/layout/Sidebar/config.ts | 6 ++---- .../src/layout/Sidebar/index.ts | 2 ++ plugins/shortcuts/src/ShortcutItem.test.tsx | 4 +--- plugins/shortcuts/src/Shortcuts.test.tsx | 4 +--- 7 files changed, 43 insertions(+), 21 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 4cfab11374..b71d29e2a6 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -838,8 +838,7 @@ export const SidebarContext: Context; // @public (undocumented) export type SidebarContextType = { isOpen: boolean; - handleOpen: () => any; - handleClose: () => any; + setOpen: (open: boolean) => void; }; // Warning: (ae-missing-release-tag) "SidebarDivider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -2109,6 +2108,18 @@ export type StructuredMetadataTableListClassKey = 'root'; // @public (undocumented) export type StructuredMetadataTableNestedListClassKey = 'root'; +// @public +export const Submenu: ({ + title, + children, +}: PropsWithChildren) => JSX.Element; + +// @public +export type SubmenuProps = { + title?: string; + children: ReactNode; +}; + // Warning: (ae-forgotten-export) The symbol "SubvalueCellProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "SubvalueCell" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index a4cd4349a2..775c537695 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -148,6 +148,14 @@ export function Sidebar(props: PropsWithChildren) { const isOpen = (state === State.Open && !isSmallScreen) || isPinned; + const setOpen = (open: boolean) => { + if (open) { + handleOpen(); + } else { + handleClose(); + } + }; + return (
) {
) { */ export const SidebarExpandButton = () => { const classes = useStyles(); - const { isOpen, handleOpen, handleClose } = useContext(SidebarContext); + const { isOpen, setOpen } = useContext(SidebarContext); const { isPinned } = useContext(SidebarPinStateContext); const isSmallScreen = useMediaQuery(theme => theme.breakpoints.down('md'), ); const handleClick = () => { - if (isOpen) { - handleClose(); - } else { - handleOpen(); - } + setOpen(!isOpen); }; if (isPinned || isSmallScreen) { diff --git a/packages/core-components/src/layout/Sidebar/Submenu.tsx b/packages/core-components/src/layout/Sidebar/Submenu.tsx index 73033164b4..7db0eab17d 100644 --- a/packages/core-components/src/layout/Sidebar/Submenu.tsx +++ b/packages/core-components/src/layout/Sidebar/Submenu.tsx @@ -67,10 +67,22 @@ const useStyles = (props: { left: number }) => }, })); -type SubmenuProps = { +/** + * Holds a title for text Header of a Submenu and children + * components to be rendered inside Submenu + * + * @public + */ +export type SubmenuProps = { title?: string; children: ReactNode; }; + +/** + * Used inside SidebarItem to display an expandable Submenu + * + * @public + */ export const Submenu = ({ title, children, diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index f9eea08ec2..c4f73d0a9d 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -59,14 +59,12 @@ export const SIDEBAR_INTRO_LOCAL_STORAGE = export type SidebarContextType = { isOpen: boolean; - handleOpen: () => any; - handleClose: () => any; + setOpen: (open: boolean) => void; }; export const SidebarContext = createContext({ isOpen: false, - handleOpen: () => {}, - handleClose: () => {}, + setOpen: _open => {}, }); export type ItemWithSubmenuContextType = { diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index f816b8f7f4..f8025e3295 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -16,6 +16,8 @@ export { Sidebar, SidebarExpandButton } from './Bar'; export { SidebarSubItem } from './SidebarSubItem'; +export { Submenu } from './Submenu'; +export type { SubmenuProps } from './Submenu'; export type { SidebarSubItemProps, DropDownItem } from './SidebarSubItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; diff --git a/plugins/shortcuts/src/ShortcutItem.test.tsx b/plugins/shortcuts/src/ShortcutItem.test.tsx index c8f5e4b0ca..e080026f00 100644 --- a/plugins/shortcuts/src/ShortcutItem.test.tsx +++ b/plugins/shortcuts/src/ShortcutItem.test.tsx @@ -37,9 +37,7 @@ describe('ShortcutItem', () => { it('displays the shortcut', async () => { await renderInTestApp( - {}, handleClose: () => {} }} - > + {} }}> , ); diff --git a/plugins/shortcuts/src/Shortcuts.test.tsx b/plugins/shortcuts/src/Shortcuts.test.tsx index f0c85aaf5f..692040027c 100644 --- a/plugins/shortcuts/src/Shortcuts.test.tsx +++ b/plugins/shortcuts/src/Shortcuts.test.tsx @@ -30,9 +30,7 @@ const apis = ApiRegistry.from([ describe('Shortcuts', () => { it('displays an add button', async () => { await renderInTestApp( - {}, handleClose: () => {} }} - > + {} }}> From 10376e33c49889a439f7cbe99c6c4c4e3542331b Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 22 Nov 2021 14:57:20 +0000 Subject: [PATCH 23/39] Improve use of conditional classes Signed-off-by: hiba-aldalaty --- .../core-components/src/layout/Sidebar/Items.tsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index f1b51e497f..8cdb8f75aa 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -221,7 +221,7 @@ const ItemWithSubmenu = ({ color="secondary" variant="dot" overlap="circular" - className={isOpen ? undefined : classes.closedItemIcon} + className={isOpen ? '' : classes.closedItemIcon} invisible={!hasNotifications} > @@ -251,7 +251,7 @@ const ItemWithSubmenu = ({ >
{isOpen ? openContent : closedContent} @@ -372,7 +372,7 @@ export const SidebarItem = forwardRef((props, ref) => { variant="dot" overlap="circular" invisible={!hasNotifications} - className={clsx(isOpen ? undefined : classes.closedItemIcon)} + className={clsx({ [classes.closeItemIcon]: !isOpen })} > @@ -403,7 +403,7 @@ export const SidebarItem = forwardRef((props, ref) => { classes.root, isOpen ? classes.open : classes.closed, isButtonItem(props) && classes.buttonItem, - disableHighlight ? undefined : classes.highlightable, + { [classes.highlightable]: !disableHighlight }, ), }; From 1ea036426c31f30205007db91d04c09322900c13 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 22 Nov 2021 15:07:28 +0000 Subject: [PATCH 24/39] Change fontsize of dropdown items Signed-off-by: hiba-aldalaty --- packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx index c5125ce476..a4be6fdb29 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx @@ -76,6 +76,7 @@ const useStyles = makeStyles(theme => ({ color: theme.palette.navigation.color, display: 'flex', justifyContent: 'center', + fontSize: '14px', }, })); @@ -168,7 +169,7 @@ export const SidebarSubItem = ({ onClick={closeSubmenu} key={key} > - + {object.title} From 3944b5e9b88f056e6b39e1c6de6a4365e4e69d59 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 22 Nov 2021 16:15:18 +0000 Subject: [PATCH 25/39] Update tests Signed-off-by: hiba-aldalaty --- .../core-components/src/layout/Sidebar/Bar.test.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 68b05fc393..a4413dfd00 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -69,13 +69,13 @@ describe('Sidebar', () => { }); it('Sidebar should not show expanded items when hovered on', async () => { userEvent.hover(screen.getByTestId('sidebar-root')); - expect(await screen.queryByText('Create...')).not.toBeInTheDocument(); + expect(screen.queryByText('Create...')).not.toBeInTheDocument(); }); }); describe('Submenu Items', () => { it('Extended sidebar with submenu content hidden by default', async () => { - expect(await screen.queryByText('Tools')).not.toBeInTheDocument(); - expect(await screen.queryByText('Misc')).not.toBeInTheDocument(); + expect(screen.queryByText('Tools')).not.toBeInTheDocument(); + expect(screen.queryByText('Misc')).not.toBeInTheDocument(); }); it('Extended sidebar with submenu content visible when hover over submenu items', async () => { @@ -87,8 +87,8 @@ describe('Sidebar', () => { it('Multicategory item in submenu shows drop down on click', async () => { userEvent.hover(screen.getByTestId('item-with-submenu')); userEvent.click(screen.getByText('Misc')); - expect(await screen.getByText('dropdown item 1')).toBeInTheDocument(); - expect(await screen.getByText('dropdown item 2')).toBeInTheDocument(); + expect(screen.getByText('dropdown item 1')).toBeInTheDocument(); + expect(screen.getByText('dropdown item 2')).toBeInTheDocument(); }); it('Dropdown item in submenu renders a link when `to` value is provided', async () => { From 949633623f11c6efbcffe144d73a2bb067898aa6 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 24 Nov 2021 09:29:41 +0000 Subject: [PATCH 26/39] Fix tSidebar ests and storybook after merging change caused isPinned to be true by default Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Bar.test.tsx | 59 ++++++----- .../src/layout/Sidebar/Sidebar.stories.tsx | 99 ++++++++++--------- 2 files changed, 86 insertions(+), 72 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index a4413dfd00..4d89008ea3 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -26,34 +26,43 @@ import { Sidebar, SidebarExpandButton } from './Bar'; import { SidebarItem, SidebarSearchField } from './Items'; import { SidebarSubItem } from './SidebarSubItem'; import { Submenu } from './Submenu'; +import { SidebarPinStateContext } from '.'; async function renderScalableSidebar() { await renderInTestApp( - - {}} to="/search" /> - {}} text="Catalog"> - - - - - - - - , + {} }} + > + + {}} to="/search" /> + {}} + text="Catalog" + > + + + + + + + + + , ); } diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index e25693cc81..978987e028 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -27,6 +27,7 @@ import { SidebarExpandButton, SidebarIntro, SidebarItem, + SidebarPage, SidebarSearchField, SidebarSpace, } from '.'; @@ -53,54 +54,58 @@ const handleSearch = (input: string) => { }; export const SampleSidebar = () => ( - - - - - - - - - + + + + + + + + + + + ); export const SampleScalableSidebar = () => ( - - - - {}} text="Catalog"> - - - - - - - - - - - - - - - - + + + + + {}} text="Catalog"> + + + + + + + + + + + + + + + + + ); From fce9870fff91995ee792f4eee3d6bb9d01c59819 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 24 Nov 2021 10:58:43 +0000 Subject: [PATCH 27/39] Rename Submenu -> SidebarSubmenu, SidebarSubItem -> SidebarSubmenuItem Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 30 +++++++++---------- .../src/layout/Sidebar/Bar.test.tsx | 12 ++++---- .../src/layout/Sidebar/Items.tsx | 6 ++-- .../src/layout/Sidebar/Sidebar.stories.tsx | 20 ++++++------- .../{Submenu.tsx => SidebarSubmenu.tsx} | 10 +++---- ...ebarSubItem.tsx => SidebarSubmenuItem.tsx} | 6 ++-- .../src/layout/Sidebar/index.ts | 11 ++++--- 7 files changed, 49 insertions(+), 46 deletions(-) rename packages/core-components/src/layout/Sidebar/{Submenu.tsx => SidebarSubmenu.tsx} (91%) rename packages/core-components/src/layout/Sidebar/{SidebarSubItem.tsx => SidebarSubmenuItem.tsx} (97%) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index b71d29e2a6..ec04b14bd3 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1988,21 +1988,33 @@ export const SidebarSpacer: React_2.ComponentType< >; // @public -export const SidebarSubItem: ({ +export const SidebarSubmenu: ({ + title, + children, +}: PropsWithChildren) => JSX.Element; + +// @public +export const SidebarSubmenuItem: ({ title, to, icon: Icon, dropdownItems, -}: SidebarSubItemProps) => JSX.Element; +}: SidebarSubmenuItemProps) => JSX.Element; // @public -export type SidebarSubItemProps = { +export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; dropdownItems?: DropDownItem[]; }; +// @public +export type SidebarSubmenuProps = { + title?: string; + children: ReactNode; +}; + // Warning: (ae-forgotten-export) The symbol "Props" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "SignInPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -2108,18 +2120,6 @@ export type StructuredMetadataTableListClassKey = 'root'; // @public (undocumented) export type StructuredMetadataTableNestedListClassKey = 'root'; -// @public -export const Submenu: ({ - title, - children, -}: PropsWithChildren) => JSX.Element; - -// @public -export type SubmenuProps = { - title?: string; - children: ReactNode; -}; - // Warning: (ae-forgotten-export) The symbol "SubvalueCellProps" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "SubvalueCell" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 4d89008ea3..560f761531 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -24,8 +24,8 @@ import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; import { MiscIcon } from './icons/MiscIcon'; import { Sidebar, SidebarExpandButton } from './Bar'; import { SidebarItem, SidebarSearchField } from './Items'; -import { SidebarSubItem } from './SidebarSubItem'; -import { Submenu } from './Submenu'; +import { SidebarSubmenuItem } from './SidebarSubmenuItem'; +import { SidebarSubmenu } from './SidebarSubmenu'; import { SidebarPinStateContext } from '.'; async function renderScalableSidebar() { @@ -40,9 +40,9 @@ async function renderScalableSidebar() { onClick={() => {}} text="Catalog" > - - - + + - + diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 8cdb8f75aa..5871867ce2 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -44,7 +44,7 @@ import { SidebarContext, ItemWithSubmenuContext, } from './config'; -import { Submenu } from './Submenu'; +import { SidebarSubmenu } from './SidebarSubmenu'; export type SidebarItemClassKey = | 'root' @@ -410,9 +410,9 @@ export const SidebarItem = forwardRef((props, ref) => { let hasSubmenu = false; let submenu: any; const componentType = ( - + <> - + ).type; Children.forEach(children, element => { if (!React.isValidElement(element)) return; diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index 978987e028..7102d40f14 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -31,12 +31,12 @@ import { SidebarSearchField, SidebarSpace, } from '.'; -import { SidebarSubItem } from './SidebarSubItem'; +import { SidebarSubmenuItem } from './SidebarSubmenuItem'; import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; import { APIsIcon } from './icons/APIsIcon'; import { ServicesIcon } from './icons/ServicesIcon'; import { MiscIcon } from './icons/MiscIcon'; -import { Submenu } from './Submenu'; +import { SidebarSubmenu } from './SidebarSubmenu'; export default { title: 'Layout/Sidebar', @@ -73,17 +73,17 @@ export const SampleScalableSidebar = () => ( {}} text="Catalog"> - - - - - + + + + - - + ( }, ]} /> - + diff --git a/packages/core-components/src/layout/Sidebar/Submenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx similarity index 91% rename from packages/core-components/src/layout/Sidebar/Submenu.tsx rename to packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index 7db0eab17d..9b8b9ca145 100644 --- a/packages/core-components/src/layout/Sidebar/Submenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -68,12 +68,12 @@ const useStyles = (props: { left: number }) => })); /** - * Holds a title for text Header of a Submenu and children - * components to be rendered inside Submenu + * Holds a title for text Header of a sidebar submenu and children + * components to be rendered inside SidebarSubmenu * * @public */ -export type SubmenuProps = { +export type SidebarSubmenuProps = { title?: string; children: ReactNode; }; @@ -83,10 +83,10 @@ export type SubmenuProps = { * * @public */ -export const Submenu = ({ +export const SidebarSubmenu = ({ title, children, -}: PropsWithChildren) => { +}: PropsWithChildren) => { const { isOpen } = useContext(SidebarContext); const left = isOpen ? sidebarConfig.drawerWidthOpen diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx similarity index 97% rename from packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx rename to packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index a4be6fdb29..969356541d 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -101,7 +101,7 @@ export type DropDownItem = { * * @public */ -export type SidebarSubItemProps = { +export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; @@ -113,12 +113,12 @@ export type SidebarSubItemProps = { * * @public */ -export const SidebarSubItem = ({ +export const SidebarSubmenuItem = ({ title, to, icon: Icon, dropdownItems, -}: SidebarSubItemProps) => { +}: SidebarSubmenuItemProps) => { const classes = useStyles(); const { pathname: locationPathname } = useLocation(); const { pathname: toPathname } = useResolvedPath(to); diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index f8025e3295..60ca9cc93c 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -15,10 +15,13 @@ */ export { Sidebar, SidebarExpandButton } from './Bar'; -export { SidebarSubItem } from './SidebarSubItem'; -export { Submenu } from './Submenu'; -export type { SubmenuProps } from './Submenu'; -export type { SidebarSubItemProps, DropDownItem } from './SidebarSubItem'; +export { SidebarSubmenuItem } from './SidebarSubmenuItem'; +export { SidebarSubmenu } from './SidebarSubmenu'; +export type { SidebarSubmenuProps } from './SidebarSubmenu'; +export type { + SidebarSubmenuItemProps, + DropDownItem, +} from './SidebarSubmenuItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page'; From 9f8e9a04d17f0319eb4fe51dd61871979f0d96ca Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 24 Nov 2021 11:09:01 +0000 Subject: [PATCH 28/39] Rename DropDownItem -> SidebarSubItemDropDownItem Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 14 +++++++------- .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 4 ++-- .../core-components/src/layout/Sidebar/index.ts | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index ec04b14bd3..d622595630 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -301,12 +301,6 @@ export type DismissbleBannerClassKey = DismissableBannerClassKey; // @public (undocumented) export function DocsIcon(props: IconComponentProps): JSX.Element; -// @public -export type DropDownItem = { - title: string; - to: string; -}; - // @public (undocumented) export function EmailIcon(props: IconComponentProps): JSX.Element; @@ -1987,6 +1981,12 @@ export const SidebarSpacer: React_2.ComponentType< } >; +// @public +export type SidebarSubItemDropDownItem = { + title: string; + to: string; +}; + // @public export const SidebarSubmenu: ({ title, @@ -2006,7 +2006,7 @@ export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: DropDownItem[]; + dropdownItems?: SidebarSubItemDropDownItem[]; }; // @public diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 969356541d..eccb3475fb 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -87,7 +87,7 @@ const useStyles = makeStyles(theme => ({ * * @public */ -export type DropDownItem = { +export type SidebarSubItemDropDownItem = { title: string; to: string; }; @@ -105,7 +105,7 @@ export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: DropDownItem[]; + dropdownItems?: SidebarSubItemDropDownItem[]; }; /** diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 60ca9cc93c..c5a047b2ac 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -20,7 +20,7 @@ export { SidebarSubmenu } from './SidebarSubmenu'; export type { SidebarSubmenuProps } from './SidebarSubmenu'; export type { SidebarSubmenuItemProps, - DropDownItem, + SidebarSubItemDropDownItem, } from './SidebarSubmenuItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; From 34706291e7685c4d0fc4504de288e1755f677069 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Wed, 24 Nov 2021 11:16:53 +0000 Subject: [PATCH 29/39] Move destructuring of the props into function SidebarSubmenuItem Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 9 +++------ .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 8 ++------ 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index d622595630..f11cb6f3cc 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1994,12 +1994,9 @@ export const SidebarSubmenu: ({ }: PropsWithChildren) => JSX.Element; // @public -export const SidebarSubmenuItem: ({ - title, - to, - icon: Icon, - dropdownItems, -}: SidebarSubmenuItemProps) => JSX.Element; +export const SidebarSubmenuItem: ( + props: SidebarSubmenuItemProps, +) => JSX.Element; // @public export type SidebarSubmenuItemProps = { diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index eccb3475fb..2aa7b54f09 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -113,12 +113,8 @@ export type SidebarSubmenuItemProps = { * * @public */ -export const SidebarSubmenuItem = ({ - title, - to, - icon: Icon, - dropdownItems, -}: SidebarSubmenuItemProps) => { +export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { + const { title, to, icon: Icon, dropdownItems } = props; const classes = useStyles(); const { pathname: locationPathname } = useLocation(); const { pathname: toPathname } = useResolvedPath(to); From 378a6a82a0bd824d4026188307b62fca75fc8d49 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Thu, 25 Nov 2021 11:06:50 +0000 Subject: [PATCH 30/39] Simplify code/extract some logic in Items.tsx Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Items.tsx | 66 +++++++++++-------- .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 1 - packages/storybook/.storybook/apis.js | 4 ++ 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 5871867ce2..fa1d2c1c60 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -14,7 +14,7 @@ * limitations under the License. */ -import { IconComponent } from '@backstage/core-plugin-api'; +import { IconComponent, useElementFilter } from '@backstage/core-plugin-api'; import { BackstageTheme } from '@backstage/theme'; import { makeStyles, styled, Theme } from '@material-ui/core/styles'; import Badge from '@material-ui/core/Badge'; @@ -173,25 +173,16 @@ type ItemWithSubmenuProps = { icon: IconComponent; submenu: ReactNode; }; -const ItemWithSubmenu = ({ - label, - hasNotifications = false, - icon: Icon, - submenu, -}: ItemWithSubmenuProps) => { - const classes = useStyles(); - const [isHoveredOn, setIsHoveredOn] = useState(false); + +function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { + // Item is active if any of submenu items have active paths + const toPathnames: string[] = []; + let isActive = false; let submenuItems: ReactNode; Children.forEach(submenu, element => { if (!React.isValidElement(element)) return; submenuItems = element.props.children; }); - - const toPathnames: string[] = []; - let isActive; - const { pathname: locationPathname } = useLocation(); - - // SidebarItem is active if any of submenu items have active paths Children.forEach(submenuItems, element => { if (!React.isValidElement(element)) return; if (element.props.dropdownItems) { @@ -202,11 +193,23 @@ const ItemWithSubmenu = ({ toPathnames.push(element.props.to); } }); - toPathnames.some(to => { + isActive = toPathnames.some(to => { const toPathname = resolvePath(to); - isActive = locationPathname === toPathname.pathname; - return isActive; + return locationPathname === toPathname.pathname; }); + return isActive; +} + +const ItemWithSubmenu = ({ + label, + hasNotifications = false, + icon: Icon, + submenu, +}: ItemWithSubmenuProps) => { + const classes = useStyles(); + const [isHoveredOn, setIsHoveredOn] = useState(false); + const { pathname: locationPathname } = useLocation(); + const isActive = isItemWithSubmenuActive(submenu, locationPathname); const handleMouseEnter = () => { setIsHoveredOn(true); @@ -408,19 +411,30 @@ export const SidebarItem = forwardRef((props, ref) => { }; let hasSubmenu = false; - let submenu: any; + let submenu: ReactNode; const componentType = ( <> ).type; - Children.forEach(children, element => { - if (!React.isValidElement(element)) return; - if (element.type === componentType) { - submenu = element; - hasSubmenu = true; - } - }); + // Filter children for SidebarSubmenu components + const submenus = useElementFilter(children, elements => + elements + .getElements() + .filter( + child => React.isValidElement(child) && child.type === componentType, + ), + ); + // Error thrown if more than one SidebarSubmenu in a SidebarItem + if (submenus.length > 1) { + throw new Error( + 'Cannot render more than one SidebarSubmenu inside a SidebarItem', + ); + } else if (submenus.length === 1) { + hasSubmenu = true; + submenu = submenus[0]; + } + if (hasSubmenu) { return ( { dropdownItems.some(item => { const resolvedPath = resolvePath(item.to); isActive = locationPathname === resolvedPath.pathname; - return isActive; }); return (
diff --git a/packages/storybook/.storybook/apis.js b/packages/storybook/.storybook/apis.js index 3b7f6119ef..bc4377c794 100644 --- a/packages/storybook/.storybook/apis.js +++ b/packages/storybook/.storybook/apis.js @@ -11,6 +11,7 @@ import { OktaAuth, Auth0Auth, ConfigReader, + LocalStorageFeatureFlags, } from '@backstage/core-app-api'; import { @@ -25,10 +26,13 @@ import { oktaAuthApiRef, auth0AuthApiRef, configApiRef, + featureFlagsApiRef, } from '@backstage/core-plugin-api'; const builder = ApiRegistry.builder(); +builder.add(featureFlagsApiRef, new LocalStorageFeatureFlags()); + builder.add(configApiRef, new ConfigReader({})); const alertApi = builder.add(alertApiRef, new AlertApiForwarder()); From 303503ab9e5154f471b381afa8925cd88042534d Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Thu, 25 Nov 2021 15:05:07 +0000 Subject: [PATCH 31/39] SidebarItem no longer requires 'to' or 'onClick' props if children provided Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Items.tsx | 53 +++++++++++-------- 1 file changed, 31 insertions(+), 22 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index fa1d2c1c60..544d7010fe 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -28,6 +28,7 @@ import React, { Children, forwardRef, KeyboardEventHandler, + PropsWithChildren, ReactNode, useContext, useState, @@ -167,13 +168,6 @@ const useStyles = makeStyles( { name: 'BackstageSidebarItem' }, ); -type ItemWithSubmenuProps = { - label?: string; - hasNotifications?: boolean; - icon: IconComponent; - submenu: ReactNode; -}; - function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { // Item is active if any of submenu items have active paths const toPathnames: string[] = []; @@ -201,15 +195,15 @@ function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { } const ItemWithSubmenu = ({ - label, + text, hasNotifications = false, icon: Icon, - submenu, -}: ItemWithSubmenuProps) => { + children, +}: PropsWithChildren) => { const classes = useStyles(); const [isHoveredOn, setIsHoveredOn] = useState(false); const { pathname: locationPathname } = useLocation(); - const isActive = isItemWithSubmenuActive(submenu, locationPathname); + const isActive = isItemWithSubmenuActive(children, locationPathname); const handleMouseEnter = () => { setIsHoveredOn(true); @@ -235,9 +229,9 @@ const ItemWithSubmenu = ({
{itemIcon}
- {label && ( - - {label} + {text && ( + + {text} )}
{}
@@ -272,7 +266,7 @@ const ItemWithSubmenu = ({ )}
- {isHoveredOn && submenu} + {isHoveredOn && children}
); @@ -283,12 +277,12 @@ type SidebarItemBaseProps = { text?: string; hasNotifications?: boolean; disableHighlight?: boolean; - children?: ReactNode; className?: string; }; type SidebarItemButtonProps = SidebarItemBaseProps & { onClick: (ev: React.MouseEvent) => void; + children?: ReactNode; }; type SidebarItemLinkProps = SidebarItemBaseProps & { @@ -296,7 +290,21 @@ type SidebarItemLinkProps = SidebarItemBaseProps & { onClick?: (ev: React.MouseEvent) => void; } & NavLinkProps; -type SidebarItemProps = SidebarItemButtonProps | SidebarItemLinkProps; +type ItemWithSubmenuProps = SidebarItemBaseProps & { + to?: string; + onClick?: (ev: React.MouseEvent) => void; + children: ReactNode; +}; + +/** + * SidebarItem with 'to' property will be a clickable link. + * SidebarItem with 'onClick' property and without 'to' property will be a clickable button. + * SidebarItem which wraps a SidebarSubmenu will be a clickable button which opens a submenu. + */ +type SidebarItemProps = + | SidebarItemLinkProps + | SidebarItemButtonProps + | ItemWithSubmenuProps; function isButtonItem( props: SidebarItemProps, @@ -389,7 +397,7 @@ export const SidebarItem = forwardRef((props, ref) => { {itemIcon}
{text && ( - + {text} )} @@ -438,11 +446,12 @@ export const SidebarItem = forwardRef((props, ref) => { if (hasSubmenu) { return ( + > + {submenu} + ); } @@ -458,7 +467,7 @@ export const SidebarItem = forwardRef((props, ref) => { Date: Fri, 26 Nov 2021 10:25:10 +0000 Subject: [PATCH 32/39] Move styling from themes/palette and make optional Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 2 + .../src/layout/Sidebar/Items.tsx | 212 +++++++++--------- .../src/layout/Sidebar/SidebarSubmenu.tsx | 8 +- packages/theme/api-report.md | 6 - packages/theme/src/themes.ts | 12 - packages/theme/src/types.ts | 6 - 6 files changed, 116 insertions(+), 130 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index f11cb6f3cc..0c2f009092 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1990,6 +1990,7 @@ export type SidebarSubItemDropDownItem = { // @public export const SidebarSubmenu: ({ title, + backgroundColor, children, }: PropsWithChildren) => JSX.Element; @@ -2009,6 +2010,7 @@ export type SidebarSubmenuItemProps = { // @public export type SidebarSubmenuProps = { title?: string; + backgroundColor?: string; children: ReactNode; }; diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 544d7010fe..f4e2124ab6 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -61,112 +61,114 @@ export type SidebarItemClassKey = | 'secondaryAction' | 'selected'; -const useStyles = makeStyles( - theme => { - const { - selectedIndicatorWidth, - drawerWidthClosed, - drawerWidthOpen, - iconContainerWidth, - } = sidebarConfig; - return { - root: { - color: theme.palette.navigation.color, - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center', - height: 48, - cursor: 'pointer', - }, - buttonItem: { - background: 'none', - border: 'none', - width: 'auto', - margin: 0, - padding: 0, - textAlign: 'inherit', - font: 'inherit', - }, - closed: { - width: drawerWidthClosed, - justifyContent: 'center', - }, - open: { - width: drawerWidthOpen, - }, - highlightable: { - '&:hover': { - background: theme.palette.navigation.navItem.hoverBackground, +const useStyles = (props: { hoverBackgroundColor?: string }) => + makeStyles( + theme => { + const { + selectedIndicatorWidth, + drawerWidthClosed, + drawerWidthOpen, + iconContainerWidth, + } = sidebarConfig; + return { + root: { + color: theme.palette.navigation.color, + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + height: 48, + cursor: 'pointer', }, - }, - highlighted: { - background: theme.palette.navigation.navItem.hoverBackground, - }, - label: { - // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs - fontWeight: 'bold', - whiteSpace: 'nowrap', - lineHeight: 'auto', - flex: '3 1 auto', - width: '110px', - overflow: 'hidden', - 'text-overflow': 'ellipsis', - }, - iconContainer: { - boxSizing: 'border-box', - height: '100%', - width: iconContainerWidth, - marginRight: -theme.spacing(2), - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - searchRoot: { - marginBottom: 12, - }, - searchField: { - color: '#b5b5b5', - fontWeight: 'bold', - fontSize: theme.typography.fontSize, - }, - searchFieldHTMLInput: { - padding: `${theme.spacing(2)} 0 ${theme.spacing(2)}`, - }, - searchContainer: { - width: drawerWidthOpen - iconContainerWidth, - }, - secondaryAction: { - width: theme.spacing(6), - textAlign: 'center', - marginRight: theme.spacing(1), - }, - closedItemIcon: { - width: '100%', - justifyContent: 'center', - }, - submenuArrow: { - position: 'absolute', - right: 0, - }, - selected: { - '&$root': { - borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - color: theme.palette.navigation.selectedColor, + buttonItem: { + background: 'none', + border: 'none', + width: 'auto', + margin: 0, + padding: 0, + textAlign: 'inherit', + font: 'inherit', }, - '&$closed': { + closed: { width: drawerWidthClosed, + justifyContent: 'center', }, - '& $closedItemIcon': { - paddingRight: selectedIndicatorWidth, + open: { + width: drawerWidthOpen, }, - '& $iconContainer': { - marginLeft: -selectedIndicatorWidth, + highlightable: { + '&:hover': { + // Ideally this would be added to the pallette but would cause a breaking change + background: props.hoverBackgroundColor || '#404040', + }, }, - }, - }; - }, - { name: 'BackstageSidebarItem' }, -); + highlighted: { + background: props.hoverBackgroundColor || '#404040', + }, + label: { + // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs + fontWeight: 'bold', + whiteSpace: 'nowrap', + lineHeight: 'auto', + flex: '3 1 auto', + width: '110px', + overflow: 'hidden', + 'text-overflow': 'ellipsis', + }, + iconContainer: { + boxSizing: 'border-box', + height: '100%', + width: iconContainerWidth, + marginRight: -theme.spacing(2), + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + searchRoot: { + marginBottom: 12, + }, + searchField: { + color: '#b5b5b5', + fontWeight: 'bold', + fontSize: theme.typography.fontSize, + }, + searchFieldHTMLInput: { + padding: `${theme.spacing(2)} 0 ${theme.spacing(2)}`, + }, + searchContainer: { + width: drawerWidthOpen - iconContainerWidth, + }, + secondaryAction: { + width: theme.spacing(6), + textAlign: 'center', + marginRight: theme.spacing(1), + }, + closedItemIcon: { + width: '100%', + justifyContent: 'center', + }, + submenuArrow: { + position: 'absolute', + right: 0, + }, + selected: { + '&$root': { + borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + color: theme.palette.navigation.selectedColor, + }, + '&$closed': { + width: drawerWidthClosed, + }, + '& $closedItemIcon': { + paddingRight: selectedIndicatorWidth, + }, + '& $iconContainer': { + marginLeft: -selectedIndicatorWidth, + }, + }, + }; + }, + { name: 'BackstageSidebarItem' }, + ); function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { // Item is active if any of submenu items have active paths @@ -197,10 +199,11 @@ function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { const ItemWithSubmenu = ({ text, hasNotifications = false, + hoverBackgroundColor, icon: Icon, children, }: PropsWithChildren) => { - const classes = useStyles(); + const classes = useStyles({ hoverBackgroundColor })(); const [isHoveredOn, setIsHoveredOn] = useState(false); const { pathname: locationPathname } = useLocation(); const isActive = isItemWithSubmenuActive(children, locationPathname); @@ -277,6 +280,7 @@ type SidebarItemBaseProps = { text?: string; hasNotifications?: boolean; disableHighlight?: boolean; + hoverBackgroundColor?: string; className?: string; }; @@ -366,12 +370,13 @@ export const SidebarItem = forwardRef((props, ref) => { text, hasNotifications = false, disableHighlight = false, + hoverBackgroundColor, onClick, children, className, ...navLinkProps } = props; - const classes = useStyles(); + const classes = useStyles({ hoverBackgroundColor })(); // XXX (@koroeskohr): unsure this is optimal. But I just really didn't want to have the item component // depend on the current location, and at least have it being optionally forced to selected. // Still waiting on a Q answered to fine tune the implementation @@ -449,6 +454,7 @@ export const SidebarItem = forwardRef((props, ref) => { text={text} icon={Icon} hasNotifications={hasNotifications} + hoverBackgroundColor={hoverBackgroundColor} > {submenu} @@ -485,7 +491,7 @@ type SidebarSearchFieldProps = { export function SidebarSearchField(props: SidebarSearchFieldProps) { const [input, setInput] = useState(''); - const classes = useStyles(); + const classes = useStyles({})(); const Icon = props.icon ? props.icon : SearchIcon; const search = () => { diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index 9b8b9ca145..a53bf2328d 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -25,7 +25,7 @@ import { } from './config'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = (props: { left: number }) => +const useStyles = (props: { left: number; backgroundColor?: string }) => makeStyles(theme => ({ root: { zIndex: 1000, @@ -42,7 +42,7 @@ const useStyles = (props: { left: number }) => top: 0, bottom: 0, padding: 0, - background: theme.palette.navigation.submenu.background, + background: props.backgroundColor || '#404040', overflowX: 'hidden', msOverflowStyle: 'none', scrollbarWidth: 'none', @@ -75,6 +75,7 @@ const useStyles = (props: { left: number }) => */ export type SidebarSubmenuProps = { title?: string; + backgroundColor?: string; children: ReactNode; }; @@ -85,13 +86,14 @@ export type SidebarSubmenuProps = { */ export const SidebarSubmenu = ({ title, + backgroundColor, children, }: PropsWithChildren) => { const { isOpen } = useContext(SidebarContext); const left = isOpen ? sidebarConfig.drawerWidthOpen : sidebarConfig.drawerWidthClosed; - const props = { left: left }; + const props = { left, backgroundColor }; const classes = useStyles(props)(); const { isHoveredOn } = useContext(ItemWithSubmenuContext); diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index 4331278e60..2dc6ab7b55 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -41,12 +41,6 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; - navItem: { - hoverBackground: string; - }; - submenu: { - background: string; - }; }; tabbar: { indicator: string; diff --git a/packages/theme/src/themes.ts b/packages/theme/src/themes.ts index b048c70fec..7e99ce8e8a 100644 --- a/packages/theme/src/themes.ts +++ b/packages/theme/src/themes.ts @@ -76,12 +76,6 @@ export const lightTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', - navItem: { - hoverBackground: '#404040', - }, - submenu: { - background: '#404040', - }, }, pinSidebarButton: { icon: '#181818', @@ -157,12 +151,6 @@ export const darkTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', - navItem: { - hoverBackground: '#404040', - }, - submenu: { - background: '#404040', - }, }, pinSidebarButton: { icon: '#404040', diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index 44d9165417..e1acba3a01 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -53,12 +53,6 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; - navItem: { - hoverBackground: string; - }; - submenu: { - background: string; - }; }; tabbar: { indicator: string; From 06878bf8108793261dc3976f2ee4a0b59f68f165 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 26 Nov 2021 11:23:46 +0000 Subject: [PATCH 33/39] Revert "Move styling from themes/palette and make optional" This reverts commit 04e1b87a894d0c4a7c28e13e89a0cba75159586d. Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 2 - .../src/layout/Sidebar/Items.tsx | 212 +++++++++--------- .../src/layout/Sidebar/SidebarSubmenu.tsx | 8 +- packages/theme/api-report.md | 6 + packages/theme/src/themes.ts | 12 + packages/theme/src/types.ts | 6 + 6 files changed, 130 insertions(+), 116 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 0c2f009092..f11cb6f3cc 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1990,7 +1990,6 @@ export type SidebarSubItemDropDownItem = { // @public export const SidebarSubmenu: ({ title, - backgroundColor, children, }: PropsWithChildren) => JSX.Element; @@ -2010,7 +2009,6 @@ export type SidebarSubmenuItemProps = { // @public export type SidebarSubmenuProps = { title?: string; - backgroundColor?: string; children: ReactNode; }; diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index f4e2124ab6..544d7010fe 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -61,114 +61,112 @@ export type SidebarItemClassKey = | 'secondaryAction' | 'selected'; -const useStyles = (props: { hoverBackgroundColor?: string }) => - makeStyles( - theme => { - const { - selectedIndicatorWidth, - drawerWidthClosed, - drawerWidthOpen, - iconContainerWidth, - } = sidebarConfig; - return { - root: { - color: theme.palette.navigation.color, - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center', - height: 48, - cursor: 'pointer', +const useStyles = makeStyles( + theme => { + const { + selectedIndicatorWidth, + drawerWidthClosed, + drawerWidthOpen, + iconContainerWidth, + } = sidebarConfig; + return { + root: { + color: theme.palette.navigation.color, + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + height: 48, + cursor: 'pointer', + }, + buttonItem: { + background: 'none', + border: 'none', + width: 'auto', + margin: 0, + padding: 0, + textAlign: 'inherit', + font: 'inherit', + }, + closed: { + width: drawerWidthClosed, + justifyContent: 'center', + }, + open: { + width: drawerWidthOpen, + }, + highlightable: { + '&:hover': { + background: theme.palette.navigation.navItem.hoverBackground, }, - buttonItem: { - background: 'none', - border: 'none', - width: 'auto', - margin: 0, - padding: 0, - textAlign: 'inherit', - font: 'inherit', + }, + highlighted: { + background: theme.palette.navigation.navItem.hoverBackground, + }, + label: { + // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs + fontWeight: 'bold', + whiteSpace: 'nowrap', + lineHeight: 'auto', + flex: '3 1 auto', + width: '110px', + overflow: 'hidden', + 'text-overflow': 'ellipsis', + }, + iconContainer: { + boxSizing: 'border-box', + height: '100%', + width: iconContainerWidth, + marginRight: -theme.spacing(2), + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + searchRoot: { + marginBottom: 12, + }, + searchField: { + color: '#b5b5b5', + fontWeight: 'bold', + fontSize: theme.typography.fontSize, + }, + searchFieldHTMLInput: { + padding: `${theme.spacing(2)} 0 ${theme.spacing(2)}`, + }, + searchContainer: { + width: drawerWidthOpen - iconContainerWidth, + }, + secondaryAction: { + width: theme.spacing(6), + textAlign: 'center', + marginRight: theme.spacing(1), + }, + closedItemIcon: { + width: '100%', + justifyContent: 'center', + }, + submenuArrow: { + position: 'absolute', + right: 0, + }, + selected: { + '&$root': { + borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + color: theme.palette.navigation.selectedColor, }, - closed: { + '&$closed': { width: drawerWidthClosed, - justifyContent: 'center', }, - open: { - width: drawerWidthOpen, + '& $closedItemIcon': { + paddingRight: selectedIndicatorWidth, }, - highlightable: { - '&:hover': { - // Ideally this would be added to the pallette but would cause a breaking change - background: props.hoverBackgroundColor || '#404040', - }, + '& $iconContainer': { + marginLeft: -selectedIndicatorWidth, }, - highlighted: { - background: props.hoverBackgroundColor || '#404040', - }, - label: { - // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs - fontWeight: 'bold', - whiteSpace: 'nowrap', - lineHeight: 'auto', - flex: '3 1 auto', - width: '110px', - overflow: 'hidden', - 'text-overflow': 'ellipsis', - }, - iconContainer: { - boxSizing: 'border-box', - height: '100%', - width: iconContainerWidth, - marginRight: -theme.spacing(2), - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }, - searchRoot: { - marginBottom: 12, - }, - searchField: { - color: '#b5b5b5', - fontWeight: 'bold', - fontSize: theme.typography.fontSize, - }, - searchFieldHTMLInput: { - padding: `${theme.spacing(2)} 0 ${theme.spacing(2)}`, - }, - searchContainer: { - width: drawerWidthOpen - iconContainerWidth, - }, - secondaryAction: { - width: theme.spacing(6), - textAlign: 'center', - marginRight: theme.spacing(1), - }, - closedItemIcon: { - width: '100%', - justifyContent: 'center', - }, - submenuArrow: { - position: 'absolute', - right: 0, - }, - selected: { - '&$root': { - borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - color: theme.palette.navigation.selectedColor, - }, - '&$closed': { - width: drawerWidthClosed, - }, - '& $closedItemIcon': { - paddingRight: selectedIndicatorWidth, - }, - '& $iconContainer': { - marginLeft: -selectedIndicatorWidth, - }, - }, - }; - }, - { name: 'BackstageSidebarItem' }, - ); + }, + }; + }, + { name: 'BackstageSidebarItem' }, +); function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { // Item is active if any of submenu items have active paths @@ -199,11 +197,10 @@ function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { const ItemWithSubmenu = ({ text, hasNotifications = false, - hoverBackgroundColor, icon: Icon, children, }: PropsWithChildren) => { - const classes = useStyles({ hoverBackgroundColor })(); + const classes = useStyles(); const [isHoveredOn, setIsHoveredOn] = useState(false); const { pathname: locationPathname } = useLocation(); const isActive = isItemWithSubmenuActive(children, locationPathname); @@ -280,7 +277,6 @@ type SidebarItemBaseProps = { text?: string; hasNotifications?: boolean; disableHighlight?: boolean; - hoverBackgroundColor?: string; className?: string; }; @@ -370,13 +366,12 @@ export const SidebarItem = forwardRef((props, ref) => { text, hasNotifications = false, disableHighlight = false, - hoverBackgroundColor, onClick, children, className, ...navLinkProps } = props; - const classes = useStyles({ hoverBackgroundColor })(); + const classes = useStyles(); // XXX (@koroeskohr): unsure this is optimal. But I just really didn't want to have the item component // depend on the current location, and at least have it being optionally forced to selected. // Still waiting on a Q answered to fine tune the implementation @@ -454,7 +449,6 @@ export const SidebarItem = forwardRef((props, ref) => { text={text} icon={Icon} hasNotifications={hasNotifications} - hoverBackgroundColor={hoverBackgroundColor} > {submenu} @@ -491,7 +485,7 @@ type SidebarSearchFieldProps = { export function SidebarSearchField(props: SidebarSearchFieldProps) { const [input, setInput] = useState(''); - const classes = useStyles({})(); + const classes = useStyles(); const Icon = props.icon ? props.icon : SearchIcon; const search = () => { diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index a53bf2328d..9b8b9ca145 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -25,7 +25,7 @@ import { } from './config'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = (props: { left: number; backgroundColor?: string }) => +const useStyles = (props: { left: number }) => makeStyles(theme => ({ root: { zIndex: 1000, @@ -42,7 +42,7 @@ const useStyles = (props: { left: number; backgroundColor?: string }) => top: 0, bottom: 0, padding: 0, - background: props.backgroundColor || '#404040', + background: theme.palette.navigation.submenu.background, overflowX: 'hidden', msOverflowStyle: 'none', scrollbarWidth: 'none', @@ -75,7 +75,6 @@ const useStyles = (props: { left: number; backgroundColor?: string }) => */ export type SidebarSubmenuProps = { title?: string; - backgroundColor?: string; children: ReactNode; }; @@ -86,14 +85,13 @@ export type SidebarSubmenuProps = { */ export const SidebarSubmenu = ({ title, - backgroundColor, children, }: PropsWithChildren) => { const { isOpen } = useContext(SidebarContext); const left = isOpen ? sidebarConfig.drawerWidthOpen : sidebarConfig.drawerWidthClosed; - const props = { left, backgroundColor }; + const props = { left: left }; const classes = useStyles(props)(); const { isHoveredOn } = useContext(ItemWithSubmenuContext); diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index 2dc6ab7b55..4331278e60 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -41,6 +41,12 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; + navItem: { + hoverBackground: string; + }; + submenu: { + background: string; + }; }; tabbar: { indicator: string; diff --git a/packages/theme/src/themes.ts b/packages/theme/src/themes.ts index 7e99ce8e8a..b048c70fec 100644 --- a/packages/theme/src/themes.ts +++ b/packages/theme/src/themes.ts @@ -76,6 +76,12 @@ export const lightTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', + navItem: { + hoverBackground: '#404040', + }, + submenu: { + background: '#404040', + }, }, pinSidebarButton: { icon: '#181818', @@ -151,6 +157,12 @@ export const darkTheme = createTheme({ indicator: '#9BF0E1', color: '#b5b5b5', selectedColor: '#FFF', + navItem: { + hoverBackground: '#404040', + }, + submenu: { + background: '#404040', + }, }, pinSidebarButton: { icon: '#404040', diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index e1acba3a01..44d9165417 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -53,6 +53,12 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; + navItem: { + hoverBackground: string; + }; + submenu: { + background: string; + }; }; tabbar: { indicator: string; From de81ed2cd05e2d09ab7da4d60438c5ee772fc30e Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 26 Nov 2021 11:36:08 +0000 Subject: [PATCH 34/39] Remove unnecessary code, Rename ItemWithSubmenu, Make style properties optional in pallette Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Items.tsx | 37 ++++++++++--------- .../src/layout/Sidebar/Sidebar.stories.tsx | 2 +- .../src/layout/Sidebar/SidebarSubmenu.tsx | 6 +-- .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 4 +- .../src/layout/Sidebar/config.ts | 9 ++--- packages/theme/src/types.ts | 4 +- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 544d7010fe..501b735176 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -43,7 +43,7 @@ import { import { sidebarConfig, SidebarContext, - ItemWithSubmenuContext, + SidebarItemWithSubmenuContext, } from './config'; import { SidebarSubmenu } from './SidebarSubmenu'; @@ -96,11 +96,13 @@ const useStyles = makeStyles( }, highlightable: { '&:hover': { - background: theme.palette.navigation.navItem.hoverBackground, + background: + theme.palette.navigation.navItem?.hoverBackground ?? '#404040', }, }, highlighted: { - background: theme.palette.navigation.navItem.hoverBackground, + background: + theme.palette.navigation.navItem?.hoverBackground ?? '#404040', }, label: { // XXX (@koroeskohr): I can't seem to achieve the desired font-weight from the designs @@ -168,7 +170,10 @@ const useStyles = makeStyles( { name: 'BackstageSidebarItem' }, ); -function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { +function isSidebarItemWithSubmenuActive( + submenu: ReactNode, + locationPathname: string, +) { // Item is active if any of submenu items have active paths const toPathnames: string[] = []; let isActive = false; @@ -194,16 +199,16 @@ function isItemWithSubmenuActive(submenu: ReactNode, locationPathname: string) { return isActive; } -const ItemWithSubmenu = ({ +const SidebarItemWithSubmenu = ({ text, hasNotifications = false, icon: Icon, children, -}: PropsWithChildren) => { +}: PropsWithChildren) => { const classes = useStyles(); const [isHoveredOn, setIsHoveredOn] = useState(false); const { pathname: locationPathname } = useLocation(); - const isActive = isItemWithSubmenuActive(children, locationPathname); + const isActive = isSidebarItemWithSubmenuActive(children, locationPathname); const handleMouseEnter = () => { setIsHoveredOn(true); @@ -240,7 +245,7 @@ const ItemWithSubmenu = ({ const closedContent = itemIcon; return ( - {isHoveredOn && children}
- + ); }; @@ -290,7 +295,7 @@ type SidebarItemLinkProps = SidebarItemBaseProps & { onClick?: (ev: React.MouseEvent) => void; } & NavLinkProps; -type ItemWithSubmenuProps = SidebarItemBaseProps & { +type SidebarItemWithSubmenuProps = SidebarItemBaseProps & { to?: string; onClick?: (ev: React.MouseEvent) => void; children: ReactNode; @@ -304,7 +309,7 @@ type ItemWithSubmenuProps = SidebarItemBaseProps & { type SidebarItemProps = | SidebarItemLinkProps | SidebarItemButtonProps - | ItemWithSubmenuProps; + | SidebarItemWithSubmenuProps; function isButtonItem( props: SidebarItemProps, @@ -427,11 +432,7 @@ export const SidebarItem = forwardRef((props, ref) => { ).type; // Filter children for SidebarSubmenu components const submenus = useElementFilter(children, elements => - elements - .getElements() - .filter( - child => React.isValidElement(child) && child.type === componentType, - ), + elements.getElements().filter(child => child.type === componentType), ); // Error thrown if more than one SidebarSubmenu in a SidebarItem if (submenus.length > 1) { @@ -445,13 +446,13 @@ export const SidebarItem = forwardRef((props, ref) => { if (hasSubmenu) { return ( - {submenu} - + ); } diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index 7102d40f14..c070c90b2d 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -72,7 +72,7 @@ export const SampleScalableSidebar = () => ( - {}} text="Catalog"> + diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index 9b8b9ca145..51324980fe 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -18,7 +18,7 @@ import Typography from '@material-ui/core/Typography'; import clsx from 'clsx'; import React, { PropsWithChildren, ReactNode, useContext } from 'react'; import { - ItemWithSubmenuContext, + SidebarItemWithSubmenuContext, sidebarConfig, SidebarContext, submenuConfig, @@ -42,7 +42,7 @@ const useStyles = (props: { left: number }) => top: 0, bottom: 0, padding: 0, - background: theme.palette.navigation.submenu.background, + background: theme.palette.navigation.submenu?.background ?? '#404040', overflowX: 'hidden', msOverflowStyle: 'none', scrollbarWidth: 'none', @@ -94,7 +94,7 @@ export const SidebarSubmenu = ({ const props = { left: left }; const classes = useStyles(props)(); - const { isHoveredOn } = useContext(ItemWithSubmenuContext); + const { isHoveredOn } = useContext(SidebarItemWithSubmenuContext); return (
(theme => ({ item: { @@ -118,7 +118,7 @@ export const SidebarSubmenuItem = (props: SidebarSubmenuItemProps) => { const classes = useStyles(); const { pathname: locationPathname } = useLocation(); const { pathname: toPathname } = useResolvedPath(to); - const { setIsHoveredOn } = useContext(ItemWithSubmenuContext); + const { setIsHoveredOn } = useContext(SidebarItemWithSubmenuContext); const closeSubmenu = () => { setIsHoveredOn(false); }; diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index c4f73d0a9d..dbcdb7d788 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -67,14 +67,13 @@ export const SidebarContext = createContext({ setOpen: _open => {}, }); -export type ItemWithSubmenuContextType = { +export type SidebarItemWithSubmenuContextType = { isHoveredOn: boolean; setIsHoveredOn: Dispatch>; }; -export const ItemWithSubmenuContext = createContext( - { +export const SidebarItemWithSubmenuContext = + createContext({ isHoveredOn: false, setIsHoveredOn: () => {}, - }, -); + }); diff --git a/packages/theme/src/types.ts b/packages/theme/src/types.ts index 44d9165417..3d1a64c38f 100644 --- a/packages/theme/src/types.ts +++ b/packages/theme/src/types.ts @@ -53,10 +53,10 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; - navItem: { + navItem?: { hoverBackground: string; }; - submenu: { + submenu?: { background: string; }; }; From 32cac6699185237aed3a40b21423f3518a9efa44 Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Fri, 26 Nov 2021 11:44:52 +0000 Subject: [PATCH 35/39] Rename SidebarSubItemDropDownItem to SidebarSubmenuItemDropDownItem, update api-reports Signed-off-by: hiba-aldalaty --- packages/core-components/api-report.md | 14 +++++++------- .../src/layout/Sidebar/SidebarSubmenuItem.tsx | 4 ++-- .../core-components/src/layout/Sidebar/index.ts | 2 +- packages/theme/api-report.md | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index f11cb6f3cc..700c271306 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1981,12 +1981,6 @@ export const SidebarSpacer: React_2.ComponentType< } >; -// @public -export type SidebarSubItemDropDownItem = { - title: string; - to: string; -}; - // @public export const SidebarSubmenu: ({ title, @@ -1998,12 +1992,18 @@ export const SidebarSubmenuItem: ( props: SidebarSubmenuItemProps, ) => JSX.Element; +// @public +export type SidebarSubmenuItemDropDownItem = { + title: string; + to: string; +}; + // @public export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: SidebarSubItemDropDownItem[]; + dropdownItems?: SidebarSubmenuItemDropDownItem[]; }; // @public diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index bbd4b0510c..136ac37d9e 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -87,7 +87,7 @@ const useStyles = makeStyles(theme => ({ * * @public */ -export type SidebarSubItemDropDownItem = { +export type SidebarSubmenuItemDropDownItem = { title: string; to: string; }; @@ -105,7 +105,7 @@ export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: SidebarSubItemDropDownItem[]; + dropdownItems?: SidebarSubmenuItemDropDownItem[]; }; /** diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index c5a047b2ac..1a51d7f903 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -20,7 +20,7 @@ export { SidebarSubmenu } from './SidebarSubmenu'; export type { SidebarSubmenuProps } from './SidebarSubmenu'; export type { SidebarSubmenuItemProps, - SidebarSubItemDropDownItem, + SidebarSubmenuItemDropDownItem, } from './SidebarSubmenuItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; diff --git a/packages/theme/api-report.md b/packages/theme/api-report.md index 4331278e60..f650636710 100644 --- a/packages/theme/api-report.md +++ b/packages/theme/api-report.md @@ -41,10 +41,10 @@ export type BackstagePaletteAdditions = { indicator: string; color: string; selectedColor: string; - navItem: { + navItem?: { hoverBackground: string; }; - submenu: { + submenu?: { background: string; }; }; From 8836aef4a3a59f0c08039ed6250442c775d1f7ae Mon Sep 17 00:00:00 2001 From: hiba-aldalaty Date: Mon, 29 Nov 2021 09:49:50 +0000 Subject: [PATCH 36/39] Remove icon svgs, replace with v4 mui icons. Signed-off-by: hiba-aldalaty --- .../src/layout/Sidebar/Bar.test.tsx | 12 ++---- .../src/layout/Sidebar/Items.tsx | 2 +- .../src/layout/Sidebar/Sidebar.stories.tsx | 20 +++++---- .../src/layout/Sidebar/icons/APIsIcon.tsx | 33 --------------- .../Sidebar/icons/CatalogSidebarLogo.tsx | 41 ------------------- .../layout/Sidebar/icons/DoubleArrowLeft.tsx | 40 +++++++++--------- .../layout/Sidebar/icons/DoubleArrowRight.tsx | 36 ++++++++-------- .../src/layout/Sidebar/icons/MiscIcon.tsx | 33 --------------- .../src/layout/Sidebar/icons/ServicesIcon.tsx | 33 --------------- 9 files changed, 53 insertions(+), 197 deletions(-) delete mode 100644 packages/core-components/src/layout/Sidebar/icons/APIsIcon.tsx delete mode 100644 packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx delete mode 100644 packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx delete mode 100644 packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx diff --git a/packages/core-components/src/layout/Sidebar/Bar.test.tsx b/packages/core-components/src/layout/Sidebar/Bar.test.tsx index 560f761531..d288aa94c5 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.test.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.test.tsx @@ -20,8 +20,8 @@ import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import BuildRoundedIcon from '@material-ui/icons/BuildRounded'; import CreateComponentIcon from '@material-ui/icons/AddCircleOutline'; -import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; -import { MiscIcon } from './icons/MiscIcon'; +import MenuBookIcon from '@material-ui/icons/MenuBook'; +import AcUnitIcon from '@material-ui/icons/AcUnit'; import { Sidebar, SidebarExpandButton } from './Bar'; import { SidebarItem, SidebarSearchField } from './Items'; import { SidebarSubmenuItem } from './SidebarSubmenuItem'; @@ -35,17 +35,13 @@ async function renderScalableSidebar() { > {}} to="/search" /> - {}} - text="Catalog" - > + {}} text="Catalog"> ((props, ref) => { variant="dot" overlap="circular" invisible={!hasNotifications} - className={clsx({ [classes.closeItemIcon]: !isOpen })} + className={clsx({ [classes.closedItemIcon]: !isOpen })} > diff --git a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx index c070c90b2d..5e68aa8d62 100644 --- a/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx +++ b/packages/core-components/src/layout/Sidebar/Sidebar.stories.tsx @@ -32,10 +32,10 @@ import { SidebarSpace, } from '.'; import { SidebarSubmenuItem } from './SidebarSubmenuItem'; -import { CatalogSidebarLogo } from './icons/CatalogSidebarLogo'; -import { APIsIcon } from './icons/APIsIcon'; -import { ServicesIcon } from './icons/ServicesIcon'; -import { MiscIcon } from './icons/MiscIcon'; +import MenuBookIcon from '@material-ui/icons/MenuBook'; +import CloudQueueIcon from '@material-ui/icons/CloudQueue'; +import SettingsApplications from '@material-ui/icons/SettingsApplications'; +import AcUnitIcon from '@material-ui/icons/AcUnit'; import { SidebarSubmenu } from './SidebarSubmenu'; export default { @@ -72,11 +72,15 @@ export const SampleScalableSidebar = () => ( - + - - + + ( { - return ( - - - - ); -}; diff --git a/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx b/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx deleted file mode 100644 index fe37c9c74f..0000000000 --- a/packages/core-components/src/layout/Sidebar/icons/CatalogSidebarLogo.tsx +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2021 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 SvgIcon from '@material-ui/core/SvgIcon'; -import React from 'react'; - -export const CatalogSidebarLogo = () => { - return ( - - - - - ); -}; diff --git a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx index 3e773221e2..eb487940a8 100644 --- a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx +++ b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowLeft.tsx @@ -16,35 +16,33 @@ import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; +import ArrowBackIosIcon from '@material-ui/icons/ArrowBackIos'; const useStyles = makeStyles({ - svg: { - width: 'auto', - height: 15, + iconContainer: { + display: 'flex', + position: 'relative', + width: '100%', }, - path: { - fill: '#7df3e1', + arrow1: { + right: '6px', + position: 'absolute', }, }); -const DoubleArrowRight = () => { + +const DoubleArrowLeft = () => { const classes = useStyles(); return ( - - - - +
+
+ +
+
+ +
+
); }; -export default DoubleArrowRight; +export default DoubleArrowLeft; diff --git a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx index f0700a8610..e1e9b9476d 100644 --- a/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx +++ b/packages/core-components/src/layout/Sidebar/icons/DoubleArrowRight.tsx @@ -16,34 +16,32 @@ import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; +import ArrowForwardIosIcon from '@material-ui/icons/ArrowForwardIos'; const useStyles = makeStyles({ - svg: { - width: 'auto', - height: 15, + iconContainer: { + display: 'flex', + position: 'relative', + width: '100%', }, - path: { - fill: '#7df3e1', + arrow1: { + right: '6px', + position: 'absolute', }, }); + const DoubleArrowRight = () => { const classes = useStyles(); return ( - - - - +
+
+ +
+
+ +
+
); }; diff --git a/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx b/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx deleted file mode 100644 index 67010baeb5..0000000000 --- a/packages/core-components/src/layout/Sidebar/icons/MiscIcon.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2021 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 React from 'react'; - -export const MiscIcon = () => { - return ( - - - - ); -}; diff --git a/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx b/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx deleted file mode 100644 index 49a619d422..0000000000 --- a/packages/core-components/src/layout/Sidebar/icons/ServicesIcon.tsx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright 2021 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 React from 'react'; - -export const ServicesIcon = () => { - return ( - - - - ); -}; From 04305a3c599aebe4405cad7916aae882b51017dc Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 2 Dec 2021 11:32:29 +0100 Subject: [PATCH 37/39] chore: update the naming Signed-off-by: blam --- packages/core-components/api-report.md | 4 ++-- .../core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx | 4 ++-- packages/core-components/src/layout/Sidebar/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 700c271306..c1e021391e 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1993,7 +1993,7 @@ export const SidebarSubmenuItem: ( ) => JSX.Element; // @public -export type SidebarSubmenuItemDropDownItem = { +export type SidebarSubmenuItemDropdownItem = { title: string; to: string; }; @@ -2003,7 +2003,7 @@ export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: SidebarSubmenuItemDropDownItem[]; + dropdownItems?: SidebarSubmenuItemDropdownItem[]; }; // @public diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx index 136ac37d9e..2bb8a13592 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenuItem.tsx @@ -87,7 +87,7 @@ const useStyles = makeStyles(theme => ({ * * @public */ -export type SidebarSubmenuItemDropDownItem = { +export type SidebarSubmenuItemDropdownItem = { title: string; to: string; }; @@ -105,7 +105,7 @@ export type SidebarSubmenuItemProps = { title: string; to: string; icon: IconComponent; - dropdownItems?: SidebarSubmenuItemDropDownItem[]; + dropdownItems?: SidebarSubmenuItemDropdownItem[]; }; /** diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 1a51d7f903..79a86023ee 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -20,7 +20,7 @@ export { SidebarSubmenu } from './SidebarSubmenu'; export type { SidebarSubmenuProps } from './SidebarSubmenu'; export type { SidebarSubmenuItemProps, - SidebarSubmenuItemDropDownItem, + SidebarSubmenuItemDropdownItem, } from './SidebarSubmenuItem'; export type { SidebarClassKey } from './Bar'; export { SidebarPage, SidebarPinStateContext } from './Page'; From 7877857b2d5e8c79edf435e02cf5e8e0cc61c22e Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 2 Dec 2021 11:33:00 +0100 Subject: [PATCH 38/39] chore: reset the ADOPTERS.md file Signed-off-by: blam --- ADOPTERS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ADOPTERS.md b/ADOPTERS.md index 529c22d144..11bda10020 100644 --- a/ADOPTERS.md +++ b/ADOPTERS.md @@ -72,4 +72,4 @@ | [Globo](https://globo.com) | [Carlos Gusmão](https://github.com/caeugusmao), [Guilherme Vierno](https://github.com/vierno), [Denis Aoki](https://github.com/dnsaoki2), [Maycon Dionisio](https://github.com/MayconDionisio), | Reduce the friction of accessing the information engineers need about Globo's digital services through a coherent and centralized experience. | | [QBE](https://www.qbe.com/) | [Daniel Steel](https://github.com/danielsteelqbe), [Pete Jespers](https://github.com/petejespersqbe) | Developer portal allowing our global teams to explore and create applications, documentation and cloud infrastructure easily and quickly 🚀 | | [LogMeIn](https://www.logmein.com) | [Lorenzo Orsatti](https://github.com/lorsatti) | Improve onboarding experience of new developers. Discover faster and painlessly developer documentation, API definitions and team information. Provide useful dev metrics in a central place. Provide easy-to-use templates for new services. | -| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates
Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc | +| [Telstra](https://www.telstra.com.au) | [@kiranpatel11](https://github.com/kiranpatel11), [JasonC](https://github.com/JasonC17) | Primary usage: software catalog and templates
Emerging usage : TechDocs, Explore Ecosystem, TechRadar, etc | From e34f174fc5a29252d82307219331f899d325cda6 Mon Sep 17 00:00:00 2001 From: blam Date: Thu, 2 Dec 2021 11:38:25 +0100 Subject: [PATCH 39/39] chore: added changeset Signed-off-by: blam --- .changeset/cool-clocks-cheer.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .changeset/cool-clocks-cheer.md diff --git a/.changeset/cool-clocks-cheer.md b/.changeset/cool-clocks-cheer.md new file mode 100644 index 0000000000..4d5e5b76bd --- /dev/null +++ b/.changeset/cool-clocks-cheer.md @@ -0,0 +1,8 @@ +--- +'@backstage/core-components': patch +'@backstage/theme': patch +--- + +Added `` and `` to enable building better sidebars. You can check out the storybook for more inspiration and how to get started. + +Added two new theme props for styling the sidebar too, `navItem.hoverBackground` and `submenu.background`.