-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce the USWDS Site Alert as a info banner, use the USWDS Banner…
… as intended
- Loading branch information
Showing
14 changed files
with
396 additions
and
119 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.usa-banner__button:after { | ||
top: 3px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,78 +1,141 @@ | ||
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); | ||
} | ||
|
||
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; | ||
} | ||
|
||
export default function Banner({ | ||
appTitle, | ||
expires, | ||
url, | ||
text, | ||
type = infoTypeFlag | ||
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 <strong>lock</strong> or <strong>https://</strong> 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' | ||
} | ||
}; | ||
|
||
export default function GovBanner({ | ||
headerText, | ||
headerActionText = "Here's how you know", | ||
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 defaultHeaderText = | ||
'An official website of the United States government'; | ||
|
||
function onClose() { | ||
localStorage.setItem(BANNER_KEY, url); | ||
setIsOpen(false); | ||
} | ||
const leftContent = { | ||
...defaultGuidance.left, | ||
...leftGuidance | ||
}; | ||
|
||
const rightContent = { | ||
...defaultGuidance.right, | ||
...rightGuidance | ||
}; | ||
|
||
return ( | ||
<div> | ||
{isOpen && ( | ||
<div className='position-relative'> | ||
<USWDSBanner | ||
aria-label={appTitle} | ||
className={type !== infoTypeFlag ? 'bg-secondary-lighter' : ''} | ||
> | ||
<a href={url} target='_blank' rel='noreferrer'> | ||
<USWDSBannerContent | ||
className='padding-top-1 padding-bottom-1' | ||
isOpen={true} | ||
> | ||
<div dangerouslySetInnerHTML={{ __html: text }} /> | ||
<USWDSBanner | ||
aria-label={ariaLabel ?? defaultHeaderText} | ||
className={className} | ||
> | ||
<USWDSBannerHeader | ||
isOpen={isOpen} | ||
flagImg={ | ||
<USWDSBannerFlag src='/img/us_flag_small.png' alt={flagImgAlt} /> | ||
} | ||
headerText={headerText ?? defaultHeaderText} | ||
headerActionText={headerActionText} | ||
> | ||
<USWDSBannerButton | ||
isOpen={isOpen} | ||
onClick={() => setIsOpen((prev) => !prev)} | ||
aria-controls={contentId} | ||
> | ||
{headerActionText} | ||
</USWDSBannerButton> | ||
</USWDSBannerHeader> | ||
|
||
<USWDSBannerContent id={contentId} isOpen={isOpen}> | ||
<div className='grid-row grid-gap-lg'> | ||
<USWDSBannerGuidance className='tablet:grid-col-6'> | ||
<USWDSBannerIcon | ||
src={leftContent.icon} | ||
alt={leftContent.iconAlt || ''} | ||
/> | ||
<USWDSMediaBlockBody> | ||
<p> | ||
<strong>{leftContent.title}</strong> | ||
<br /> | ||
<span | ||
dangerouslySetInnerHTML={{ | ||
__html: decode(leftContent.text) | ||
}} | ||
/> | ||
</p> | ||
</USWDSMediaBlockBody> | ||
</USWDSBannerGuidance> | ||
|
||
</USWDSBannerContent> | ||
</a> | ||
</USWDSBanner> | ||
<div className='position-absolute top-0 right-0 margin-right-3 height-full display-flex'> | ||
<button | ||
className='usa-button usa-button--unstyled' | ||
type='button' | ||
aria-label='Close Banner' | ||
onClick={onClose} | ||
> | ||
<Icon.Close /> | ||
</button> | ||
</div> | ||
<USWDSBannerGuidance className='tablet:grid-col-6'> | ||
<USWDSBannerIcon | ||
src={rightContent.icon} | ||
alt={rightContent.iconAlt || ''} | ||
/> | ||
<USWDSMediaBlockBody> | ||
<p> | ||
<strong>{rightContent.title}</strong> | ||
<br /> | ||
<span | ||
dangerouslySetInnerHTML={{ | ||
__html: decode(rightContent.text) | ||
}} | ||
/> | ||
</p> | ||
</USWDSMediaBlockBody> | ||
</USWDSBannerGuidance> | ||
</div> | ||
)} | ||
</div> | ||
</USWDSBannerContent> | ||
</USWDSBanner> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import React, { useState } from 'react'; | ||
import { Icon } from '@trussworks/react-uswds'; | ||
import { decode } from 'he'; | ||
import { USWDSSiteAlert } from '$components/common/uswds/site-alert'; | ||
|
||
const ALERT_KEY = 'dismissedSiteAlertUrl'; | ||
|
||
function hasExpired(expiryDatetime?: Date): boolean { | ||
if (!expiryDatetime) return false; | ||
const expiryDate = new Date(expiryDatetime); | ||
const currentDate = new Date(); | ||
return !!(currentDate > 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 SiteAlertMessage({ | ||
appTitle, | ||
expires, | ||
content, | ||
type = infoTypeFlag, | ||
heading, | ||
showIcon = true, | ||
slim = false, | ||
className = '' | ||
}: SiteAlertProps) { | ||
const alertId = content; | ||
const showAlert = localStorage.getItem(ALERT_KEY) !== alertId; | ||
const [isOpen, setIsOpen] = useState(showAlert && !hasExpired(expires)); | ||
|
||
function onClose() { | ||
localStorage.setItem(ALERT_KEY, alertId); | ||
setIsOpen(false); | ||
} | ||
|
||
return ( | ||
<div> | ||
{isOpen && ( | ||
<div className='position-relative'> | ||
<USWDSSiteAlert | ||
aria-label={`${appTitle} site alert`} | ||
variant={type} | ||
heading={heading} | ||
showIcon={showIcon} | ||
slim={slim} | ||
className={`${className} ${ | ||
type !== infoTypeFlag ? 'bg-secondary-lighter' : '' | ||
}`} | ||
> | ||
<div dangerouslySetInnerHTML={{ __html: decode(content) }} /> | ||
</USWDSSiteAlert> | ||
<div className='position-absolute top-0 right-0 margin-right-3 height-full display-flex'> | ||
<button | ||
className='usa-button usa-button--unstyled' | ||
type='button' | ||
aria-label={`Close ${appTitle} site alert`} | ||
onClick={onClose} | ||
> | ||
<Icon.Close /> | ||
</button> | ||
</div> | ||
</div> | ||
)} | ||
</div> | ||
); | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 <Banner {...props} />; | ||
} | ||
|
||
export function USWDSBannerContent(props) { | ||
return <BannerContent {...props} />; | ||
} | ||
|
||
export function USWDSBannerButton(props) { | ||
return <BannerButton {...props} />; | ||
} | ||
|
||
export function USWDSBannerFlag(props) { | ||
return <BannerFlag {...props} />; | ||
} | ||
|
||
export function USWDSBannerHeader(props) { | ||
return <BannerHeader {...props} />; | ||
} | ||
|
||
export function USWDSBannerIcon(props) { | ||
return <BannerIcon {...props} />; | ||
} | ||
|
||
export function USWDSBannerGuidance(props) { | ||
return <BannerGuidance {...props} />; | ||
} | ||
|
||
export function USWDSMediaBlockBody(props) { | ||
return <MediaBlockBody {...props} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
import { SiteAlert } from '@trussworks/react-uswds'; | ||
|
||
export function USWDSSiteAlert(props) { | ||
return <SiteAlert {...props} />; | ||
} |
Oops, something went wrong.