mirror of
https://github.com/Unleash/unleash.git
synced 2025-08-04 13:48:56 +02:00
feat: release template feedback module (#9614)
## About the changes Adds a release template feedback module to release templates:  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:
parent
b885a927e6
commit
380d2c2c5d
@ -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',
|
display: 'flex',
|
||||||
flexDirection: 'column',
|
flexDirection: 'column',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
@ -11,30 +75,33 @@ const StyledCard = styled(MUICard)(({ theme }) => ({
|
|||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
},
|
},
|
||||||
transition: 'background-color 0.2s ease-in-out',
|
transition: 'background-color 0.2s ease-in-out',
|
||||||
backgroundColor: theme.palette.background.default,
|
|
||||||
'&:hover': {
|
|
||||||
backgroundColor: theme.palette.neutral.light,
|
|
||||||
},
|
|
||||||
borderRadius: theme.shape.borderRadiusMedium,
|
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),
|
padding: theme.spacing(2),
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
flexFlow: 'column',
|
flexFlow: 'column',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
position: 'relative',
|
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',
|
display: 'flex',
|
||||||
gap: theme.spacing(1),
|
gap: theme.spacing(1),
|
||||||
width: '100%',
|
width: '100%',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
fontWeight: theme.typography.fontWeightRegular,
|
|
||||||
fontSize: theme.typography.body1.fontSize,
|
fontSize: theme.typography.body1.fontSize,
|
||||||
|
color: theme.palette.text.primary,
|
||||||
lineHeight: '1.2',
|
lineHeight: '1.2',
|
||||||
|
...variants[cardVariant].header(theme),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledCardIconContainer = styled(Box)(({ theme }) => ({
|
const StyledCardIconContainer = styled(Box)(({ theme }) => ({
|
||||||
@ -58,23 +125,20 @@ const StyledCardActions = styled(Box)(({ theme }) => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const StyledCardBodyContent = styled(Box)(({ theme }) => ({
|
const StyledCardBodyContent = styled(Box)(({ theme }) => ({
|
||||||
color: theme.palette.text.secondary,
|
|
||||||
fontSize: theme.fontSizes.smallBody,
|
|
||||||
marginTop: theme.spacing(2),
|
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),
|
padding: theme.spacing(0, 2),
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
background: theme.palette.background.elevation1,
|
|
||||||
boxShadow: theme.boxShadows.accordionFooter,
|
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
borderTop: `1px solid ${theme.palette.divider}`,
|
|
||||||
minHeight: theme.spacing(6.25),
|
minHeight: theme.spacing(6.25),
|
||||||
fontSize: theme.fontSizes.smallerBody,
|
fontSize: theme.fontSizes.smallerBody,
|
||||||
color: theme.palette.text.secondary,
|
|
||||||
textWrap: 'nowrap',
|
textWrap: 'nowrap',
|
||||||
|
...variants[cardVariant].footer(theme),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
interface ICardProps extends Omit<CardProps, 'title'> {
|
interface ICardProps extends Omit<CardProps, 'title'> {
|
||||||
@ -82,6 +146,7 @@ interface ICardProps extends Omit<CardProps, 'title'> {
|
|||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
headerActions?: React.ReactNode;
|
headerActions?: React.ReactNode;
|
||||||
footer?: React.ReactNode;
|
footer?: React.ReactNode;
|
||||||
|
cardVariant?: CardVariant;
|
||||||
children?: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -90,12 +155,13 @@ export const Card = ({
|
|||||||
title,
|
title,
|
||||||
headerActions,
|
headerActions,
|
||||||
footer,
|
footer,
|
||||||
|
cardVariant = 'primary',
|
||||||
children,
|
children,
|
||||||
...props
|
...props
|
||||||
}: ICardProps) => (
|
}: ICardProps) => (
|
||||||
<StyledCard {...props}>
|
<StyledCard cardVariant={cardVariant} {...props}>
|
||||||
<StyledCardBody>
|
<StyledCardBody cardVariant={cardVariant}>
|
||||||
<StyledCardBodyHeader>
|
<StyledCardBodyHeader cardVariant={cardVariant}>
|
||||||
{icon && (
|
{icon && (
|
||||||
<StyledCardIconContainer>{icon}</StyledCardIconContainer>
|
<StyledCardIconContainer>{icon}</StyledCardIconContainer>
|
||||||
)}
|
)}
|
||||||
@ -108,6 +174,10 @@ export const Card = ({
|
|||||||
<StyledCardBodyContent>{children}</StyledCardBodyContent>
|
<StyledCardBodyContent>{children}</StyledCardBodyContent>
|
||||||
)}
|
)}
|
||||||
</StyledCardBody>
|
</StyledCardBody>
|
||||||
{footer && <StyledCardFooter>{footer}</StyledCardFooter>}
|
{footer && (
|
||||||
|
<StyledCardFooter cardVariant={cardVariant}>
|
||||||
|
{footer}
|
||||||
|
</StyledCardFooter>
|
||||||
|
)}
|
||||||
</StyledCard>
|
</StyledCard>
|
||||||
);
|
);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { Grid, styled } from '@mui/material';
|
import { Grid, styled } from '@mui/material';
|
||||||
import { ReleasePlanTemplateCard } from './ReleasePlanTemplateCard/ReleasePlanTemplateCard';
|
import { ReleasePlanTemplateCard } from './ReleasePlanTemplateCard/ReleasePlanTemplateCard';
|
||||||
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
|
import type { IReleasePlanTemplate } from 'interfaces/releasePlans';
|
||||||
|
import { ReleasesFeedback } from './ReleasesFeedback';
|
||||||
|
|
||||||
const StyledGridItem = styled(Grid)({
|
const StyledGridItem = styled(Grid)({
|
||||||
minHeight: '180px',
|
minHeight: '180px',
|
||||||
@ -20,6 +21,15 @@ export const ReleasePlanTemplateList: React.FC<ITemplateList> = ({
|
|||||||
<ReleasePlanTemplateCard template={template} />
|
<ReleasePlanTemplateCard template={template} />
|
||||||
</StyledGridItem>
|
</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>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user