About page sprint4 (#544)

* Card sections of the About page
* Create index.test.tsx
* Add test that verifies no console errors and no undefined variables.
* Added unit test with snapshot
* use global.console.error
* Fix unit test for console.error()
* Remove areasOfFocusList since it's no longer used
* CSS adjustments from PR
* Add back in AlertWrapper
* github.com link opens in new tab
* adds comment to globalize console.error check
* Refactor AboutCard
* Fixing the top grid so it resizes correctly on mobile. (e.g. using `<Grid desktop={{col: 9}}>` will expand to full width when going to mobile.
* So AboutCard can now do 'large' cards (ones at the top) and 'small' cards (ones at the bottom that are 2x per row).
* change `desktop` -> `tablet`
* `<Grid col={1}>{' '}</Grid>`

Co-authored-by: Vim <86254807+vim-usds@users.noreply.github.com>
This commit is contained in:
TomNUSDS 2021-08-19 20:41:54 -07:00 committed by GitHub
commit a2eabda319
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 448 additions and 266 deletions

View file

@ -0,0 +1,22 @@
import * as React from 'react';
import {render} from '@testing-library/react';
import {LocalizedComponent} from '../../test/testHelpers';
import AboutCard from './AboutCard';
describe('rendering of the AboutCard', () => {
const {asFragment} = render(
<LocalizedComponent>
<AboutCard
imgSrc={'about:blank'}
header={'Test Header'}
actionText={'Test Action'}
actionUrl={'#'}>
Content body of the action card.
</AboutCard>
</LocalizedComponent>,
);
it('checks if component renders', () => {
expect(asFragment()).toMatchSnapshot();
});
});

View file

@ -0,0 +1,77 @@
import React from 'react';
import {Grid} from '@trussworks/react-uswds';
// the "body" section is the child object to allow for html versus just text
interface AboutCardProps {
imgSrc: string;
header: string;
size?: 'small' | 'large';
actionText?: string;
actionUrl?: string;
actionOpenInNewTab?: boolean;
className?: string;
}
const AboutCard = (props: React.PropsWithChildren<AboutCardProps>) => {
if (props.size === 'large') {
// large are the cards on top
// note it uses a top className='j40-aboutcard-lg-card'
return (
<Grid tablet={{col: true}} gap={'lg'} className={(props.className || '')}>
<Grid row className={'j40-aboutcard-lg-card'}>
<Grid tablet={{col: 3}} className={'j40-aboutpage-image-container'}>
<img
className={'j40-aboutcard-image'}
alt={props.header}
src={props.imgSrc}/>
</Grid>
<Grid tablet={{col: 9}}>
<Grid row>
<h3 className={'j40-section-header'}>{props.header}</h3>
<div className={'j40-section-body'}>{props.children}</div>
</Grid>
</Grid>
</Grid>
</Grid>
);
} else {
// small are the cards on the bottom
// note it uses a top className='j40-aboutcard-sm-card'
return (
<Grid tablet={{col: true}} gap={'lg'} className={(props.className || '')}>
<Grid row className={'j40-aboutcard-sm-card'}>
<Grid tablet={{col: 2}} className={'j40-aboutpage-image-container'}>
<img
className={'j40-aboutcard-image'}
alt={props.header}
src={props.imgSrc}/>
</Grid>
<Grid tablet={{col: 9}}>
<Grid row>
<h3 className={'j40-section-header'}>{props.header}</h3>
<div className={'j40-section-body'}>{props.children}</div>
<div className={'j40-section-footer'}>
{props.actionOpenInNewTab ?
<a
className={'j40-aboutcard-link'}
href={props.actionUrl}
target="_blank"
rel="noreferrer">{props.actionText}</a> :
<a
className={'j40-aboutcard-link'}
href={props.actionUrl}>{props.actionText}</a>
}
</div>
</Grid>
</Grid>
<Grid col={1}>{' '}</Grid>
</Grid>
</Grid>
);
}
};
export default AboutCard;

View file

@ -0,0 +1,17 @@
import React from 'react';
import {Grid} from '@trussworks/react-uswds';
type AboutCardsContainerProps = {
className?: string
}
// note: this assumes a J40MainGridContainer container!
const AboutCardsContainer = (props: React.PropsWithChildren<AboutCardsContainerProps>) => {
return (
<Grid row gap={'lg'} className={'j40-aboutcard-container ' + (props.className || '')}>
{props.children}
</Grid>
);
};
export default AboutCardsContainer;

View file

@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`rendering of the AboutCard checks if component renders 1`] = `
<DocumentFragment>
<div
class="grid-gap-lg tablet:grid-col"
data-testid="grid"
>
<div
class="grid-row j40-aboutcard-card"
data-testid="grid"
>
<div
class="grid-col-2"
data-testid="grid"
>
<img
alt="Test Header"
class="j40-aboutcard-image"
src="about:blank"
/>
</div>
<div
class="grid-col-10"
data-testid="grid"
>
<div
class="grid-row"
data-testid="grid"
>
<div
class="j40-section-header"
>
Test Header
</div>
<div
class="j40-section-body"
>
Content body of the action card.
</div>
<div
class="j40-section-footer"
>
<a
class="j40-aboutcard-link"
href="#"
>
Test Action
</a>
</div>
</div>
</div>
</div>
</div>
</DocumentFragment>
`;

View file

@ -6,13 +6,18 @@ import {GridContainer} from '@trussworks/react-uswds';
interface ILayoutProps {
children: ReactNode,
fullWidth?: boolean,
blueBackground?: boolean,
className?: string
}
const J40MainGridContainer = ({
children,
fullWidth = false,
className = 'j40-grid-container'}: ILayoutProps) => {
blueBackground = false,
className = 'j40-grid-container '}: ILayoutProps) => {
// is it a blue background strip?
className += (blueBackground ? 'j40-main-grid-blue-bk ' : '');
return fullWidth ? (
<div
className={'j40-grid-container ' + className}>

View file

@ -1,97 +0,0 @@
import * as React from 'react';
// import * as styles from './areasOfFocusList.module.scss'; // TODO: move styles
import {useIntl} from 'gatsby-plugin-intl';
import {defineMessages} from 'react-intl';
// this section seems too verbose? must be a more readable way to do this.
// this inlines the svg as data:image/svg+xml For larger images this
// can cause page bloat, but it should be fine here.
// @ts-ignore
import ecoIcon from '/node_modules/uswds/dist/img/usa-icons/eco.svg';
// @ts-ignore
import busIcon from '/node_modules/uswds/dist/img/usa-icons/directions_bus.svg';
// @ts-ignore
import homeIcon from '/node_modules/uswds/dist/img/usa-icons/home.svg';
// @ts-ignore
import groupsIcon from '/node_modules/uswds/dist/img/usa-icons/groups.svg';
import pollutionIcon // @ts-ignore
from '/node_modules/uswds/dist/img/usa-icons/severe_weather.svg';
// @ts-ignore
import washIcon from '/node_modules/uswds/dist/img/usa-icons/wash.svg';
// @ts-ignore
import publicIcon from '/node_modules/uswds/dist/img/usa-icons/public.svg';
const AreasOfFocusList = () => {
const intl = useIntl();
const messages = defineMessages({
climate: {
id: 'areasOfInterest.climate',
defaultMessage: 'Climate change',
description: 'item in areasOfInterest list',
},
energy: {
id: 'areasOfInterest.energy',
defaultMessage: 'Clean energy and energy efficiency',
description: 'item in areasOfInterest list',
},
transit: {
id: 'areasOfInterest.transit',
defaultMessage: 'Clean transit',
description: 'item in areasOfInterest list',
},
housing: {
id: 'areasOfInterest.housing',
defaultMessage: 'Affordable and sustainable housing',
description: 'item in areasOfInterest list',
},
training: {
id: 'areasOfInterest.training',
defaultMessage: 'Training and workforce development',
description: 'item in areasOfInterest list',
},
pollution: {
id: 'areasOfInterest.pollution',
defaultMessage: 'Remediation of legacy pollution',
description: 'item in areasOfInterest list',
},
water: {
id: 'areasOfInterest.water',
defaultMessage: 'Clean water infrastructure',
description: 'item in areasOfInterest list',
},
});
const readMoreList: (any | string)[][] = [
[publicIcon, intl.formatMessage(messages.climate)],
[ecoIcon, intl.formatMessage(messages.energy)],
[busIcon, intl.formatMessage(messages.transit)],
[homeIcon, intl.formatMessage(messages.housing)],
[groupsIcon, intl.formatMessage(messages.training)],
[pollutionIcon, intl.formatMessage(messages.pollution)],
[washIcon, intl.formatMessage(messages.water)],
];
return (
<div className={'j40-two-column-confine'}>
<ul className={'j40-two-column'}>
{readMoreList.map((item, index) => {
return (
<li key={`readmore_li_${index}`}>
<div className={'usa-icon-list__icon'}>
<img
className={'j40-two-column-icons-spacing'}
key={`readmore_img_${index}`}
src={item[0]} alt={item[1] + ' icon'}/>
</div>
<div
className={'usa-icon-list__content'}> {item[1]} </div>
</li>
);
})
}
</ul>
</div>
);
};
export default AreasOfFocusList;