1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-07-26 13:48:33 +02:00

feat: release template feedback module (#9614)

## About the changes

Adds a release template feedback module to release templates: 

![image](https://github.com/user-attachments/assets/848d386b-0e20-43d0-b113-51e1e26c5a13)

It uses the Card component by defining a new variant of it.

---------

Co-authored-by: Nuno Góis <github@nunogois.com>
This commit is contained in:
Gastón Fournier 2025-03-25 17:01:04 +01:00 committed by GitHub
parent b885a927e6
commit 380d2c2c5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 138 additions and 20 deletions

View File

@ -1,6 +1,70 @@
import { styled, Card as MUICard, Box, type CardProps } from '@mui/material';
import {
styled,
Card as MUICard,
Box,
type CardProps,
type Theme,
type CSSObject,
} from '@mui/material';
const StyledCard = styled(MUICard)(({ theme }) => ({
type CardVariant = 'primary' | 'secondary';
type CardComponent = 'card' | 'header' | 'body' | 'footer';
type VariantProps = {
[key in CardVariant]: {
[key in CardComponent]: (theme: Theme) => CSSObject;
};
};
const variants: VariantProps = {
primary: {
card: (theme: Theme): CSSObject => ({
backgroundColor: theme.palette.background.default,
background: theme.palette.secondary.light,
'&:hover': {
backgroundColor: theme.palette.neutral.light,
},
}),
header: (theme: Theme): CSSObject => ({
fontWeight: theme.typography.fontWeightRegular,
}),
body: (theme: Theme): CSSObject => ({
backgroundColor: theme.palette.background.default,
color: theme.palette.text.secondary,
'&:hover': {
backgroundColor: theme.palette.neutral.light,
},
fontSize: theme.fontSizes.smallBody,
}),
footer: (theme: Theme): CSSObject => ({
borderTop: `1px solid ${theme.palette.divider}`,
background: theme.palette.background.elevation1,
boxShadow: theme.boxShadows.accordionFooter,
color: theme.palette.text.secondary,
}),
},
secondary: {
card: (theme: Theme): CSSObject => ({
backgroundColor: theme.palette.secondary.light,
borderColor: theme.palette.secondary.border,
color: theme.palette.text.primary,
}),
header: (theme: Theme): CSSObject => ({
fontWeight: theme.typography.fontWeightBold,
}),
body: (theme: Theme): CSSObject => ({
backgroundColor: theme.palette.secondary.light,
color: theme.palette.text.primary,
}),
footer: (theme: Theme): CSSObject => ({
background: theme.palette.secondary.light,
fontSize: theme.fontSizes.bodySize,
}),
},
};
const StyledCard = styled(MUICard, {
shouldForwardProp: (prop) => prop !== 'cardVariant',
})<{ cardVariant: CardVariant }>(({ theme, cardVariant }) => ({
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
@ -11,30 +75,33 @@ const StyledCard = styled(MUICard)(({ theme }) => ({
justifyContent: 'center',
},
transition: 'background-color 0.2s ease-in-out',
backgroundColor: theme.palette.background.default,
'&:hover': {
backgroundColor: theme.palette.neutral.light,
},
borderRadius: theme.shape.borderRadiusMedium,
...variants[cardVariant].card(theme),
}));
const StyledCardBody = styled(Box)(({ theme }) => ({
const StyledCardBody = styled(Box, {
shouldForwardProp: (prop) => prop !== 'cardVariant',
})<{ cardVariant: CardVariant }>(({ theme, cardVariant }) => ({
padding: theme.spacing(2),
display: 'flex',
flexFlow: 'column',
height: '100%',
position: 'relative',
...variants[cardVariant].body(theme),
}));
const StyledCardBodyHeader = styled(Box)(({ theme }) => ({
const StyledCardBodyHeader = styled(Box, {
shouldForwardProp: (prop) => prop !== 'cardVariant',
})<{ cardVariant: CardVariant }>(({ theme, cardVariant }) => ({
display: 'flex',
gap: theme.spacing(1),
width: '100%',
alignItems: 'center',
justifyContent: 'space-between',
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.body1.fontSize,
color: theme.palette.text.primary,
lineHeight: '1.2',
...variants[cardVariant].header(theme),
}));
const StyledCardIconContainer = styled(Box)(({ theme }) => ({
@ -58,23 +125,20 @@ const StyledCardActions = styled(Box)(({ theme }) => ({
}));
const StyledCardBodyContent = styled(Box)(({ theme }) => ({
color: theme.palette.text.secondary,
fontSize: theme.fontSizes.smallBody,
marginTop: theme.spacing(2),
}));
const StyledCardFooter = styled(Box)(({ theme }) => ({
const StyledCardFooter = styled(Box, {
shouldForwardProp: (prop) => prop !== 'cardVariant',
})<{ cardVariant: CardVariant }>(({ theme, cardVariant }) => ({
padding: theme.spacing(0, 2),
display: 'flex',
background: theme.palette.background.elevation1,
boxShadow: theme.boxShadows.accordionFooter,
alignItems: 'center',
justifyContent: 'space-between',
borderTop: `1px solid ${theme.palette.divider}`,
minHeight: theme.spacing(6.25),
fontSize: theme.fontSizes.smallerBody,
color: theme.palette.text.secondary,
textWrap: 'nowrap',
...variants[cardVariant].footer(theme),
}));
interface ICardProps extends Omit<CardProps, 'title'> {
@ -82,6 +146,7 @@ interface ICardProps extends Omit<CardProps, 'title'> {
title?: React.ReactNode;
headerActions?: React.ReactNode;
footer?: React.ReactNode;
cardVariant?: CardVariant;
children?: React.ReactNode;
}
@ -90,12 +155,13 @@ export const Card = ({
title,
headerActions,
footer,
cardVariant = 'primary',
children,
...props
}: ICardProps) => (
<StyledCard {...props}>
<StyledCardBody>
<StyledCardBodyHeader>
<StyledCard cardVariant={cardVariant} {...props}>
<StyledCardBody cardVariant={cardVariant}>
<StyledCardBodyHeader cardVariant={cardVariant}>
{icon && (
<StyledCardIconContainer>{icon}</StyledCardIconContainer>
)}
@ -108,6 +174,10 @@ export const Card = ({
<StyledCardBodyContent>{children}</StyledCardBodyContent>
)}
</StyledCardBody>
{footer && <StyledCardFooter>{footer}</StyledCardFooter>}
{footer && (
<StyledCardFooter cardVariant={cardVariant}>
{footer}
</StyledCardFooter>
)}
</StyledCard>
);

View File

@ -1,6 +1,7 @@
import { Grid, styled } from '@mui/material';
import { ReleasePlanTemplateCard } from './ReleasePlanTemplateCard/ReleasePlanTemplateCard';
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
import { ReleasesFeedback } from './ReleasesFeedback';
const StyledGridItem = styled(Grid)({
minHeight: '180px',
@ -20,6 +21,15 @@ export const ReleasePlanTemplateList: React.FC<ITemplateList> = ({
<ReleasePlanTemplateCard template={template} />
</StyledGridItem>
))}
{templates.length > 0 && (
<StyledGridItem key='feedback' item xs={6} md={4}>
<ReleasesFeedback title='Release Templates'>
We would love to get your feedback on the concept around
release templates so we can bring it into our work going
forward
</ReleasesFeedback>
</StyledGridItem>
)}
</>
);
};

View File

@ -0,0 +1,38 @@
import { styled } from '@mui/material';
import { Card } from 'component/common/Card/Card';
import { Link } from 'react-router-dom';
const StyledCardLink = styled(Link)(({ theme }) => ({
textDecoration: 'none',
fontWeight: theme.typography.fontWeightBold,
color: theme.palette.links,
'&:hover, &:focus': {
textDecoration: 'underline',
},
}));
const feedbackLink =
'https://docs.google.com/forms/d/1ElbScYxbAhFcjQWgRinifoymYHeuXzqIoQXfpUVYGR8/preview';
export const ReleasesFeedback: React.FC<{
title: string;
children: React.ReactNode;
}> = ({ title, children }: { title: string; children?: React.ReactNode }) => {
return (
<Card
cardVariant='secondary'
title={title}
footer={
<StyledCardLink
to={feedbackLink}
target='_blank'
rel='noreferrer'
>
Give feedback
</StyledCardLink>
}
>
{children}
</Card>
);
};