Commit 00dc5b43 authored by Matija Obreza's avatar Matija Obreza

Merge branch '119-layout-add-spacing' into 'master'

CSS Grid

Closes #119

See merge request !98
parents cce2b97c 16ddf98e
......@@ -69,6 +69,7 @@
"babel-preset-typescript": "^7.0.0-alpha.19",
"copy-webpack-plugin": "^6.0.2",
"cross-env": "^7.0.0",
"csstype": "^3.0.2",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.2",
"enzyme-to-json": "^3.5.0",
......
import * as React from 'react';
import { withStyles, WithStyles, createStyles } from '@material-ui/core';
import { Property } from 'csstype';
const styles = (theme) => createStyles({
container: {
display: 'grid',
gridTemplateColumns: 'repeat(12, 1fr)',
},
spacing5: {
gridGap: '5px',
},
spacing10: {
gridGap: '10px',
},
spacing15: {
gridGap: '15px',
},
spacing20: {
gridGap: '20px',
},
spacing1rem: {
gridGap: '1rem',
},
item: {
display: 'inline-grid',
gridColumn: 'span 12',
height: '100%',
},
xs: (props: any) => ({
[theme.breakpoints.up('xs')]: {
gridColumn: `span ${props.xs}`,
},
}),
sm: (props: any) => ({
[theme.breakpoints.up('sm')]: {
gridColumn: `span ${props.sm}`,
},
}),
md: (props: any) => ({
[theme.breakpoints.up('md')]: {
gridColumn: `span ${props.md}`,
},
}),
lg: (props: any) => ({
[theme.breakpoints.up('lg')]: {
gridColumn: `span ${props.lg}`,
},
}),
alignItems: (props: any) => ({
alignItems: props.alignItems,
}),
alignSelf: (props: any) => ({
alignSelf: props.alignSelf,
}),
});
type GridSize = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
interface IGridContainer extends React.ClassAttributes<any>, Partial<WithStyles> {
children: React.ReactNode;
spacing?: 5 | 10 | 15 | 20 | '1rem';
alignItems?: Property.AlignItems;
}
interface IGridItem extends React.ClassAttributes<any>, Partial<WithStyles> {
children: React.ReactNode;
xs?: GridSize;
sm?: GridSize;
md?: GridSize;
lg?: GridSize;
alignSelf?: Property.AlignSelf;
}
/**
* Container with a fixed space between items based on the 12 column grid layout
* Items have to be wrapped into <GridItem/>
*/
function GridContainer(props: IGridContainer): JSX.Element {
const { classes, children, spacing = '1rem', alignItems } = props;
return (
<div
className={ `
${classes.container}
${classes[`spacing${spacing}`]}
${alignItems ? classes.alignItems : ''}
` }
>
{ children }
</div>
);
}
/**
* By default GridItem takes 12 columns
* <GridItem sm={ 6 } md={ 4 }> equals <GridItem xs={ 12 } sm={ 6 } md={ 4 } lg={ 4 }>
*/
function GridItem(props: IGridItem): JSX.Element {
const { classes, children, xs, sm, md, lg, alignSelf } = props;
return (
<div
className={ `
${classes.item}
${xs ? classes.xs : ''}
${sm ? classes.sm : ''}
${md ? classes.md : ''}
${lg ? classes.lg : ''}
${alignSelf ? classes.alignSelf : ''}
` }
>
{ children }
</div>
);
}
const StyledGridContainer = withStyles(styles)(GridContainer);
const StyledGridItem = withStyles(styles)(GridItem);
export { StyledGridItem as GridItem, StyledGridContainer as GridContainer }
......@@ -24,6 +24,7 @@ import Table, { TextAlign } from '@gringlobal/client/ui/common/table/Table';
import { CooperatorOwnedTableConfiguration as TableConfiguration } from '@gringlobal/client/ui/common/table/TableConfiguration';
import { PageSection } from '@gringlobal/client/ui/common/layout/Section';
import Narrative from '@gringlobal/client/ui/common/Narrative';
import { GridContainer, GridItem } from '@gringlobal/client/ui/common/grid';
interface ICropTraitDetailsPage extends React.ClassAttributes<any>, WithTranslation {
......@@ -95,77 +96,81 @@ class CropTraitDetailsPage extends React.Component<ICropTraitDetailsPage> {
<ContentHeader title={ t('crop.public.p.traitsDetails.title') }/>
{ loading && <Loading /> }
{ cropTrait && (
<div>
<Card>
<CardHeader
title={ cropTrait.title || cropTrait.codedName }
subheader={ <code>{ cropTrait.codedName }</code> }
/>
<CardContent>
{ cropTrait.description && <Narrative>{ cropTrait.description }</Narrative> }
<Properties>
{ cropTrait.crop &&
<PropertiesItem title={ t('client:model.CropTrait.crop') }>
<CropLink crop={ cropTrait.crop } />
<GridContainer spacing="1rem">
<GridItem>
<Card>
<CardHeader
title={ cropTrait.title || cropTrait.codedName }
subheader={ <code>{ cropTrait.codedName }</code> }
/>
<CardContent>
{ cropTrait.description && <Narrative>{ cropTrait.description }</Narrative> }
<Properties>
{ cropTrait.crop &&
<PropertiesItem title={ t('client:model.CropTrait.crop') }>
<CropLink crop={ cropTrait.crop } />
</PropertiesItem>
}
<PropertiesItem title={ t('client:model.CropTrait.dataTypeCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.dataTypeCode } value={ cropTrait.dataTypeCode } />
</PropertiesItem>
}
<PropertiesItem title={ t('client:model.CropTrait.dataTypeCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.dataTypeCode } value={ cropTrait.dataTypeCode } />
</PropertiesItem>
<PropertiesItem title={ t('client:model.CropTrait.categoryCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.categoryCode } value={ cropTrait.categoryCode } />
</PropertiesItem>
{ [ 'maxLength', 'originalValueFormat', 'numericFormat', 'numericMinimum', 'numericMaximum', 'ontologyUrl' ].map((property) => property && (
<PropertiesItem key={ property } title={ t(`client:model.CropTrait.${property}`, `client:model._.${property}`) }>
{ cropTrait[property] }
<PropertiesItem title={ t('client:model.CropTrait.categoryCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.categoryCode } value={ cropTrait.categoryCode } />
</PropertiesItem>
)) }
{ cropTrait.originalValueTypeCode &&
<PropertiesItem title={ t('client:model.CropTrait.originalValueTypeCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.originalValueTypeCode } value={ cropTrait.originalValueTypeCode } />
</PropertiesItem>
}
{ ['isArchived', 'isCoded', 'isPeerReviewed'].map((property) => (
<PropertiesItem key={ property } title={ t(`client:model.CropTrait.${property}`, `client:model._.${property}`) }>
{ YesNoToBoolean(cropTrait[property]) ? t('common:label.yes') : t('common:label.no') }
</PropertiesItem>
)) }
{ cropTrait.createdDate &&
<PropertiesItem title={ t('client:model._.createdDate') }>
<PrettyDate value={ cropTrait.createdDate } />
</PropertiesItem>
}
{ cropTrait.modifiedDate &&
<PropertiesItem title={ t('client:model._.modifiedDate') }>
<PrettyDate value={ cropTrait.modifiedDate } />
</PropertiesItem>
}
{ cropTrait.ownedDate &&
<PropertiesItem title={ t('client:model._.ownedDate') }>
<PrettyDate value={ cropTrait.ownedDate } />
</PropertiesItem>
}
{ cropTrait.ownedBy &&
<PropertiesItem title={ t('client:model._.ownedBy') }>
<CooperatorLink cooperator={ cropTrait.ownedBy }/>
</PropertiesItem>
}
{ cropTrait.note &&
<PropertiesItem title={ t('client:model._.note') }>
{ cropTrait.note }
</PropertiesItem>
}
</Properties>
</CardContent>
<CardActions>
<Button variant="contained" color="secondary" onClick={ this.handleEdit }>
{ t('common:action.edit') }
</Button>
<Button variant="outlined" color="secondary" onClick={ this.handleRemove }>
{ t('common:action.remove') }
</Button>
</CardActions>
{ YesNoToBoolean(cropTrait.isCoded) && cropTrait.codes && cropTrait.codes.length > 0 &&
{ [ 'maxLength', 'originalValueFormat', 'numericFormat', 'numericMinimum', 'numericMaximum', 'ontologyUrl' ].map((property) => property && (
<PropertiesItem key={ property } title={ t(`client:model.CropTrait.${property}`, `client:model._.${property}`) }>
{ cropTrait[property] }
</PropertiesItem>
)) }
{ cropTrait.originalValueTypeCode &&
<PropertiesItem title={ t('client:model.CropTrait.originalValueTypeCode') }>
<CodeValueDisplay codeGroup={ CropTrait.CodeValues.originalValueTypeCode } value={ cropTrait.originalValueTypeCode } />
</PropertiesItem>
}
{ ['isArchived', 'isCoded', 'isPeerReviewed'].map((property) => (
<PropertiesItem key={ property } title={ t(`client:model.CropTrait.${property}`, `client:model._.${property}`) }>
{ YesNoToBoolean(cropTrait[property]) ? t('common:label.yes') : t('common:label.no') }
</PropertiesItem>
)) }
{ cropTrait.createdDate &&
<PropertiesItem title={ t('client:model._.createdDate') }>
<PrettyDate value={ cropTrait.createdDate } />
</PropertiesItem>
}
{ cropTrait.modifiedDate &&
<PropertiesItem title={ t('client:model._.modifiedDate') }>
<PrettyDate value={ cropTrait.modifiedDate } />
</PropertiesItem>
}
{ cropTrait.ownedDate &&
<PropertiesItem title={ t('client:model._.ownedDate') }>
<PrettyDate value={ cropTrait.ownedDate } />
</PropertiesItem>
}
{ cropTrait.ownedBy &&
<PropertiesItem title={ t('client:model._.ownedBy') }>
<CooperatorLink cooperator={ cropTrait.ownedBy }/>
</PropertiesItem>
}
{ cropTrait.note &&
<PropertiesItem title={ t('client:model._.note') }>
{ cropTrait.note }
</PropertiesItem>
}
</Properties>
</CardContent>
<CardActions>
<Button variant="contained" color="secondary" onClick={ this.handleEdit }>
{ t('common:action.edit') }
</Button>
<Button variant="outlined" color="secondary" onClick={ this.handleRemove }>
{ t('common:action.remove') }
</Button>
</CardActions>
</Card>
</GridItem>
{ YesNoToBoolean(cropTrait.isCoded) && cropTrait.codes && cropTrait.codes.length > 0 &&
<GridItem>
<PageSection title={ t('crop.public.p.traitsDetails.codes') }>
<Table
noWrap
......@@ -177,9 +182,9 @@ class CropTraitDetailsPage extends React.Component<ICropTraitDetailsPage> {
total={ cropTrait.codes.length }
/>
</PageSection>
}
</Card>
</div>
</GridItem>
}
</GridContainer>
) }
</>
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment