diff --git a/client/package-lock.json b/client/package-lock.json index 0de7e06c..ff6eaa20 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -1503,6 +1503,11 @@ "tslib": "^2.1.0" } }, + "@formatjs/fast-memoize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@formatjs/fast-memoize/-/fast-memoize-1.1.1.tgz", + "integrity": "sha512-mIqBr5uigIlx13eZTOPSEh2buDiy3BCdMYUtewICREQjbb4xarDiVWoXSnrERM7NanZ+0TAHNXSqDe6HpEFQUg==" + }, "@formatjs/icu-messageformat-parser": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.7.tgz", @@ -1524,22 +1529,39 @@ "tslib": "^2.1.0" } }, - "@formatjs/intl-displaynames": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-1.2.10.tgz", - "integrity": "sha512-GROA2RP6+7Ouu0WnHFF78O5XIU7pBfI19WM1qm93l6MFWibUk67nCfVCK3VAYJkLy8L8ZxjkYT11VIAfvSz8wg==", + "@formatjs/intl": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@formatjs/intl/-/intl-1.13.2.tgz", + "integrity": "sha512-aonTXXaI/Guqr4t87m/XWfmgE9aPefDTLRnCwadxBDkUHw1/HQeUV+lp/3BgiPZfemIdBq9UgdigDCwrpEwrTA==", "dev": true, "requires": { - "@formatjs/intl-utils": "^2.3.0" + "@formatjs/ecma402-abstract": "1.9.4", + "@formatjs/fast-memoize": "1.1.1", + "@formatjs/icu-messageformat-parser": "2.0.7", + "@formatjs/intl-displaynames": "5.1.6", + "@formatjs/intl-listformat": "6.2.6", + "intl-messageformat": "9.7.1", + "tslib": "^2.1.0" + } + }, + "@formatjs/intl-displaynames": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-5.1.6.tgz", + "integrity": "sha512-s0eDyQFM2gQIPgn+MyaH+UcCvp6ui2ft9UW1gsIkjBkaprRlzKMd3fjxcUFO/I7oyXXA6FYR4qHR8u1I0+PvXA==", + "dev": true, + "requires": { + "@formatjs/ecma402-abstract": "1.9.4", + "tslib": "^2.1.0" } }, "@formatjs/intl-listformat": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-1.4.8.tgz", - "integrity": "sha512-WNMQlEg0e50VZrGIkgD5n7+DAMGt3boKi1GJALfhFMymslJb5i+5WzWxyj/3a929Z6MAFsmzRIJjKuv+BxKAOQ==", + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-6.2.6.tgz", + "integrity": "sha512-6FMdQY1+QKqJW5IhsVPFuEaR/uRiBKP+Y1oDvamZKzDfJ2vQmk9jqSF51VztlZH8XSfdO0IgvBzeRPHahKChQA==", "dev": true, "requires": { - "@formatjs/intl-utils": "^2.3.0" + "@formatjs/ecma402-abstract": "1.9.4", + "tslib": "^2.1.0" } }, "@formatjs/intl-pluralrules": { @@ -5772,8 +5794,7 @@ "csstype": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.8.tgz", - "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==", - "dev": true + "integrity": "sha512-jXKhWqXPmlUeoQnF/EhTtTl4C9SnrxSH/jZUih3jmO6lBKr99rP3/+FmrMj4EFpOXzMtXHAZkd3x0E6h6Fgflw==" }, "currently-unhandled": { "version": "0.4.1", @@ -9258,6 +9279,56 @@ "browser-lang": "^0.1.0", "intl": "^1.2.5", "react-intl": "^3.12.0" + }, + "dependencies": { + "@formatjs/intl-displaynames": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@formatjs/intl-displaynames/-/intl-displaynames-1.2.10.tgz", + "integrity": "sha512-GROA2RP6+7Ouu0WnHFF78O5XIU7pBfI19WM1qm93l6MFWibUk67nCfVCK3VAYJkLy8L8ZxjkYT11VIAfvSz8wg==", + "dev": true, + "requires": { + "@formatjs/intl-utils": "^2.3.0" + } + }, + "@formatjs/intl-listformat": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/@formatjs/intl-listformat/-/intl-listformat-1.4.8.tgz", + "integrity": "sha512-WNMQlEg0e50VZrGIkgD5n7+DAMGt3boKi1GJALfhFMymslJb5i+5WzWxyj/3a929Z6MAFsmzRIJjKuv+BxKAOQ==", + "dev": true, + "requires": { + "@formatjs/intl-utils": "^2.3.0" + } + }, + "intl-messageformat": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-7.8.4.tgz", + "integrity": "sha512-yS0cLESCKCYjseCOGXuV4pxJm/buTfyCJ1nzQjryHmSehlptbZbn9fnlk1I9peLopZGGbjj46yHHiTAEZ1qOTA==", + "dev": true, + "requires": { + "intl-format-cache": "^4.2.21", + "intl-messageformat-parser": "^3.6.4" + } + }, + "react-intl": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz", + "integrity": "sha512-cgumW29mwROIqyp8NXStYsoIm27+8FqnxykiLSawWjOxGIBeLuN/+p2srei5SRIumcJefOkOIHP+NDck05RgHg==", + "dev": true, + "requires": { + "@formatjs/intl-displaynames": "^1.2.0", + "@formatjs/intl-listformat": "^1.4.1", + "@formatjs/intl-relativetimeformat": "^4.5.9", + "@formatjs/intl-unified-numberformat": "^3.2.0", + "@formatjs/intl-utils": "^2.2.0", + "@types/hoist-non-react-statics": "^3.3.1", + "@types/invariant": "^2.2.31", + "hoist-non-react-statics": "^3.3.2", + "intl-format-cache": "^4.2.21", + "intl-messageformat": "^7.8.4", + "intl-messageformat-parser": "^3.6.4", + "shallow-equal": "^1.2.1" + } + } } }, "gatsby-plugin-page-creator": { @@ -10856,13 +10927,14 @@ "dev": true }, "intl-messageformat": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-7.8.4.tgz", - "integrity": "sha512-yS0cLESCKCYjseCOGXuV4pxJm/buTfyCJ1nzQjryHmSehlptbZbn9fnlk1I9peLopZGGbjj46yHHiTAEZ1qOTA==", + "version": "9.7.1", + "resolved": "https://registry.npmjs.org/intl-messageformat/-/intl-messageformat-9.7.1.tgz", + "integrity": "sha512-DNiuD+/59G9qaYu3U0KgwCV0zpN9XRoUvc8izSNCNAA5MknhiIUONFE0WtScP+E/7JfoENu+CX57P/SURRbI0A==", "dev": true, "requires": { - "intl-format-cache": "^4.2.21", - "intl-messageformat-parser": "^3.6.4" + "@formatjs/fast-memoize": "1.1.1", + "@formatjs/icu-messageformat-parser": "2.0.7", + "tslib": "^2.1.0" } }, "intl-messageformat-parser": { @@ -16313,23 +16385,20 @@ } }, "react-intl": { - "version": "3.12.1", - "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-3.12.1.tgz", - "integrity": "sha512-cgumW29mwROIqyp8NXStYsoIm27+8FqnxykiLSawWjOxGIBeLuN/+p2srei5SRIumcJefOkOIHP+NDck05RgHg==", + "version": "5.20.4", + "resolved": "https://registry.npmjs.org/react-intl/-/react-intl-5.20.4.tgz", + "integrity": "sha512-lYUL8hWkRHbpVtedGSjpQ1kK/x2AAGZHGgOHsU0SFDufHo2aS7xdvRcaxXD3PMVDuh53KcU+vTaun+bcrwKpbA==", "dev": true, "requires": { - "@formatjs/intl-displaynames": "^1.2.0", - "@formatjs/intl-listformat": "^1.4.1", - "@formatjs/intl-relativetimeformat": "^4.5.9", - "@formatjs/intl-unified-numberformat": "^3.2.0", - "@formatjs/intl-utils": "^2.2.0", + "@formatjs/ecma402-abstract": "1.9.4", + "@formatjs/icu-messageformat-parser": "2.0.7", + "@formatjs/intl": "1.13.2", + "@formatjs/intl-displaynames": "5.1.6", + "@formatjs/intl-listformat": "6.2.6", "@types/hoist-non-react-statics": "^3.3.1", - "@types/invariant": "^2.2.31", "hoist-non-react-statics": "^3.3.2", - "intl-format-cache": "^4.2.21", - "intl-messageformat": "^7.8.4", - "intl-messageformat-parser": "^3.6.4", - "shallow-equal": "^1.2.1" + "intl-messageformat": "9.7.1", + "tslib": "^2.1.0" } }, "react-is": { diff --git a/client/package.json b/client/package.json index 49d89c1d..bd2cb8a4 100644 --- a/client/package.json +++ b/client/package.json @@ -25,7 +25,7 @@ "lint": "eslint './src/**/*.{ts,tsx}' --ignore-pattern node_modules/ --ignore-pattern public --ignore-pattern *scss.d.ts", "lint:fix": "npm run lint -- --quiet --fix", "intl:extract": "formatjs extract 'src/(pages|components)/*.tsx' --out-file src/intl/en.json", - "intl:compile": "formatjs compile src/intl/en.json --ast --out-file compiled-lang/en.json" + "intl:compile-es": "formatjs compile src/intl/es.json --ast --out-file compiled-lang/es.json" }, "devDependencies": { "@formatjs/cli": "^4.2.15", @@ -73,9 +73,10 @@ "chroma-js": "^2.1.2", "maplibre-gl": ">=1.14.0", "query-string": "^7.0.0", - "react": "^17.0.1", + "react": "^17.0.2", "react-dom": "^17.0.1", "react-helmet": "^6.1.0", + "react-intl": "^5.20.4", "uswds": "^2.10.3" } } diff --git a/client/src/components/J40Header.tsx b/client/src/components/J40Header.tsx index d2ba8618..3a0db46b 100644 --- a/client/src/components/J40Header.tsx +++ b/client/src/components/J40Header.tsx @@ -10,17 +10,45 @@ import { } from '@trussworks/react-uswds'; import {Helmet} from 'react-helmet'; import {useFlags} from '../contexts/FlagContext'; +import {defineMessages} from 'react-intl'; const J40Header = () => { const flags = useFlags(); const intl = useIntl(); - const title = intl.formatMessage({ - id: '71L0pp', - defaultMessage: 'Justice40', - description: 'Title of the project', - }); - const [mobileNavOpen, setMobileNavOpen] = useState(false); + const messages = defineMessages({ + title: { + id: 'header.title', + defaultMessage: 'Justice40', + description: 'Title in header', + }, + about: { + id: 'header.about', + defaultMessage: 'About', + description: 'Navigate to the about page', + }, + explore: { + id: 'header.explore', + defaultMessage: 'Explore the tool', + description: 'Navigate to the Explore the tool page', + }, + methodology: { + id: 'header.methodology', + defaultMessage: 'Methodology', + description: 'Navigate to the Methodology page', + }, + contact: { + id: 'header.contact', + defaultMessage: 'Contact', + description: 'Navigate to the Contact page', + }, + timeline: { + id: 'header.timeline', + defaultMessage: 'Timeline', + description: 'Navigate to the Timeline page', + }, + }); + const title = intl.formatMessage(messages.title); const toggleMobileNav = (): void => setMobileNavOpen((prevOpen) => !prevOpen); @@ -34,31 +62,31 @@ const J40Header = () => { to={'/'} key={'about'} activeClassName="usa-current" - className={'j40-header'}>About], + className={'j40-header'}>{intl.formatMessage(messages.about)}], ['cejst', Explore the tool], + className={'j40-header'}>{intl.formatMessage(messages.explore)}], ['methodology', Methodology], + className={'j40-header'}>{intl.formatMessage(messages.methodology)}], ['contact', Contact], + className={'j40-header'}>{intl.formatMessage(messages.contact)}], ['timeline', Timeline], + className={'j40-header'}>{intl.formatMessage(messages.timeline)}], ]); // select which items from the above map to show, right now it's only two diff --git a/client/src/components/areasOfFocusList.tsx b/client/src/components/areasOfFocusList.tsx new file mode 100644 index 00000000..a1becef3 --- /dev/null +++ b/client/src/components/areasOfFocusList.tsx @@ -0,0 +1,97 @@ +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 ( +
- In an effort to address historical environmental injustices, - President Biden created the Justice40 Initiative on January - 27, 2021. The Justice40 Initiative directs 40% of the - benefits from federal investments in seven key areas to - overburdened and underserved communities. -
+- Federal agencies will prioritize benefits using a new - climate and economic justice screening tool. This screening - tool will be a map that visualizes data to compare the - cumulative impacts of environmental, climate, and economic - factors. It is being developed by the Council on - Environmental Quality (CEQ) with guidance from environmental - justice leaders and communities affected by environmental - injustices. The first version of the screening tool will be - released in July 2021. However, the screening tool and data - being used will be continuously updated to better reflect +
- Read more about the Justice40 Initiative in President - Biden’s - Executive Order on Tackling the Climate Crisis at Home and - Abroad. -
- -
- Successful initiatives are guided by direct input from the
- communities they are serving. CEQ commits to transparency,
- inclusivity, and iteration in building this screening tool.
+
- Transparent: The code and data behind the screening
- tool are open source, meaning it is available for the public
- to review and contribute to. This tool is being developed
- publicly so that communities, academic experts, and anyone
- who’s interested can be involved in the tool-building
- process.
+
- Inclusive: Many areas which lack investments also - lack environmental data and would be overlooked using - available environmental data. CEQ is actively reaching out - to groups that have historically been excluded from - decision-making, such as groups in rural and tribal areas, - to understand their needs and ask for their input. -
- -
- Iterative: The initial community prioritization list
- provided by the screening tool is the beginning of a
- collaborative process in score refinement, rather than a
- final answer. CEQ has received recommendations on data sets
- from community interviews, the White House Environmental
- Justice Advisory Council, and through public comment, but
- establishing a score that is truly representative will be a
- long-term, ongoing process. As communities submit feedback
- and recommendations, CEQ will continue to improve the tools
- being built and the processes for stakeholder and public
- engagement.
+