diff --git a/client/src/components/AboutCard/AboutCard.test.tsx b/client/src/components/AboutCard/AboutCard.test.tsx new file mode 100644 index 00000000..51edbcb2 --- /dev/null +++ b/client/src/components/AboutCard/AboutCard.test.tsx @@ -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( + + + Content body of the action card. + + , + ); + + it('checks if component renders', () => { + expect(asFragment()).toMatchSnapshot(); + }); +}); diff --git a/client/src/components/AboutCard/AboutCard.tsx b/client/src/components/AboutCard/AboutCard.tsx new file mode 100644 index 00000000..4821515e --- /dev/null +++ b/client/src/components/AboutCard/AboutCard.tsx @@ -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) => { + if (props.size === 'large') { + // large are the cards on top + // note it uses a top className='j40-aboutcard-lg-card' + return ( + + + + {props.header} + + + + +

{props.header}

+
{props.children}
+
+
+ +
+
+ ); + } else { + // small are the cards on the bottom + // note it uses a top className='j40-aboutcard-sm-card' + return ( + + + + {props.header} + + + + +

{props.header}

+
{props.children}
+
+ {props.actionOpenInNewTab ? + {props.actionText} : + {props.actionText} + } +
+
+
+ {' '} +
+
+ ); + } +}; + +export default AboutCard; diff --git a/client/src/components/AboutCard/AboutCardsContainer.tsx b/client/src/components/AboutCard/AboutCardsContainer.tsx new file mode 100644 index 00000000..85f8773b --- /dev/null +++ b/client/src/components/AboutCard/AboutCardsContainer.tsx @@ -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) => { + return ( + + {props.children} + + ); +}; + +export default AboutCardsContainer; diff --git a/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap b/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap new file mode 100644 index 00000000..ab5e9205 --- /dev/null +++ b/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`rendering of the AboutCard checks if component renders 1`] = ` + +
+
+
+ Test Header +
+
+
+
+ Test Header +
+
+ Content body of the action card. +
+ +
+
+
+
+
+`; diff --git a/client/src/components/J40MainGridContainer.tsx b/client/src/components/J40MainGridContainer.tsx index 5f3b38a8..9b9de73f 100644 --- a/client/src/components/J40MainGridContainer.tsx +++ b/client/src/components/J40MainGridContainer.tsx @@ -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 ? (
diff --git a/client/src/components/areasOfFocusList.tsx b/client/src/components/areasOfFocusList.tsx deleted file mode 100644 index a1becef3..00000000 --- a/client/src/components/areasOfFocusList.tsx +++ /dev/null @@ -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 ( -
-
    - {readMoreList.map((item, index) => { - return ( -
  • -
    - {item[1] -
    -
    {item[1]}
    -
  • - ); - }) - } -
-
- ); -}; - -export default AreasOfFocusList; diff --git a/client/src/images/about-j40.svg b/client/src/images/about-j40.svg new file mode 100644 index 00000000..ba896055 --- /dev/null +++ b/client/src/images/about-j40.svg @@ -0,0 +1 @@ +40% \ No newline at end of file diff --git a/client/src/images/about-usmap.svg b/client/src/images/about-usmap.svg new file mode 100644 index 00000000..46f9d3cf --- /dev/null +++ b/client/src/images/about-usmap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/src/pages/index.test.tsx b/client/src/pages/index.test.tsx new file mode 100644 index 00000000..474cec4e --- /dev/null +++ b/client/src/pages/index.test.tsx @@ -0,0 +1,30 @@ +import * as React from 'react'; +import {render} from '@testing-library/react'; +import Index from './index'; +import {LocalizedComponent} from '../test/testHelpers'; + +// TODO: Move this to a location that will detect on all tests +// See ticket: #550 +jest.spyOn(console, 'error').mockImplementation(() => {}); + +afterAll(() => { + // Restore mock after all tests are done, so it won't affect other test suites + jest.resetAllMocks(); +}); + +describe('rendering of the component', () => { + const {asFragment} = render( + + + , + ); + + it(`should not contain 'undefined" anywhere`, () => { + expect(asFragment()).not.toContain('undefined'); + }); + + it('No console errors', () => { + expect(global.console.error).toBeCalledTimes(0); + }); +}); + diff --git a/client/src/pages/index.tsx b/client/src/pages/index.tsx index ad5e8687..7d751d2b 100644 --- a/client/src/pages/index.tsx +++ b/client/src/pages/index.tsx @@ -1,12 +1,29 @@ import * as React from 'react'; import {defineMessages} from 'react-intl'; -import {Grid} from '@trussworks/react-uswds'; import {FormattedMessage, useIntl} from 'gatsby-plugin-intl'; -import AreasOfFocusList from '../components/areasOfFocusList'; import AlertWrapper from '../components/AlertWrapper'; import J40MainGridContainer from '../components/J40MainGridContainer'; import Layout from '../components/layout'; +import AboutCard from '../components/AboutCard/AboutCard'; + +// @ts-ignore +import aboutUSMapImg from '../images/about-usmap.svg'; +// @ts-ignore +import aboutJ40Img from '../images/about-j40.svg'; +import accountBalanceIcon // @ts-ignore + from '/node_modules/uswds/dist/img/usa-icons/account_balance.svg'; + +import groupsIcon from // @ts-ignore + '/node_modules/uswds/dist/img/usa-icons/groups.svg'; + +import commentIcon from // @ts-ignore + '/node_modules/uswds/dist/img/usa-icons/comment.svg'; + +import githubIcon from // @ts-ignore + '/node_modules/uswds/dist/img/usa-icons/github.svg'; +import AboutCardsContainer from '../components/AboutCard/AboutCardsContainer'; + interface IndexPageProps { location: Location; @@ -16,11 +33,6 @@ interface IndexPageProps { const IndexPage = ({location}: IndexPageProps) => { const intl = useIntl(); const messages = defineMessages({ - aboutHeader: { - id: 'index.aboutContent.header', - defaultMessage: 'About Justice40', - description: 'h1 header on About page', - }, presidentalLinkUri: { id: 'index.presidentalLinkUri', defaultMessage: 'https://www.whitehouse.gov/briefing-room/' + @@ -53,151 +65,157 @@ const IndexPage = ({location}: IndexPageProps) => { return ( + + - - - + + - - - -
-

{intl.formatMessage(messages.aboutHeader)}

- -

- -

-

- + + + + + + -

-

{intl.formatMessage(messages.presidentalLinkLabel)} - , - }}/> -

+ values={{ + presidentLink: + {intl.formatMessage(messages.presidentalLinkLabel)} + , + }}/> +

-

- -

+ + - + {/* */} + {/* */} + {/* */} + {/* */} + {/* */} -

- -

+ {/* */} + {/*

About the screening tool

*/} + {/* */} + {/*
*/} + {/*
*/} -

-

+ {/* */} + {/* */} + {/* */} + {/* */} -

- {intl.formatMessage(messages.transparentLabel)}, - }}/> -

+ {/* */} + {/*

About the Justice40 Initiative

*/} + {/* */} + {/*
*/} + {/*
*/} + {/*
*/} + -

- {intl.formatMessage(messages.inclusiveLabel)}, - }}/> -

+ + + + + Download the screening tool’s draft list of prioritized + communities and information on how to use it for your program in + the future on the data and methodology page. + -

- {intl.formatMessage(messages.iterativeLabel)}, - }}/> -

-
-
-
+ + Find your community or communities that you may be familiar with + and check their prioritization information on the map. + +
+
+ + + + + + Have ideas about how to acknowledge the on-the-ground experiences + of your community? + + + + The screening tool’s code is open source, which means it is + available for the public to view and contribute to. Anyone can + view and contribute on GitHub. + +
); }; diff --git a/client/src/styles/global.scss b/client/src/styles/global.scss index 06cecaf8..055b7e4f 100644 --- a/client/src/styles/global.scss +++ b/client/src/styles/global.scss @@ -29,43 +29,12 @@ $theme-font-role-heading: "sans"; // Custom SASS/CSS goes here $j40-max-width: 80ex; $primary-color: #112f4e; +$j40-blue-background-color: #EFF6FB; #main-content { border-top: 0; } -.j40-two-column { - overflow: hidden; - padding: 0; - - @media (min-width: 40em) { - column-count: 2; - column-gap: 1em; - } - @media (max-width: 40em) { - column-count: 1; - column-gap: 0; - } -} - -.j40-two-column > * { - display: inline-flex; - width: 90%; - padding-bottom: 1.2em; /* space between items */ - padding-left: 1em; -} - -.j40-two-column-icons-spacing { - padding-right: 1em; - width: 2.3em; - max-width: revert; -} - -.j40-two-column-confine { - display: inline-flex; - max-width: fit-content; -} - @include at-media("mobile-lg") { .j40-grid-container { line-height: 1.5rem; @@ -198,6 +167,25 @@ $primary-color: #112f4e; } } +// we can use to to make all section headers consistent +.j40-section-sm-header { + font-weight: bold; + padding-bottom: 0.24rem; + padding-right: 0.24rem; +} + +.j40-section-sm-body { + line-height: 1.5; + padding-bottom: 1.2rem; + padding-right: 1.2rem; + +} + +.j40-section-sm-footer { + padding-bottom: 0.5rem; +} + + // This should really be part of uswds and use $theme-step-indicator-segment-color-complete // The Progress element doesn't really support color changing the line connecting progress // (like the Steps element does) and the checkbox. @@ -337,6 +325,7 @@ $primary-color: #112f4e; list are not affected (e.g.
    • not styled

    • */ .j40-process-list-wrapper > { $j40-steps-list-color: #002D3F; + ul { margin-top: 3rem; margin-bottom: 1rem; @@ -424,3 +413,66 @@ ul.j40-process-nested-list { margin-block-end: auto; font-style: italic; } + +/* this is used by J40MainGridContainer to show a blue background */ +.j40-main-grid-blue-bk { + background-color: $j40-blue-background-color; +} + +/* about card - based on datasetCard... need to combine */ +.j40-aboutcard-container { + + .j40-aboutcard-lg-card { + margin: 1.2rem 0 3rem 0; + + .j40-aboutpage-image-container { + width: 10.5rem; + padding: 1.24rem 1.24rem 0 .24rem; + } + + .j40-aboutcard-image { + flex: 1 0 10%; + align-self: flex-start; + } + + .j40-aboutcard-header { + } + + .j40-aboutcard-body { + } + + .j40-aboutcard-footer { + } + + .j40-aboutcard-link { + font-weight: bold; + } + } + + .j40-aboutcard-sm-card { + margin: 1.2rem 0 3rem 0; + + .j40-aboutpage-image-container { + padding: 1.24rem 1.24rem 0 .24rem; + } + + .j40-aboutcard-image { + width: 3rem; + } + + .j40-aboutcard-header { + } + + .j40-aboutcard-body { + } + + .j40-aboutcard-footer { + } + + .j40-aboutcard-link { + font-weight: bold; + } + } + +} +