-
Notifications
You must be signed in to change notification settings - Fork 229
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #9698 from bbc/frosted-glass-promo
Frosted Glass Promos
- Loading branch information
Showing
20 changed files
with
1,756 additions
and
1,986 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
83 changes: 83 additions & 0 deletions
83
src/app/components/FrostedGlassPromo/FrostedGlassPanel.jsx
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,83 @@ | ||
import React from 'react'; | ||
import styled from '@emotion/styled'; | ||
import { node, string } from 'prop-types'; | ||
|
||
import { GEL_SPACING_DBL } from '@bbc/gel-foundations/spacings'; | ||
import useImageColour from '../../hooks/useImageColour'; | ||
|
||
const BLUR_RADIUS = 15; | ||
const FALLBACK_COLOUR = '#202224'; | ||
|
||
const Wrapper = styled.div` | ||
position: relative; | ||
overflow: hidden; | ||
`; | ||
const scaleAmount = 1 + BLUR_RADIUS / 100; | ||
const scaleX = `scaleX(${scaleAmount})`; | ||
const scaleY = `scaleY(${-1 * scaleAmount})`; | ||
|
||
const Background = styled.div` | ||
display: none; | ||
@supports (filter: blur(${BLUR_RADIUS}px)) { | ||
display: block; | ||
z-index: 1; | ||
position: absolute; | ||
bottom: 0; | ||
top: -${BLUR_RADIUS}px; | ||
left: 0; | ||
right: 0; | ||
background: ${FALLBACK_COLOUR} url('${({ image }) => image}'); | ||
background-repeat: no-repeat; | ||
background-size: cover; | ||
background-position: bottom; | ||
transform: ${scaleX} ${scaleY}; | ||
filter: blur(${BLUR_RADIUS}px); | ||
} | ||
`; | ||
|
||
const Overlay = styled.div` | ||
z-index: 2; | ||
position: absolute; | ||
bottom: 0; | ||
top: 0; | ||
left: 0; | ||
right: 0; | ||
transition: background 0.5s ease-in-out; | ||
background: rgb(${({ colour }) => `${colour.join(',')}`}); | ||
${({ isLoading, colour }) => | ||
!isLoading && | ||
` | ||
@supports (filter: blur(${BLUR_RADIUS}px)) { | ||
background: rgba(${`${colour.join(',')}, 0.62`}); | ||
} | ||
`} | ||
`; | ||
|
||
const Children = styled.div` | ||
position: relative; | ||
z-index: 3; | ||
padding-bottom: ${GEL_SPACING_DBL}; | ||
`; | ||
|
||
const FrostedGlassPanel = ({ image, children }) => { | ||
const { isLoading, colour } = useImageColour(image, { | ||
fallbackColour: FALLBACK_COLOUR, | ||
minimumContrast: 10, | ||
contrastColour: '#ffffff', | ||
}); | ||
|
||
return ( | ||
<Wrapper> | ||
<Background image={image} /> | ||
<Overlay colour={colour.rgb} isLoading={isLoading} /> | ||
<Children>{children}</Children> | ||
</Wrapper> | ||
); | ||
}; | ||
|
||
FrostedGlassPanel.propTypes = { | ||
image: string.isRequired, | ||
children: node.isRequired, | ||
}; | ||
|
||
export default FrostedGlassPanel; |
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,21 @@ | ||
import styled from '@emotion/styled'; | ||
|
||
import { getSansRegular } from '@bbc/psammead-styles/font-styles'; | ||
import { GEL_GROUP_2_SCREEN_WIDTH_MIN } from '@bbc/gel-foundations/breakpoints'; | ||
import { GEL_SPACING, GEL_SPACING_DBL } from '@bbc/gel-foundations/spacings'; | ||
|
||
import Timestamp from '../../containers/StoryPromo/Timestamp'; | ||
|
||
const StyledTimestamp = styled(Timestamp)` | ||
${({ service }) => service && getSansRegular(service)} | ||
color: white; | ||
font-size: 0.8125rem; | ||
padding: 0.625rem ${GEL_SPACING} 0 ${GEL_SPACING}; | ||
@media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { | ||
font-size: 0.875rem; | ||
padding: 0.625rem ${GEL_SPACING_DBL} 0 ${GEL_SPACING_DBL}; | ||
} | ||
`; | ||
|
||
export default StyledTimestamp; |
565 changes: 565 additions & 0 deletions
565
src/app/components/FrostedGlassPromo/__snapshots__/index.test.jsx.snap
Large diffs are not rendered by default.
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,99 @@ | ||
export const promoProps = { | ||
children: | ||
'Además de sus decenas de museos tradicionales, Ciudad de México es una galería al aire libre de arte callejero, en la que exponen artistas nacionales y extranjeros. Lo invitamos a un recorrido.', | ||
footer: '4 mayo 2021', | ||
url: '/mundo/internacional-23038380', | ||
image: { | ||
ratio: 52, | ||
src: 'https://ichef.bbci.co.uk/news/400/cpsdevpb/DDFC/test/_63482865_orange2.jpg', | ||
alt: 'Orange 2', | ||
width: 976, | ||
}, | ||
}; | ||
|
||
export const linkPromoFixture = { | ||
item: { | ||
name: 'Man City vs West Ham: Bad weather force Premier League to cancel Sunday match', | ||
summary: | ||
'Man City vs West Ham: Bad weather force Premier League to cancel Sunday match', | ||
indexImage: { | ||
id: '63731494', | ||
subType: 'index', | ||
href: 'http://b.files.bbci.co.uk/C105/test/_63731494__110870927_climategrief5.jpg', | ||
path: '/cpsdevpb/C105/test/_63731494__110870927_climategrief5.jpg', | ||
height: 351, | ||
width: 624, | ||
altText: 'E dey good for your', | ||
caption: 'E dey good for your wellbeing to reconnect wit nature', | ||
copyrightHolder: 'BBC', | ||
type: 'image', | ||
}, | ||
uri: 'https://www.bbc.com/pidgin/sport-51434980', | ||
contentType: 'RadioBulletin', | ||
assetTypeCode: 'PRO', | ||
timestamp: 1581941235000, | ||
type: 'link', | ||
}, | ||
dir: 'ltr', | ||
displayImage: true, | ||
displaySummary: false, | ||
eventTrackingData: { | ||
block: { | ||
componentName: 'features', | ||
}, | ||
}, | ||
}; | ||
|
||
export const cpsPromoFixture = { | ||
item: { | ||
headlines: { | ||
headline: 'El colorido encanto del arte callejero chilango 17', | ||
}, | ||
locators: { | ||
assetUri: '/mundo/internacional-23038380', | ||
cpsUrn: 'urn:bbc:content:assetUri:mundo/internacional-23038380', | ||
assetId: '23038380', | ||
}, | ||
summary: | ||
'Además de sus decenas de museos tradicionales, Ciudad de México es una galería al aire libre de arte callejero, en la que exponen artistas nacionales y extranjeros. Lo invitamos a un recorrido.', | ||
timestamp: 1462445134000, | ||
language: 'es', | ||
byline: { | ||
name: 'Aled Scourfield', | ||
title: 'BBC News, Wales', | ||
persons: [ | ||
{ | ||
name: 'Aled Scourfield', | ||
function: 'BBC News, Wales', | ||
}, | ||
], | ||
}, | ||
cpsType: 'STY', | ||
indexImage: { | ||
id: '63482865', | ||
subType: 'index', | ||
href: 'http://b.files.bbci.co.uk/DDFC/test/_63482865_orange2.jpg', | ||
path: '/cpsdevpb/DDFC/test/_63482865_orange2.jpg', | ||
height: 549, | ||
width: 976, | ||
altText: 'Orange 2', | ||
caption: 'Orange 2', | ||
copyrightHolder: 'BBC', | ||
type: 'image', | ||
}, | ||
options: { | ||
isBreakingNews: false, | ||
isFactCheck: false, | ||
}, | ||
id: 'urn:bbc:ares::asset:mundo/internacional-23038380', | ||
type: 'cps', | ||
}, | ||
dir: 'ltr', | ||
displayImage: true, | ||
displaySummary: false, | ||
eventTrackingData: { | ||
block: { | ||
componentName: 'features', | ||
}, | ||
}, | ||
}; |
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,96 @@ | ||
import React, { useContext } from 'react'; | ||
import { shape, node, string, number } from 'prop-types'; | ||
import styled from '@emotion/styled'; | ||
import pick from 'ramda/src/pick'; | ||
|
||
import { getSerifRegular } from '@bbc/psammead-styles/font-styles'; | ||
import { GEL_GROUP_2_SCREEN_WIDTH_MIN } from '@bbc/gel-foundations/breakpoints'; | ||
import { GEL_SPACING, GEL_SPACING_DBL } from '@bbc/gel-foundations/spacings'; | ||
|
||
import useClickTrackerHandler from '#hooks/useClickTrackerHandler'; | ||
import { ServiceContext } from '#contexts/ServiceContext'; | ||
import FrostedGlassPanel from './FrostedGlassPanel'; | ||
|
||
import ImageWithPlaceholder from '../../containers/ImageWithPlaceholder'; | ||
|
||
import withData from './withData'; | ||
|
||
const Body = styled.div` | ||
${({ service }) => service && getSerifRegular(service)} | ||
color: white; | ||
font-size: 0.9375rem; | ||
line-height: 1.33; | ||
padding: 0.625rem ${GEL_SPACING} 0 ${GEL_SPACING}; | ||
@media (min-width: ${GEL_GROUP_2_SCREEN_WIDTH_MIN}) { | ||
font-size: 1rem; | ||
line-height: 1.25; | ||
padding: 0.875rem ${GEL_SPACING_DBL} 0 ${GEL_SPACING_DBL}; | ||
} | ||
`; | ||
|
||
const Wrapper = styled.a` | ||
display: inline-block; | ||
width: 100%; | ||
max-width: 400px; | ||
text-decoration: none; | ||
&:hover, | ||
&:focus { | ||
${Body} { | ||
text-decoration: underline; | ||
} | ||
} | ||
`; | ||
|
||
const FrostedGlassPromo = props => { | ||
const { script, service } = useContext(ServiceContext); | ||
const { image, children, footer, url, eventTrackingData } = props; | ||
|
||
const clickTracker = useClickTrackerHandler({ | ||
...(eventTrackingData || {}), | ||
url, | ||
}); | ||
|
||
const onClick = eventTrackingData ? clickTracker : () => {}; | ||
|
||
return ( | ||
<Wrapper href={url} onClick={onClick}> | ||
<ImageWithPlaceholder | ||
darkMode | ||
{...pick( | ||
['src', 'srcset', 'sizes', 'alt', 'ratio', 'width', 'height'], | ||
image, | ||
)} | ||
/> | ||
<FrostedGlassPanel image={image.smallSrc || image.src}> | ||
<Body script={script} service={service}> | ||
{children} | ||
</Body> | ||
{footer} | ||
</FrostedGlassPanel> | ||
</Wrapper> | ||
); | ||
}; | ||
|
||
FrostedGlassPromo.propTypes = { | ||
children: node.isRequired, | ||
url: string.isRequired, | ||
footer: node, | ||
eventTrackingData: shape({}), | ||
image: shape({ | ||
src: string.isRequired, | ||
alt: string.isRequired, | ||
ratio: number.isRequired, | ||
width: number.isRequired, | ||
height: number.isRequired, | ||
smallSrc: string, | ||
srcset: string, | ||
sizes: string, | ||
}).isRequired, | ||
}; | ||
|
||
FrostedGlassPromo.defaultProps = { | ||
footer: null, | ||
eventTrackingData: null, | ||
}; | ||
|
||
export default withData(FrostedGlassPromo); |
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,74 @@ | ||
import React from 'react'; | ||
import { withServicesKnob } from '@bbc/psammead-storybook-helpers'; | ||
import { withKnobs, text } from '@storybook/addon-knobs'; | ||
|
||
import { RequestContextProvider } from '#contexts/RequestContext'; | ||
import { ServiceContextProvider } from '#contexts/ServiceContext'; | ||
import { ToggleContextProvider } from '#contexts/ToggleContext'; | ||
|
||
import Promo from '.'; | ||
import { cpsPromoFixture, linkPromoFixture } from './fixtures'; | ||
|
||
// eslint-disable-next-line react/prop-types | ||
const Wrappers = ({ service, variant, children }) => { | ||
return ( | ||
<ServiceContextProvider service={service} variant={variant}> | ||
<RequestContextProvider isAmp={false} service={service}> | ||
<ToggleContextProvider | ||
toggles={{ | ||
eventTracking: { enabled: false }, | ||
}} | ||
> | ||
{children} | ||
</ToggleContextProvider> | ||
</RequestContextProvider> | ||
</ServiceContextProvider> | ||
); | ||
}; | ||
|
||
const Component = props => { | ||
const imageUrl = text( | ||
'Image URL', | ||
'https://ichef.bbci.co.uk/news/976/cpsprodpb/189F/production/_121530360_hi071904982.jpg', | ||
); | ||
const mainBody = text( | ||
'Main Body', | ||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean quam magna, lacinia ut arcu in, vulputate ultricies lectus. Vestibulum purus ligula, finibus vel ultrices in, pretium non neque. Sed mauris ante, mollis ac metus fermentum, vestibulum malesuada felis. Nullam a congue mauris. Nulla venenatis felis ac eleifend rutrum.', | ||
); | ||
return ( | ||
<Wrappers {...props}> | ||
<Promo | ||
image={{ src: imageUrl, alt: '', width: 500, height: 250, ratio: 52 }} | ||
url="#" | ||
> | ||
{mainBody} | ||
</Promo> | ||
</Wrappers> | ||
); | ||
}; | ||
|
||
const WithCPSPromoData = props => { | ||
return ( | ||
<Wrappers {...props}> | ||
<Promo {...cpsPromoFixture} /> | ||
</Wrappers> | ||
); | ||
}; | ||
|
||
const WithLinkPromoData = props => { | ||
return ( | ||
<Wrappers {...props}> | ||
<Promo {...linkPromoFixture} /> | ||
</Wrappers> | ||
); | ||
}; | ||
|
||
export default { | ||
title: 'Components/Frosted Glass Promo', | ||
Component, | ||
decorators: [withKnobs, withServicesKnob()], | ||
}; | ||
|
||
export const Standalone = Component; | ||
export const CPSPromo = WithCPSPromoData; | ||
export const LinkPromo = WithLinkPromoData; |
Oops, something went wrong.