Expose layout components to material-ui overrides system by providing a name

Signed-off-by: Daniel Ortiz Lira <dortiz@vmware.com>
This commit is contained in:
Daniel Ortiz Lira
2021-09-21 11:45:56 -05:00
parent 8835041c50
commit 3e3869a3c3
34 changed files with 675 additions and 489 deletions
@@ -21,19 +21,24 @@ import { BackstageTheme } from '@backstage/theme';
import Box from '@material-ui/core/Box';
import { Link } from '../../components/Link';
const useStyles = makeStyles<BackstageTheme>(theme => ({
root: {
maxWidth: 'fit-content',
padding: theme.spacing(2, 2, 2, 2.5),
},
boxTitle: {
margin: 0,
color: theme.palette.textSubtle,
},
arrow: {
color: theme.palette.textSubtle,
},
}));
export type BottomLinkClassKey = 'root' | 'boxTitle' | 'arrow';
const useStyles = makeStyles<BackstageTheme>(
theme => ({
root: {
maxWidth: 'fit-content',
padding: theme.spacing(2, 2, 2, 2.5),
},
boxTitle: {
margin: 0,
color: theme.palette.textSubtle,
},
arrow: {
color: theme.palette.textSubtle,
},
}),
{ name: 'BackstageBottomLink' },
);
export type BottomLinkProps = {
link: string;
@@ -15,4 +15,4 @@
*/
export { BottomLink } from './BottomLink';
export type { BottomLinkProps } from './BottomLink';
export type { BottomLinkClassKey, BottomLinkProps } from './BottomLink';
@@ -27,19 +27,29 @@ import React, { ComponentProps, Fragment } from 'react';
type Props = ComponentProps<typeof MaterialBreadcrumbs>;
const ClickableText = withStyles({
root: {
textDecoration: 'underline',
cursor: 'pointer',
},
})(Typography);
export type BreadcrumbsClickableTextClassKey = 'root';
const StyledBox = withStyles({
root: {
textDecoration: 'underline',
color: 'inherit',
const ClickableText = withStyles(
{
root: {
textDecoration: 'underline',
cursor: 'pointer',
},
},
})(Box);
{ name: 'BackstageBreadcrumbsClickableText' },
)(Typography);
export type BreadcrumbsStyledBoxClassKey = 'root';
const StyledBox = withStyles(
{
root: {
textDecoration: 'underline',
color: 'inherit',
},
},
{ name: 'BackstageBreadcrumbsStyledBox' },
)(Box);
export function Breadcrumbs(props: Props) {
const { children, ...restProps } = props;
@@ -15,3 +15,7 @@
*/
export { Breadcrumbs } from './Breadcrumbs';
export type {
BreadcrumbsClickableTextClassKey,
BreadcrumbsStyledBoxClassKey,
} from './Breadcrumbs';
@@ -18,28 +18,33 @@ import React, { PropsWithChildren } from 'react';
import classNames from 'classnames';
import { Theme, makeStyles } from '@material-ui/core';
const useStyles = makeStyles((theme: Theme) => ({
root: {
gridArea: 'pageContent',
minWidth: 0,
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(3),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(3),
export type BackstageContentClassKey = 'root' | 'stretch' | 'noPadding';
const useStyles = makeStyles(
(theme: Theme) => ({
root: {
gridArea: 'pageContent',
minWidth: 0,
paddingTop: theme.spacing(3),
paddingBottom: theme.spacing(3),
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(2),
[theme.breakpoints.up('sm')]: {
paddingLeft: theme.spacing(3),
paddingRight: theme.spacing(3),
},
},
},
stretch: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
noPadding: {
padding: 0,
},
}));
stretch: {
display: 'flex',
flexDirection: 'column',
flexGrow: 1,
},
noPadding: {
padding: 0,
},
}),
{ name: 'BackstageContent' },
);
type Props = {
stretch?: boolean;
@@ -15,3 +15,4 @@
*/
export { Content } from './Content';
export type { BackstageContentClassKey } from './Content';
@@ -22,39 +22,49 @@ import React, { PropsWithChildren, ReactNode } from 'react';
import { Typography, makeStyles } from '@material-ui/core';
import { Helmet } from 'react-helmet';
export type ContentHeaderClassKey =
| 'container'
| 'leftItemsBox'
| 'rightItemsBox'
| 'description'
| 'title';
const useStyles = (props: ContentHeaderProps) =>
makeStyles(theme => ({
container: {
width: '100%',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: theme.spacing(2),
textAlign: props.textAlign,
},
leftItemsBox: {
flex: '1 1 auto',
minWidth: 0,
overflow: 'visible',
},
rightItemsBox: {
flex: '0 1 auto',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
marginLeft: theme.spacing(1),
minWidth: 0,
overflow: 'visible',
},
description: {},
title: {
display: 'inline-flex',
marginBottom: 0,
},
}));
makeStyles(
theme => ({
container: {
width: '100%',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
justifyContent: 'flex-end',
alignItems: 'center',
marginBottom: theme.spacing(2),
textAlign: props.textAlign,
},
leftItemsBox: {
flex: '1 1 auto',
minWidth: 0,
overflow: 'visible',
},
rightItemsBox: {
flex: '0 1 auto',
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
marginLeft: theme.spacing(1),
minWidth: 0,
overflow: 'visible',
},
description: {},
title: {
display: 'inline-flex',
marginBottom: 0,
},
}),
{ name: 'BackstageContentHeader' },
);
type ContentHeaderTitleProps = {
title?: string;
@@ -15,3 +15,4 @@
*/
export { ContentHeader } from './ContentHeader';
export type { ContentHeaderClassKey } from './ContentHeader';
@@ -28,24 +28,29 @@ interface IErrorPageProps {
additionalInfo?: string;
}
const useStyles = makeStyles<BackstageTheme>(theme => ({
container: {
padding: theme.spacing(8),
[theme.breakpoints.down('xs')]: {
padding: theme.spacing(2),
export type ErrorPageClassKey = 'container' | 'title' | 'subtitle';
const useStyles = makeStyles<BackstageTheme>(
theme => ({
container: {
padding: theme.spacing(8),
[theme.breakpoints.down('xs')]: {
padding: theme.spacing(2),
},
},
},
title: {
paddingBottom: theme.spacing(5),
[theme.breakpoints.down('xs')]: {
paddingBottom: theme.spacing(4),
fontSize: 32,
title: {
paddingBottom: theme.spacing(5),
[theme.breakpoints.down('xs')]: {
paddingBottom: theme.spacing(4),
fontSize: 32,
},
},
},
subtitle: {
color: theme.palette.textSubtle,
},
}));
subtitle: {
color: theme.palette.textSubtle,
},
}),
{ name: 'BackstageErrorPage' },
);
export function ErrorPage(props: IErrorPageProps) {
const { status, statusMessage, additionalInfo } = props;
@@ -18,21 +18,26 @@ import React from 'react';
import { makeStyles } from '@material-ui/core';
import MicDropSvgUrl from './mic-drop.svg';
const useStyles = makeStyles(theme => ({
micDrop: {
maxWidth: '60%',
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(2),
[theme.breakpoints.down('xs')]: {
maxWidth: '96%',
position: 'relative',
bottom: 'unset',
right: 'unset',
margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,
const useStyles = makeStyles(
theme => ({
micDrop: {
maxWidth: '60%',
position: 'absolute',
bottom: theme.spacing(2),
right: theme.spacing(2),
[theme.breakpoints.down('xs')]: {
maxWidth: '96%',
position: 'relative',
bottom: 'unset',
right: 'unset',
margin: `${theme.spacing(10)}px auto ${theme.spacing(4)}px`,
},
},
},
}));
}),
{ name: 'BackstageErrorPageMicDrop' },
);
export type MicDropClassKey = 'micDrop';
export const MicDrop = () => {
const classes = useStyles();
@@ -15,3 +15,5 @@
*/
export { ErrorPage } from './ErrorPage';
export type { ErrorPageClassKey } from './ErrorPage';
export type { MicDropClassKey } from './MicDrop';
@@ -22,64 +22,78 @@ import { Helmet } from 'react-helmet';
import { Link } from '../../components/Link';
import { Breadcrumbs } from '../Breadcrumbs';
const useStyles = makeStyles<BackstageTheme>(theme => ({
header: {
gridArea: 'pageHeader',
padding: theme.spacing(3),
width: '100%',
boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
position: 'relative',
zIndex: 100,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
backgroundImage: theme.page.backgroundImage,
backgroundPosition: 'center',
backgroundSize: 'cover',
},
leftItemsBox: {
maxWidth: '100%',
flexGrow: 1,
},
rightItemsBox: {
width: 'auto',
},
title: {
color: theme.palette.bursts.fontColor,
wordBreak: 'break-all',
fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))',
marginBottom: 0,
},
subtitle: {
color: 'rgba(255, 255, 255, 0.8)',
lineHeight: '1.0em',
display: 'inline-block', // prevents margin collapse of adjacent siblings
marginTop: theme.spacing(1),
},
type: {
textTransform: 'uppercase',
fontSize: 11,
opacity: 0.8,
marginBottom: theme.spacing(1),
color: theme.palette.bursts.fontColor,
},
breadcrumb: {
fontSize: 'calc(15px + 1 * ((100vw - 320px) / 680))',
color: theme.palette.bursts.fontColor,
},
breadcrumbType: {
fontSize: 'inherit',
opacity: 0.7,
marginRight: -theme.spacing(0.3),
marginBottom: theme.spacing(0.3),
},
breadcrumbTitle: {
fontSize: 'inherit',
marginLeft: -theme.spacing(0.3),
marginBottom: theme.spacing(0.3),
},
}));
export type HeaderClassKey =
| 'header'
| 'leftItemsBox'
| 'rightItemsBox'
| 'title'
| 'subtitle'
| 'type'
| 'breadcrumb'
| 'breadcrumbType'
| 'breadcrumbTitle';
const useStyles = makeStyles<BackstageTheme>(
theme => ({
header: {
gridArea: 'pageHeader',
padding: theme.spacing(3),
width: '100%',
boxShadow: '0 0 8px 3px rgba(20, 20, 20, 0.3)',
position: 'relative',
zIndex: 100,
display: 'flex',
flexDirection: 'row',
flexWrap: 'wrap',
alignItems: 'center',
backgroundImage: theme.page.backgroundImage,
backgroundPosition: 'center',
backgroundSize: 'cover',
},
leftItemsBox: {
maxWidth: '100%',
flexGrow: 1,
},
rightItemsBox: {
width: 'auto',
},
title: {
color: theme.palette.bursts.fontColor,
wordBreak: 'break-all',
fontSize: 'calc(24px + 6 * ((100vw - 320px) / 680))',
marginBottom: 0,
},
subtitle: {
color: 'rgba(255, 255, 255, 0.8)',
lineHeight: '1.0em',
display: 'inline-block', // prevents margin collapse of adjacent siblings
marginTop: theme.spacing(1),
},
type: {
textTransform: 'uppercase',
fontSize: 11,
opacity: 0.8,
marginBottom: theme.spacing(1),
color: theme.palette.bursts.fontColor,
},
breadcrumb: {
fontSize: 'calc(15px + 1 * ((100vw - 320px) / 680))',
color: theme.palette.bursts.fontColor,
},
breadcrumbType: {
fontSize: 'inherit',
opacity: 0.7,
marginRight: -theme.spacing(0.3),
marginBottom: theme.spacing(0.3),
},
breadcrumbTitle: {
fontSize: 'inherit',
marginLeft: -theme.spacing(0.3),
marginBottom: theme.spacing(0.3),
},
}),
{ name: 'BackstageHeader' },
);
type HeaderStyles = ReturnType<typeof useStyles>;
@@ -195,20 +209,22 @@ export function Header(props: PropsWithChildren<Props>) {
<>
<Helmet titleTemplate={titleTemplate} defaultTitle={defaultTitle} />
<header style={style} className={classes.header}>
<Box className={classes.leftItemsBox}>
<TypeFragment
classes={classes}
type={type}
typeLink={typeLink}
pageTitle={pageTitle}
/>
<TitleFragment
classes={classes}
pageTitle={pageTitle}
tooltip={tooltip}
/>
<SubtitleFragment classes={classes} subtitle={subtitle} />
</Box>
<div style={{ border: '2px solid green' }}>
<Box className={classes.leftItemsBox}>
<TypeFragment
classes={classes}
type={type}
typeLink={typeLink}
pageTitle={pageTitle}
/>
<TitleFragment
classes={classes}
pageTitle={pageTitle}
tooltip={tooltip}
/>
<SubtitleFragment classes={classes} subtitle={subtitle} />
</Box>
</div>
<Grid container className={classes.rightItemsBox} spacing={4}>
{children}
</Grid>
@@ -15,3 +15,4 @@
*/
export { Header } from './Header';
export type { HeaderClassKey } from './Header';
@@ -17,24 +17,29 @@
import { Link, makeStyles, Typography, Grid } from '@material-ui/core';
import React from 'react';
const useStyles = makeStyles(theme => ({
root: {
textAlign: 'left',
},
label: {
color: theme.palette.common.white,
fontWeight: 'bold',
letterSpacing: 0,
fontSize: theme.typography.fontSize,
marginBottom: theme.spacing(1) / 2,
lineHeight: 1,
},
value: {
color: 'rgba(255, 255, 255, 0.8)',
fontSize: theme.typography.fontSize,
lineHeight: 1,
},
}));
export type HeaderLabelClassKey = 'root' | 'label' | 'value';
const useStyles = makeStyles(
theme => ({
root: {
textAlign: 'left',
},
label: {
color: theme.palette.common.white,
fontWeight: 'bold',
letterSpacing: 0,
fontSize: theme.typography.fontSize,
marginBottom: theme.spacing(1) / 2,
lineHeight: 1,
},
value: {
color: 'rgba(255, 255, 255, 0.8)',
fontSize: theme.typography.fontSize,
lineHeight: 1,
},
}),
{ name: 'BackstageHeaderLabel' },
);
type HeaderLabelContentProps = {
value: React.ReactNode;
@@ -15,3 +15,4 @@
*/
export { HeaderLabel } from './HeaderLabel';
export type { HeaderLabelClassKey } from './HeaderLabel';
@@ -20,29 +20,38 @@
import React, { useState, useEffect } from 'react';
import { makeStyles, Tabs, Tab as TabUI, TabProps } from '@material-ui/core';
const useStyles = makeStyles(theme => ({
tabsWrapper: {
gridArea: 'pageSubheader',
backgroundColor: theme.palette.background.paper,
paddingLeft: theme.spacing(3),
},
defaultTab: {
padding: theme.spacing(3, 3),
...theme.typography.caption,
textTransform: 'uppercase',
fontWeight: 'bold',
color: theme.palette.text.secondary,
},
selected: {
color: theme.palette.text.primary,
},
tabRoot: {
'&:hover': {
backgroundColor: theme.palette.background.default,
export type HeaderTabsClassKey =
| 'tabsWrapper'
| 'defaultTab'
| 'selected'
| 'tabRoot';
const useStyles = makeStyles(
theme => ({
tabsWrapper: {
gridArea: 'pageSubheader',
backgroundColor: theme.palette.background.paper,
paddingLeft: theme.spacing(3),
},
defaultTab: {
padding: theme.spacing(3, 3),
...theme.typography.caption,
textTransform: 'uppercase',
fontWeight: 'bold',
color: theme.palette.text.secondary,
},
selected: {
color: theme.palette.text.primary,
},
},
}));
tabRoot: {
'&:hover': {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
},
},
}),
{ name: 'BackstageHeaderTabs' },
);
export type Tab = {
id: string;
@@ -14,5 +14,5 @@
* limitations under the License.
*/
export type { Tab } from './HeaderTabs';
export type { Tab, HeaderTabsClassKey } from './HeaderTabs';
export { HeaderTabs } from './HeaderTabs';
@@ -29,34 +29,51 @@ import classNames from 'classnames';
import { ErrorBoundary, ErrorBoundaryProps } from '../ErrorBoundary';
import { BottomLink, BottomLinkProps } from '../BottomLink';
const useStyles = makeStyles(theme => ({
noPadding: {
padding: 0,
'&:last-child': {
paddingBottom: 0,
},
},
header: {
padding: theme.spacing(2, 2, 2, 2.5),
},
headerTitle: {
fontWeight: 700,
},
headerSubheader: {
paddingTop: theme.spacing(1),
},
headerAvatar: {},
headerAction: {},
headerContent: {},
}));
export type InfoCardClassKey =
| 'noPadding'
| 'header'
| 'headerTitle'
| 'headerSubheader'
| 'headerAvatar'
| 'headerAction'
| 'headerContent';
const CardActionsTopRight = withStyles(theme => ({
root: {
display: 'inline-block',
padding: theme.spacing(8, 8, 0, 0),
float: 'right',
},
}))(CardActions);
const useStyles = makeStyles(
theme => ({
noPadding: {
padding: 0,
'&:last-child': {
paddingBottom: 0,
},
},
header: {
padding: theme.spacing(2, 2, 2, 2.5),
},
headerTitle: {
fontWeight: 700,
},
headerSubheader: {
paddingTop: theme.spacing(1),
},
headerAvatar: {},
headerAction: {},
headerContent: {},
}),
{ name: 'BackstageInfoCard' },
);
export type CardActionsTopRightClassKey = 'root';
const CardActionsTopRight = withStyles(
theme => ({
root: {
display: 'inline-block',
padding: theme.spacing(8, 8, 0, 0),
float: 'right',
},
}),
{ name: 'BackstageInfoCardCardActionsTopRight' },
)(CardActions);
const VARIANT_STYLES = {
card: {
@@ -15,4 +15,8 @@
*/
export { InfoCard } from './InfoCard';
export type { InfoCardVariants } from './InfoCard';
export type {
InfoCardVariants,
InfoCardClassKey,
CardActionsTopRightClassKey,
} from './InfoCard';
@@ -17,6 +17,8 @@
import { createStyles, makeStyles, Theme, WithStyles } from '@material-ui/core';
import React from 'react';
export type ItemCardGridClassKey = 'root';
const styles = (theme: Theme) =>
createStyles({
root: {
@@ -27,7 +29,7 @@ const styles = (theme: Theme) =>
},
});
const useStyles = makeStyles(styles);
const useStyles = makeStyles(styles, { name: 'BackstageItemCardGrid' });
export type ItemCardGridProps = Partial<WithStyles<typeof styles>> & {
/**
@@ -23,6 +23,8 @@ import {
import React from 'react';
import { BackstageTheme } from '@backstage/theme';
export type ItemCardHeaderClassKey = 'root';
const styles = (theme: BackstageTheme) =>
createStyles({
root: {
@@ -34,7 +36,7 @@ const styles = (theme: BackstageTheme) =>
},
});
const useStyles = makeStyles(styles);
const useStyles = makeStyles(styles, { name: 'BackstageItemCardHeader' });
export type ItemCardHeaderProps = Partial<WithStyles<typeof styles>> & {
/**
@@ -16,6 +16,9 @@
export { ItemCard } from './ItemCard';
export { ItemCardGrid } from './ItemCardGrid';
export type { ItemCardGridProps } from './ItemCardGrid';
export type { ItemCardGridProps, ItemCardGridClassKey } from './ItemCardGrid';
export { ItemCardHeader } from './ItemCardHeader';
export type { ItemCardHeaderProps } from './ItemCardHeader';
export type {
ItemCardHeaderProps,
ItemCardHeaderClassKey,
} from './ItemCardHeader';
@@ -18,17 +18,22 @@ import React, { PropsWithChildren } from 'react';
import { BackstageTheme } from '@backstage/theme';
import { makeStyles, ThemeProvider } from '@material-ui/core';
const useStyles = makeStyles(() => ({
root: {
display: 'grid',
gridTemplateAreas:
"'pageHeader pageHeader pageHeader' 'pageSubheader pageSubheader pageSubheader' 'pageNav pageContent pageSidebar'",
gridTemplateRows: 'max-content auto 1fr',
gridTemplateColumns: 'auto 1fr auto',
height: '100vh',
overflowY: 'auto',
},
}));
export type PageClassKey = 'root';
const useStyles = makeStyles(
() => ({
root: {
display: 'grid',
gridTemplateAreas:
"'pageHeader pageHeader pageHeader' 'pageSubheader pageSubheader pageSubheader' 'pageNav pageContent pageSidebar'",
gridTemplateRows: 'max-content auto 1fr',
gridTemplateColumns: 'auto 1fr auto',
height: '100vh',
overflowY: 'auto',
},
}),
{ name: 'BackstagePage' },
);
type Props = {
themeId: string;
@@ -15,4 +15,5 @@
*/
export { Page } from './Page';
export type { PageClassKey } from './Page';
export { PageWithHeader } from './PageWithHeader';
@@ -21,47 +21,52 @@ import { sidebarConfig, SidebarContext } from './config';
import { BackstageTheme } from '@backstage/theme';
import { SidebarPinStateContext } from './Page';
const useStyles = makeStyles<BackstageTheme>(theme => ({
root: {
zIndex: 1000,
position: 'relative',
overflow: 'visible',
width: theme.spacing(7) + 1,
},
drawer: {
display: 'flex',
flexFlow: 'column nowrap',
alignItems: 'flex-start',
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
padding: 0,
background: theme.palette.navigation.background,
overflowX: 'hidden',
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,
}),
'& > *': {
flexShrink: 0,
export type SidebarClassKey = 'root' | 'drawer' | 'drawerOpen';
const useStyles = makeStyles<BackstageTheme>(
theme => ({
root: {
zIndex: 1000,
position: 'relative',
overflow: 'visible',
width: theme.spacing(7) + 1,
},
'&::-webkit-scrollbar': {
display: 'none',
drawer: {
display: 'flex',
flexFlow: 'column nowrap',
alignItems: 'flex-start',
position: 'fixed',
left: 0,
top: 0,
bottom: 0,
padding: 0,
background: theme.palette.navigation.background,
overflowX: 'hidden',
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,
}),
'& > *': {
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,
}),
},
}));
drawerOpen: {
width: sidebarConfig.drawerWidthOpen,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.shorter,
}),
},
}),
{ name: 'BackstageSidebar' },
);
enum State {
Closed,
@@ -26,48 +26,58 @@ import {
} from './config';
import { SidebarDivider } from './Items';
const useStyles = makeStyles<BackstageTheme>(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,
}),
export type SidebarIntroClassKey =
| 'introCard'
| 'introDismiss'
| 'introDismissLink'
| 'introDismissText'
| 'introDismissIcon';
const useStyles = makeStyles<BackstageTheme>(
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,
},
},
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' },
);
type IntroCardProps = {
text: string;
@@ -42,90 +42,107 @@ import {
} from 'react-router-dom';
import { sidebarConfig, SidebarContext } from './config';
const useStyles = makeStyles<BackstageTheme>(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,
},
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),
},
selected: {
'&$root': {
borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`,
color: theme.palette.navigation.selectedColor,
export type SidebarItemClassKey =
| 'root'
| 'buttonItem'
| 'closed'
| 'open'
| 'label'
| 'iconContainer'
| 'searchRoot'
| 'searchField'
| 'searchFieldHTMLInput'
| 'searchContainer'
| 'secondaryAction'
| 'selected';
const useStyles = makeStyles<BackstageTheme>(
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',
},
'&$closed': {
width: drawerWidthClosed - selectedIndicatorWidth,
buttonItem: {
background: 'none',
border: 'none',
width: 'auto',
margin: 0,
padding: 0,
textAlign: 'inherit',
font: 'inherit',
},
'& $iconContainer': {
marginLeft: -selectedIndicatorWidth,
closed: {
width: drawerWidthClosed,
justifyContent: 'center',
},
},
};
});
open: {
width: drawerWidthOpen,
},
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),
},
selected: {
'&$root': {
borderLeft: `solid ${selectedIndicatorWidth}px ${theme.palette.navigation.indicator}`,
color: theme.palette.navigation.selectedColor,
},
'&$closed': {
width: drawerWidthClosed - selectedIndicatorWidth,
},
'& $iconContainer': {
marginLeft: -selectedIndicatorWidth,
},
},
};
},
{ name: 'BackstageSidebarItem' },
);
type SidebarItemBaseProps = {
icon: IconComponent;
@@ -25,17 +25,22 @@ import { sidebarConfig } from './config';
import { BackstageTheme } from '@backstage/theme';
import { LocalStorage } from './localStorage';
const useStyles = makeStyles<BackstageTheme, { isPinned: boolean }>({
root: {
width: '100%',
minHeight: '100%',
transition: 'padding-left 0.1s ease-out',
paddingLeft: ({ isPinned }) =>
isPinned
? sidebarConfig.drawerWidthOpen
: sidebarConfig.drawerWidthClosed,
export type SidebarPageClassKey = 'root';
const useStyles = makeStyles<BackstageTheme, { isPinned: boolean }>(
{
root: {
width: '100%',
minHeight: '100%',
transition: 'padding-left 0.1s ease-out',
paddingLeft: ({ isPinned }) =>
isPinned
? sidebarConfig.drawerWidthOpen
: sidebarConfig.drawerWidthClosed,
},
},
});
{ name: 'BackstageSidebarPage' },
);
export type SidebarPinStateContextType = {
isPinned: boolean;
@@ -15,8 +15,9 @@
*/
export { Sidebar } from './Bar';
export type { SidebarClassKey } from './Bar';
export { SidebarPage, SidebarPinStateContext } from './Page';
export type { SidebarPinStateContextType } from './Page';
export type { SidebarPinStateContextType, SidebarPageClassKey } from './Page';
export {
SidebarDivider,
SidebarItem,
@@ -25,7 +26,9 @@ export {
SidebarSpacer,
SidebarScrollWrapper,
} from './Items';
export type { SidebarItemClassKey } from './Items';
export { IntroCard, SidebarIntro } from './Intro';
export type { SidebarIntroClassKey } from './Intro';
export {
SIDEBAR_INTRO_LOCAL_STORAGE,
SidebarContext,
@@ -32,16 +32,21 @@ import { GridItem } from './styles';
// accept base64url format according to RFC7515 (https://tools.ietf.org/html/rfc7515#section-3)
const ID_TOKEN_REGEX = /^[a-z0-9_\-]+\.[a-z0-9_\-]+\.[a-z0-9_\-]+$/i;
const useFormStyles = makeStyles(theme => ({
form: {
display: 'flex',
flexFlow: 'column nowrap',
},
button: {
alignSelf: 'center',
marginTop: theme.spacing(2),
},
}));
export type CustomProviderClassKey = 'form' | 'button';
const useFormStyles = makeStyles(
theme => ({
form: {
display: 'flex',
flexFlow: 'column nowrap',
},
button: {
alignSelf: 'center',
marginTop: theme.spacing(2),
},
}),
{ name: 'BackstageCustomProvider' },
);
type Data = {
userId: string;
@@ -16,3 +16,5 @@
export type { SignInProviderConfig } from './types';
export { SignInPage } from './SignInPage';
export type { SignInPageClassKey } from './styles';
export type { CustomProviderClassKey } from './customProvider';
@@ -16,20 +16,25 @@
import React from 'react';
import { Grid, makeStyles } from '@material-ui/core';
export const useStyles = makeStyles({
container: {
padding: 0,
listStyle: 'none',
export type SignInPageClassKey = 'container' | 'item';
export const useStyles = makeStyles(
{
container: {
padding: 0,
listStyle: 'none',
},
item: {
display: 'flex',
flexDirection: 'column',
width: '100%',
maxWidth: '400px',
margin: 0,
padding: 0,
},
},
item: {
display: 'flex',
flexDirection: 'column',
width: '100%',
maxWidth: '400px',
margin: 0,
padding: 0,
},
});
{ name: 'BackstageSignInPage' },
);
export const GridItem = ({ children }: { children: JSX.Element }) => {
const classes = useStyles();
@@ -34,22 +34,32 @@ import {
import { BottomLink, BottomLinkProps } from '../BottomLink';
import { ErrorBoundary, ErrorBoundaryProps } from '../ErrorBoundary';
const useTabsStyles = makeStyles(theme => ({
root: {
padding: theme.spacing(0, 2, 0, 2.5),
minHeight: theme.spacing(3),
},
indicator: {
backgroundColor: theme.palette.info.main,
height: theme.spacing(0.3),
},
}));
export type TabbedCardClassKey = 'root' | 'indicator';
const BoldHeader = withStyles(theme => ({
root: { padding: theme.spacing(2, 2, 2, 2.5), display: 'inline-block' },
title: { fontWeight: 700 },
subheader: { paddingTop: theme.spacing(1) },
}))(CardHeader);
const useTabsStyles = makeStyles(
theme => ({
root: {
padding: theme.spacing(0, 2, 0, 2.5),
minHeight: theme.spacing(3),
},
indicator: {
backgroundColor: theme.palette.info.main,
height: theme.spacing(0.3),
},
}),
{ name: 'BackstageTabbedCard' },
);
export type BoldHeaderClassKey = 'root' | 'title' | 'subheader';
const BoldHeader = withStyles(
theme => ({
root: { padding: theme.spacing(2, 2, 2, 2.5), display: 'inline-block' },
title: { fontWeight: 700 },
subheader: { paddingTop: theme.spacing(1) },
}),
{ name: 'BackstageTabbedCardBoldHeader' },
)(CardHeader);
type Props = {
/** @deprecated Use errorBoundaryProps instead */
@@ -114,23 +124,28 @@ export function TabbedCard(props: PropsWithChildren<Props>) {
);
}
const useCardTabStyles = makeStyles(theme => ({
root: {
minWidth: theme.spacing(6),
minHeight: theme.spacing(3),
margin: theme.spacing(0, 2, 0, 0),
padding: theme.spacing(0.5, 0, 0.5, 0),
textTransform: 'none',
'&:hover': {
opacity: 1,
backgroundColor: 'transparent',
color: theme.palette.text.primary,
export type CardTabClassKey = 'root' | 'selected';
const useCardTabStyles = makeStyles(
theme => ({
root: {
minWidth: theme.spacing(6),
minHeight: theme.spacing(3),
margin: theme.spacing(0, 2, 0, 0),
padding: theme.spacing(0.5, 0, 0.5, 0),
textTransform: 'none',
'&:hover': {
opacity: 1,
backgroundColor: 'transparent',
color: theme.palette.text.primary,
},
},
},
selected: {
fontWeight: 'bold',
},
}));
selected: {
fontWeight: 'bold',
},
}),
{ name: 'BackstageCardTab' },
);
type CardTabProps = TabProps & {
children: ReactNode;
@@ -15,3 +15,8 @@
*/
export { CardTab, TabbedCard } from './TabbedCard';
export type {
CardTabClassKey,
TabbedCardClassKey,
BoldHeaderClassKey,
} from './TabbedCard';