From 7741e47eae4f09a250ec981c968ffa32300b19f7 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Tue, 15 Feb 2022 10:33:36 +0000 Subject: [PATCH 1/8] Added ability to override properties of Sidebar config and Sidebar Submenu config Signed-off-by: Jonathan Ash --- .changeset/thin-deers-turn.md | 5 + .../src/layout/Sidebar/Bar.tsx | 158 ++++++------ .../src/layout/Sidebar/Intro.tsx | 97 +++---- .../src/layout/Sidebar/Items.tsx | 239 +++++++++--------- .../src/layout/Sidebar/MobileSidebar.tsx | 82 +++--- .../src/layout/Sidebar/Page.tsx | 58 +++-- .../src/layout/Sidebar/SidebarGroup.tsx | 38 +-- .../src/layout/Sidebar/SidebarSubmenu.tsx | 15 +- .../src/layout/Sidebar/config.ts | 52 ++++ 9 files changed, 419 insertions(+), 325 deletions(-) create mode 100644 .changeset/thin-deers-turn.md diff --git a/.changeset/thin-deers-turn.md b/.changeset/thin-deers-turn.md new file mode 100644 index 0000000000..cec95355d4 --- /dev/null +++ b/.changeset/thin-deers-turn.md @@ -0,0 +1,5 @@ +--- +'@backstage/core-components': patch +--- + + now accepts custom configuration options by supplying props sidebarConfig and submenuConfig diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 74a57ea6ee..246878567d 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -21,7 +21,14 @@ import classnames from 'classnames'; import React, { useState, useContext, useRef } from 'react'; import Button from '@material-ui/core/Button'; -import { sidebarConfig, SidebarContext } from './config'; +import { + makeSidebarConfig, + makeSidebarSubmenuConfig, + SidebarConfig, + SidebarContext, + SidebarConfigContext, + SubmenuConfig, +} from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext, useContent } from './Page'; import { MobileSidebar } from './MobileSidebar'; @@ -29,52 +36,55 @@ import { MobileSidebar } from './MobileSidebar'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; -const useStyles = makeStyles( - theme => ({ - drawer: { - display: 'flex', - flexFlow: 'column nowrap', - alignItems: 'flex-start', - position: 'fixed', - left: 0, - top: 0, - bottom: 0, - zIndex: theme.zIndex.appBar, - background: theme.palette.navigation.background, - overflowX: 'hidden', - msOverflowStyle: 'none', - scrollbarWidth: 'none', - width: sidebarConfig.drawerWidthClosed, - transition: theme.transitions.create('width', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - '& > *': { - flexShrink: 0, - }, - '&::-webkit-scrollbar': { - display: 'none', - }, +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => + makeStyles( + theme => { + return { + drawer: { + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'flex-start', + position: 'fixed', + left: 0, + top: 0, + bottom: 0, + zIndex: theme.zIndex.appBar, + background: theme.palette.navigation.background, + overflowX: 'hidden', + msOverflowStyle: 'none', + scrollbarWidth: 'none', + width: sidebarConfig.drawerWidthClosed, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), + '& > *': { + flexShrink: 0, + }, + '&::-webkit-scrollbar': { + display: 'none', + }, + }, + drawerOpen: { + width: sidebarConfig.drawerWidthOpen, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shorter, + }), + }, + visuallyHidden: { + top: 0, + position: 'absolute', + zIndex: 1000, + transform: 'translateY(-200%)', + '&:focus': { + transform: 'translateY(5px)', + }, + }, + }; }, - drawerOpen: { - width: sidebarConfig.drawerWidthOpen, - transition: theme.transitions.create('width', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shorter, - }), - }, - visuallyHidden: { - top: 0, - position: 'absolute', - zIndex: 1000, - transform: 'translateY(-200%)', - '&:focus': { - transform: 'translateY(5px)', - }, - }, - }), - { name: 'BackstageSidebar' }, -); + { name: 'BackstageSidebar' }, + ); enum State { Closed, @@ -84,8 +94,13 @@ enum State { /** @public */ export type SidebarProps = { - openDelayMs?: number; - closeDelayMs?: number; + sidebarConfig?: Partial; + submenuConfig?: Partial; + disableExpandOnHover?: boolean; + children?: React.ReactNode; +}; + +export type DesktopSidebarProps = { disableExpandOnHover?: boolean; children?: React.ReactNode; }; @@ -100,14 +115,14 @@ export type SidebarProps = { * @returns * @internal */ -const DesktopSidebar = (props: SidebarProps) => { - const { - openDelayMs = sidebarConfig.defaultOpenDelayMs, - closeDelayMs = sidebarConfig.defaultCloseDelayMs, - disableExpandOnHover, - children, - } = props; - const classes = useStyles(); +const DesktopSidebar = (props: DesktopSidebarProps) => { + const { sidebarConfig } = useContext(SidebarConfigContext); + const { defaultOpenDelayMs: openDelayMs, defaultCloseDelayMs: closeDelayMs } = + sidebarConfig; + + const { disableExpandOnHover, children } = props; + + const classes = useStyles({ sidebarConfig })(); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), { noSsr: true }, @@ -172,12 +187,7 @@ const DesktopSidebar = (props: SidebarProps) => { return (
- +
{ * @public */ export const Sidebar = (props: SidebarProps) => { - const { children, openDelayMs, closeDelayMs, disableExpandOnHover } = props; + const sidebarConfig: SidebarConfig = makeSidebarConfig( + props.sidebarConfig ?? {}, + ); + const submenuConfig: SubmenuConfig = makeSidebarSubmenuConfig( + props.submenuConfig ?? {}, + sidebarConfig, + ); + const { children, disableExpandOnHover } = props; const { isMobile } = useContext(SidebarPinStateContext); return isMobile ? ( {children} ) : ( - - {children} - + + + {children} + + ); }; function A11ySkipSidebar() { + const { sidebarConfig } = useContext(SidebarConfigContext); const { focusContent, contentRef } = useContent(); - const classes = useStyles(); + const classes = useStyles({ sidebarConfig })(); if (!contentRef?.current) { return null; diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 1fcc54188f..5abe0112a2 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -23,7 +23,8 @@ import CloseIcon from '@material-ui/icons/Close'; import React, { useContext, useState } from 'react'; import { useLocalStorageValue } from '@react-hookz/web'; import { - sidebarConfig, + SidebarConfigContext, + SidebarConfig, SidebarContext, SIDEBAR_INTRO_LOCAL_STORAGE, } from './config'; @@ -37,51 +38,54 @@ export type SidebarIntroClassKey = | 'introDismissText' | 'introDismissIcon'; -const useStyles = makeStyles( - theme => ({ - introCard: { - color: '#b5b5b5', - // XXX (@koroeskohr): should I be using a Mui theme variable? - fontSize: 12, - width: sidebarConfig.drawerWidthOpen, - marginTop: 18, - marginBottom: 12, - paddingLeft: sidebarConfig.iconPadding, - paddingRight: sidebarConfig.iconPadding, +const useStyles = ({sidebarConfig}: { sidebarConfig: SidebarConfig }) => + makeStyles( + theme => { + return { + introCard: { + color: '#b5b5b5', + // XXX (@koroeskohr): should I be using a Mui theme variable? + fontSize: 12, + width: sidebarConfig.drawerWidthOpen, + marginTop: 18, + marginBottom: 12, + paddingLeft: sidebarConfig.iconPadding, + paddingRight: sidebarConfig.iconPadding, + }, + introDismiss: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + marginTop: 12, + }, + introDismissLink: { + color: '#dddddd', + display: 'flex', + alignItems: 'center', + marginBottom: 4, + '&:hover': { + color: theme.palette.linkHover, + transition: theme.transitions.create('color', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), + }, + }, + introDismissText: { + fontSize: '0.7rem', + fontWeight: 'bold', + textTransform: 'uppercase', + letterSpacing: 1, + }, + introDismissIcon: { + width: 18, + height: 18, + marginRight: 12, + }, + }; }, - introDismiss: { - display: 'flex', - justifyContent: 'flex-end', - alignItems: 'center', - marginTop: 12, - }, - introDismissLink: { - color: '#dddddd', - display: 'flex', - alignItems: 'center', - marginBottom: 4, - '&:hover': { - color: theme.palette.linkHover, - transition: theme.transitions.create('color', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - }, - }, - introDismissText: { - fontSize: '0.7rem', - fontWeight: 'bold', - textTransform: 'uppercase', - letterSpacing: 1, - }, - introDismissIcon: { - width: 18, - height: 18, - marginRight: 12, - }, - }), - { name: 'BackstageSidebarIntro' }, -); + { name: 'BackstageSidebarIntro' }, + ); type IntroCardProps = { text: string; @@ -96,7 +100,8 @@ type IntroCardProps = { */ export function IntroCard(props: IntroCardProps) { - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); const { text, onClose } = props; const handleClose = () => onClose(); diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 7eb86772f9..79ab925d93 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -47,9 +47,10 @@ import { useResolvedPath, } from 'react-router-dom'; import { - sidebarConfig, SidebarContext, + SidebarConfigContext, SidebarItemWithSubmenuContext, + SidebarConfig, } from './config'; import { SidebarSubmenuItemProps, @@ -82,128 +83,124 @@ export type SidebarItemClassKey = | 'arrows' | '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: '100%', - margin: 0, - padding: 0, - textAlign: 'inherit', - font: 'inherit', - }, - closed: { - width: drawerWidthClosed, - justifyContent: 'center', - }, - open: { - [theme.breakpoints.up('sm')]: { - width: drawerWidthOpen, +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => + makeStyles( + theme => { + return { + root: { + color: theme.palette.navigation.color, + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + height: 48, + cursor: 'pointer', }, - }, - highlightable: { - '&:hover': { + buttonItem: { + background: 'none', + border: 'none', + width: '100%', + margin: 0, + padding: 0, + textAlign: 'inherit', + font: 'inherit', + }, + closed: { + width: sidebarConfig.drawerWidthClosed, + justifyContent: 'center', + }, + open: { + [theme.breakpoints.up('sm')]: { + width: sidebarConfig.drawerWidthOpen, + }, + }, + highlightable: { + '&:hover': { + background: + theme.palette.navigation.navItem?.hoverBackground ?? '#404040', + }, + }, + highlighted: { background: theme.palette.navigation.navItem?.hoverBackground ?? '#404040', }, - }, - highlighted: { - background: - theme.palette.navigation.navItem?.hoverBackground ?? '#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, 2), - }, - searchContainer: { - width: drawerWidthOpen - iconContainerWidth, - }, - secondaryAction: { - width: theme.spacing(6), - textAlign: 'center', - marginRight: theme.spacing(1), - }, - closedItemIcon: { - width: '100%', - justifyContent: 'center', - }, - submenuArrow: { - display: 'flex', - }, - expandButton: { - background: 'none', - border: 'none', - color: theme.palette.navigation.color, - width: '100%', - cursor: 'pointer', - position: 'relative', - height: 48, - }, - arrows: { - position: 'absolute', - right: 10, - }, - selected: { - '&$root': { - borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - color: theme.palette.navigation.selectedColor, + 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', }, - '&$closed': { - width: drawerWidthClosed, + iconContainer: { + boxSizing: 'border-box', + height: '100%', + width: sidebarConfig.iconContainerWidth, + marginRight: -theme.spacing(2), + display: 'flex', + alignItems: 'center', + justifyContent: 'center', }, - '& $closedItemIcon': { - paddingRight: selectedIndicatorWidth, + searchRoot: { + marginBottom: 12, }, - '& $iconContainer': { - marginLeft: -selectedIndicatorWidth, + searchField: { + color: '#b5b5b5', + fontWeight: 'bold', + fontSize: theme.typography.fontSize, }, - }, - }; - }, - { name: 'BackstageSidebarItem' }, -); + searchFieldHTMLInput: { + padding: theme.spacing(2, 0, 2), + }, + searchContainer: { + width: + sidebarConfig.drawerWidthOpen - sidebarConfig.iconContainerWidth, + }, + secondaryAction: { + width: theme.spacing(6), + textAlign: 'center', + marginRight: theme.spacing(1), + }, + closedItemIcon: { + width: '100%', + justifyContent: 'center', + }, + submenuArrow: { + display: 'flex', + }, + expandButton: { + background: 'none', + border: 'none', + color: theme.palette.navigation.color, + width: '100%', + cursor: 'pointer', + position: 'relative', + height: 48, + }, + arrows: { + position: 'absolute', + right: 10, + }, + selected: { + '&$root': { + borderLeft: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + color: theme.palette.navigation.selectedColor, + }, + '&$closed': { + width: sidebarConfig.drawerWidthClosed, + }, + '& $closedItemIcon': { + paddingRight: sidebarConfig.selectedIndicatorWidth, + }, + '& $iconContainer': { + marginLeft: -sidebarConfig.selectedIndicatorWidth, + }, + }, + }; + }, + { name: 'BackstageSidebarItem' }, + ); /** * Evaluates the routes of the SubmenuItems & nested DropdownItems. @@ -356,7 +353,8 @@ const SidebarItemBase = forwardRef((props, ref) => { className, ...navLinkProps } = props; - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); // 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 @@ -429,7 +427,8 @@ const SidebarItemWithSubmenu = ({ }: SidebarItemBaseProps & { children: React.ReactElement; }) => { - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); const [isHoveredOn, setIsHoveredOn] = useState(false); const location = useLocation(); const isActive = useLocationMatch(children, location); @@ -518,8 +517,9 @@ type SidebarSearchFieldProps = { }; export function SidebarSearchField(props: SidebarSearchFieldProps) { + const { sidebarConfig } = useContext(SidebarConfigContext); const [input, setInput] = useState(''); - const classes = useStyles(); + const classes = useStyles({ sidebarConfig })(); const Icon = props.icon ? props.icon : SearchIcon; const search = () => { @@ -647,7 +647,8 @@ export const SidebarScrollWrapper = styled('div')(({ theme }) => { * @public */ export const SidebarExpandButton = () => { - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); const { isOpen, setOpen } = useContext(SidebarContext); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 6734d4b53a..8bf5198ea8 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -25,11 +25,10 @@ import Typography from '@material-ui/core/Typography'; import CloseIcon from '@material-ui/icons/Close'; import MenuIcon from '@material-ui/icons/Menu'; import { orderBy } from 'lodash'; -import React, { createContext, useEffect, useState } from 'react'; +import React, { createContext, useEffect, useState, useContext } from 'react'; import { useLocation } from 'react-router'; -import { SidebarContext } from '.'; -import { sidebarConfig } from './config'; import { SidebarGroup } from './SidebarGroup'; +import { SidebarConfigContext, SidebarContext, SidebarConfig } from './config'; /** * Type of `MobileSidebarContext` @@ -60,44 +59,47 @@ type OverlayMenuProps = { children?: React.ReactNode; }; -const useStyles = makeStyles(theme => ({ - root: { - position: 'fixed', - backgroundColor: theme.palette.navigation.background, - color: theme.palette.navigation.color, - bottom: 0, - left: 0, - right: 0, - zIndex: theme.zIndex.snackbar, - // SidebarDivider color - borderTop: '1px solid #383838', - }, +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => + makeStyles(theme => { + return { + root: { + position: 'fixed', + backgroundColor: theme.palette.navigation.background, + color: theme.palette.navigation.color, + bottom: 0, + left: 0, + right: 0, + zIndex: theme.zIndex.snackbar, + // SidebarDivider color + borderTop: '1px solid #383838', + }, - overlay: { - background: theme.palette.navigation.background, - width: '100%', - bottom: `${sidebarConfig.mobileSidebarHeight}px`, - height: `calc(100% - ${sidebarConfig.mobileSidebarHeight}px)`, - flex: '0 1 auto', - overflow: 'auto', - }, + overlay: { + background: theme.palette.navigation.background, + width: '100%', + bottom: `${sidebarConfig.mobileSidebarHeight}px`, + height: `calc(100% - ${sidebarConfig.mobileSidebarHeight}px)`, + flex: '0 1 auto', + overflow: 'auto', + }, - overlayHeader: { - display: 'flex', - color: theme.palette.bursts.fontColor, - alignItems: 'center', - justifyContent: 'space-between', - padding: theme.spacing(2, 3), - }, + overlayHeader: { + display: 'flex', + color: theme.palette.bursts.fontColor, + alignItems: 'center', + justifyContent: 'space-between', + padding: theme.spacing(2, 3), + }, - overlayHeaderClose: { - color: theme.palette.bursts.fontColor, - }, + overlayHeaderClose: { + color: theme.palette.bursts.fontColor, + }, - marginMobileSidebar: { - marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, - }, -})); + marginMobileSidebar: { + marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, + }, + }; + }) const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => orderBy( @@ -114,7 +116,8 @@ const OverlayMenu = ({ open, onClose, }: OverlayMenuProps) => { - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); return ( ({ * @public */ export const MobileSidebar = (props: MobileSidebarProps) => { + const { sidebarConfig } = useContext(SidebarConfigContext); const { children } = props; - const classes = useStyles(); + const classes = useStyles({ sidebarConfig })(); const location = useLocation(); const [selectedMenuItemIndex, setSelectedMenuItemIndex] = useState(-1); diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 3b0efb62c1..86d990e7f8 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -25,39 +25,45 @@ import React, { useRef, useState, } from 'react'; -import { sidebarConfig } from './config'; +import { SidebarConfigContext } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; import useMediaQuery from '@material-ui/core/useMediaQuery'; export type SidebarPageClassKey = 'root'; -const useStyles = makeStyles( - theme => ({ - root: { - width: '100%', - transition: 'padding-left 0.1s ease-out', - isolation: 'isolate', - [theme.breakpoints.up('sm')]: { - paddingLeft: ({ isPinned }) => - isPinned - ? sidebarConfig.drawerWidthOpen - : sidebarConfig.drawerWidthClosed, - }, - [theme.breakpoints.down('xs')]: { - paddingBottom: sidebarConfig.mobileSidebarHeight, - }, +const useStyles = ({ isPinned }: { isPinned: boolean }) => { + const { sidebarConfig } = useContext(SidebarConfigContext); + + return makeStyles( + theme => { + return { + root: { + width: '100%', + transition: 'padding-left 0.1s ease-out', + isolation: 'isolate', + [theme.breakpoints.up('sm')]: { + paddingLeft: () => + isPinned + ? sidebarConfig.drawerWidthOpen + : sidebarConfig.drawerWidthClosed, + }, + [theme.breakpoints.down('xs')]: { + paddingBottom: sidebarConfig.mobileSidebarHeight, + }, + }, + content: { + zIndex: 0, + isolation: 'isolate', + '&:focus': { + outline: 0, + }, + }, + }; }, - content: { - zIndex: 0, - isolation: 'isolate', - '&:focus': { - outline: 0, - }, - }, - }), - { name: 'BackstageSidebarPage' }, -); + { name: 'BackstageSidebarPage' }, + )(); +}; /** * Type of `SidebarPinStateContext` diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index 16395d86f2..cc43963112 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -24,7 +24,7 @@ import React, { useContext } from 'react'; import { useLocation } from 'react-router-dom'; import { SidebarPinStateContext } from '.'; import { Link } from '../../components'; -import { sidebarConfig } from './config'; +import { SidebarConfigContext, SidebarConfig } from './config'; import { MobileSidebarContext } from './MobileSidebar'; /** @@ -48,23 +48,26 @@ export interface SidebarGroupProps extends BottomNavigationActionProps { children?: React.ReactNode; } -const useStyles = makeStyles(theme => ({ - root: { - flexGrow: 0, - margin: theme.spacing(0, 2), - color: theme.palette.navigation.color, - }, +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => + makeStyles(theme => { + return { + root: { + flexGrow: 0, + margin: theme.spacing(0, 2), + color: theme.palette.navigation.color, + }, - selected: { - color: `${theme.palette.navigation.selectedColor}!important`, - borderTop: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - marginTop: '-1px', - }, + selected: { + color: `${theme.palette.navigation.selectedColor}!important`, + borderTop: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + marginTop: '-1px', + }, - label: { - display: 'none', - }, -})); + label: { + display: 'none', + }, + }; + }); /** * Returns a MUI `BottomNavigationAction`, which is aware of the current location & the selected item in the `BottomNavigation`, @@ -75,7 +78,8 @@ const useStyles = makeStyles(theme => ({ */ const MobileSidebarGroup = (props: SidebarGroupProps) => { const { to, label, icon, value } = props; - const classes = useStyles(); + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig })(); const location = useLocation(); const { selectedMenuItemIndex, setSelectedMenuItemIndex } = useContext(MobileSidebarContext); diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index 5a511b2094..ff0086bffb 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -19,13 +19,13 @@ import classnames from 'classnames'; import React, { ReactNode, useContext, useEffect, useState } from 'react'; import { SidebarItemWithSubmenuContext, - sidebarConfig, SidebarContext, - submenuConfig, + SidebarConfigContext, + SubmenuConfig, } from './config'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = (props: { left: number }) => +const useStyles = (props: { left: number, submenuConfig: SubmenuConfig }) => makeStyles( theme => ({ root: { @@ -54,8 +54,8 @@ const useStyles = (props: { left: number }) => msOverflowStyle: 'none', scrollbarWidth: 'none', cursor: 'default', - width: submenuConfig.drawerWidthClosed, - transitionDelay: `${submenuConfig.defaultOpenDelayMs}ms`, + width: props.submenuConfig.drawerWidthClosed, + transitionDelay: `${props.submenuConfig.defaultOpenDelayMs}ms`, '& > *': { flexShrink: 0, }, @@ -64,7 +64,7 @@ const useStyles = (props: { left: number }) => }, }, drawerOpen: { - width: submenuConfig.drawerWidthOpen, + width: props.submenuConfig.drawerWidthOpen, [theme.breakpoints.down('xs')]: { width: '100%', position: 'relative', @@ -104,10 +104,11 @@ export type SidebarSubmenuProps = { */ export const SidebarSubmenu = (props: SidebarSubmenuProps) => { const { isOpen } = useContext(SidebarContext); + const { sidebarConfig, submenuConfig } = useContext(SidebarConfigContext); const left = isOpen ? sidebarConfig.drawerWidthOpen : sidebarConfig.drawerWidthClosed; - const classes = useStyles({ left })(); + const classes = useStyles({ left, submenuConfig })(); const { isHoveredOn } = useContext(SidebarItemWithSubmenuContext); const [isSubmenuOpen, setIsSubmenuOpen] = useState(false); diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index 55b9787b13..2021b4ed69 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -20,6 +20,22 @@ const drawerWidthClosed = 72; const iconPadding = 24; const userBadgePadding = 18; +export type SidebarConfig = { + drawerWidthClosed: number; + drawerWidthOpen: number; + defaultOpenDelayMs: number; + defaultCloseDelayMs: number; + defaultFadeDuration: number; + logoHeight: number; + iconContainerWidth: number; + iconSize: number; + iconPadding: number; + selectedIndicatorWidth: number; + userBadgePadding: number; + userBadgeDiameter: number; + mobileSidebarHeight: number; +}; + export const sidebarConfig = { drawerWidthClosed, drawerWidthOpen: 224, @@ -38,12 +54,38 @@ export const sidebarConfig = { mobileSidebarHeight: 56, }; +export const makeSidebarConfig = ( + customSidebarConfig: Partial, +) => ({ + ...sidebarConfig, + ...customSidebarConfig, + iconContainerWidth: sidebarConfig.drawerWidthClosed, + iconSize: sidebarConfig.drawerWidthClosed - sidebarConfig.iconPadding * 2, + userBadgeDiameter: + sidebarConfig.drawerWidthClosed - sidebarConfig.userBadgePadding * 2, +}); + +export type SubmenuConfig = { + drawerWidthClosed: number; + drawerWidthOpen: number; + defaultOpenDelayMs: number; +}; + export const submenuConfig = { drawerWidthClosed: 0, drawerWidthOpen: 202, defaultOpenDelayMs: sidebarConfig.defaultOpenDelayMs + 200, }; +export const makeSidebarSubmenuConfig = ( + customSubmenuConfig: Partial, + customSidebarConfig: SidebarConfig, +) => ({ + ...submenuConfig, + ...customSubmenuConfig, + defaultOpenDelayMs: customSidebarConfig.defaultOpenDelayMs + 200, +}); + export const SIDEBAR_INTRO_LOCAL_STORAGE = '@backstage/core/sidebar-intro-dismissed'; @@ -63,6 +105,16 @@ export const SidebarContext = createContext({ setOpen: () => {}, }); +export type SidebarConfigContextType = { + sidebarConfig: SidebarConfig; + submenuConfig: SubmenuConfig; +}; + +export const SidebarConfigContext = createContext({ + sidebarConfig, + submenuConfig, +}); + export type SidebarItemWithSubmenuContextType = { isHoveredOn: boolean; setIsHoveredOn: Dispatch>; From c9a07a5664b471966d0dc402f69918cf3457078a Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Thu, 24 Feb 2022 17:45:07 +0000 Subject: [PATCH 2/8] Changed sidebar to accept new props sidebarOptions and submenuOptions Signed-off-by: Jonathan Ash --- .changeset/thin-deers-turn.md | 2 +- .../src/layout/Sidebar/Bar.tsx | 35 ++++++++++++------- .../src/layout/Sidebar/Intro.tsx | 2 +- .../src/layout/Sidebar/Items.tsx | 34 ++++++++++++++++++ .../src/layout/Sidebar/MobileSidebar.tsx | 21 +++++++++++ .../src/layout/Sidebar/Page.tsx | 18 ++++++---- .../src/layout/Sidebar/SidebarGroup.tsx | 8 +++++ .../src/layout/Sidebar/config.ts | 16 ++++++--- 8 files changed, 111 insertions(+), 25 deletions(-) diff --git a/.changeset/thin-deers-turn.md b/.changeset/thin-deers-turn.md index cec95355d4..c23bf15182 100644 --- a/.changeset/thin-deers-turn.md +++ b/.changeset/thin-deers-turn.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- - now accepts custom configuration options by supplying props sidebarConfig and submenuConfig + now accepts additional props sidebarOptions and submenuOptions to allow further customization diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 246878567d..025f0e2c3e 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -28,6 +28,8 @@ import { SidebarContext, SidebarConfigContext, SubmenuConfig, + SidebarOptions, + SubmenuOptions, } from './config'; import { BackstageTheme } from '@backstage/theme'; import { SidebarPinStateContext, useContent } from './Page'; @@ -84,7 +86,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => }; }, { name: 'BackstageSidebar' }, - ); + ) enum State { Closed, @@ -94,13 +96,17 @@ enum State { /** @public */ export type SidebarProps = { - sidebarConfig?: Partial; - submenuConfig?: Partial; + openDelayMs?: number; + closeDelayMs?: number; + sidebarOptions?: SidebarOptions; + submenuOptions?: SubmenuOptions; disableExpandOnHover?: boolean; children?: React.ReactNode; }; export type DesktopSidebarProps = { + openDelayMs?: number; + closeDelayMs?: number; disableExpandOnHover?: boolean; children?: React.ReactNode; }; @@ -117,10 +123,12 @@ export type DesktopSidebarProps = { */ const DesktopSidebar = (props: DesktopSidebarProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); - const { defaultOpenDelayMs: openDelayMs, defaultCloseDelayMs: closeDelayMs } = - sidebarConfig; - - const { disableExpandOnHover, children } = props; + const { + openDelayMs = sidebarConfig.defaultOpenDelayMs, + closeDelayMs = sidebarConfig.defaultCloseDelayMs, + disableExpandOnHover, + children, + } = props; const classes = useStyles({ sidebarConfig })(); const isSmallScreen = useMediaQuery( @@ -216,20 +224,23 @@ const DesktopSidebar = (props: DesktopSidebarProps) => { */ export const Sidebar = (props: SidebarProps) => { const sidebarConfig: SidebarConfig = makeSidebarConfig( - props.sidebarConfig ?? {}, + props.sidebarOptions ?? {}, ); const submenuConfig: SubmenuConfig = makeSidebarSubmenuConfig( - props.submenuConfig ?? {}, - sidebarConfig, + props.submenuOptions ?? {}, ); - const { children, disableExpandOnHover } = props; + const { children, disableExpandOnHover, openDelayMs, closeDelayMs } = props; const { isMobile } = useContext(SidebarPinStateContext); return isMobile ? ( {children} ) : ( - + {children} diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 5abe0112a2..05171bb089 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -38,7 +38,7 @@ export type SidebarIntroClassKey = | 'introDismissText' | 'introDismissIcon'; -const useStyles = ({sidebarConfig}: { sidebarConfig: SidebarConfig }) => +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => makeStyles( theme => { return { diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 79ab925d93..9636959ada 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -83,7 +83,20 @@ export type SidebarItemClassKey = | 'arrows' | 'selected'; +<<<<<<< HEAD const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => +======= +const useStyles = ({ + sidebarConfig: { + drawerWidthClosed, + drawerWidthOpen, + iconContainerWidth, + selectedIndicatorWidth, + }, +}: { + sidebarConfig: SidebarConfig; +}) => +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions makeStyles( theme => { return { @@ -200,7 +213,11 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => }; }, { name: 'BackstageSidebarItem' }, +<<<<<<< HEAD ); +======= + )(); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Evaluates the routes of the SubmenuItems & nested DropdownItems. @@ -354,7 +371,11 @@ const SidebarItemBase = forwardRef((props, ref) => { ...navLinkProps } = props; const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions // 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 @@ -428,7 +449,11 @@ const SidebarItemWithSubmenu = ({ children: React.ReactElement; }) => { const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const [isHoveredOn, setIsHoveredOn] = useState(false); const location = useLocation(); const isActive = useLocationMatch(children, location); @@ -518,8 +543,13 @@ type SidebarSearchFieldProps = { export function SidebarSearchField(props: SidebarSearchFieldProps) { const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const [input, setInput] = useState(''); const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); + const [input, setInput] = useState(''); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const Icon = props.icon ? props.icon : SearchIcon; const search = () => { @@ -648,7 +678,11 @@ export const SidebarScrollWrapper = styled('div')(({ theme }) => { */ export const SidebarExpandButton = () => { const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const { isOpen, setOpen } = useContext(SidebarContext); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 8bf5198ea8..892bb29719 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -28,7 +28,11 @@ import { orderBy } from 'lodash'; import React, { createContext, useEffect, useState, useContext } from 'react'; import { useLocation } from 'react-router'; import { SidebarGroup } from './SidebarGroup'; +<<<<<<< HEAD import { SidebarConfigContext, SidebarContext, SidebarConfig } from './config'; +======= +import { SidebarConfigContext, SidebarConfig } from './config'; +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Type of `MobileSidebarContext` @@ -59,7 +63,11 @@ type OverlayMenuProps = { children?: React.ReactNode; }; +<<<<<<< HEAD const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => +======= +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions makeStyles(theme => { return { root: { @@ -99,7 +107,11 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, }, }; +<<<<<<< HEAD }) +======= + })(); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => orderBy( @@ -117,7 +129,11 @@ const OverlayMenu = ({ onClose, }: OverlayMenuProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions return ( ({ export const MobileSidebar = (props: MobileSidebarProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); const { children } = props; +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const { sidebarConfig } = useContext(SidebarConfigContext); + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const location = useLocation(); const [selectedMenuItemIndex, setSelectedMenuItemIndex] = useState(-1); diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 86d990e7f8..88c6c19c0e 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -25,17 +25,21 @@ import React, { useRef, useState, } from 'react'; -import { SidebarConfigContext } from './config'; +import { SidebarConfigContext, SidebarConfig } from './config'; import { BackstageTheme } from '@backstage/theme'; import { LocalStorage } from './localStorage'; import useMediaQuery from '@material-ui/core/useMediaQuery'; export type SidebarPageClassKey = 'root'; -const useStyles = ({ isPinned }: { isPinned: boolean }) => { - const { sidebarConfig } = useContext(SidebarConfigContext); - - return makeStyles( +const useStyles = ({ + isPinned, + sidebarConfig, +}: { + isPinned: boolean; + sidebarConfig: SidebarConfig; +}) => + makeStyles( theme => { return { root: { @@ -63,7 +67,6 @@ const useStyles = ({ isPinned }: { isPinned: boolean }) => { }, { name: 'BackstageSidebarPage' }, )(); -}; /** * Type of `SidebarPinStateContext` @@ -113,6 +116,7 @@ export function SidebarPage(props: SidebarPageProps) { const [isPinned, setIsPinned] = useState(() => LocalStorage.getSidebarPinState(), ); + const { sidebarConfig } = useContext(SidebarConfigContext); const contentRef = useRef(null); @@ -136,7 +140,7 @@ export function SidebarPage(props: SidebarPageProps) { const toggleSidebarPinState = () => setIsPinned(!isPinned); - const classes = useStyles({ isPinned }); + const classes = useStyles({ isPinned, sidebarConfig }); return ( display: 'none', }, }; +<<<<<<< HEAD }); +======= + })(); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Returns a MUI `BottomNavigationAction`, which is aware of the current location & the selected item in the `BottomNavigation`, @@ -79,7 +83,11 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => const MobileSidebarGroup = (props: SidebarGroupProps) => { const { to, label, icon, value } = props; const { sidebarConfig } = useContext(SidebarConfigContext); +<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); +======= + const classes = useStyles({ sidebarConfig }); +>>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const location = useLocation(); const { selectedMenuItemIndex, setSelectedMenuItemIndex } = useContext(MobileSidebarContext); diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index 2021b4ed69..e39109d6db 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -20,6 +20,16 @@ const drawerWidthClosed = 72; const iconPadding = 24; const userBadgePadding = 18; +export type SidebarOptions = { + drawerWidthClosed?: number; + drawerWidthOpen?: number; +}; + +export type SubmenuOptions = { + drawerWidthClosed?: number; + drawerWidthOpen?: number; +}; + export type SidebarConfig = { drawerWidthClosed: number; drawerWidthOpen: number; @@ -55,7 +65,7 @@ export const sidebarConfig = { }; export const makeSidebarConfig = ( - customSidebarConfig: Partial, + customSidebarConfig: Partial, ) => ({ ...sidebarConfig, ...customSidebarConfig, @@ -78,12 +88,10 @@ export const submenuConfig = { }; export const makeSidebarSubmenuConfig = ( - customSubmenuConfig: Partial, - customSidebarConfig: SidebarConfig, + customSubmenuConfig: Partial, ) => ({ ...submenuConfig, ...customSubmenuConfig, - defaultOpenDelayMs: customSidebarConfig.defaultOpenDelayMs + 200, }); export const SIDEBAR_INTRO_LOCAL_STORAGE = From 6499e057af0c680ed162be564696066ad29edb46 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Mon, 14 Mar 2022 10:37:17 +0000 Subject: [PATCH 3/8] Generated api reports for packages/core-components Signed-off-by: Jonathan Ash --- packages/core-components/api-report.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index a8c51b6913..2eae1d4904 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -1001,6 +1001,8 @@ export type SidebarPinStateContextType = { export type SidebarProps = { openDelayMs?: number; closeDelayMs?: number; + sidebarOptions?: SidebarOptions; + submenuOptions?: SubmenuOptions; disableExpandOnHover?: boolean; children?: React_2.ReactNode; }; @@ -1450,4 +1452,6 @@ export type WarningPanelClassKey = // src/components/TabbedLayout/RoutedTabs.d.ts:9:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts // src/components/Table/Table.d.ts:20:5 - (ae-forgotten-export) The symbol "SelectedFilters" needs to be exported by the entry point index.d.ts // src/layout/ErrorBoundary/ErrorBoundary.d.ts:8:5 - (ae-forgotten-export) The symbol "SlackChannel" needs to be exported by the entry point index.d.ts +// src/layout/Sidebar/Bar.d.ts:9:5 - (ae-forgotten-export) The symbol "SidebarOptions" needs to be exported by the entry point index.d.ts +// src/layout/Sidebar/Bar.d.ts:10:5 - (ae-forgotten-export) The symbol "SubmenuOptions" needs to be exported by the entry point index.d.ts ``` From 68d17c619fd90353db3189f2b88ab70a27ff4d18 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Tue, 15 Mar 2022 10:34:47 +0000 Subject: [PATCH 4/8] fixes for pull from master Signed-off-by: Jonathan Ash --- .../src/layout/Sidebar/Intro.tsx | 84 +++++++++---------- .../src/layout/Sidebar/Items.tsx | 34 -------- .../src/layout/Sidebar/MobileSidebar.tsx | 21 ----- .../src/layout/Sidebar/SidebarGroup.tsx | 8 -- .../src/layout/Sidebar/SidebarSubmenu.tsx | 2 +- 5 files changed, 42 insertions(+), 107 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 05171bb089..9f65be946b 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -40,50 +40,48 @@ export type SidebarIntroClassKey = const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => makeStyles( - theme => { - return { - introCard: { - color: '#b5b5b5', - // XXX (@koroeskohr): should I be using a Mui theme variable? - fontSize: 12, - width: sidebarConfig.drawerWidthOpen, - marginTop: 18, - marginBottom: 12, - paddingLeft: sidebarConfig.iconPadding, - paddingRight: sidebarConfig.iconPadding, + theme => ({ + introCard: { + color: '#b5b5b5', + // XXX (@koroeskohr): should I be using a Mui theme variable? + fontSize: 12, + width: sidebarConfig.drawerWidthOpen, + marginTop: 18, + marginBottom: 12, + paddingLeft: sidebarConfig.iconPadding, + paddingRight: sidebarConfig.iconPadding, + }, + introDismiss: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + marginTop: 12, + }, + introDismissLink: { + color: '#dddddd', + display: 'flex', + alignItems: 'center', + marginBottom: 4, + '&:hover': { + color: theme.palette.linkHover, + transition: theme.transitions.create('color', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), }, - introDismiss: { - display: 'flex', - justifyContent: 'flex-end', - alignItems: 'center', - marginTop: 12, - }, - introDismissLink: { - color: '#dddddd', - display: 'flex', - alignItems: 'center', - marginBottom: 4, - '&:hover': { - color: theme.palette.linkHover, - transition: theme.transitions.create('color', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - }, - }, - introDismissText: { - fontSize: '0.7rem', - fontWeight: 'bold', - textTransform: 'uppercase', - letterSpacing: 1, - }, - introDismissIcon: { - width: 18, - height: 18, - marginRight: 12, - }, - }; - }, + }, + introDismissText: { + fontSize: '0.7rem', + fontWeight: 'bold', + textTransform: 'uppercase', + letterSpacing: 1, + }, + introDismissIcon: { + width: 18, + height: 18, + marginRight: 12, + }, + }), { name: 'BackstageSidebarIntro' }, ); diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 9636959ada..79ab925d93 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -83,20 +83,7 @@ export type SidebarItemClassKey = | 'arrows' | 'selected'; -<<<<<<< HEAD const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => -======= -const useStyles = ({ - sidebarConfig: { - drawerWidthClosed, - drawerWidthOpen, - iconContainerWidth, - selectedIndicatorWidth, - }, -}: { - sidebarConfig: SidebarConfig; -}) => ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions makeStyles( theme => { return { @@ -213,11 +200,7 @@ const useStyles = ({ }; }, { name: 'BackstageSidebarItem' }, -<<<<<<< HEAD ); -======= - )(); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Evaluates the routes of the SubmenuItems & nested DropdownItems. @@ -371,11 +354,7 @@ const SidebarItemBase = forwardRef((props, ref) => { ...navLinkProps } = props; const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions // 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,11 +428,7 @@ const SidebarItemWithSubmenu = ({ children: React.ReactElement; }) => { const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const [isHoveredOn, setIsHoveredOn] = useState(false); const location = useLocation(); const isActive = useLocationMatch(children, location); @@ -543,13 +518,8 @@ type SidebarSearchFieldProps = { export function SidebarSearchField(props: SidebarSearchFieldProps) { const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const [input, setInput] = useState(''); const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); - const [input, setInput] = useState(''); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const Icon = props.icon ? props.icon : SearchIcon; const search = () => { @@ -678,11 +648,7 @@ export const SidebarScrollWrapper = styled('div')(({ theme }) => { */ export const SidebarExpandButton = () => { const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const { isOpen, setOpen } = useContext(SidebarContext); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 892bb29719..8bf5198ea8 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -28,11 +28,7 @@ import { orderBy } from 'lodash'; import React, { createContext, useEffect, useState, useContext } from 'react'; import { useLocation } from 'react-router'; import { SidebarGroup } from './SidebarGroup'; -<<<<<<< HEAD import { SidebarConfigContext, SidebarContext, SidebarConfig } from './config'; -======= -import { SidebarConfigContext, SidebarConfig } from './config'; ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Type of `MobileSidebarContext` @@ -63,11 +59,7 @@ type OverlayMenuProps = { children?: React.ReactNode; }; -<<<<<<< HEAD const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => -======= -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions makeStyles(theme => { return { root: { @@ -107,11 +99,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, }, }; -<<<<<<< HEAD }) -======= - })(); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => orderBy( @@ -129,11 +117,7 @@ const OverlayMenu = ({ onClose, }: OverlayMenuProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions return ( ({ export const MobileSidebar = (props: MobileSidebarProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); const { children } = props; -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const location = useLocation(); const [selectedMenuItemIndex, setSelectedMenuItemIndex] = useState(-1); diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index 92a4bb49ef..cc43963112 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -67,11 +67,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => display: 'none', }, }; -<<<<<<< HEAD }); -======= - })(); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions /** * Returns a MUI `BottomNavigationAction`, which is aware of the current location & the selected item in the `BottomNavigation`, @@ -83,11 +79,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => const MobileSidebarGroup = (props: SidebarGroupProps) => { const { to, label, icon, value } = props; const { sidebarConfig } = useContext(SidebarConfigContext); -<<<<<<< HEAD const classes = useStyles({ sidebarConfig })(); -======= - const classes = useStyles({ sidebarConfig }); ->>>>>>> Changed sidebar to accept new props sidebarOptions and submenuOptions const location = useLocation(); const { selectedMenuItemIndex, setSelectedMenuItemIndex } = useContext(MobileSidebarContext); diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index ff0086bffb..ab83ba3a49 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, submenuConfig: SubmenuConfig }) => +const useStyles = (props: { left: number; submenuConfig: SubmenuConfig }) => makeStyles( theme => ({ root: { From 5a32db06b8ce0e029e48ff90a1eb84a180d9fda9 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Tue, 15 Mar 2022 17:35:19 +0000 Subject: [PATCH 5/8] Prettier fixes Signed-off-by: Jonathan Ash --- packages/core-components/src/layout/Sidebar/Bar.tsx | 2 +- packages/core-components/src/layout/Sidebar/MobileSidebar.tsx | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index 025f0e2c3e..c17ea56aef 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -86,7 +86,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => }; }, { name: 'BackstageSidebar' }, - ) + ); enum State { Closed, diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 8bf5198ea8..2e34eefd54 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -59,7 +59,7 @@ type OverlayMenuProps = { children?: React.ReactNode; }; -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => +const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => makeStyles(theme => { return { root: { @@ -99,7 +99,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, }, }; - }) + }); const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => orderBy( From 35b78976e9269b3cb966aca2ccd5d6373aa9648c Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Thu, 24 Mar 2022 14:46:19 +0000 Subject: [PATCH 6/8] Updated core-components api-report, changed useStyles for components in Sidebar/ Signed-off-by: Jonathan Ash --- packages/core-components/api-report.md | 14 +- .../src/layout/Sidebar/Bar.tsx | 98 ++++---- .../src/layout/Sidebar/Intro.tsx | 91 ++++--- .../src/layout/Sidebar/Items.tsx | 234 +++++++++--------- .../src/layout/Sidebar/MobileSidebar.tsx | 77 +++--- .../src/layout/Sidebar/Page.tsx | 62 +++-- .../src/layout/Sidebar/SidebarGroup.tsx | 37 ++- .../src/layout/Sidebar/SidebarSubmenu.tsx | 116 ++++----- .../src/layout/Sidebar/config.ts | 4 + .../src/layout/Sidebar/index.ts | 6 +- 10 files changed, 372 insertions(+), 367 deletions(-) diff --git a/packages/core-components/api-report.md b/packages/core-components/api-report.md index 2eae1d4904..2058fe2122 100644 --- a/packages/core-components/api-report.md +++ b/packages/core-components/api-report.md @@ -972,6 +972,12 @@ export type SidebarItemClassKey = | 'arrows' | 'selected'; +// @public (undocumented) +export type SidebarOptions = { + drawerWidthClosed?: number; + drawerWidthOpen?: number; +}; + // Warning: (ae-missing-release-tag) "SidebarPage" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) @@ -1183,6 +1189,12 @@ export type StructuredMetadataTableListClassKey = 'root'; // @public (undocumented) export type StructuredMetadataTableNestedListClassKey = 'root'; +// @public (undocumented) +export type SubmenuOptions = { + drawerWidthClosed?: number; + drawerWidthOpen?: number; +}; + // 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) // @@ -1452,6 +1464,4 @@ export type WarningPanelClassKey = // src/components/TabbedLayout/RoutedTabs.d.ts:9:5 - (ae-forgotten-export) The symbol "SubRoute" needs to be exported by the entry point index.d.ts // src/components/Table/Table.d.ts:20:5 - (ae-forgotten-export) The symbol "SelectedFilters" needs to be exported by the entry point index.d.ts // src/layout/ErrorBoundary/ErrorBoundary.d.ts:8:5 - (ae-forgotten-export) The symbol "SlackChannel" needs to be exported by the entry point index.d.ts -// src/layout/Sidebar/Bar.d.ts:9:5 - (ae-forgotten-export) The symbol "SidebarOptions" needs to be exported by the entry point index.d.ts -// src/layout/Sidebar/Bar.d.ts:10:5 - (ae-forgotten-export) The symbol "SubmenuOptions" needs to be exported by the entry point index.d.ts ``` diff --git a/packages/core-components/src/layout/Sidebar/Bar.tsx b/packages/core-components/src/layout/Sidebar/Bar.tsx index c17ea56aef..7a0b3f5b76 100644 --- a/packages/core-components/src/layout/Sidebar/Bar.tsx +++ b/packages/core-components/src/layout/Sidebar/Bar.tsx @@ -37,56 +37,52 @@ import { MobileSidebar } from './MobileSidebar'; /** @public */ export type SidebarClassKey = 'drawer' | 'drawerOpen'; - -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => - makeStyles( - theme => { - return { - drawer: { - display: 'flex', - flexFlow: 'column nowrap', - alignItems: 'flex-start', - position: 'fixed', - left: 0, - top: 0, - bottom: 0, - zIndex: theme.zIndex.appBar, - background: theme.palette.navigation.background, - overflowX: 'hidden', - msOverflowStyle: 'none', - scrollbarWidth: 'none', - width: sidebarConfig.drawerWidthClosed, - transition: theme.transitions.create('width', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - '& > *': { - flexShrink: 0, - }, - '&::-webkit-scrollbar': { - display: 'none', - }, - }, - drawerOpen: { - width: sidebarConfig.drawerWidthOpen, - transition: theme.transitions.create('width', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shorter, - }), - }, - visuallyHidden: { - top: 0, - position: 'absolute', - zIndex: 1000, - transform: 'translateY(-200%)', - '&:focus': { - transform: 'translateY(5px)', - }, - }, - }; +const useStyles = makeStyles( + theme => ({ + drawer: props => ({ + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'flex-start', + position: 'fixed', + left: 0, + top: 0, + bottom: 0, + zIndex: theme.zIndex.appBar, + background: theme.palette.navigation.background, + overflowX: 'hidden', + msOverflowStyle: 'none', + scrollbarWidth: 'none', + width: props.sidebarConfig.drawerWidthClosed, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), + '& > *': { + flexShrink: 0, + }, + '&::-webkit-scrollbar': { + display: 'none', + }, + }), + drawerOpen: props => ({ + width: props.sidebarConfig.drawerWidthOpen, + transition: theme.transitions.create('width', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shorter, + }), + }), + visuallyHidden: { + top: 0, + position: 'absolute', + zIndex: 1000, + transform: 'translateY(-200%)', + '&:focus': { + transform: 'translateY(5px)', + }, }, - { name: 'BackstageSidebar' }, - ); + }), + { name: 'BackstageSidebar' }, +); enum State { Closed, @@ -130,7 +126,7 @@ const DesktopSidebar = (props: DesktopSidebarProps) => { children, } = props; - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), { noSsr: true }, @@ -250,7 +246,7 @@ export const Sidebar = (props: SidebarProps) => { function A11ySkipSidebar() { const { sidebarConfig } = useContext(SidebarConfigContext); const { focusContent, contentRef } = useContent(); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); if (!contentRef?.current) { return null; diff --git a/packages/core-components/src/layout/Sidebar/Intro.tsx b/packages/core-components/src/layout/Sidebar/Intro.tsx index 9f65be946b..d1d8f4b2a2 100644 --- a/packages/core-components/src/layout/Sidebar/Intro.tsx +++ b/packages/core-components/src/layout/Sidebar/Intro.tsx @@ -38,52 +38,51 @@ export type SidebarIntroClassKey = | 'introDismissText' | 'introDismissIcon'; -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => - makeStyles( - theme => ({ - introCard: { - color: '#b5b5b5', - // XXX (@koroeskohr): should I be using a Mui theme variable? - fontSize: 12, - width: sidebarConfig.drawerWidthOpen, - marginTop: 18, - marginBottom: 12, - paddingLeft: sidebarConfig.iconPadding, - paddingRight: sidebarConfig.iconPadding, - }, - introDismiss: { - display: 'flex', - justifyContent: 'flex-end', - alignItems: 'center', - marginTop: 12, - }, - introDismissLink: { - color: '#dddddd', - display: 'flex', - alignItems: 'center', - marginBottom: 4, - '&:hover': { - color: theme.palette.linkHover, - transition: theme.transitions.create('color', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - }, - }, - introDismissText: { - fontSize: '0.7rem', - fontWeight: 'bold', - textTransform: 'uppercase', - letterSpacing: 1, - }, - introDismissIcon: { - width: 18, - height: 18, - marginRight: 12, - }, +const useStyles = makeStyles( + theme => ({ + introCard: props => ({ + color: '#b5b5b5', + // XXX (@koroeskohr): should I be using a Mui theme variable? + fontSize: 12, + width: props.sidebarConfig.drawerWidthOpen, + marginTop: 18, + marginBottom: 12, + paddingLeft: props.sidebarConfig.iconPadding, + paddingRight: props.sidebarConfig.iconPadding, }), - { name: 'BackstageSidebarIntro' }, - ); + introDismiss: { + display: 'flex', + justifyContent: 'flex-end', + alignItems: 'center', + marginTop: 12, + }, + introDismissLink: { + color: '#dddddd', + display: 'flex', + alignItems: 'center', + marginBottom: 4, + '&:hover': { + color: theme.palette.linkHover, + transition: theme.transitions.create('color', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), + }, + }, + introDismissText: { + fontSize: '0.7rem', + fontWeight: 'bold', + textTransform: 'uppercase', + letterSpacing: 1, + }, + introDismissIcon: { + width: 18, + height: 18, + marginRight: 12, + }, + }), + { name: 'BackstageSidebarIntro' }, +); type IntroCardProps = { text: string; @@ -99,7 +98,7 @@ type IntroCardProps = { export function IntroCard(props: IntroCardProps) { const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const { text, onClose } = props; const handleClose = () => onClose(); diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 79ab925d93..142da6af7c 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -83,124 +83,122 @@ export type SidebarItemClassKey = | 'arrows' | 'selected'; -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => - makeStyles( - theme => { - return { - root: { - color: theme.palette.navigation.color, - display: 'flex', - flexFlow: 'row nowrap', - alignItems: 'center', - height: 48, - cursor: 'pointer', - }, - buttonItem: { - background: 'none', - border: 'none', - width: '100%', - margin: 0, - padding: 0, - textAlign: 'inherit', - font: 'inherit', - }, - closed: { - width: sidebarConfig.drawerWidthClosed, - justifyContent: 'center', - }, - open: { - [theme.breakpoints.up('sm')]: { - width: sidebarConfig.drawerWidthOpen, - }, - }, - highlightable: { - '&:hover': { - background: - theme.palette.navigation.navItem?.hoverBackground ?? '#404040', - }, - }, - highlighted: { - background: - theme.palette.navigation.navItem?.hoverBackground ?? '#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: sidebarConfig.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, 2), - }, - searchContainer: { - width: - sidebarConfig.drawerWidthOpen - sidebarConfig.iconContainerWidth, - }, - secondaryAction: { - width: theme.spacing(6), - textAlign: 'center', - marginRight: theme.spacing(1), - }, - closedItemIcon: { - width: '100%', - justifyContent: 'center', - }, - submenuArrow: { - display: 'flex', - }, - expandButton: { - background: 'none', - border: 'none', - color: theme.palette.navigation.color, - width: '100%', - cursor: 'pointer', - position: 'relative', - height: 48, - }, - arrows: { - position: 'absolute', - right: 10, - }, - selected: { - '&$root': { - borderLeft: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - color: theme.palette.navigation.selectedColor, - }, - '&$closed': { - width: sidebarConfig.drawerWidthClosed, - }, - '& $closedItemIcon': { - paddingRight: sidebarConfig.selectedIndicatorWidth, - }, - '& $iconContainer': { - marginLeft: -sidebarConfig.selectedIndicatorWidth, - }, - }, - }; +const useStyles = makeStyles( + theme => ({ + root: { + color: theme.palette.navigation.color, + display: 'flex', + flexFlow: 'row nowrap', + alignItems: 'center', + height: 48, + cursor: 'pointer', }, - { name: 'BackstageSidebarItem' }, - ); + buttonItem: { + background: 'none', + border: 'none', + width: '100%', + margin: 0, + padding: 0, + textAlign: 'inherit', + font: 'inherit', + }, + closed: props => ({ + width: props.sidebarConfig.drawerWidthClosed, + justifyContent: 'center', + }), + open: props => ({ + [theme.breakpoints.up('sm')]: { + width: props.sidebarConfig.drawerWidthOpen, + }, + }), + highlightable: { + '&:hover': { + background: + theme.palette.navigation.navItem?.hoverBackground ?? '#404040', + }, + }, + highlighted: { + background: + theme.palette.navigation.navItem?.hoverBackground ?? '#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: props => ({ + boxSizing: 'border-box', + height: '100%', + width: props.sidebarConfig.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, 2), + }, + searchContainer: props => ({ + width: + props.sidebarConfig.drawerWidthOpen - + props.sidebarConfig.iconContainerWidth, + }), + secondaryAction: { + width: theme.spacing(6), + textAlign: 'center', + marginRight: theme.spacing(1), + }, + closedItemIcon: { + width: '100%', + justifyContent: 'center', + }, + submenuArrow: { + display: 'flex', + }, + expandButton: { + background: 'none', + border: 'none', + color: theme.palette.navigation.color, + width: '100%', + cursor: 'pointer', + position: 'relative', + height: 48, + }, + arrows: { + position: 'absolute', + right: 10, + }, + selected: props => ({ + '&$root': { + borderLeft: `solid ${props.sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + color: theme.palette.navigation.selectedColor, + }, + '&$closed': { + width: props.sidebarConfig.drawerWidthClosed, + }, + '& $closedItemIcon': { + paddingRight: props.sidebarConfig.selectedIndicatorWidth, + }, + '& $iconContainer': { + marginLeft: -props.sidebarConfig.selectedIndicatorWidth, + }, + }), + }), + { name: 'BackstageSidebarItem' }, +); /** * Evaluates the routes of the SubmenuItems & nested DropdownItems. @@ -648,7 +646,7 @@ export const SidebarScrollWrapper = styled('div')(({ theme }) => { */ export const SidebarExpandButton = () => { const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const { isOpen, setOpen } = useContext(SidebarContext); const isSmallScreen = useMediaQuery( theme => theme.breakpoints.down('md'), diff --git a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx index 2e34eefd54..aefc58bc45 100644 --- a/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx +++ b/packages/core-components/src/layout/Sidebar/MobileSidebar.tsx @@ -59,47 +59,46 @@ type OverlayMenuProps = { children?: React.ReactNode; }; -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => - makeStyles(theme => { - return { - root: { - position: 'fixed', - backgroundColor: theme.palette.navigation.background, - color: theme.palette.navigation.color, - bottom: 0, - left: 0, - right: 0, - zIndex: theme.zIndex.snackbar, - // SidebarDivider color - borderTop: '1px solid #383838', - }, +const useStyles = makeStyles( + theme => ({ + root: { + position: 'fixed', + backgroundColor: theme.palette.navigation.background, + color: theme.palette.navigation.color, + bottom: 0, + left: 0, + right: 0, + zIndex: theme.zIndex.snackbar, + // SidebarDivider color + borderTop: '1px solid #383838', + }, - overlay: { - background: theme.palette.navigation.background, - width: '100%', - bottom: `${sidebarConfig.mobileSidebarHeight}px`, - height: `calc(100% - ${sidebarConfig.mobileSidebarHeight}px)`, - flex: '0 1 auto', - overflow: 'auto', - }, + overlay: props => ({ + background: theme.palette.navigation.background, + width: '100%', + bottom: `${props.sidebarConfig.mobileSidebarHeight}px`, + height: `calc(100% - ${props.sidebarConfig.mobileSidebarHeight}px)`, + flex: '0 1 auto', + overflow: 'auto', + }), - overlayHeader: { - display: 'flex', - color: theme.palette.bursts.fontColor, - alignItems: 'center', - justifyContent: 'space-between', - padding: theme.spacing(2, 3), - }, + overlayHeader: { + display: 'flex', + color: theme.palette.bursts.fontColor, + alignItems: 'center', + justifyContent: 'space-between', + padding: theme.spacing(2, 3), + }, - overlayHeaderClose: { - color: theme.palette.bursts.fontColor, - }, + overlayHeaderClose: { + color: theme.palette.bursts.fontColor, + }, - marginMobileSidebar: { - marginBottom: `${sidebarConfig.mobileSidebarHeight}px`, - }, - }; - }); + marginMobileSidebar: props => ({ + marginBottom: `${props.sidebarConfig.mobileSidebarHeight}px`, + }), + }), +); const sortSidebarGroupsForPriority = (children: React.ReactElement[]) => orderBy( @@ -117,7 +116,7 @@ const OverlayMenu = ({ onClose, }: OverlayMenuProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); return ( ({ export const MobileSidebar = (props: MobileSidebarProps) => { const { sidebarConfig } = useContext(SidebarConfigContext); const { children } = props; - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const location = useLocation(); const [selectedMenuItemIndex, setSelectedMenuItemIndex] = useState(-1); diff --git a/packages/core-components/src/layout/Sidebar/Page.tsx b/packages/core-components/src/layout/Sidebar/Page.tsx index 88c6c19c0e..4e2dcd8770 100644 --- a/packages/core-components/src/layout/Sidebar/Page.tsx +++ b/packages/core-components/src/layout/Sidebar/Page.tsx @@ -32,41 +32,35 @@ import useMediaQuery from '@material-ui/core/useMediaQuery'; export type SidebarPageClassKey = 'root'; -const useStyles = ({ - isPinned, - sidebarConfig, -}: { - isPinned: boolean; - sidebarConfig: SidebarConfig; -}) => - makeStyles( - theme => { - return { - root: { - width: '100%', - transition: 'padding-left 0.1s ease-out', - isolation: 'isolate', - [theme.breakpoints.up('sm')]: { - paddingLeft: () => - isPinned - ? sidebarConfig.drawerWidthOpen - : sidebarConfig.drawerWidthClosed, - }, - [theme.breakpoints.down('xs')]: { - paddingBottom: sidebarConfig.mobileSidebarHeight, - }, - }, - content: { - zIndex: 0, - isolation: 'isolate', - '&:focus': { - outline: 0, - }, - }, - }; +const useStyles = makeStyles< + BackstageTheme, + { sidebarConfig: SidebarConfig; isPinned: boolean } +>( + theme => ({ + root: props => ({ + width: '100%', + transition: 'padding-left 0.1s ease-out', + isolation: 'isolate', + [theme.breakpoints.up('sm')]: { + paddingLeft: () => + props.isPinned + ? props.sidebarConfig.drawerWidthOpen + : props.sidebarConfig.drawerWidthClosed, + }, + [theme.breakpoints.down('xs')]: { + paddingBottom: props.sidebarConfig.mobileSidebarHeight, + }, + }), + content: { + zIndex: 0, + isolation: 'isolate', + '&:focus': { + outline: 0, + }, }, - { name: 'BackstageSidebarPage' }, - )(); + }), + { name: 'BackstageSidebarPage' }, +); /** * Type of `SidebarPinStateContext` diff --git a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx index cc43963112..55b5e770b0 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarGroup.tsx @@ -48,26 +48,25 @@ export interface SidebarGroupProps extends BottomNavigationActionProps { children?: React.ReactNode; } -const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => - makeStyles(theme => { - return { - root: { - flexGrow: 0, - margin: theme.spacing(0, 2), - color: theme.palette.navigation.color, - }, +const useStyles = makeStyles( + theme => ({ + root: { + flexGrow: 0, + margin: theme.spacing(0, 2), + color: theme.palette.navigation.color, + }, - selected: { - color: `${theme.palette.navigation.selectedColor}!important`, - borderTop: `solid ${sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, - marginTop: '-1px', - }, + selected: props => ({ + color: `${theme.palette.navigation.selectedColor}!important`, + borderTop: `solid ${props.sidebarConfig.selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`, + marginTop: '-1px', + }), - label: { - display: 'none', - }, - }; - }); + label: { + display: 'none', + }, + }), +); /** * Returns a MUI `BottomNavigationAction`, which is aware of the current location & the selected item in the `BottomNavigation`, @@ -79,7 +78,7 @@ const useStyles = ({ sidebarConfig }: { sidebarConfig: SidebarConfig }) => const MobileSidebarGroup = (props: SidebarGroupProps) => { const { to, label, icon, value } = props; const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const location = useLocation(); const { selectedMenuItemIndex, setSelectedMenuItemIndex } = useContext(MobileSidebarContext); diff --git a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx index ab83ba3a49..d1b79263eb 100644 --- a/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx +++ b/packages/core-components/src/layout/Sidebar/SidebarSubmenu.tsx @@ -25,66 +25,68 @@ import { } from './config'; import { BackstageTheme } from '@backstage/theme'; -const useStyles = (props: { left: number; submenuConfig: SubmenuConfig }) => - makeStyles( - theme => ({ - root: { - zIndex: 1000, - position: 'relative', - overflow: 'visible', - width: theme.spacing(7) + 1, +const useStyles = makeStyles< + BackstageTheme, + { submenuConfig: SubmenuConfig; left: number } +>( + theme => ({ + root: { + zIndex: 1000, + position: 'relative', + overflow: 'visible', + width: theme.spacing(7) + 1, + }, + drawer: props => ({ + display: 'flex', + flexFlow: 'column nowrap', + alignItems: 'flex-start', + position: 'fixed', + [theme.breakpoints.up('sm')]: { + marginLeft: props.left, + transition: theme.transitions.create('margin-left', { + easing: theme.transitions.easing.sharp, + duration: theme.transitions.duration.shortest, + }), }, - drawer: { - display: 'flex', - flexFlow: 'column nowrap', - alignItems: 'flex-start', - position: 'fixed', - [theme.breakpoints.up('sm')]: { - marginLeft: props.left, - transition: theme.transitions.create('margin-left', { - easing: theme.transitions.easing.sharp, - duration: theme.transitions.duration.shortest, - }), - }, - top: 0, - bottom: 0, - padding: 0, - background: theme.palette.navigation.submenu?.background ?? '#404040', - overflowX: 'hidden', - msOverflowStyle: 'none', - scrollbarWidth: 'none', - cursor: 'default', - width: props.submenuConfig.drawerWidthClosed, - transitionDelay: `${props.submenuConfig.defaultOpenDelayMs}ms`, - '& > *': { - flexShrink: 0, - }, - '&::-webkit-scrollbar': { - display: 'none', - }, + top: 0, + bottom: 0, + padding: 0, + background: theme.palette.navigation.submenu?.background ?? '#404040', + overflowX: 'hidden', + msOverflowStyle: 'none', + scrollbarWidth: 'none', + cursor: 'default', + width: props.submenuConfig.drawerWidthClosed, + transitionDelay: `${props.submenuConfig.defaultOpenDelayMs}ms`, + '& > *': { + flexShrink: 0, }, - drawerOpen: { - width: props.submenuConfig.drawerWidthOpen, - [theme.breakpoints.down('xs')]: { - width: '100%', - position: 'relative', - paddingLeft: theme.spacing(3), - left: 0, - top: 0, - }, - }, - title: { - fontSize: 24, - fontWeight: 500, - color: '#FFF', - padding: 20, - [theme.breakpoints.down('xs')]: { - display: 'none', - }, + '&::-webkit-scrollbar': { + display: 'none', }, }), - { name: 'BackstageSidebarSubmenu' }, - ); + drawerOpen: props => ({ + width: props.submenuConfig.drawerWidthOpen, + [theme.breakpoints.down('xs')]: { + width: '100%', + position: 'relative', + paddingLeft: theme.spacing(3), + left: 0, + top: 0, + }, + }), + title: { + fontSize: 24, + fontWeight: 500, + color: '#FFF', + padding: 20, + [theme.breakpoints.down('xs')]: { + display: 'none', + }, + }, + }), + { name: 'BackstageSidebarSubmenu' }, +); /** * Holds a title for text Header of a sidebar submenu and children @@ -108,7 +110,7 @@ export const SidebarSubmenu = (props: SidebarSubmenuProps) => { const left = isOpen ? sidebarConfig.drawerWidthOpen : sidebarConfig.drawerWidthClosed; - const classes = useStyles({ left, submenuConfig })(); + const classes = useStyles({ left, submenuConfig }); const { isHoveredOn } = useContext(SidebarItemWithSubmenuContext); const [isSubmenuOpen, setIsSubmenuOpen] = useState(false); diff --git a/packages/core-components/src/layout/Sidebar/config.ts b/packages/core-components/src/layout/Sidebar/config.ts index e39109d6db..a74e7dd6cc 100644 --- a/packages/core-components/src/layout/Sidebar/config.ts +++ b/packages/core-components/src/layout/Sidebar/config.ts @@ -20,16 +20,19 @@ const drawerWidthClosed = 72; const iconPadding = 24; const userBadgePadding = 18; +/** @public **/ export type SidebarOptions = { drawerWidthClosed?: number; drawerWidthOpen?: number; }; +/** @public **/ export type SubmenuOptions = { drawerWidthClosed?: number; drawerWidthOpen?: number; }; +/** @internal **/ export type SidebarConfig = { drawerWidthClosed: number; drawerWidthOpen: number; @@ -75,6 +78,7 @@ export const makeSidebarConfig = ( sidebarConfig.drawerWidthClosed - sidebarConfig.userBadgePadding * 2, }); +/** @internal **/ export type SubmenuConfig = { drawerWidthClosed: number; drawerWidthOpen: number; diff --git a/packages/core-components/src/layout/Sidebar/index.ts b/packages/core-components/src/layout/Sidebar/index.ts index 96fedaa75a..ecc573fbda 100644 --- a/packages/core-components/src/layout/Sidebar/index.ts +++ b/packages/core-components/src/layout/Sidebar/index.ts @@ -59,4 +59,8 @@ export { SidebarContext, sidebarConfig, } from './config'; -export type { SidebarContextType } from './config'; +export type { + SidebarContextType, + SidebarOptions, + SubmenuOptions, +} from './config'; From 38466a3f3dde016f9c3c6292036d28832e51eb07 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Mon, 28 Mar 2022 11:20:23 +0000 Subject: [PATCH 7/8] Small fix to Sidebar/Items.tsx Signed-off-by: Jonathan Ash --- packages/core-components/src/layout/Sidebar/Items.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/core-components/src/layout/Sidebar/Items.tsx b/packages/core-components/src/layout/Sidebar/Items.tsx index 142da6af7c..b3beed9147 100644 --- a/packages/core-components/src/layout/Sidebar/Items.tsx +++ b/packages/core-components/src/layout/Sidebar/Items.tsx @@ -352,7 +352,7 @@ const SidebarItemBase = forwardRef((props, ref) => { ...navLinkProps } = props; const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); // 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 @@ -426,7 +426,7 @@ const SidebarItemWithSubmenu = ({ children: React.ReactElement; }) => { const { sidebarConfig } = useContext(SidebarConfigContext); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const [isHoveredOn, setIsHoveredOn] = useState(false); const location = useLocation(); const isActive = useLocationMatch(children, location); @@ -517,7 +517,7 @@ type SidebarSearchFieldProps = { export function SidebarSearchField(props: SidebarSearchFieldProps) { const { sidebarConfig } = useContext(SidebarConfigContext); const [input, setInput] = useState(''); - const classes = useStyles({ sidebarConfig })(); + const classes = useStyles({ sidebarConfig }); const Icon = props.icon ? props.icon : SearchIcon; const search = () => { From a7456236e0c0060f21445c58d7c1124308358a55 Mon Sep 17 00:00:00 2001 From: Jonathan Ash Date: Mon, 28 Mar 2022 11:37:23 +0000 Subject: [PATCH 8/8] Updated changeset Signed-off-by: Jonathan Ash --- .changeset/thin-deers-turn.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/thin-deers-turn.md b/.changeset/thin-deers-turn.md index c23bf15182..d148c3fcdf 100644 --- a/.changeset/thin-deers-turn.md +++ b/.changeset/thin-deers-turn.md @@ -2,4 +2,4 @@ '@backstage/core-components': patch --- - now accepts additional props sidebarOptions and submenuOptions to allow further customization +`` now accepts additional props `sidebarOptions` and `submenuOptions` to allow further customization