diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 01f46d77c..d74622d30 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,6 +21,9 @@ jobs: app-id: ${{ secrets.APP_ID }} private-key: ${{ secrets.APP_PEM }} owner: ${{ github.repository_owner }} + repositories: | + veda-ui + veda-config - uses: actions/checkout@v4 with: fetch-depth: 0 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} +
+ +

+
+
+); + export default function Banner({ - appTitle, - expires, - url, - text, - type = infoTypeFlag + headerText, + headerActionText, + ariaLabel, + flagImgAlt = '', + leftGuidance, + rightGuidance, + className = '', + defaultIsOpen = false, + contentId = 'gov-banner-content' }: BannerProps) { + const [isOpen, setIsOpen] = useState(defaultIsOpen); - const showBanner = localStorage.getItem(BANNER_KEY) !== url; - const [isOpen, setIsOpen] = useState(showBanner && !hasExpired(expires)); + const leftContent = { + ...DEFAULT_GUIDANCE.left, + ...leftGuidance + } as GuidanceContent; - function onClose() { - localStorage.setItem(BANNER_KEY, url); - setIsOpen(false); - } + const rightContent = { + ...DEFAULT_GUIDANCE.right, + ...rightGuidance + } as GuidanceContent; return ( -
- {isOpen && ( -
- - - -
+ + + } + headerText={headerText ?? DEFAULT_HEADER_TEXT} + headerActionText={headerActionText ?? DEFAULT_HEADER_ACTION_TEXT} + > + setIsOpen((prev) => !prev)} + aria-controls={contentId} + > + {headerActionText ?? DEFAULT_HEADER_ACTION_TEXT} + + - - - -
- -
+ +
+ +
- )} -
+ +
); } diff --git a/app/scripts/components/common/layout-root/index.tsx b/app/scripts/components/common/layout-root/index.tsx index 9f67192bb..f69bbd47b 100644 --- a/app/scripts/components/common/layout-root/index.tsx +++ b/app/scripts/components/common/layout-root/index.tsx @@ -10,10 +10,15 @@ import { useDeepCompareEffect } from 'use-deep-compare'; import styled from 'styled-components'; import { Outlet } from 'react-router'; import { reveal } from '@devseed-ui/animation'; -import { getBannerFromVedaConfig, getCookieConsentFromVedaConfig } from 'veda'; +import { + getBannerFromVedaConfig, + getCookieConsentFromVedaConfig, + getSiteAlertFromVedaConfig +} from 'veda'; import MetaTags from '../meta-tags'; import PageFooter from '../page-footer'; const Banner = React.lazy(() => import('../banner')); +const SiteAlert = React.lazy(() => import('../site-alert')); const CookieConsent = React.lazy(() => import('../cookie-consent')); import { LayoutRootContext } from './context'; @@ -50,6 +55,7 @@ const PageBody = styled.div` function LayoutRoot(props: { children?: ReactNode }) { const cookieConsentContent = getCookieConsentFromVedaConfig(); const bannerContent = getBannerFromVedaConfig(); + const siteAlertContent = getSiteAlertFromVedaConfig(); const { children } = props; const [displayCookieConsentForm, setDisplayCookieConsentForm] = useState(true); @@ -74,8 +80,9 @@ function LayoutRoot(props: { children?: ReactNode }) { description={description || appDescription} thumbnail={thumbnail} /> - {bannerContent && ( - + {bannerContent && } + {siteAlertContent && ( + )} expiryDate); +} + +enum SiteAlertType { + info = 'info', + emergency = 'emergency' +} + +const infoTypeFlag = SiteAlertType.info; + +interface SiteAlertProps { + appTitle: string; + expires?: Date; + content: string; + type?: SiteAlertType; + heading?: string; + showIcon?: boolean; + slim?: boolean; + className?: string; +} + +export default function SiteAlert({ + appTitle, + expires, + content, + type = infoTypeFlag, + heading, + showIcon = true, + slim = false, + className = '' +}: SiteAlertProps) { + const showAlert = localStorage.getItem(ALERT_KEY) !== content; + const [isOpen, setIsOpen] = useState(showAlert && !hasExpired(expires)); + + function onClose() { + localStorage.setItem(ALERT_KEY, content); + setIsOpen(false); + } + + return ( +
+ {isOpen && ( +
+ +
+ +
+ +
+
+ )} +
+ ); +} diff --git a/app/scripts/components/common/uswds/banner.tsx b/app/scripts/components/common/uswds/banner.tsx deleted file mode 100644 index ed6cb535e..000000000 --- a/app/scripts/components/common/uswds/banner.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from "react"; -import { Banner, BannerContent } from "@trussworks/react-uswds"; - -export function USWDSBanner (props) { - return ; -} - -export function USWDSBannerContent (props) { - return ; -} \ No newline at end of file diff --git a/app/scripts/components/common/uswds/banner/index.tsx b/app/scripts/components/common/uswds/banner/index.tsx new file mode 100644 index 000000000..375470421 --- /dev/null +++ b/app/scripts/components/common/uswds/banner/index.tsx @@ -0,0 +1,42 @@ +import React from 'react'; +import { + Banner, + BannerContent, + BannerButton, + BannerFlag, + BannerHeader, + BannerIcon, + BannerGuidance, MediaBlockBody +} from '@trussworks/react-uswds'; + +export function USWDSBanner(props) { + return ; +} + +export function USWDSBannerContent(props) { + return ; +} + +export function USWDSBannerButton(props) { + return ; +} + +export function USWDSBannerFlag(props) { + return ; +} + +export function USWDSBannerHeader(props) { + return ; +} + +export function USWDSBannerIcon(props) { + return ; +} + +export function USWDSBannerGuidance(props) { + return ; +} + +export function USWDSMediaBlockBody(props) { + return ; +} diff --git a/app/scripts/components/common/uswds/site-alert.tsx b/app/scripts/components/common/uswds/site-alert.tsx new file mode 100644 index 000000000..926b30e66 --- /dev/null +++ b/app/scripts/components/common/uswds/site-alert.tsx @@ -0,0 +1,6 @@ +import React from 'react'; +import { SiteAlert } from '@trussworks/react-uswds'; + +export function USWDSSiteAlert(props) { + return ; +} diff --git a/app/scripts/components/exploration/components/datasets/dataset-list-item.tsx b/app/scripts/components/exploration/components/datasets/dataset-list-item.tsx index 34fab5edd..64390cda0 100644 --- a/app/scripts/components/exploration/components/datasets/dataset-list-item.tsx +++ b/app/scripts/components/exploration/components/datasets/dataset-list-item.tsx @@ -94,10 +94,11 @@ interface DatasetListItemProps { xScaled?: ScaleTime; onDragStart?: () => void; onDragEnd?: () => void; + onNavigation?: (path: string) => void; } export function DatasetListItem(props: DatasetListItemProps) { - const { datasetId, width, xScaled, onDragStart, onDragEnd } = props; + const { datasetId, width, xScaled, onDragStart, onDragEnd, onNavigation } = props; const datasetAtom = useTimelineDatasetAtom(datasetId); const dataset = useAtomValue(datasetAtom); @@ -235,6 +236,7 @@ export function DatasetListItem(props: DatasetListItemProps) { revealed={!!modalLayerInfo} close={() => setModalLayerInfo(undefined)} layerData={modalLayerInfo} + onNavigation={onNavigation} /> )} diff --git a/app/scripts/components/exploration/components/datasets/dataset-list.tsx b/app/scripts/components/exploration/components/datasets/dataset-list.tsx index b0c7b538d..dc1178757 100644 --- a/app/scripts/components/exploration/components/datasets/dataset-list.tsx +++ b/app/scripts/components/exploration/components/datasets/dataset-list.tsx @@ -16,10 +16,11 @@ const DatasetListSelf = styled.ul` interface DatasetListProps { width: number; xScaled?: ScaleTime; + onNavigation?: (path: string) => void; } export function DatasetList(props: DatasetListProps) { - const { width, xScaled } = props; + const { width, xScaled, onNavigation } = props; const [isDragging, setIsDragging] = useState(false); const [datasets, setDatasets] = useAtom(timelineDatasetsAtom); @@ -40,6 +41,7 @@ export function DatasetList(props: DatasetListProps) { xScaled={xScaled} onDragStart={() => setIsDragging(true)} onDragEnd={() => setIsDragging(false)} + onNavigation={onNavigation} /> ))} diff --git a/app/scripts/components/exploration/components/layer-info-modal.tsx b/app/scripts/components/exploration/components/layer-info-modal.tsx index 977bbd254..75a6f49a8 100644 --- a/app/scripts/components/exploration/components/layer-info-modal.tsx +++ b/app/scripts/components/exploration/components/layer-info-modal.tsx @@ -9,9 +9,8 @@ import { ModalHeadline } from '@devseed-ui/modal'; import { glsp, themeVal } from '@devseed-ui/theme-provider'; -import { createButtonStyles } from '@devseed-ui/button'; +import { Button } from '@devseed-ui/button'; import { LayerInfo } from 'veda'; - import { getDatasetPath } from '$utils/routes'; import { CollecticonDatasetLayers } from '$components/common/icons/dataset-layers'; import { ParentDatasetTitle } from '$components/common/catalog/catalog-content'; @@ -53,13 +52,6 @@ const ParentDatasetHeading = styled.h2` padding: ${glsp(0.5)} 0; `; -// override with 'as' as LinkComponent -const ButtonStyleLink = styled.a` - &&& { - ${({ variation, size }) => createButtonStyles({ variation, size })} - } -`; - export interface LayerInfoModalData { name: string; info?: LayerInfo; @@ -75,6 +67,7 @@ interface LayerInfoModalProps { revealed: boolean; close: () => void; layerData: LayerInfoModalData + onNavigation?: (path: string) => void; } export function LayerInfoLiner(props: { info: LayerInfo }) { @@ -100,10 +93,18 @@ const LayerInfoLinerModal = styled.div` `; export default function LayerInfoModal(props: LayerInfoModalProps) { - const { revealed, close, layerData } = props; + const { revealed, close, layerData, onNavigation } = props; const { parentData } = layerData; const dataCatalogPage = getDatasetPath(parentData.id); + + const handleButtonClick = () => { + close(); + if (onNavigation) { + onNavigation(dataCatalogPage); + } + }; + return ( } footerContent={ - + } /> ); diff --git a/app/scripts/components/exploration/components/timeline/timeline.tsx b/app/scripts/components/exploration/components/timeline/timeline.tsx index 8655f34bb..4881a6915 100644 --- a/app/scripts/components/exploration/components/timeline/timeline.tsx +++ b/app/scripts/components/exploration/components/timeline/timeline.tsx @@ -170,6 +170,7 @@ interface TimelineProps { setSelectedCompareDay: (d: Date | null) => void; onDatasetAddClick?: () => void; panelHeight: number; + onNavigation?: (path: string) => void; } const getIntervalFromDate = (selectedDay: Date, dataDomain: [Date, Date]) => { @@ -200,7 +201,8 @@ export default function Timeline(props: TimelineProps) { selectedCompareDay, setSelectedCompareDay, onDatasetAddClick, - panelHeight + panelHeight, + onNavigation, } = props; // Refs for non react based interactions. @@ -798,7 +800,7 @@ export default function Timeline(props: TimelineProps) { ref={datasetsContainerRef} panelHeight={panelHeight} > - + diff --git a/app/scripts/components/exploration/container.tsx b/app/scripts/components/exploration/container.tsx index b8439c738..16020a585 100644 --- a/app/scripts/components/exploration/container.tsx +++ b/app/scripts/components/exploration/container.tsx @@ -1,5 +1,6 @@ import React, { useState } from 'react'; import { TourProvider } from '@reactour/tour'; +import { useNavigate } from "react-router-dom"; import { DevTools } from 'jotai-devtools'; import { useAtom, useSetAtom } from 'jotai'; import { PopoverTourComponent, TourManager } from './tour-manager'; @@ -39,6 +40,7 @@ export default function ExplorationAndAnalysisContainer() { const [datasetModalRevealed, setDatasetModalRevealed] = useState( !timelineDatasets.length ); + const navigate = useNavigate(); // @NOTE: When Exploration page is preloaded (ex. Linked with react-router) // atomWithLocation gets initialized outside of Exploration page and returns the previous page's value @@ -49,6 +51,15 @@ export default function ExplorationAndAnalysisContainer() { const openModal = () => setDatasetModalRevealed(true); const closeModal = () => setDatasetModalRevealed(false); + const handleNavigation = (path: string) => { + navigate(path); + }; + + const linkProps = { + LinkElement: SmartLink, + pathAttributeKeyName: 'to' + }; + return ( diff --git a/app/scripts/components/exploration/index.tsx b/app/scripts/components/exploration/index.tsx index 5e4242cba..a809507f3 100644 --- a/app/scripts/components/exploration/index.tsx +++ b/app/scripts/components/exploration/index.tsx @@ -59,10 +59,11 @@ interface ExplorationAndAnalysisProps { datasets: TimelineDataset[]; setDatasets: (datasets: TimelineDataset[]) => void; openDatasetsSelectionModal?: () => void; + onNavigation?: (path: string) => void; } function ExplorationAndAnalysis(props: ExplorationAndAnalysisProps) { - const { datasets, setDatasets, openDatasetsSelectionModal } = props; + const { datasets, setDatasets, openDatasetsSelectionModal, onNavigation } = props; const [selectedDay, setSelectedDay] = useAtom(selectedDateAtom); @@ -111,6 +112,7 @@ function ExplorationAndAnalysis(props: ExplorationAndAnalysisProps) { setSelectedCompareDay={setSelectedCompareDay} onDatasetAddClick={openDatasetsSelectionModal} panelHeight={panelHeight} + onNavigation={onNavigation} /> diff --git a/app/scripts/components/home/index.tsx b/app/scripts/components/home/index.tsx index a79767758..d32beaf59 100644 --- a/app/scripts/components/home/index.tsx +++ b/app/scripts/components/home/index.tsx @@ -5,7 +5,7 @@ import { Button } from '@devseed-ui/button'; import { glsp, listReset, media, themeVal } from '@devseed-ui/theme-provider'; import { Heading } from '@devseed-ui/typography'; import { CollecticonChevronRightSmall } from '@devseed-ui/collecticons'; -import { getOverride, getBannerFromVedaConfig } from 'veda'; +import { getOverride, getSiteAlertFromVedaConfig } from 'veda'; import rootCoverImage from '../../../graphics/layout/root-welcome--cover.jpg'; @@ -25,7 +25,6 @@ import { ContentOverride } from '$components/common/page-overrides'; - const homeContent = getOverride('homeContent'); const Connections = styled(Hug)` @@ -115,10 +114,10 @@ const getCoverProps = () => { return author ? { - ...coverProps, - attributionAuthor: author.name, - attributionUrl: author.url - } + ...coverProps, + attributionAuthor: author.name, + attributionUrl: author.url + } : coverProps; } else { return { @@ -134,14 +133,14 @@ const getCoverProps = () => { function RootHome() { const { show: showFeedbackModal } = useFeedbackModal(); - const banner = getBannerFromVedaConfig(); - const renderBanner = !!banner && banner.text && banner.url && banner.expires; + const siteAlert = getSiteAlertFromVedaConfig(); + const renderSiteAlert = !!siteAlert && siteAlert.content && siteAlert.expires; return ( - diff --git a/app/scripts/styles/styles.scss b/app/scripts/styles/styles.scss index fc0fc6f20..277ef6b26 100644 --- a/app/scripts/styles/styles.scss +++ b/app/scripts/styles/styles.scss @@ -2,13 +2,14 @@ @use 'uswds-utilities'; @use 'usa-layout-grid'; -@use 'usa-banner'; @use 'usa-button'; +@use 'usa-icon'; @use 'usa-card'; -@use 'usa-alert'; @use 'usa-button-group'; -@use 'usa-icon'; @use 'usa-modal'; @use 'usa-header'; +@use 'usa-alert'; +@use 'usa-site-alert'; +@use 'usa-banner'; -@use './veda-components'; \ No newline at end of file +@use './veda-components'; diff --git a/mock/veda.config.js b/mock/veda.config.js index 5aadadc95..33c8d8a9c 100644 --- a/mock/veda.config.js +++ b/mock/veda.config.js @@ -71,6 +71,21 @@ let subNavItems = [ } ]; +const defaultGuidance = { + 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 icon 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' + } +}; + if (config.GOOGLE_FORM) { subNavItems = [ ...subNavItems, @@ -103,10 +118,26 @@ module.exports = { } }, banner: { - text: 'Read the new data insight on using EMIT and AVIRIS-3 for monitoring large methane emission events.', - url: 'stories/emit-and-aviris-3', - expires: '2024-08-03T12:00:00-04:00', - type: 'info' + headerText: 'An official website of the United States government', + headerActionText: "Here's how you know", + ariaLabel: 'Banner for official government website', + flagImgSrc: '/img/us_flag_small.png', + flagImgAlt: 'US flag', + leftGuidance: defaultGuidance.left, + rightGuidance: defaultGuidance.right, + className: '', + defaultIsOpen: false, + contentId: 'gov-banner-content' + }, + siteAlert: { + content: `

+ + 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 17e8a4148..f18114730 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@developmentseed/veda-ui", "description": "Dashboard", - "version": "5.11.3", + "version": "5.11.4", "author": { "name": "Development Seed", "url": "https://developmentseed.org/" @@ -166,6 +166,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", @@ -185,6 +186,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 1e8e6c43d..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"