Move variant style handling for Infocard to seperate file and use some of it for TabbedCard
This commit is contained in:
@@ -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} />;
|
||||
|
||||
Reference in New Issue
Block a user