Move variant style handling for Infocard to seperate file and use some of it for TabbedCard

This commit is contained in:
Marcus Eide
2020-09-25 09:58:18 +02:00
parent cea6c4604e
commit 94fa82b741
4 changed files with 156 additions and 85 deletions
+4 -70
View File
@@ -28,6 +28,7 @@ import {
import classNames from 'classnames';
import { ErrorBoundary } from '../ErrorBoundary';
import { BottomLink, BottomLinkProps } from '../BottomLink';
import { getVariantStyles } from './variants';
const useStyles = makeStyles(theme => ({
noPadding: {
@@ -59,51 +60,6 @@ const CardActionsTopRight = withStyles(theme => ({
},
}))(CardActions);
const VARIANT_STYLES = {
card: {
flex: {
display: 'flex',
flexDirection: 'column',
},
fullHeight: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
height100: {
display: 'flex',
flexDirection: 'column',
height: 'calc(100% - 10px)', // for pages without content header
marginBottom: '10px',
},
contentheader: {
height: 'calc(100% - 40px)', // for pages with content header
},
contentheadertabs: {
height: 'calc(100% - 97px)', // for pages with content header and tabs (Tingle)
},
noShrink: {
flexShrink: 0,
},
minheight300: {
minHeight: 300,
overflow: 'initial',
},
},
cardContent: {
fullHeight: {
flex: 1,
},
height100: {
flex: 1,
},
contentRow: {
display: 'flex',
flexDirection: 'row',
},
},
};
/**
* InfoCard is used to display a paper-styled block on the screen, similar to a panel.
*
@@ -163,32 +119,10 @@ export const InfoCard = ({
noPadding,
}: Props): JSX.Element => {
const classes = useStyles();
/**
* If variant is specified, we build up styles for that particular variant for both
* the Card and the CardContent (since these need to be synced)
*/
let calculatedStyle = {};
let calculatedCardStyle = {};
if (variant) {
const variants = variant.split(/[\s]+/g);
variants.forEach(name => {
calculatedStyle = {
...calculatedStyle,
...VARIANT_STYLES.card[name as keyof typeof VARIANT_STYLES['card']],
};
calculatedCardStyle = {
...calculatedCardStyle,
...VARIANT_STYLES.cardContent[
name as keyof typeof VARIANT_STYLES['cardContent']
],
};
});
}
const { cardStyle, contentStyle } = getVariantStyles(variant);
return (
<Card style={calculatedStyle} className={className}>
<Card style={cardStyle} className={className}>
<ErrorBoundary slackChannel={slackChannel}>
{title && (
<>
@@ -217,7 +151,7 @@ export const InfoCard = ({
className={classNames(cardClassName, {
[classes.noPadding]: noPadding,
})}
style={calculatedCardStyle}
style={contentStyle}
>
{children}
</CardContent>
@@ -0,0 +1,86 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const VARIANT_STYLES = {
card: {
flex: {
display: 'flex',
flexDirection: 'column',
},
fullHeight: {
display: 'flex',
flexDirection: 'column',
height: '100%',
},
height100: {
display: 'flex',
flexDirection: 'column',
height: 'calc(100% - 10px)', // for pages without content header
marginBottom: '10px',
},
contentheader: {
height: 'calc(100% - 40px)', // for pages with content header
},
contentheadertabs: {
height: 'calc(100% - 97px)', // for pages with content header and tabs (Tingle)
},
noShrink: {
flexShrink: 0,
},
minheight300: {
minHeight: 300,
overflow: 'initial',
},
flat: {
boxShadow: 'none',
},
},
cardContent: {
fullHeight: {
flex: 1,
},
height100: {
flex: 1,
},
contentRow: {
display: 'flex',
flexDirection: 'row',
},
},
};
export const getVariantStyles = (variant?: string): Record<string, object> => {
const cardStyle = {};
const contentStyle = {};
if (variant) {
const variants = variant.split(/[\s]+/g);
variants.forEach(name => {
Object.assign(
cardStyle,
VARIANT_STYLES.card[name as keyof typeof VARIANT_STYLES['card']],
);
Object.assign(
contentStyle,
VARIANT_STYLES.cardContent[
name as keyof typeof VARIANT_STYLES['cardContent']
],
);
});
}
return { cardStyle, contentStyle };
};
@@ -50,6 +50,25 @@ export const Default = () => {
);
};
export const WithSubheader = () => {
return (
<TabbedCard title="Default Example Header" subheader="Subheader">
<CardTab label="Option 1">
<div style={cardContentStyle}>Some content</div>
</CardTab>
<CardTab label="Option 2">
<div style={cardContentStyle}>Some content 2</div>
</CardTab>
<CardTab label="Option 3">
<div style={cardContentStyle}>Some content 3</div>
</CardTab>
<CardTab label="Option 4">
<div style={cardContentStyle}>Some content 4</div>
</CardTab>
</TabbedCard>
);
};
const linkInfo = { title: 'Go to XYZ Location', link: '#' };
export const WithFooterLink = () => {
@@ -14,13 +14,12 @@
* limitations under the License.
*/
import React, { FC, useState, ReactElement, ReactNode } from 'react';
import React, { useState, ReactElement, ReactNode } from 'react';
import {
Card,
CardContent,
CardHeader,
Divider,
withStyles,
makeStyles,
Tabs,
Tab,
@@ -28,6 +27,7 @@ import {
} from '@material-ui/core';
import { BottomLink, BottomLinkProps } from '../BottomLink';
import { ErrorBoundary } from '../ErrorBoundary';
import { getVariantStyles } from '../InfoCard/variants';
const useTabsStyles = makeStyles(theme => ({
root: {
@@ -38,31 +38,46 @@ const useTabsStyles = makeStyles(theme => ({
backgroundColor: theme.palette.info.main,
height: theme.spacing(0.3),
},
header: {
padding: theme.spacing(2, 2, 2, 2.5),
},
headerTitle: {
fontWeight: 700,
},
headerSubheader: {
paddingTop: theme.spacing(1),
},
noPadding: {
padding: 0,
'&:last-child': {
paddingBottom: 0,
},
},
}));
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);
type Props = {
slackChannel?: string;
children?: ReactElement<TabProps>[];
onChange?: (event: React.ChangeEvent<{}>, value: number | string) => void;
title?: string;
subheader?: string;
value?: number | string;
deepLink?: BottomLinkProps;
variant?: string;
noPadding?: boolean;
};
const TabbedCard: FC<Props> = ({
const TabbedCard = ({
slackChannel = '#backstage',
children,
title,
subheader,
deepLink,
value,
onChange,
}) => {
variant,
noPadding,
}: Props) => {
const tabsClasses = useTabsStyles();
const [selectedIndex, selectIndex] = useState(0);
@@ -82,19 +97,36 @@ const TabbedCard: FC<Props> = ({
});
}
const { cardStyle, contentStyle } = getVariantStyles(variant);
return (
<Card>
<Card style={cardStyle}>
<ErrorBoundary slackChannel={slackChannel}>
{title && <BoldHeader title={title} />}
{title && (
<CardHeader
classes={{
root: tabsClasses.header,
title: tabsClasses.headerTitle,
subheader: tabsClasses.headerSubheader,
}}
title={title}
subheader={subheader}
/>
)}
<Tabs
classes={tabsClasses}
classes={{ root: tabsClasses.root, indicator: tabsClasses.indicator }}
value={value || selectedIndex}
onChange={handleChange}
>
{children}
</Tabs>
<Divider />
<CardContent>{selectedTabContent}</CardContent>
<CardContent
className={noPadding ? tabsClasses.noPadding : undefined}
style={contentStyle}
>
{selectedTabContent}
</CardContent>
{deepLink && <BottomLink {...deepLink} />}
</ErrorBoundary>
</Card>
@@ -118,7 +150,7 @@ type CardTabProps = TabProps & {
children: ReactNode;
};
const CardTab: FC<CardTabProps> = ({ children, ...props }) => {
const CardTab = ({ children, ...props }: CardTabProps) => {
const classes = useCardTabStyles();
return <Tab disableRipple classes={classes} {...props} />;