diff --git a/src/server/v2/constants.js b/src/server/v2/constants.js index 32a64f541d..f48567d786 100644 --- a/src/server/v2/constants.js +++ b/src/server/v2/constants.js @@ -1,2 +1,20 @@ export const VARIANT = 'B'; export const PORT = process.env.PORT || 8080; + +export const FLEX_DEFAULTS = { + color: 'blue', + ratio: '1x1' +}; + +// Maps flex style.color to logo asset variant keys (see flexLogoMutations + v5 flex defaults). +export const FLEX_COLOR_TO_LOGO_TEXT_COLOR = { + blue: 'white', + black: 'white', + white: 'black', + 'white-no-border': 'black', + gray: 'black', + grey: 'black', + monochrome: 'monochrome', + grayscale: 'grayscale', + greyscale: 'grayscale' +}; diff --git a/src/server/v2/flex.jsx b/src/server/v2/flex.jsx new file mode 100644 index 0000000000..78df68a0d1 --- /dev/null +++ b/src/server/v2/flex.jsx @@ -0,0 +1,107 @@ +/** @jsx h */ +/** @jsxFrag Fragment */ +import { h, Fragment } from 'preact'; + +import { buildContentLabel } from './utils/buildContentLabel'; +import { renderBlock } from './utils/renderBlock'; +import { getLogoBrandClass, resolveLogoAssets } from './logos'; +import flexStyles from './flexStyles'; +import { FLEX_COLOR_TO_LOGO_TEXT_COLOR, FLEX_DEFAULTS } from './constants'; + +function renderFlexLogo(logoBlock, flexColor) { + const textColor = FLEX_COLOR_TO_LOGO_TEXT_COLOR[flexColor] ?? 'white'; + const brandClass = getLogoBrandClass({ + logoName: logoBlock.name, + alternativeText: logoBlock.alternative_text + }); + const logoClassName = ['pp-flex__logo', brandClass].filter(Boolean).join(' '); + const assets = resolveLogoAssets({ + logoName: logoBlock.name, + effectiveLogoType: 'wordmark', + effectiveLogoPosition: 'left', + textColor + }); + + if (assets) { + return assets.map(({ src, dimensions: [width, height] }, idx) => ( + // eslint-disable-next-line react/no-array-index-key + + + + )); + } + + return ( + + {renderBlock(logoBlock)} + + ); +} + +export default function FlexMessage({ style, v2Content }) { + const color = style.color ?? FLEX_DEFAULTS.color; + const ratio = style.ratio ?? FLEX_DEFAULTS.ratio; + + const mainItems = v2Content?.main_items ?? []; + const actionItems = v2Content?.action_items ?? []; + const disclaimerItems = v2Content?.disclaimer_items ?? []; + + const logoBlock = mainItems.find(item => item.type === 'IMAGE'); + const mainBlocks = mainItems.filter(item => item.type !== 'IMAGE'); + + const mainLabel = buildContentLabel(logoBlock ? [logoBlock, ...mainBlocks] : mainBlocks); + const actionLabel = buildContentLabel(actionItems); + + return ( +
+ {/* eslint-disable react/no-danger */} +
Pay Later.
Learn more
Subject to approval.
" +`; + +exports[`v2 render flex snapshots no-custom-font snapshot uses v5 Helvetica/Arial default stack 1`] = ` +" +html, +body, +button { + height: 100%; +} + +body { + margin: 0; + padding: 0; +} + +button { + width: 100%; + border: none; + padding: 0; +} + +html { + font-size: 14px; + overflow: hidden; +} + +.pp-message.pp-flex { + position: relative; + width: 100%; + height: 100%; + font-family: Helvetica, Arial, sans-serif; + font-weight: 300; + cursor: pointer; + box-sizing: border-box; + overflow: hidden; +} + +.pp-message.pp-flex .pp-flex__background, +.pp-message.pp-flex .pp-flex__content { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + box-sizing: border-box; +} + +.pp-message.pp-flex .pp-flex__background { + z-index: -1; +} + + +* { + box-sizing: border-box; +} + +.pp-flex__logo img { + display: block; + width: 100%; + height: auto; +} + +.pp-flex__logo--fallback { + width: 100%; +} + +button:focus .pp-message.pp-flex .pp-flex__content, +button:focus .pp-message.pp-flex .pp-flex__content span.br { + text-decoration: underline; +} + +.pp-flex__disclaimer span, +.pp-flex__action span { + text-decoration: underline; + font-weight: 300; +} + +.pp-flex__action span { + white-space: nowrap; +} + +.pp-flex__disclaimer { + white-space: normal; +} + +.pp-flex__logo-container { + display: flex; + align-items: center; +} + +.pp-message.pp-flex.blue .pp-flex__background { background: #023188; } +.pp-message.pp-flex.blue .pp-flex__content { color: #fff; } +.pp-message.pp-flex.black .pp-flex__background { background: #000; } +.pp-message.pp-flex.black .pp-flex__content { color: #fff; } +.pp-message.pp-flex.white .pp-flex__background { background: #fff; } +.pp-message.pp-flex.white .pp-flex__content { color: #023187; border: 1px solid #009cde; } +.pp-message.pp-flex.white-no-border .pp-flex__background { background: #fff; } +.pp-message.pp-flex.white-no-border .pp-flex__content { color: #023187; } +.pp-message.pp-flex.gray .pp-flex__background { background: #eaeced; } +.pp-message.pp-flex.gray .pp-flex__content { color: #023187; } +.pp-message.pp-flex.monochrome .pp-flex__background { background: #fff; } +.pp-message.pp-flex.monochrome .pp-flex__content { color: #000; border: 1px solid #000; } +.pp-message.pp-flex.grayscale .pp-flex__background { background: #fff; } +.pp-message.pp-flex.grayscale .pp-flex__content { border: 1px solid #b7bcbf; } + +.pp-message.pp-flex.blue .pp-flex__logo img, +.pp-message.pp-flex.black .pp-flex__logo img { filter: brightness(0) invert(1); } +.pp-message.pp-flex.monochrome .pp-flex__logo img { filter: grayscale(100%) brightness(0); } +.pp-message.pp-flex.grayscale .pp-flex__logo img { filter: grayscale(100%); } + + +.pp-message.pp-flex.r-8x1 .pp-flex__content { + display: flex; + flex-direction: row; + align-items: center; + padding-right: 1rem; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__logo-container { + flex: 0 0 33%; + justify-content: center; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__logo { + width: 60%; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(2) { + display: none; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__messaging { + flex: 1 1 100%; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__main { + font-size: 5vw; + line-height: 1; + font-weight: 400; + display: block; +} + +.pp-message.pp-flex.r-8x1 .pp-flex__disclaimer, +.pp-message.pp-flex.r-8x1 .pp-flex__action { + font-size: 10px; + line-height: 1.1; + display: inline; +} + +@media (max-aspect-ratio: 61/10) { + .pp-message.pp-flex.r-8x1 .pp-flex__logo-container { + flex-basis: 12%; + margin-bottom: -6px; + justify-content: flex-start; + margin-left: 5px; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { + margin-left: 10px; + margin-right: 0; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { + margin-left: 0; + margin-right: 0; + } +} + +@media (max-aspect-ratio: 61/10) and (min-width: 324px) { + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { width: 45%; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { width: 60%; } +} + +@media (max-aspect-ratio: 61/10) and (max-width: 374px) { + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { width: 50%; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { width: 60%; } +} + +@media (max-width: 374px) { + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { width: 55%; } + .pp-message.pp-flex.r-8x1 .pp-flex__logo-container { margin-right: 2.5%; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { width: 60%; } +} + +@media (max-aspect-ratio: 61/10) and (max-width: 323px) { + .pp-message.pp-flex.r-8x1 .pp-flex__logo-container { margin-right: 7%; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { + margin: 0 5px; + width: 30%; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(2) { + display: inline; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { + margin: 0; + width: 60%; + } +} + +@media (max-aspect-ratio: 61/10) and (min-width: 400px) { + .pp-message.pp-flex.r-8x1 .pp-flex__main { font-size: 4vw; margin-bottom: 0.5rem; } +} + +@media (max-aspect-ratio: 61/10) and (min-width: 520px) { + .pp-message.pp-flex.r-8x1 .pp-flex__disclaimer, + .pp-message.pp-flex.r-8x1 .pp-flex__action { font-size: 0.85rem; } +} + +@media (max-aspect-ratio: 61/10) and (min-width: 640px) { + .pp-message.pp-flex.r-8x1 .pp-flex__main { font-size: 1.7rem; } +} +.pp-message.pp-flex.r-8x1 .pp-flex__logo-container { + padding-bottom: 2.5px; +} + +@media (min-aspect-ratio: 80/11) { + .pp-message.pp-flex.r-8x1 .pp-flex__main { + display: block; + line-height: 1.3em; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo-container { + flex-basis: 12%; + margin-bottom: -6px; + justify-content: flex-start; + margin-left: 5px; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { + width: 50%; + margin-left: 10px; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { + width: 60%; + margin-left: 0; + } +} + +@media (min-aspect-ratio: 80/11) and (min-width: 500px) { + .pp-message.pp-flex.r-8x1 .pp-flex__main { font-size: 3vw; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo-container { flex-basis: 22%; } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(1) { + width: 18%; + margin-right: 5%; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo:nth-of-type(2) { + display: inline-block; + width: 55%; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__logo.paypal-credit:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo.venmo:nth-of-type(1), + .pp-message.pp-flex.r-8x1 .pp-flex__logo:only-child { + width: 60%; + margin-right: 0; + } + + .pp-message.pp-flex.r-8x1 .pp-flex__disclaimer, + .pp-message.pp-flex.r-8x1 .pp-flex__action { + font-size: 0.9rem; + } +} +" +`; + +exports[`v2 render flex snapshots renders flex stylesheet once 1`] = ` +"" +`; + exports[`v2 render snapshots full render snapshot for representative case 1`] = ` "