mirror of
https://github.com/DOI-DO/j40-cejst-2.git
synced 2025-08-03 23:34:18 -07:00
Modifies ExploreTool page to match sprint 4 design (#481)
* initial commit of sprint 4 explore page * adds styling on HowYouCanHelp module * troubleshooting li element on deployed URL removing local bullet styles * removing unused styles * recreating HowYouCanHelp * explicit list el styles * adds bullets back in * fixes tooltip style and alert padding * componentize MapLegend * fix links * inital intl and unit tests * adds trusswork tooltip for comparison * updates based on various feedback and disucssions: - removes react-tooltip - placeholder trussworks tooltip - removes download packet component - intl on HowYouCanHelp - updates MapLegend tests - add initial cy test on ExploreTool page * removes bold on alert * PR feedback: - removes location from J40Alert - localizes `COLOR KEY` * adds intl to constants file * modifies download zip URL to new S3 location * removes location depedencies on Alerts * add localization for HowYouCanHelp
This commit is contained in:
parent
ebe6180f7c
commit
174a0e1330
44 changed files with 974 additions and 426 deletions
11
client/src/components/AlertWrapper/alertWrapper.module.scss
Normal file
11
client/src/components/AlertWrapper/alertWrapper.module.scss
Normal file
|
@ -0,0 +1,11 @@
|
|||
.alertWrapper {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.alertHide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.alertWarning {
|
||||
margin-top: 0;
|
||||
}
|
14
client/src/components/AlertWrapper/alertWrapper.module.scss.d.ts
vendored
Normal file
14
client/src/components/AlertWrapper/alertWrapper.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
declare namespace AlertWrapperScssNamespace {
|
||||
export interface IAlertWrapperScss {
|
||||
alertWrapper: string;
|
||||
alertHide: string;
|
||||
alertWarning: string;
|
||||
}
|
||||
}
|
||||
|
||||
declare const AlertWrapperScssModule: AlertWrapperScssNamespace.IAlertWrapperScss & {
|
||||
/** WARNING: Only available when `css-loader` is used without `style-loader` or `mini-css-extract-plugin` */
|
||||
locals: AlertWrapperScssNamespace.IAlertWrapperScss;
|
||||
};
|
||||
|
||||
export = AlertWrapperScssModule;
|
41
client/src/components/AlertWrapper/index.tsx
Normal file
41
client/src/components/AlertWrapper/index.tsx
Normal file
|
@ -0,0 +1,41 @@
|
|||
import React from 'react';
|
||||
import {Alert} from '@trussworks/react-uswds';
|
||||
import {FormattedMessage} from 'gatsby-plugin-intl';
|
||||
|
||||
import * as styles from './alertWrapper.module.scss';
|
||||
|
||||
interface IAlertWrapperProps {
|
||||
hideWarningAlert?: boolean
|
||||
}
|
||||
|
||||
const AlertWrapper = ({hideWarningAlert}:IAlertWrapperProps) => {
|
||||
return (
|
||||
<div className={styles.alertWrapper}>
|
||||
<Alert className={'j40-sitealert'} type="info">
|
||||
<span className={'j40-sitealert-title'}><FormattedMessage
|
||||
id='header.alertTitleBeta'
|
||||
description={'Alerts that appear on every page - title'}
|
||||
defaultMessage={`Public beta`}/> - </span>
|
||||
<span className={'j40-sitealert-body'}>
|
||||
<FormattedMessage
|
||||
id='header.alertBodyBeta'
|
||||
description={'Alerts that appear on every page'}
|
||||
defaultMessage={`This website will be continuously updated`}/>
|
||||
</span>
|
||||
<br/>
|
||||
</Alert>
|
||||
<Alert
|
||||
className={`j40-sitealert' ${hideWarningAlert ? styles.alertHide : null} ${styles.alertWarning}`}
|
||||
type="warning">
|
||||
<b>Limited data sources — </b>
|
||||
This tool currently includes 16 datasets. Over time, datasets could be
|
||||
added, updated, or removed. The datasets come from a variety of sources
|
||||
based on availability, quality, and relevance to environmental, energy,
|
||||
and climate issues. Each dataset has limitations, such as how recently
|
||||
the data was updated.
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
}; ;
|
||||
|
||||
export default AlertWrapper;
|
|
@ -4,11 +4,10 @@ import {defineMessages} from 'react-intl';
|
|||
import * as styles from './datasetCard.module.scss';
|
||||
|
||||
interface IDatasetCardProps {
|
||||
key: number,
|
||||
datasetCardProps: { [key:string]: string }
|
||||
}
|
||||
|
||||
const DatasetCard = ({key, datasetCardProps}:IDatasetCardProps) => {
|
||||
const DatasetCard = ({datasetCardProps}:IDatasetCardProps) => {
|
||||
const intl = useIntl();
|
||||
const messages = defineMessages({
|
||||
whatIsIt: {
|
||||
|
@ -33,11 +32,6 @@ const DatasetCard = ({key, datasetCardProps}:IDatasetCardProps) => {
|
|||
},
|
||||
});
|
||||
|
||||
// Todo VS: figure out how to ignore unused variables such as keys
|
||||
// tried tsconfig, no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
// Also check associated unit test warning.
|
||||
console.log(key);
|
||||
|
||||
return (
|
||||
<div className={styles.datasetCard}>
|
||||
<h3 className={styles.datasetCardIndicator}>{datasetCardProps.indicator}</h3>
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
@import "../utils.scss";
|
||||
|
||||
$headingFontColor: #122e51;
|
||||
|
||||
.datasetContainer {
|
||||
background-color: #eef6fb;
|
||||
}
|
||||
|
@ -30,5 +28,5 @@ $headingFontColor: #122e51;
|
|||
}
|
||||
|
||||
.j40AlertContainer {
|
||||
background-color: #faf3d1;
|
||||
background-color: $j40AlertWarningColor;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ const DatasetContainer = () => {
|
|||
<h1 className={styles.datasetContainerHeader}>{intl.formatMessage(messages.cumulativeScore)}</h1>
|
||||
<p className={styles.datasetContainerSubTitle}>{intl.formatMessage(messages.subTitle)}</p>
|
||||
<div className={styles.datasetCardsContainer}>
|
||||
{cards.map((card, index) => <DatasetCard key={index} datasetCardProps={card}/>)}
|
||||
{cards.map((card) => <DatasetCard key={card.indicator} datasetCardProps={card}/>)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
.howYouCanHelpContainer {
|
||||
margin: 29px 24px 49px 42px;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
import React from 'react';
|
||||
import * as styles from './HowYouCanHelp.module.scss';
|
||||
|
||||
const HowYouCanHelp = () => {
|
||||
return (
|
||||
<div className={styles.howYouCanHelpContainer}>
|
||||
<h2>How You Can Help Improve the Tool</h2>
|
||||
<ul className={'usa-list'}>
|
||||
<li>If you have information that could help, we’d love to hear from you.</li>
|
||||
<li>View our full set of data sources and methodology
|
||||
where you can add or download sources and check statuses on our data roadmap.</li>
|
||||
<li>Check out our timeline and send feedback or attend relevant events.</li>
|
||||
<li>Contact us and share the stories of your community.</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HowYouCanHelp;
|
|
@ -0,0 +1,24 @@
|
|||
@import "../utils.scss";
|
||||
|
||||
.howYouCanHelpContainer {
|
||||
margin: 2rem 0;
|
||||
|
||||
.howYouCanHelpText {
|
||||
color: $headingFontColor;
|
||||
padding-left: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.howYouCanHelpHeader {
|
||||
color: $headingFontColor;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.howYouCanHelpList {
|
||||
list-style-type: disc;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.howYouCanHelpListWrapper {
|
||||
padding-left: 2rem;
|
||||
}
|
|
@ -1,6 +1,12 @@
|
|||
declare namespace HowYouCanHelpModuleScssNamespace {
|
||||
export interface IHowYouCanHelpModuleScss {
|
||||
howYouCanHelpContainer: string;
|
||||
howYouCanHelpHeader: string;
|
||||
howYouCanHelpBullet: string,
|
||||
listWrapper: string;
|
||||
howYouCanHelpText: string;
|
||||
howYouCanHelpList: string;
|
||||
howYouCanHelpListWrapper: string;
|
||||
}
|
||||
}
|
||||
|
95
client/src/components/HowYouCanHelp/index.tsx
Normal file
95
client/src/components/HowYouCanHelp/index.tsx
Normal file
|
@ -0,0 +1,95 @@
|
|||
import React from 'react';
|
||||
import {Link} from 'gatsby-plugin-intl';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {defineMessages} from 'react-intl';
|
||||
|
||||
import * as styles from './howYouCanHelp.module.scss';
|
||||
|
||||
const HowYouCanHelp = () => {
|
||||
const intl = useIntl();
|
||||
const messages = defineMessages({
|
||||
youCanHelpHeader: {
|
||||
id: 'howYouCanHelp.header.text',
|
||||
defaultMessage: 'How You Can Help Improve the Tool',
|
||||
description: 'the header of the how you can help section',
|
||||
},
|
||||
youCanHelpInfoText: {
|
||||
id: 'youCanHelpInfoText.list.element.prefix',
|
||||
defaultMessage: 'If you have helpful information, we’d love to',
|
||||
description: 'you can help info text ',
|
||||
},
|
||||
youCanHelpInfoLinkText: {
|
||||
id: 'youCanHelpInfoLink.link.text',
|
||||
defaultMessage: 'get an email from you',
|
||||
description: 'you can help info text ',
|
||||
},
|
||||
youCanHelpDataMethPrefixText: {
|
||||
id: 'youCanHelpDataMethPrefixText.link.prefix.text',
|
||||
defaultMessage: 'View our',
|
||||
description: 'view our',
|
||||
},
|
||||
youCanHelpDataMethLinkText: {
|
||||
id: 'youCanHelpDataMethLinkText.link.text',
|
||||
defaultMessage: 'Data & methodology',
|
||||
description: 'Data & methodology link',
|
||||
},
|
||||
youCanHelpDataMethSuffixText: {
|
||||
id: 'youCanHelpDataMethSuffixText.link.suffix.text',
|
||||
defaultMessage: 'and send us feedback',
|
||||
description: 'send us feedbackv via email',
|
||||
},
|
||||
youCanHelpSharingPrefixText: {
|
||||
id: 'youCanHelpSharingPrefixText.link.prefix.text',
|
||||
defaultMessage: 'Find your community and',
|
||||
description: 'find your community',
|
||||
},
|
||||
youCanHelpSharingLinkText: {
|
||||
id: 'youCanHelpSharingLinkText.link.text',
|
||||
defaultMessage: 'share your feedback',
|
||||
description: 'sharing link to email',
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={styles.howYouCanHelpContainer}>
|
||||
<h2 className={styles.howYouCanHelpHeader}>
|
||||
{intl.formatMessage(messages.youCanHelpHeader)}
|
||||
</h2>
|
||||
<ul className={styles.howYouCanHelpListWrapper}>
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
<div className={styles.howYouCanHelpText}>
|
||||
{intl.formatMessage(messages.youCanHelpInfoText)}
|
||||
{` `}
|
||||
<a href={'mailto:screeningtool.feedback@usds.gov'}>
|
||||
{intl.formatMessage(messages.youCanHelpInfoLinkText)}
|
||||
</a>
|
||||
{` `}.
|
||||
</div>
|
||||
</li>
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
<div className={styles.howYouCanHelpText}>
|
||||
{intl.formatMessage(messages.youCanHelpDataMethPrefixText)}
|
||||
{` `}
|
||||
<Link to={'/methodology'}>
|
||||
{intl.formatMessage(messages.youCanHelpDataMethLinkText)}
|
||||
</Link>
|
||||
{` `}
|
||||
{intl.formatMessage(messages.youCanHelpDataMethSuffixText)}
|
||||
</div>
|
||||
</li>
|
||||
<li className={styles.howYouCanHelpList}>
|
||||
<div className={styles.howYouCanHelpText}>
|
||||
{intl.formatMessage(messages.youCanHelpSharingPrefixText)}
|
||||
{` `}
|
||||
<a href={'mailto:screeningtool.feedback@usds.gov'}>
|
||||
{intl.formatMessage(messages.youCanHelpSharingLinkText)}
|
||||
</a>
|
||||
{` `}.
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HowYouCanHelp;
|
|
@ -0,0 +1,46 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of the HowYouCanHelp checks if various text fields are visible 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
<h2>
|
||||
How You Can Help Improve the Tool
|
||||
</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<div>
|
||||
If you have helpful information, we’d love to
|
||||
<a
|
||||
href="mailto:screeningtool.feedback@usds.gov"
|
||||
>
|
||||
get an email from you
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
View our
|
||||
<a
|
||||
href="/en/methodology"
|
||||
>
|
||||
Data & methodology
|
||||
</a>
|
||||
and send us feedback.
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div>
|
||||
Find your community and
|
||||
<a
|
||||
href="mailto:screeningtool.feedback@usds.gov"
|
||||
>
|
||||
share your feedback
|
||||
</a>
|
||||
.
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</DocumentFragment>
|
||||
`;
|
|
@ -0,0 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../../test/testHelpers';
|
||||
import HowYouCanHelp from '../index';
|
||||
|
||||
describe('rendering of the HowYouCanHelp', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<HowYouCanHelp />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
||||
it('checks if various text fields are visible', () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -3,7 +3,13 @@ import {useIntl} from 'gatsby-plugin-intl';
|
|||
import {defineMessages} from 'react-intl';
|
||||
import * as styles from './j40Alert.module.scss';
|
||||
|
||||
const J40Alert = () => {
|
||||
// This prop follows an inversion of control pattern allowing the user of this component to specify
|
||||
// how it's rendered. See more here: https://kentcdodds.com/blog/inversion-of-control
|
||||
interface IJ40AlertProps {
|
||||
alertStyle?: {[key:string]: string};
|
||||
}
|
||||
|
||||
const J40Alert = ({alertStyle}:IJ40AlertProps) => {
|
||||
const intl = useIntl();
|
||||
const messages = defineMessages({
|
||||
alertMsg: {
|
||||
|
@ -13,7 +19,7 @@ const J40Alert = () => {
|
|||
},
|
||||
});
|
||||
return (
|
||||
<div className={styles.j40Alert}>
|
||||
<div className={styles.j40Alert} style={alertStyle}>
|
||||
{intl.formatMessage(messages.alertMsg)}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,5 +1,13 @@
|
|||
.j40Alert {
|
||||
@import "../utils.scss";
|
||||
|
||||
@mixin j40AlertBase {
|
||||
font-size: large;
|
||||
font-weight: 600;
|
||||
padding: 1rem 0;
|
||||
background-color: $j40AlertWarningColor;
|
||||
margin-top: 2rem;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
|
||||
.j40Alert {
|
||||
@include j40AlertBase;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
declare namespace J40AlertScssNamespace {
|
||||
export interface IJ40AlertScss {
|
||||
j40Alert: string;
|
||||
j40AlertLeftPad: string;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`rendering of the J40Alert checks if various text fields are visible 1`] = `
|
||||
exports[`rendering of the J40Alert tests the rendering of J40Alert 1`] = `
|
||||
<DocumentFragment>
|
||||
<div>
|
||||
Limited data sources — Datasets may be added, updated, or removed.
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
import * as React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
import {LocalizedComponent} from '../../../test/testHelpers';
|
||||
import J40Alert from '../../J40Alert';
|
||||
import J40Alert from '../index';
|
||||
|
||||
describe('rendering of the J40Alert', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<J40Alert />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
it('tests the rendering of J40Alert', () => {
|
||||
const {asFragment} = render(
|
||||
<LocalizedComponent>
|
||||
<J40Alert />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
||||
it('checks if various text fields are visible', () => {
|
||||
expect(asFragment()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import React, {useState} from 'react';
|
||||
import {FormattedMessage, Link, useIntl} from 'gatsby-plugin-intl';
|
||||
import {Link, useIntl} from 'gatsby-plugin-intl';
|
||||
import {
|
||||
Alert,
|
||||
Header,
|
||||
NavMenuButton,
|
||||
PrimaryNav,
|
||||
|
@ -11,11 +10,7 @@ import {defineMessages} from 'react-intl';
|
|||
// @ts-ignore
|
||||
import siteLogo from '../../src/images/icon.png';
|
||||
|
||||
interface IJ40HeaderProps {
|
||||
location: Location
|
||||
}
|
||||
const J40Header = ({location}:IJ40HeaderProps) => {
|
||||
const isMethodologyPage = location.pathname.match(/methodology\/?/);
|
||||
const J40Header = () => {
|
||||
const intl = useIntl();
|
||||
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
||||
const messages = defineMessages({
|
||||
|
@ -119,29 +114,6 @@ const J40Header = ({location}:IJ40HeaderProps) => {
|
|||
</PrimaryNav>
|
||||
</div>
|
||||
</Header>
|
||||
<Alert className={'j40-sitealert'} type="info">
|
||||
<span className={'j40-sitealert-title'}><FormattedMessage
|
||||
id='header.alertTitleBeta'
|
||||
description={'Alerts that appear on every page - title'}
|
||||
defaultMessage={`Public beta`}/> - </span>
|
||||
<span className={'j40-sitealert-body'}>
|
||||
<FormattedMessage
|
||||
id='header.alertBodyBeta'
|
||||
description={'Alerts that appear on every page'}
|
||||
defaultMessage={`This website will be continuously updated`}/>
|
||||
</span>
|
||||
<br/>
|
||||
</Alert>
|
||||
{!isMethodologyPage && <Alert
|
||||
className={'j40-sitealert'}
|
||||
type="warning">
|
||||
<b>Limited data sources — </b>
|
||||
This tool currently includes 16 datasets. Over time, datasets could be
|
||||
added, updated, or removed. The datasets come from a variety of sources
|
||||
based on availability, quality, and relevance to environmental, energy,
|
||||
and climate issues. Each dataset has limitations, such as how recently
|
||||
the data was updated.
|
||||
</Alert>}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
117
client/src/components/MapLegend/index.tsx
Normal file
117
client/src/components/MapLegend/index.tsx
Normal file
|
@ -0,0 +1,117 @@
|
|||
import React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {Tooltip} from '@trussworks/react-uswds';
|
||||
|
||||
import * as styles from './mapLegend.module.scss';
|
||||
import * as constants from '../../data/constants';
|
||||
|
||||
// @ts-ignore
|
||||
import infoIcon from '/node_modules/uswds/dist/img/usa-icons/info_outline.svg';
|
||||
|
||||
// Todo VS: This information will be used in the re-design of the tool-tip
|
||||
// const getToolTipContent = (type:string) => {
|
||||
// const intl = useIntl();
|
||||
// const messages = defineMessages({
|
||||
// priorityHeader: {
|
||||
// id: 'tooltip.info.priority.header',
|
||||
// defaultMessage: constants.PRIORITIZED_COMMUNITY,
|
||||
// description: 'the header of the prioritized community tooltip',
|
||||
// },
|
||||
// thresholdHeader: {
|
||||
// id: 'tooltip.info.threshold.header',
|
||||
// defaultMessage: constants.THRESHOLD_COMMUNITY,
|
||||
// description: 'the header of the threshold community tooltip',
|
||||
// },
|
||||
// priorityText: {
|
||||
// id: 'tooltip.info.priority.text',
|
||||
// defaultMessage: 'A prioritized community is one that has a cumulative index score of Xth ' +
|
||||
// 'percentile and above. 40% of the benefits from investments outlined by the ' +
|
||||
// 'Justice40 Initiative should go to prioritized communities.',
|
||||
// description: 'the text of the prioritized community tooltip',
|
||||
// },
|
||||
// thresholdText: {
|
||||
// id: 'tooltip.info.threshold.text',
|
||||
// defaultMessage: 'Communities with a cumulative index score between Y - X.99th percentile are ' +
|
||||
// 'considered threshold communities. While these communities are currently not considered a ' +
|
||||
// 'prioritized community, this may change based on updates to the scoring method.',
|
||||
// description: 'the text of the threshold community tooltip',
|
||||
// },
|
||||
// });
|
||||
|
||||
// return (type === 'prioritized') ?
|
||||
// (
|
||||
// <div>
|
||||
// <h2>{intl.formatMessage(messages.priorityHeader)}</h2>
|
||||
// <p className={styles.legendTooltipText}>{intl.formatMessage(messages.priorityText)}</p>
|
||||
// </div>
|
||||
// ) :
|
||||
// (
|
||||
// <div>
|
||||
// <h2>{intl.formatMessage(messages.thresholdHeader)}</h2>
|
||||
// <p className={styles.legendTooltipText}>{intl.formatMessage(messages.thresholdText)}</p>
|
||||
// </div>
|
||||
// );
|
||||
// };
|
||||
|
||||
const MapLegend = () => {
|
||||
const intl = useIntl();
|
||||
|
||||
// Type definitions required for @trussworks tooltip. This type defines the div that wraps the icon.
|
||||
// This allows to pass children and other attributes.
|
||||
type IconWrapperProps = React.PropsWithChildren<{
|
||||
className?: string
|
||||
}> &
|
||||
JSX.IntrinsicElements['div'] &
|
||||
React.RefAttributes<HTMLDivElement>
|
||||
const IconWrapper: React.ForwardRefExoticComponent<IconWrapperProps> = React.forwardRef(
|
||||
({className, children, ...tooltipProps}: IconWrapperProps, ref) => (
|
||||
<div ref={ref} className={styles.infoIconWrapper} {...tooltipProps}>
|
||||
{children}
|
||||
</div>
|
||||
),
|
||||
);
|
||||
IconWrapper.displayName = 'custom info wrapper';
|
||||
|
||||
return (
|
||||
<div className={styles.legendContainer}>
|
||||
<h3 className={styles.legendHeader}>{intl.formatMessage(constants.EXPLORE_TOOL_PAGE_TEXT.LEGEND_LABEL)}</h3>
|
||||
<div className={styles.swatchContainer}>
|
||||
<div className={styles.legendItem}>
|
||||
<div className={styles.colorSwatch} id={styles.prioritized} />
|
||||
<span>{intl.formatMessage(constants.EXPLORE_TOOL_PAGE_TEXT.PRIORITY_LABEL)}</span>
|
||||
|
||||
{/* Using @trussworks tooltip */}
|
||||
<Tooltip<IconWrapperProps>
|
||||
label={`
|
||||
Communities that have cumulative
|
||||
index score of Xth percentile
|
||||
and above
|
||||
`}
|
||||
position='left'
|
||||
asCustom={IconWrapper}>
|
||||
<img className={styles.infoIcon} src={infoIcon} />
|
||||
</Tooltip>
|
||||
|
||||
</div>
|
||||
<div className={styles.legendItem}>
|
||||
<div className={styles.colorSwatch} id={styles.threshold} />
|
||||
<span>{intl.formatMessage(constants.EXPLORE_TOOL_PAGE_TEXT.THRESHOLD_LABEL)}</span>
|
||||
|
||||
{/* Using @trussworks tooltip */}
|
||||
<Tooltip<IconWrapperProps>
|
||||
label={`
|
||||
Communities with a cumulative
|
||||
index score between Y - X.99th
|
||||
percentile
|
||||
`}
|
||||
position='left'
|
||||
asCustom={IconWrapper}>
|
||||
<img className={styles.infoIcon} src={infoIcon} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapLegend;
|
96
client/src/components/MapLegend/mapLegend.module.scss
Normal file
96
client/src/components/MapLegend/mapLegend.module.scss
Normal file
|
@ -0,0 +1,96 @@
|
|||
@import "../utils.scss";
|
||||
|
||||
$min-color: #fafaf8;
|
||||
$med-color: rgba(26, 68, 128, 0.2);
|
||||
$max-color: rgba(26, 68, 128, 0.6);
|
||||
$alertInfoColor: #e7f6f8;
|
||||
|
||||
.legendContainer {
|
||||
margin: 1rem 1.2rem 1rem 2.5rem;
|
||||
font-size: 0.8em;
|
||||
border: 1px solid #8c9297;
|
||||
padding: 0 1.8rem;
|
||||
flex: 1;
|
||||
color: $headingFontColor;
|
||||
|
||||
.legendTooltipText {
|
||||
max-width: 14rem;
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $mobileBreakpoint) {
|
||||
margin: 1rem 0;
|
||||
}
|
||||
}
|
||||
|
||||
.legendHeader {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.swatchContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
@media screen and (max-width: $mobileBreakpoint) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
|
||||
.legendItem {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
span {
|
||||
font-size: medium;
|
||||
}
|
||||
|
||||
.infoIconWrapper {
|
||||
margin-left: 0.8rem;
|
||||
.infoIcon {
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
margin-top: 0.4rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: $mobileBreakpoint) {
|
||||
padding-left: 3rem;
|
||||
}
|
||||
}
|
||||
|
||||
.colorSwatch {
|
||||
box-sizing: border-box;
|
||||
height: 1.7rem;
|
||||
width: 1.7rem;
|
||||
margin-right: 10px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
#prioritized {
|
||||
background-color: $max-color;
|
||||
}
|
||||
|
||||
#threshold {
|
||||
background-color: $med-color;
|
||||
}
|
||||
|
||||
#nonPrioritized {
|
||||
background-color: $min-color;
|
||||
}
|
||||
|
||||
.legendTooltipTheme {
|
||||
color: $headingFontColor !important;
|
||||
background-color: white !important;
|
||||
opacity: 1 !important;
|
||||
border: $sidePanelBorder !important;
|
||||
box-shadow: 0 0 11px rgba(33, 33, 33, 0.2) !important;
|
||||
&.place-top {
|
||||
&:after {
|
||||
border-top-color: white !important;
|
||||
border-top-style: solid !important;
|
||||
border-top-width: 6px !important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,11 @@ declare namespace HowYouCanHelpModuleScssNamespace {
|
|||
prioritized: string,
|
||||
threshold: string,
|
||||
nonPrioritized: string,
|
||||
legendItem: string
|
||||
legendItem: string,
|
||||
infoIcon: string,
|
||||
legendTooltipText: string,
|
||||
legendTooltipTheme: string,
|
||||
infoIconWrapper: string,
|
||||
}
|
||||
}
|
||||
|
25
client/src/components/MapLegend/tests/mapLegend.test.tsx
Normal file
25
client/src/components/MapLegend/tests/mapLegend.test.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
import * as React from 'react';
|
||||
import {render} from '@testing-library/react';
|
||||
|
||||
import {LocalizedComponent} from '../../../test/testHelpers';
|
||||
import MapLegend from '../index';
|
||||
import * as constants from '../../../data/constants';
|
||||
|
||||
describe('rendering of the MapLegend', () => {
|
||||
const {getAllByText} = render(
|
||||
<LocalizedComponent>
|
||||
<MapLegend />
|
||||
</LocalizedComponent>,
|
||||
);
|
||||
|
||||
// Snapshot testing was unusable as the Tooltip lib rendered hash based class
|
||||
// names on each render
|
||||
|
||||
const intlPriorityLabel = constants.EXPLORE_TOOL_PAGE_TEXT.PRIORITY_LABEL.defaultMessage;
|
||||
const intlThresholdLabel = constants.EXPLORE_TOOL_PAGE_TEXT.THRESHOLD_LABEL.defaultMessage;
|
||||
|
||||
it('checks if various objects in the component rendered', () => {
|
||||
expect(getAllByText(intlPriorityLabel)[0]).toHaveTextContent(intlPriorityLabel);
|
||||
expect(getAllByText(intlThresholdLabel)[0]).toHaveTextContent(intlThresholdLabel);
|
||||
});
|
||||
});
|
44
client/src/components/MapWrapper/index.tsx
Normal file
44
client/src/components/MapWrapper/index.tsx
Normal file
|
@ -0,0 +1,44 @@
|
|||
import * as React from 'react';
|
||||
import {useIntl} from 'gatsby-plugin-intl';
|
||||
import {defineMessages} from 'react-intl';
|
||||
|
||||
import J40Alert from '../J40Alert';
|
||||
import J40Map from '../J40Map';
|
||||
|
||||
import * as styles from './mapWrapper.module.scss';
|
||||
import * as constants from '../../data/constants';
|
||||
|
||||
interface IMapWrapperProps {
|
||||
location: Location
|
||||
}
|
||||
|
||||
const MapWrapper = ({location}: IMapWrapperProps) => {
|
||||
const intl = useIntl();
|
||||
const messages = defineMessages({
|
||||
downloadLinkText: {
|
||||
id: 'mapwrapper.download.link',
|
||||
defaultMessage: 'Download the draft list of prioritized communities (pre-decisional) and datasets used',
|
||||
description: 'download link for datasets',
|
||||
},
|
||||
downloadContents: {
|
||||
id: 'mapwrapper.download.contents',
|
||||
defaultMessage: 'ZIP file will contain one .xlsx, one .csv and one .pdf (30 MB).',
|
||||
description: 'download link contents',
|
||||
},
|
||||
});
|
||||
return (
|
||||
<>
|
||||
<J40Alert alertStyle={{'padding-left': '1rem'}}/>
|
||||
<J40Map location={location}/>
|
||||
<div className={styles.mapCaptionTextLink}>
|
||||
<a href={constants.DOWNLOAD_ZIP_URL}>
|
||||
{intl.formatMessage(messages.downloadLinkText)}
|
||||
</a>
|
||||
</div>
|
||||
<div>{intl.formatMessage(messages.downloadContents)}</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default MapWrapper;
|
4
client/src/components/MapWrapper/mapWrapper.module.scss
Normal file
4
client/src/components/MapWrapper/mapWrapper.module.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
.mapCaptionTextLink {
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 0.4rem;
|
||||
}
|
13
client/src/components/MapWrapper/mapWrapper.module.scss.d.ts
vendored
Normal file
13
client/src/components/MapWrapper/mapWrapper.module.scss.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
declare namespace MapWrapperScssNamespace {
|
||||
export interface IMapWrapperScss {
|
||||
mapCaptionTextLink: string;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
declare const MapWrapperScssModule: MapWrapperScssNamespace.IMapWrapperScss & {
|
||||
/** WARNING: Only available when `css-loader` is used without `style-loader` or `mini-css-extract-plugin` */
|
||||
locals: MapWrapperScssNamespace.IMapWrapperScss;
|
||||
};
|
||||
|
||||
export = MapWrapperScssModule;
|
|
@ -1,10 +1,9 @@
|
|||
import React from 'react';
|
||||
import {Button} from '@trussworks/react-uswds';
|
||||
import * as styles from './downloadPacket.module.scss';
|
||||
// @ts-ignore
|
||||
import downloadIcon from '/node_modules/uswds/dist/img/usa-icons/file_download.svg';
|
||||
|
||||
export const cbgFileURL = 'https://justice40-data.s3.amazonaws.com/Score/usa.zip';
|
||||
import * as styles from './downloadPacket.module.scss';
|
||||
import * as constants from '../data/constants';
|
||||
|
||||
const DownloadPacket = () => {
|
||||
return (
|
||||
|
@ -16,7 +15,7 @@ const DownloadPacket = () => {
|
|||
prioritized communities (30,021 census block groups) and 18 datasets.
|
||||
</div>
|
||||
<div className={styles.downloadBoxButtonContainer}>
|
||||
<a id={'download-link'} href={cbgFileURL}>
|
||||
<a id={'download-link'} href={constants.DOWNLOAD_ZIP_URL}>
|
||||
<Button className={styles.downloadBoxButton} type="button">
|
||||
<div><img src={downloadIcon} /> </div>
|
||||
<div className={styles.downloadPacketText}>Download packet</div>
|
||||
|
|
|
@ -12,7 +12,7 @@ const Layout = ({children, location}: ILayoutProps) => {
|
|||
// @ts-ignore
|
||||
return (
|
||||
<URLFlagProvider location={location}>
|
||||
<J40Header location={location}/>
|
||||
<J40Header />
|
||||
<main id={'main-content'}>
|
||||
{children}
|
||||
</main>
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
$min-color: #fafaf8;
|
||||
$med-color: rgba(26, 68, 128, 0.2);
|
||||
$max-color: rgba(26, 68, 128, 0.6);
|
||||
|
||||
.legendContainer {
|
||||
margin-top: 19px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.swatchContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.legendItem {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
margin-right: 29px;
|
||||
}
|
||||
|
||||
.colorSwatch {
|
||||
box-sizing: border-box;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border: 1px solid #1a4480;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#prioritized {
|
||||
background-color: $max-color;
|
||||
}
|
||||
|
||||
#threshold {
|
||||
background-color: $med-color;
|
||||
}
|
||||
|
||||
#nonPrioritized {
|
||||
background-color: $min-color;
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
import React from 'react';
|
||||
import * as styles from './mapLegend.module.scss';
|
||||
|
||||
const MapLegend = () => {
|
||||
return (
|
||||
<div className={styles.legendContainer}>
|
||||
<h3 className={styles.legendHeader}>COLOR KEY</h3>
|
||||
<div className={styles.swatchContainer}>
|
||||
<div className={styles.legendItem}>
|
||||
<div className={styles.colorSwatch} id={styles.prioritized} />
|
||||
<span>Prioritized Community</span>
|
||||
</div>
|
||||
<div className={styles.legendItem}>
|
||||
<div className={styles.colorSwatch} id={styles.threshold} />
|
||||
<span>Threshold Community</span>
|
||||
</div>
|
||||
<div className={styles.legendItem}>
|
||||
<div className={styles.colorSwatch} id={styles.nonPrioritized} />
|
||||
<span>Non-Prioritized Community</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MapLegend;
|
|
@ -1,20 +0,0 @@
|
|||
import * as React from 'react';
|
||||
import J40Map from './J40Map';
|
||||
import MapLegend from '../components/mapLegend';
|
||||
|
||||
interface IMapWrapperProps {
|
||||
location: Location
|
||||
}
|
||||
|
||||
const MapWrapper = ({location}: IMapWrapperProps) => {
|
||||
return (
|
||||
<>
|
||||
<h2>Explore the Tool</h2>
|
||||
<J40Map location={location}/>
|
||||
<MapLegend />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default MapWrapper;
|
|
@ -12,3 +12,5 @@ $mobileBreakpoint: 400px;
|
|||
|
||||
//Styles with Dataset container
|
||||
$datasetContainerColor: #eef6fb;
|
||||
$headingFontColor: #122e51;
|
||||
$j40AlertWarningColor: #faf3d1;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue