Merge pull request #23786 from grantila/grantila/gauge-card-align-bottom-and-small-version

Allow GaugeCard to handle multi-line titles better
This commit is contained in:
Fredrik Adelöw
2024-05-04 23:19:53 +02:00
committed by GitHub
6 changed files with 132 additions and 9 deletions
+6
View File
@@ -0,0 +1,6 @@
---
'@backstage/core-components': patch
---
Add `alignGauge` prop to the `GaugeCard`, and a small size version. When `alignGauge` is `'bottom'` the gauge will vertically align the gauge in the cards, even when the card titles span across multiple lines.
Add `alignContent` prop to the `InfoCard`, defaulting to `'normal'` with the option of `'bottom'` which vertically aligns the content to the bottom of the card.
+1
View File
@@ -448,6 +448,7 @@ export type GaugeProps = {
inverse?: boolean;
unit?: string;
max?: number;
size?: 'normal' | 'small';
description?: ReactNode;
getColor?: GaugePropsGetColor;
};
@@ -19,6 +19,7 @@ import { makeStyles, useTheme } from '@material-ui/core/styles';
import { Circle } from 'rc-progress';
import React, { ReactNode, useEffect, useState } from 'react';
import Box from '@material-ui/core/Box';
import classNames from 'classnames';
/** @public */
export type GaugeClassKey =
@@ -43,6 +44,9 @@ const useStyles = makeStyles(
fontWeight: theme.typography.fontWeightBold,
color: theme.palette.textContrast,
},
overlaySmall: {
fontSize: theme.typography.pxToRem(25),
},
description: {
fontSize: '100%',
top: '50%',
@@ -68,6 +72,7 @@ export type GaugeProps = {
inverse?: boolean;
unit?: string;
max?: number;
size?: 'normal' | 'small';
description?: ReactNode;
getColor?: GaugePropsGetColor;
};
@@ -121,7 +126,7 @@ export const getProgressColor: GaugePropsGetColor = ({
export function Gauge(props: GaugeProps) {
const [hoverRef, setHoverRef] = useState<HTMLDivElement | null>(null);
const { getColor = getProgressColor } = props;
const { getColor = getProgressColor, size = 'normal' } = props;
const classes = useStyles(props);
const { palette } = useTheme();
const { value, fractional, inverse, unit, max, description } = {
@@ -165,7 +170,11 @@ export function Gauge(props: GaugeProps) {
{description && isHovering ? (
<Box className={classes.description}>{description}</Box>
) : (
<Box className={classes.overlay}>
<Box
className={classNames(classes.overlay, {
[classes.overlaySmall]: size === 'small',
})}
>
{isNaN(value) ? 'N/A' : `${asActual}${unit}`}
</Box>
)}
@@ -175,6 +175,91 @@ export const InfoMessage = () => (
</Wrapper>
);
export const AlignedBottom = () => (
<Wrapper>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
title="Progress"
subheader="With a subheader"
progress={0.3}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
title="Progress"
subheader="With a subheader"
progress={0.57}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
title="Progress with longer title"
subheader="With a subheader"
progress={0.89}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
title="Progress"
subheader="With a subheader"
inverse
progress={0.2}
/>
</Grid>
</Wrapper>
);
export const Small = () => (
<Wrapper>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
size="small"
title="Progress"
progress={0.3}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
size="small"
title="Progress"
subheader="With a subheader"
progress={0.57}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
size="small"
title="Progress, longer title"
progress={0.89}
/>
</Grid>
<Grid item>
<GaugeCard
variant="fullHeight"
alignGauge="bottom"
size="small"
title="Progress"
inverse
progress={0.2}
/>
</Grid>
</Wrapper>
);
export const HoverMessage = () => (
<Wrapper>
<Grid item>
@@ -27,6 +27,8 @@ type Props = {
variant?: InfoCardVariants;
/** Progress in % specified as decimal, e.g. "0.23" */
progress: number;
alignGauge?: 'normal' | 'bottom';
size?: 'normal' | 'small';
description?: ReactNode;
icon?: ReactNode;
inverse?: boolean;
@@ -43,6 +45,10 @@ const useStyles = makeStyles(
height: '100%',
width: 250,
},
rootSmall: {
height: '100%',
width: 160,
},
},
{ name: 'BackstageGaugeCard' },
);
@@ -64,6 +70,8 @@ export function GaugeCard(props: Props) {
description,
icon,
variant,
alignGauge = 'normal',
size = 'normal',
getColor,
} = props;
@@ -75,15 +83,22 @@ export function GaugeCard(props: Props) {
};
return (
<Box className={classes.root}>
<Box className={size === 'small' ? classes.rootSmall : classes.root}>
<InfoCard
title={title}
subheader={subheader}
deepLink={deepLink}
variant={variant}
alignContent={alignGauge}
icon={icon}
titleTypographyProps={{
...(size === 'small' ? { variant: 'subtitle2' } : undefined),
}}
subheaderTypographyProps={{
...(size === 'small' ? { variant: 'body2' } : undefined),
}}
>
<Gauge {...gaugeProps} />
<Gauge {...gaugeProps} size={size} />
</InfoCard>
</Box>
);
@@ -43,6 +43,10 @@ const useStyles = makeStyles(
paddingBottom: 0,
},
},
contentAlignBottom: {
display: 'flex',
alignItems: 'self-end',
},
header: {
padding: theme.spacing(2, 2, 2, 2.5),
},
@@ -138,6 +142,7 @@ export type Props = {
slackChannel?: string;
errorBoundaryProps?: ErrorBoundaryProps;
variant?: InfoCardVariants;
alignContent?: 'normal' | 'bottom';
children?: ReactNode;
headerStyle?: object;
headerProps?: CardHeaderProps;
@@ -150,6 +155,7 @@ export type Props = {
className?: string;
noPadding?: boolean;
titleTypographyProps?: object;
subheaderTypographyProps?: object;
};
/**
@@ -167,6 +173,7 @@ export function InfoCard(props: Props): JSX.Element {
slackChannel,
errorBoundaryProps,
variant,
alignContent = 'normal',
children,
headerStyle,
headerProps,
@@ -179,6 +186,7 @@ export function InfoCard(props: Props): JSX.Element {
className,
noPadding,
titleTypographyProps,
subheaderTypographyProps,
} = props;
const classes = useStyles();
/**
@@ -209,10 +217,7 @@ export function InfoCard(props: Props): JSX.Element {
}
return (
<div
className={classes.headerSubheader}
data-testid="info-card-subheader"
>
<div data-testid="info-card-subheader">
{subheader && <div className={classes.subheader}>{subheader}</div>}
{icon}
</div>
@@ -228,7 +233,7 @@ export function InfoCard(props: Props): JSX.Element {
{title && (
<CardHeader
classes={{
root: classes.header,
root: classNames(classes.header),
title: classes.headerTitle,
subheader: classes.headerSubheader,
avatar: classes.headerAvatar,
@@ -240,6 +245,7 @@ export function InfoCard(props: Props): JSX.Element {
action={action}
style={{ ...headerStyle }}
titleTypographyProps={titleTypographyProps}
subheaderTypographyProps={subheaderTypographyProps}
{...headerProps}
/>
)}
@@ -250,6 +256,7 @@ export function InfoCard(props: Props): JSX.Element {
<CardContent
className={classNames(cardClassName, {
[classes.noPadding]: noPadding,
[classes.contentAlignBottom]: alignContent === 'bottom',
})}
style={calculatedCardStyle}
>