diff --git a/app/scripts/components/common/banner/banner.scss b/app/scripts/components/common/banner/banner.scss
new file mode 100644
index 000000000..4cd04cc1d
--- /dev/null
+++ b/app/scripts/components/common/banner/banner.scss
@@ -0,0 +1,3 @@
+.usa-banner__button:after {
+ top: 3px;
+}
\ No newline at end of file
diff --git a/app/scripts/components/common/banner/index.tsx b/app/scripts/components/common/banner/index.tsx
index 6272bb57f..127d6b1fd 100644
--- a/app/scripts/components/common/banner/index.tsx
+++ b/app/scripts/components/common/banner/index.tsx
@@ -1,78 +1,136 @@
import React, { useState } from 'react';
-import { Icon } from '@trussworks/react-uswds';
+import { decode } from 'he';
import {
USWDSBanner,
- USWDSBannerContent
+ USWDSBannerContent,
+ USWDSBannerButton,
+ USWDSBannerFlag,
+ USWDSBannerHeader,
+ USWDSBannerIcon,
+ USWDSBannerGuidance,
+ USWDSMediaBlockBody
} from '$components/common/uswds/banner';
-const BANNER_KEY = 'dismissedBannerUrl';
-
-function hasExpired(expiryDatetime) {
- const expiryDate = new Date(expiryDatetime);
- const currentDate = new Date();
- return !!(currentDate > expiryDate);
+interface Guidance {
+ left?: GuidanceContent;
+ right?: GuidanceContent;
}
-enum BannerType {
- info = 'info',
- warning = 'warning'
+interface GuidanceContent {
+ icon?: string;
+ iconAlt?: string;
+ title?: string;
+ text?: string;
}
-const infoTypeFlag = BannerType.info;
interface BannerProps {
- appTitle: string;
- expires: Date;
- url: string;
- text: string;
- type?: BannerType;
+ headerText?: string;
+ headerActionText?: string;
+ ariaLabel?: string;
+ flagImgAlt?: string;
+ leftGuidance?: GuidanceContent;
+ rightGuidance?: GuidanceContent;
+ className?: string;
+ defaultIsOpen?: boolean;
+ contentId?: string;
}
+const DEFAULT_HEADER_TEXT =
+ 'An official website of the United States government';
+
+const DEFAULT_HEADER_ACTION_TEXT = "Here's how you know";
+
+const DEFAULT_GUIDANCE: Guidance = {
+ left: {
+ title: 'Official websites use .gov',
+ text: 'A .gov website belongs to an official government organization in the United States.',
+ iconAlt: 'Dot gov icon',
+ icon: '/img/icon-dot-gov.svg'
+ },
+ right: {
+ title: 'Secure .gov websites use HTTPS',
+ text: `
+ A lock or https:// means you've safely
+ connected to the .gov website. Share sensitive information only on
+ official, secure websites.
+ `,
+ iconAlt: 'HTTPS icon',
+ icon: '/img/icon-https.svg'
+ }
+};
+
+const GuidanceBlock = ({
+ content,
+ className
+}: {
+ content: GuidanceContent;
+ className?: string;
+}) => (
+
+ {content.title}
+
+
+
+ + Discover insights on how the COVID-19 pandemic + impacted air quality worldwide, observed through NASA's satellite data.
`, + expires: '2026-08-03T12:00:00-04:00', + type: 'info', + slim: true, + showIcon: true }, navItems: { mainNavItems, diff --git a/package.json b/package.json index 831ffd913..7b19318b0 100644 --- a/package.json +++ b/package.json @@ -160,6 +160,7 @@ "@turf/simplify": "^6.5.0", "@turf/union": "^6.5.0", "@types/geojson": "^7946.0.10", + "@types/he": "^1.2.3", "@types/mdx": "^2.0.1", "@types/react": "18.0.32", "@types/react-dom": "18.0.11", @@ -181,6 +182,7 @@ "google-polyline": "^1.0.3", "gulp-postcss": "^10.0.0", "gulp-sass": "^6.0.0", + "he": "^1.2.0", "history": "^5.1.0", "intersection-observer": "^0.12.0", "jest-environment-jsdom": "^28.1.3", diff --git a/parcel-resolver-veda/index.d.ts b/parcel-resolver-veda/index.d.ts index a47e84c72..156df2c12 100644 --- a/parcel-resolver-veda/index.d.ts +++ b/parcel-resolver-veda/index.d.ts @@ -260,18 +260,37 @@ declare module 'veda' { * Since we are moving forward to ditching VEDA faux module */ - enum BannerType { + enum SiteAlertType { info = 'info', - warning = 'warning' + emergency = 'emergency' } - const infoTypeFlag = BannerType.info; - interface BannerData { + const infoTypeFlag = SiteAlertType.info; + interface SiteAlertData { expires: Date; title: string; - url: string; + content: string; + type?: SiteAlertType; + } + + interface BannerData { + headerText?: string; + headerActionText?: string; + ariaLabel?: string; + flagImgSrc: string; + flagImgAlt?: string; + leftGuidance?: GuidanceContent; + rightGuidance?: GuidanceContent; + className?: string; + defaultIsOpen?: boolean; + contentId?: string; + } + + interface GuidanceContent { + icon: string; + iconAlt?: string; + title: string; text: string; - type?: BannerType; } interface CookieConsentData { @@ -342,6 +361,7 @@ declare module 'veda' { export const getBoolean: (variable: string) => boolean; + export const getSiteAlertFromVedaConfig: () => SiteAlertData | undefined; export const getBannerFromVedaConfig: () => BannerData | undefined; export const getCookieConsentFromVedaConfig: () => | CookieConsentData @@ -349,12 +369,8 @@ declare module 'veda' { export const getNavItemsFromVedaConfig: () => | { - mainNavItems: - | (NavLinkItem | DropdownNavLink)[] - | undefined; - subNavItems: - | (NavLinkItem | DropdownNavLink)[] - | undefined; + mainNavItems: (NavLinkItem | DropdownNavLink)[] | undefined; + subNavItems: (NavLinkItem | DropdownNavLink)[] | undefined; } | undefined; diff --git a/parcel-resolver-veda/index.js b/parcel-resolver-veda/index.js index f00ca4028..90b2a64ae 100644 --- a/parcel-resolver-veda/index.js +++ b/parcel-resolver-veda/index.js @@ -86,7 +86,6 @@ function generateMdxDataObject(data) { function getCookieConsentForm(result) { if (!result.cookieConsentForm) return undefined; else { - const parsedCopy = md.render(result.cookieConsentForm.copy); const trimmedCopy = parsedCopy.replace(/(\r\n|\n|\r)/gm, ''); return JSON.stringify({ @@ -97,19 +96,45 @@ function getCookieConsentForm(result) { } } +function getSiteAlertContent(result) { + if (!result.siteAlert) return undefined; + + const { title, content, expires, type, slim, showIcon, className } = + result.siteAlert; + + const parsedText = content ? md.render(content) : ''; + const trimmedText = parsedText.replace(/(\r\n|\n|\r)/gm, ''); + return JSON.stringify({ + title, + content: trimmedText, + expires, + type, + slim, + showIcon, + className + }); +} + function getBannerContent(result) { if (!result.banner) return undefined; - else { - const parsedCopy = md.render(result.banner.text); - const trimmedCopy = parsedCopy.replace(/(\r\n|\n|\r)/gm, ''); - return JSON.stringify({ - title: result.banner.title, - text: trimmedCopy, - url: result.banner.url, - expires: result.banner.expires, - type: result.banner.type - }); - } + + const { title, text, leftGuidance, rightGuidance } = result.banner; + + const parsedText = text ? md.render(text) : ''; + const trimmedText = parsedText.replace(/(\r\n|\n|\r)/gm, ''); + + return JSON.stringify({ + headerText: title, + headerActionText: "Here's how you know", + ariaLabel: trimmedText || title, + flagImgSrc: '/img/us_flag_small.png', + flagImgAlt: '', + leftGuidance, + rightGuidance, + className: '', + defaultIsOpen: false, + contentId: 'gov-banner-content' + }); } // Using all the "key: path" combinations under config.pageOverrides, load the @@ -228,6 +253,7 @@ module.exports = new Resolver({ strings: ${JSON.stringify(withDefaultStrings(result.strings))}, booleans: ${JSON.stringify(withDefaultStrings(result.booleans))}, banner: ${getBannerContent(result)}, + siteAlert: ${getSiteAlertContent(result)}, navItems: ${JSON.stringify(result.navItems)}, cookieConsentForm: ${getCookieConsentForm(result)} }; @@ -248,6 +274,7 @@ module.exports = new Resolver({ export const getConfig = () => config; export const getBannerFromVedaConfig = () => config.banner; + export const getSiteAlertFromVedaConfig = () => config.siteAlert; export const getNavItemsFromVedaConfig = () => config.navItems; export const getCookieConsentFromVedaConfig = () => config.cookieConsentForm; diff --git a/yarn.lock b/yarn.lock index 480a48781..180b7d2b6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4641,6 +4641,11 @@ dependencies: "@types/unist" "*" +"@types/he@^1.2.3": + version "1.2.3" + resolved "http://verdaccio.ds.io:4873/@types%2fhe/-/he-1.2.3.tgz#c33ca3096f30cbd5d68d78211572de3f9adff75a" + integrity sha512-q67/qwlxblDzEDvzHhVkwc1gzVWxaNxeyHUBF4xElrvjL11O+Ytze+1fGpBHlr/H9myiBUaUXNnNPmBHxxfAcA== + "@types/hoist-non-react-statics@*": version "3.3.1" resolved "http://verdaccio.ds.io:4873/@types%2fhoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" @@ -9417,6 +9422,11 @@ hat@0.0.3: resolved "http://verdaccio.ds.io:4873/hat/-/hat-0.0.3.tgz#bb014a9e64b3788aed8005917413d4ff3d502d8a" integrity sha1-uwFKnmSzeIrtgAWRdBPU/z1QLYo= +he@^1.2.0: + version "1.2.0" + resolved "http://verdaccio.ds.io:4873/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + history@^5.1.0, history@^5.2.0: version "5.3.0" resolved "http://verdaccio.ds.io:4873/history/-/history-5.3.0.tgz#1548abaa245ba47992f063a0783db91ef201c73b" @@ -11378,7 +11388,7 @@ macos-release@^3.1.0: resolved "http://verdaccio.ds.io:4873/macos-release/-/macos-release-3.3.0.tgz#92cb67bc66d67c3fde4a9e14f5f909afa418b072" integrity sha512-tPJQ1HeyiU2vRruNGhZ+VleWuMQRro8iFtJxYgnS4NQe+EukKF6aGiIT+7flZhISAt2iaXBCfFGvAyif7/f8nQ== -make-dir@^3.0.0: +make-dir@^3.0.0, make-dir@~3.1.0: version "3.1.0" resolved "http://verdaccio.ds.io:4873/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== @@ -13400,10 +13410,10 @@ postcss-selector-parser@^6.0.6: cssesc "^3.0.0" util-deprecate "^1.0.2" -postcss-selector-parser@^6.1.2: - version "6.1.2" - resolved "http://verdaccio.ds.io:4873/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz#27ecb41fb0e3b6ba7a1ec84fff347f734c7929de" - integrity sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg== +postcss-selector-parser@^7.0.0: + version "7.0.0" + resolved "http://verdaccio.ds.io:4873/postcss-selector-parser/-/postcss-selector-parser-7.0.0.tgz#41bd8b56f177c093ca49435f65731befe25d6b9c" + integrity sha512-9RbEr1Y7FFfptd/1eEdntyjMwLeghW1bHX9GWjXo19vx4ytPQhANltvVxDggzJl7mnWM+dX28kb6cyS/4iQjlQ== dependencies: cssesc "^3.0.0" util-deprecate "^1.0.2" @@ -16895,7 +16905,7 @@ yaml@^2.4.2: resolved "http://verdaccio.ds.io:4873/yaml/-/yaml-2.6.1.tgz#42f2b1ba89203f374609572d5349fb8686500773" integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== -yargs-parser@>=5.0.0-security.0: +yargs-parser@21.1.1, yargs-parser@>=5.0.0-security.0: version "21.1.1" resolved "http://verdaccio.ds.io:4873/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==