From 06dc6b8f5a290483886e3c8500b3cd03edaadac3 Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Mon, 5 Feb 2024 18:00:18 +0100 Subject: [PATCH 01/30] inital setup for audiences from target --- solutions/scripts/scripts.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 006a84ddb..83bf9cb14 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -42,6 +42,19 @@ window.hlx.plugins.add('experimentation', { url: '../plugins/experimentation/src/index.js', }); +const targetPromise = (async () => { + const resp = await fetch(/* some target service*/); + return resp.json(); +})(); + +const AUDIENCES = { + mobile: () => window.innerWidth < 600, + desktop: () => window.innerWidth >= 600, + us: async () => (await geoPromise).region === 'us', + eu: async () => (await geoPromise).region === 'eu', + targetOffer: async () => { (await targetPromise).offer } +} + /** * Creates a meta tag with the given name and value and appends it to the head. * @param {String} name The name of the meta tag From 8f68debaa53d90f9f4363fc10a32f95d8ff3be38 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Tue, 6 Feb 2024 10:00:41 +0100 Subject: [PATCH 02/30] feat: resolve audiences --- solutions/scripts/scripts.js | 53 ++++++++++++++++++++++++++---------- target.sh | 14 ++++++++++ 2 files changed, 53 insertions(+), 14 deletions(-) create mode 100755 target.sh diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 83bf9cb14..f97e8b17f 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -29,32 +29,57 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANAYTICS_TAGS = 'analytics-tags'; +const targetPromise = (async () => { + const randomString = Math.random().toString(36).substring(7); + const resp = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + context: { + channel: 'web', + }, + execute: { + pageLoad: {}, + mboxes: [ + { + name: 'Experiment 1', + index: 0, + }, + ], + }, + }), + }); + const payload = await resp.json(); + console.log(JSON.stringify(payload.execute.mboxes, null, 2)); + const mbox = payload.execute.mboxes.find((mbox) => mbox.name === 'Experiment 1'); + console.log(`Mbox: ${JSON.stringify(mbox, null, 2)}`); + const { audience } = mbox?.options[0].content || false; + console.log(`Audience: ${audience}`); + return audience; +})(); + +const AUDIENCES = { + challenger1: targetPromise.then((audience) => { + console.log(audience === 'challenger1'); + return audience === 'challenger1'; + }), +}; + window.hlx.plugins.add('rum-conversion', { load: 'lazy', url: '../plugins/rum-conversion/src/index.js', }); window.hlx.plugins.add('experimentation', { - condition: () => getMetadata('experiment'), options: { prodHost: 'www.bitdefender.com.au', + audiences: AUDIENCES, }, url: '../plugins/experimentation/src/index.js', }); -const targetPromise = (async () => { - const resp = await fetch(/* some target service*/); - return resp.json(); -})(); - -const AUDIENCES = { - mobile: () => window.innerWidth < 600, - desktop: () => window.innerWidth >= 600, - us: async () => (await geoPromise).region === 'us', - eu: async () => (await geoPromise).region === 'eu', - targetOffer: async () => { (await targetPromise).offer } -} - /** * Creates a meta tag with the given name and value and appends it to the head. * @param {String} name The name of the meta tag diff --git a/target.sh b/target.sh new file mode 100755 index 000000000..1a4545007 --- /dev/null +++ b/target.sh @@ -0,0 +1,14 @@ +curl -vvv -X POST -H "Content-type: application/json" -d '{ + "context": { + "channel": "web" + }, + "execute": { + "pageLoad": {}, + "mboxes": [ + { + "name": "Experiment 1", + "index": 0 + } + ] + } + }' 'https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=9' From a3b54fd34fc825580d8d24af9b9d74db9a810714 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Tue, 6 Feb 2024 10:57:30 +0100 Subject: [PATCH 03/30] feat: resolve audiences --- solutions/scripts/scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index f97e8b17f..8c387d522 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -61,7 +61,7 @@ const targetPromise = (async () => { })(); const AUDIENCES = { - challenger1: targetPromise.then((audience) => { + challenger1: () => targetPromise.then((audience) => { console.log(audience === 'challenger1'); return audience === 'challenger1'; }), From 1c1ccb38ba0ab22a7611a7c696abf6722aefa31f Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Tue, 6 Feb 2024 13:51:24 +0100 Subject: [PATCH 04/30] added cloudflare worker --- solutions/scripts/scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 8c387d522..5127d7b7e 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -31,7 +31,7 @@ export const METADATA_ANAYTICS_TAGS = 'analytics-tags'; const targetPromise = (async () => { const randomString = Math.random().toString(36).substring(7); - const resp = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { + const resp = await fetch(`/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { method: 'POST', headers: { 'Content-Type': 'application/json', From 473e9a940e19e6319899a27ee90859bb8dd2357c Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Tue, 6 Feb 2024 14:34:06 +0100 Subject: [PATCH 05/30] read target location --- solutions/scripts/scripts.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 5127d7b7e..d5cbbc5a0 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -53,7 +53,8 @@ const targetPromise = (async () => { }); const payload = await resp.json(); console.log(JSON.stringify(payload.execute.mboxes, null, 2)); - const mbox = payload.execute.mboxes.find((mbox) => mbox.name === 'Experiment 1'); + const targetLocation = getMetadata('target-location'); + const mbox = payload.execute.mboxes.find((mbox) => mbox.name === targetLocation); console.log(`Mbox: ${JSON.stringify(mbox, null, 2)}`); const { audience } = mbox?.options[0].content || false; console.log(`Audience: ${audience}`); From 75dd80dba8d179f32a7aca4913fa87ec12b25776 Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Tue, 6 Feb 2024 14:48:59 +0100 Subject: [PATCH 06/30] fix: target location name --- solutions/scripts/scripts.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index d5cbbc5a0..241d04b7f 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -29,6 +29,8 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANAYTICS_TAGS = 'analytics-tags'; +const targetLocation = getMetadata('target-location'); + const targetPromise = (async () => { const randomString = Math.random().toString(36).substring(7); const resp = await fetch(`/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { @@ -44,7 +46,7 @@ const targetPromise = (async () => { pageLoad: {}, mboxes: [ { - name: 'Experiment 1', + name: targetLocation, index: 0, }, ], @@ -53,7 +55,6 @@ const targetPromise = (async () => { }); const payload = await resp.json(); console.log(JSON.stringify(payload.execute.mboxes, null, 2)); - const targetLocation = getMetadata('target-location'); const mbox = payload.execute.mboxes.find((mbox) => mbox.name === targetLocation); console.log(`Mbox: ${JSON.stringify(mbox, null, 2)}`); const { audience } = mbox?.options[0].content || false; From c604972bdcd49f496835d5e53c0602fb38450235 Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Tue, 6 Feb 2024 15:01:15 +0100 Subject: [PATCH 07/30] fix: target location name --- solutions/scripts/scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 241d04b7f..67f4664b1 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -29,9 +29,9 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANAYTICS_TAGS = 'analytics-tags'; -const targetLocation = getMetadata('target-location'); const targetPromise = (async () => { + const targetLocation = getMetadata('target-location'); const randomString = Math.random().toString(36).substring(7); const resp = await fetch(`/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { method: 'POST', From a68dc46abb1224a99fb143387b351ff283c56033 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 16:20:08 +0100 Subject: [PATCH 08/30] refactor: cleanup --- solutions/scripts/scripts.js | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 67f4664b1..c864db637 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -29,7 +29,6 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANAYTICS_TAGS = 'analytics-tags'; - const targetPromise = (async () => { const targetLocation = getMetadata('target-location'); const randomString = Math.random().toString(36).substring(7); @@ -54,19 +53,14 @@ const targetPromise = (async () => { }), }); const payload = await resp.json(); - console.log(JSON.stringify(payload.execute.mboxes, null, 2)); const mbox = payload.execute.mboxes.find((mbox) => mbox.name === targetLocation); - console.log(`Mbox: ${JSON.stringify(mbox, null, 2)}`); - const { audience } = mbox?.options[0].content || false; - console.log(`Audience: ${audience}`); + const { audience } = mbox?.options[0].content ?? { audience: 'default' }; + console.log(`Resolved target audience: ${audience}`); return audience; })(); const AUDIENCES = { - challenger1: () => targetPromise.then((audience) => { - console.log(audience === 'challenger1'); - return audience === 'challenger1'; - }), + challenger1: () => targetPromise.then((audience) => audience === 'challenger1'), }; window.hlx.plugins.add('rum-conversion', { From 33c641bfa5c6250ac93bb33ca6e364d46d7a7112 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 23:22:14 +0100 Subject: [PATCH 09/30] feat: add hero2 block --- solutions/blocks/hero2/hero2.css | 531 +++++++++++++++++++++++++++++++ solutions/blocks/hero2/hero2.js | 98 ++++++ 2 files changed, 629 insertions(+) create mode 100644 solutions/blocks/hero2/hero2.css create mode 100644 solutions/blocks/hero2/hero2.js diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css new file mode 100644 index 000000000..e500d46ef --- /dev/null +++ b/solutions/blocks/hero2/hero2.css @@ -0,0 +1,531 @@ + /* block specific CSS goes here */ +:root { + /* hero font size */ + --hero-font-size-xxxl: 50px; + --hero-font-size-xxl: 48px; + --hero-font-size-xl: 40px; + --hero-font-size-l: 32px; + --hero-font-size-m: 22px; + --hero-font-size-s: 20px; + --hero-font-size-xs: 18px; + --hero-font-size-xxs: 16px; + --hero-font-size-xxxs: 14px; + --hero-h1-font-size: 32px; + --hero-h2-font-size: 24px; + --hero-botton-border-color: #616161; + --hero-p-color: #3c3c3c; + + /* breadcrumbs font size */ + --breadcrumb-text-color-dark: #c5c5c5; + --breadcrumb-text-color-dark-hover: #616161; + --breadcrumbs-font-size-s: 12px; +} + + +/* breadcrumbs */ + +main .hero .hero-content .breadcrumb { + font-weight: var(--font-weight-bold); + color: #dedede; + min-height: 82px; + padding: 12px 0; + margin-bottom: 12px; +} + +main .hero .hero-content .breadcrumb a { + font-size: var(--breadcrumbs-font-size-s); + font-weight: var(--font-weight-bold); + color: var(--breadcrumb-text-color-dark-hover); + text-decoration: none; + line-height: 1.7; + letter-spacing: .96px; +} + +main .hero .hero-content .breadcrumb a:last-child { + padding: 0; + margin: 0; + pointer-events: none; +} + +main .hero .hero-content .breadcrumb a::after { + content: "/"; + display: inline-block; + color: var(--color-dark-gray); + margin: 0 3px; + font-size: 9pt; +} + +main .hero .hero-content .breadcrumb a:hover { + color: var(--text-color); +} + +main .hero.black-background .hero-content .breadcrumb a { + color: var(--breadcrumb-text-color-dark); + text-decoration: none; +} + +main .hero.black-background .hero-content .breadcrumb a::after { + color: #dedede; +} + +main .hero.black-background .hero-content .breadcrumb a:hover { + color: var(--breadcrumb-text-color-dark-hover); +} + +/* hero */ + +main .hero-container > div { + max-width: unset; +} + +main .hero-container { + padding: 0; + margin: 0 auto; +} + +main .hero .hero-content > div { + width: 100%; +} + +main .hero-container .hero-wrapper { + padding: 0; +} + +main .hero { + position: relative; + padding: 0; + min-height: 300px; +} + +main .hero.black-background { + background-color: var(--dark-background-color); +} + +main .hero.comparison { + height: 600px; +} + +main .hero .hero-picture { + border: 1px solid #000; + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +main .hero .hero-content { + display: flex; + flex-direction: column; + padding: 17px var(--body-padding) 56px; + margin: 0 auto; + position: relative; +} + +main .hero .hero-content .right-col { + display: flex; + justify-content: center; + flex-direction: column; +} + +main .hero.black-background .hero-content { + background: linear-gradient(90deg, #000 0%, #000 15%, #fff0 100%); +} + +main .hero.comparison .hero-content { + height: 100%; + padding: 40px; + justify-content: center; + flex-direction: column; +} + +main .hero h1 { + font-size: var(--hero-h1-font-size); + margin: 0 0 25px; +} + +main .hero h2 { + font-size: 18px; + color: var(--text-color); + margin: 0 0 9px; + padding: 15px 0 0; + letter-spacing: .003em; +} + +main .hero h2, +main .hero h4 { + padding: 0; + letter-spacing: normal; + margin: 0 0 9px; +} + +main .hero.black-background h1, +main .hero.black-background h2, +main .hero.black-background h4 { + color: var(--text-dark-color); +} + +main .hero.comparison h1 { + font-weight: var(--font-weight-regular); +} + +main .hero p { + color: var(--hero-p-color); + font-size: var(--hero-font-size-xxxs); + font-weight: var(--font-weight-regular); + line-height: 1.5; + display: block; + letter-spacing: .006em; + margin: 0; +} + +main .hero h1 + p { + margin: 8px 0 0; + color: #616161; + font-size: var(--hero-font-size-xxs); + font-weight: var(--font-weight-bold); + line-height: 1.5; +} + +main .hero.comparison p { + font-size: 18px; + font-weight: 400; + font-stretch: normal; + font-style: normal; + line-height: 1.5; + letter-spacing: normal; + color: #fff; + margin: 24px 0 0; +} + +main .hero.black-background h1 + p { + color: var(--text-dark-color); +} + +main .hero p.button-container { + margin: 0; + padding: 10px 0; + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + gap: 2px; +} + +main .hero p.button-container.discount-bubble-container{ + padding-top: 0; +} + +main .hero img { + object-fit: cover; + width: 100%; + height: 100%; +} + +main .hero .hero-picture picture img { + position: absolute; + display: none; + padding-left: 200px; +} + +main .hero a.button { + margin: 8px 13px 0 0; +} + +main .hero a.button.modal { + padding: 0 28px 0 0; + min-width: unset; +} + +@media (min-width: 1400px){ + main .hero a.button { + min-width: 360px; + justify-content: center; + align-items: center; + } +} + +main .hero a.button span.button-text { + transition: all .25s cubic-bezier(.4,0,.2,1); + display: inline-block; + position: relative; + font-size: var(--hero-font-size-xs); + font-weight: var(--font-weight-bold); +} + + +main .hero .discount-bubble { + background: #2cb43d; + border-radius: 50%; + width: 72px; + height: 72px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + gap: 2px; + bottom: -5px; + right: 0; + position: relative; +} + +main .hero .discount-bubble .discount-bubble-0 { + font-size: 24px; + color: #fff; + font-weight: var(--font-weight-boldest); + line-height: .8; + text-decoration: none; + padding-top: 12px; +} + +main .hero .discount-bubble .discount-bubble-1 { + font-size: 11px; + color: #fff; + line-height: 1.71; + font-weight: var(--font-weight-bold); + font-style: normal; + text-decoration: none; +} + +main .hero .wrapper-plan-discount { + margin: 0 0 10px; + display: -webkit-box; + display: flex; + flex-wrap: wrap; + -webkit-box-align: center; + -ms-flex-align: center; + align-items: center +} + +main .hero .hero-content ul { + margin: 20px 0 0; + padding: 0; + text-align: left; + list-style-type: none; +} + +main .hero .hero-content ul li { + font-size: var(--hero-font-size-xxxs); + font-weight: var(--font-weight-regular); + letter-spacing: 0.096px; + line-height: 1.5; + color: var(--hero-p-color); + margin: 13px 0 0; + padding: 0 0 0 20px; + position: relative; + list-style: none; +} + +main .hero .hero-content ul li:first-child { + margin: 9px 0 0; +} + +main .hero ul li::before { + content: ""; + position: absolute; + left: 0; + top: 3px; + width: 15px; + height: 15px; + background-color: var(--background-checkmark); + border-radius: 50%; + z-index: 1; +} + +main .hero ul li::after { + content: ""; + position: absolute; + left: 5px; + top: 5px; + width: 3px; + height: 7px; + border-bottom: 2px solid var( --white-color); + border-right: 2px solid var( --white-color); + transform: rotate(45deg); + z-index: 2; +} + +main .hero ul.hero-awards { + display: flex; + flex-flow: row wrap; + align-items: center; + justify-content: flex-start; + margin: 0; + padding: 40px 0 48px; + text-align: left; +} + +main .hero .hero-content ul.hero-awards li { + display: block; + min-height: 20px; + margin: 0 20px 30px 0; + padding: 0; + width: auto; +} + +main .hero ul.hero-awards li::before { + content: none; +} + +main .hero ul.hero-awards li picture img { + display: block; + height: 80px; + width: auto; +} + +main .hero .hero-awards li::after { + content: none; +} + +@media(min-width: 767px) { /* tablet */ + :root { + --hero-h1-font-size: 42px; + } + + main .hero h2 { + font-size: 20px; + } + + main .hero .hero-content .breadcrumb { + min-height: 58px; + } + + main .hero .hero-content .breadcrumb a::after { + margin: 0 9px; + } + +} + +@media (min-width: 990px) { /* desktop */ + + main .hero .hero-content > div.left-col { + width: 50%; + } + + main .hero .hero-content > div.right-col { + width: 50%; + padding-left: 1.25rem; + } + + main .hero h2 { + font-size: 22px; + margin-bottom: 10px; + } + + main .hero h1 { + font-size: 50px; + } + + main .hero .hero-picture { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + } + + main .hero p { + font-size: 14px; + margin: 0; + } + + main .hero .hero-picture picture img { + display: block; + padding-left: 0; + } + + main .hero .hero-content { + max-width: var(--section-desktop-max-width); + min-height: unset; + padding: 112px var(--section-desktop-padding) 54px var(--section-desktop-padding); + padding-top: 115px; + display: flex; + flex-direction: row; + } + + main .hero a.button.primary { + min-width: 360px; + } + + main .hero .hero-content > div { + width: 60%; + padding: 0 20px 0 0; + } + + main .hero.comparison .hero-content > div { + width: 65%; + padding: 40px 0 0; + } + + main .hero .hero-content .breadcrumb a { + line-height: 1; + letter-spacing: .96px; + } + + main .hero ul.hero-awards { + display: flex; + flex-direction: row; + align-items: center; + justify-content: flex-start; + margin: 0; + padding: 40px 0 0; + } + + main .hero ul.hero-awards li { + display: block; + min-height: 20px; + margin: 9px 20px 0 0; + padding: 0; + width: auto; + } + +} + +@media (min-width: 1300px) { + main .hero .hero-picture picture img { + padding-left: 20%; + } +} + +@media (min-width: 1600px) { /* large desktop */ + + + main .hero .hero-content .breadcrumb { + padding: 9px 0; + margin-bottom: 15px; + } + + main .hero h2 { + font-size: 24px; + } + + main .hero h1 { + font-size: 56px; + } + + main .hero .hero-picture picture img { + display: block; + padding-left: 25%; + } + + main .hero .discount-bubble { + width: 83px; + height: 83px; + } + + main .hero .discount-bubble .discount-bubble-0 { + font-size: 32px; + } + + main .hero .discount-bubble .discount-bubble-1 { + font-size: 14px; + } + + main .hero .hero-content { + min-height: 725px; + max-width: var(--section-large-desktop-max-width); + padding-left: var(--section-large-desktop-padding); + padding-right: var(--section-large-desktop-padding); + } +} diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js new file mode 100644 index 000000000..4ec77d913 --- /dev/null +++ b/solutions/blocks/hero2/hero2.js @@ -0,0 +1,98 @@ +// Description: Hero block +import { + createTag, + createNanoBlock, + renderNanoBlocks, + fetchProduct, +} from '../../scripts/utils/utils.js'; + +/** + * Builds hero block and prepends to main in a new section. + * @param {Element} element The container element + */ +function buildHeroBlock(element) { + const h1 = element.querySelector('h1'); + const picture = element.querySelector('picture'); + const pictureParent = picture ? picture.parentNode : false; + // eslint-disable-next-line no-bitwise + if (h1 && picture && (h1.compareDocumentPosition(picture) & Node.DOCUMENT_POSITION_PRECEDING)) { + const section = document.querySelector('div.hero'); + const subSection = document.querySelector('div.hero div'); + subSection.classList.add('hero-content'); + + const breadcrumb = createTag('div', { class: 'breadcrumb' }); + document.querySelector('div.hero div div:first-child').prepend(breadcrumb); + + const pictureEl = document.createElement('div'); + pictureEl.classList.add('hero-picture'); + pictureEl.append(picture); + + section.prepend(pictureEl); + + pictureParent.remove(); + } +} + +createNanoBlock('discount', (code, variant) => { + const root = document.createElement('div'); + root.classList.add('discount-bubble'); + root.innerHTML = ` + --% + Discount + `; + + fetchProduct(code, variant) + .then((product) => { + if (product.discount) { + const discount = Math.round( + (1 - (product.discount.discounted_price) / product.price) * 100, + ); + root.querySelector('.discount-bubble-0').textContent = `${discount}%`; + } else { + // eslint-disable-next-line no-console + console.error('no discount available'); + } + }) + .catch((err) => { + // eslint-disable-next-line no-console + console.error(err); + }); + return root; +}); + +/** + * decorates hero block + * @param {Element} block The hero block element + */ +export default async function decorate(block) { + buildHeroBlock(block); + // Eager load images to improve LCP + [...block.querySelectorAll('img')].forEach((el) => el.setAttribute('loading', 'eager')); + + // get div class hero-content + const elementHeroContent = block.querySelector('.hero div.hero-content div'); + + if (elementHeroContent !== null) { + // Select
    elements that contain a tag + const ulsWithPicture = Array.from(document.querySelectorAll('ul')).filter((ul) => ul.querySelector('picture')); + + // Apply a CSS class to each selected
      element + ulsWithPicture.forEach((ul) => ul.classList.add('hero-awards')); + + renderNanoBlocks(block); + + // move discount bubble inside the closest button + const bubble = block.querySelector('.discount-bubble'); + if (bubble) { + let sibling = bubble.previousElementSibling; + + while (sibling) { + if (sibling.matches('.button-container')) { + sibling.append(bubble); + break; + } + sibling = sibling.previousElementSibling; + } + } + } +} From b990e8a02f1883e7f672d3781d7ed81ec58470ce Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 23:36:21 +0100 Subject: [PATCH 10/30] feat: add hero2 block --- solutions/blocks/hero2/hero2.css | 128 +++++++++++++++---------------- solutions/blocks/hero2/hero2.js | 8 +- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index e500d46ef..2180790a6 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -114,7 +114,7 @@ main .hero .hero-picture { right: 0; } -main .hero .hero-content { +main .hero2 .hero2-content { display: flex; flex-direction: column; padding: 17px var(--body-padding) 56px; @@ -122,29 +122,29 @@ main .hero .hero-content { position: relative; } -main .hero .hero-content .right-col { +main .hero2 .hero2-content .right-col { display: flex; justify-content: center; flex-direction: column; } -main .hero.black-background .hero-content { +main .hero2.black-background .hero2-content { background: linear-gradient(90deg, #000 0%, #000 15%, #fff0 100%); } -main .hero.comparison .hero-content { +main .hero2.comparison .hero2-content { height: 100%; padding: 40px; justify-content: center; flex-direction: column; } -main .hero h1 { +main .hero2 h1 { font-size: var(--hero-h1-font-size); margin: 0 0 25px; } -main .hero h2 { +main .hero2 h2 { font-size: 18px; color: var(--text-color); margin: 0 0 9px; @@ -152,24 +152,24 @@ main .hero h2 { letter-spacing: .003em; } -main .hero h2, -main .hero h4 { +main .hero2 h2, +main .hero2 h4 { padding: 0; letter-spacing: normal; margin: 0 0 9px; } -main .hero.black-background h1, -main .hero.black-background h2, -main .hero.black-background h4 { +main .hero2.black-background h1, +main .hero2.black-background h2, +main .hero2.black-background h4 { color: var(--text-dark-color); } -main .hero.comparison h1 { +main .hero2.comparison h1 { font-weight: var(--font-weight-regular); } -main .hero p { +main .hero2 p { color: var(--hero-p-color); font-size: var(--hero-font-size-xxxs); font-weight: var(--font-weight-regular); @@ -179,7 +179,7 @@ main .hero p { margin: 0; } -main .hero h1 + p { +main .hero2 h1 + p { margin: 8px 0 0; color: #616161; font-size: var(--hero-font-size-xxs); @@ -187,7 +187,7 @@ main .hero h1 + p { line-height: 1.5; } -main .hero.comparison p { +main .hero2.comparison p { font-size: 18px; font-weight: 400; font-stretch: normal; @@ -198,11 +198,11 @@ main .hero.comparison p { margin: 24px 0 0; } -main .hero.black-background h1 + p { +main .hero2.black-background h1 + p { color: var(--text-dark-color); } -main .hero p.button-container { +main .hero2 p.button-container { margin: 0; padding: 10px 0; display: flex; @@ -212,40 +212,40 @@ main .hero p.button-container { gap: 2px; } -main .hero p.button-container.discount-bubble-container{ +main .hero2 p.button-container.discount-bubble-container{ padding-top: 0; } -main .hero img { +main .hero2 img { object-fit: cover; width: 100%; height: 100%; } -main .hero .hero-picture picture img { +main .hero2 .hero2-picture picture img { position: absolute; display: none; padding-left: 200px; } -main .hero a.button { +main .hero2 a.button { margin: 8px 13px 0 0; } -main .hero a.button.modal { +main .hero2 a.button.modal { padding: 0 28px 0 0; min-width: unset; } @media (min-width: 1400px){ - main .hero a.button { + main .hero2 a.button { min-width: 360px; justify-content: center; align-items: center; } } -main .hero a.button span.button-text { +main .hero2 a.button span.button-text { transition: all .25s cubic-bezier(.4,0,.2,1); display: inline-block; position: relative; @@ -254,7 +254,7 @@ main .hero a.button span.button-text { } -main .hero .discount-bubble { +main .hero2 .discount-bubble { background: #2cb43d; border-radius: 50%; width: 72px; @@ -270,7 +270,7 @@ main .hero .discount-bubble { position: relative; } -main .hero .discount-bubble .discount-bubble-0 { +main .hero2 .discount-bubble .discount-bubble-0 { font-size: 24px; color: #fff; font-weight: var(--font-weight-boldest); @@ -279,7 +279,7 @@ main .hero .discount-bubble .discount-bubble-0 { padding-top: 12px; } -main .hero .discount-bubble .discount-bubble-1 { +main .hero2 .discount-bubble .discount-bubble-1 { font-size: 11px; color: #fff; line-height: 1.71; @@ -288,7 +288,7 @@ main .hero .discount-bubble .discount-bubble-1 { text-decoration: none; } -main .hero .wrapper-plan-discount { +main .hero2 .wrapper-plan-discount { margin: 0 0 10px; display: -webkit-box; display: flex; @@ -298,14 +298,14 @@ main .hero .wrapper-plan-discount { align-items: center } -main .hero .hero-content ul { +main .hero2 .hero2-content ul { margin: 20px 0 0; padding: 0; text-align: left; list-style-type: none; } -main .hero .hero-content ul li { +main .hero2 .hero2-content ul li { font-size: var(--hero-font-size-xxxs); font-weight: var(--font-weight-regular); letter-spacing: 0.096px; @@ -317,11 +317,11 @@ main .hero .hero-content ul li { list-style: none; } -main .hero .hero-content ul li:first-child { +main .hero2 .hero2-content ul li:first-child { margin: 9px 0 0; } -main .hero ul li::before { +main .hero2 ul li::before { content: ""; position: absolute; left: 0; @@ -333,7 +333,7 @@ main .hero ul li::before { z-index: 1; } -main .hero ul li::after { +main .hero2 ul li::after { content: ""; position: absolute; left: 5px; @@ -346,7 +346,7 @@ main .hero ul li::after { z-index: 2; } -main .hero ul.hero-awards { +main .hero2 ul.hero2-awards { display: flex; flex-flow: row wrap; align-items: center; @@ -356,7 +356,7 @@ main .hero ul.hero-awards { text-align: left; } -main .hero .hero-content ul.hero-awards li { +main .hero2 .hero2-content ul.hero2-awards li { display: block; min-height: 20px; margin: 0 20px 30px 0; @@ -364,17 +364,17 @@ main .hero .hero-content ul.hero-awards li { width: auto; } -main .hero ul.hero-awards li::before { +main .hero2 ul.hero2-awards li::before { content: none; } -main .hero ul.hero-awards li picture img { +main .hero2 ul.hero2-awards li picture img { display: block; height: 80px; width: auto; } -main .hero .hero-awards li::after { +main .hero2 .hero2-awards li::after { content: none; } @@ -383,15 +383,15 @@ main .hero .hero-awards li::after { --hero-h1-font-size: 42px; } - main .hero h2 { + main .hero2 h2 { font-size: 20px; } - main .hero .hero-content .breadcrumb { + main .hero2 .hero2-content .breadcrumb { min-height: 58px; } - main .hero .hero-content .breadcrumb a::after { + main .hero2 .hero2-content .breadcrumb a::after { margin: 0 9px; } @@ -399,25 +399,25 @@ main .hero .hero-awards li::after { @media (min-width: 990px) { /* desktop */ - main .hero .hero-content > div.left-col { + main .hero2 .hero2-content > div.left-col { width: 50%; } - main .hero .hero-content > div.right-col { + main .hero2 .hero2-content > div.right-col { width: 50%; padding-left: 1.25rem; } - main .hero h2 { + main .hero2 h2 { font-size: 22px; margin-bottom: 10px; } - main .hero h1 { + main .hero2 h1 { font-size: 50px; } - main .hero .hero-picture { + main .hero2 .hero2-picture { position: absolute; top: 0; bottom: 0; @@ -425,17 +425,17 @@ main .hero .hero-awards li::after { right: 0; } - main .hero p { + main .hero2 p { font-size: 14px; margin: 0; } - main .hero .hero-picture picture img { + main .hero2 .hero2-picture picture img { display: block; padding-left: 0; } - main .hero .hero-content { + main .hero2 .hero2-content { max-width: var(--section-desktop-max-width); min-height: unset; padding: 112px var(--section-desktop-padding) 54px var(--section-desktop-padding); @@ -444,26 +444,26 @@ main .hero .hero-awards li::after { flex-direction: row; } - main .hero a.button.primary { + main .hero2 a.button.primary { min-width: 360px; } - main .hero .hero-content > div { + main .hero2 .hero2-content > div { width: 60%; padding: 0 20px 0 0; } - main .hero.comparison .hero-content > div { + main .hero2.comparison .hero2-content > div { width: 65%; padding: 40px 0 0; } - main .hero .hero-content .breadcrumb a { + main .hero2 .hero2-content .breadcrumb a { line-height: 1; letter-spacing: .96px; } - main .hero ul.hero-awards { + main .hero2 ul.hero2-awards { display: flex; flex-direction: row; align-items: center; @@ -472,7 +472,7 @@ main .hero .hero-awards li::after { padding: 40px 0 0; } - main .hero ul.hero-awards li { + main .hero2 ul.hero2-awards li { display: block; min-height: 20px; margin: 9px 20px 0 0; @@ -483,7 +483,7 @@ main .hero .hero-awards li::after { } @media (min-width: 1300px) { - main .hero .hero-picture picture img { + main .hero2 .hero2-picture picture img { padding-left: 20%; } } @@ -491,38 +491,38 @@ main .hero .hero-awards li::after { @media (min-width: 1600px) { /* large desktop */ - main .hero .hero-content .breadcrumb { + main .hero2 .hero2-content .breadcrumb { padding: 9px 0; margin-bottom: 15px; } - main .hero h2 { + main .hero2 h2 { font-size: 24px; } - main .hero h1 { + main .hero2 h1 { font-size: 56px; } - main .hero .hero-picture picture img { + main .hero2 .hero2-picture picture img { display: block; padding-left: 25%; } - main .hero .discount-bubble { + main .hero2 .discount-bubble { width: 83px; height: 83px; } - main .hero .discount-bubble .discount-bubble-0 { + main .hero2 .discount-bubble .discount-bubble-0 { font-size: 32px; } - main .hero .discount-bubble .discount-bubble-1 { + main .hero2 .discount-bubble .discount-bubble-1 { font-size: 14px; } - main .hero .hero-content { + main .hero2 .hero2-content { min-height: 725px; max-width: var(--section-large-desktop-max-width); padding-left: var(--section-large-desktop-padding); diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js index 4ec77d913..7718e3ee6 100644 --- a/solutions/blocks/hero2/hero2.js +++ b/solutions/blocks/hero2/hero2.js @@ -16,12 +16,12 @@ function buildHeroBlock(element) { const pictureParent = picture ? picture.parentNode : false; // eslint-disable-next-line no-bitwise if (h1 && picture && (h1.compareDocumentPosition(picture) & Node.DOCUMENT_POSITION_PRECEDING)) { - const section = document.querySelector('div.hero'); - const subSection = document.querySelector('div.hero div'); + const section = document.querySelector('div.hero2'); + const subSection = document.querySelector('div.hero2 div'); subSection.classList.add('hero-content'); const breadcrumb = createTag('div', { class: 'breadcrumb' }); - document.querySelector('div.hero div div:first-child').prepend(breadcrumb); + document.querySelector('div.hero2 div div:first-child').prepend(breadcrumb); const pictureEl = document.createElement('div'); pictureEl.classList.add('hero-picture'); @@ -70,7 +70,7 @@ export default async function decorate(block) { [...block.querySelectorAll('img')].forEach((el) => el.setAttribute('loading', 'eager')); // get div class hero-content - const elementHeroContent = block.querySelector('.hero div.hero-content div'); + const elementHeroContent = block.querySelector('.hero2 div.hero2-content div'); if (elementHeroContent !== null) { // Select
        elements that contain a tag From ad6369f0576104e08d08e7641ffaa22299abf680 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 23:38:52 +0100 Subject: [PATCH 11/30] feat: add hero2 block --- solutions/blocks/hero2/hero2.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js index 7718e3ee6..ddaa837d9 100644 --- a/solutions/blocks/hero2/hero2.js +++ b/solutions/blocks/hero2/hero2.js @@ -24,7 +24,7 @@ function buildHeroBlock(element) { document.querySelector('div.hero2 div div:first-child').prepend(breadcrumb); const pictureEl = document.createElement('div'); - pictureEl.classList.add('hero-picture'); + pictureEl.classList.add('hero2-picture'); pictureEl.append(picture); section.prepend(pictureEl); @@ -77,7 +77,7 @@ export default async function decorate(block) { const ulsWithPicture = Array.from(document.querySelectorAll('ul')).filter((ul) => ul.querySelector('picture')); // Apply a CSS class to each selected
          element - ulsWithPicture.forEach((ul) => ul.classList.add('hero-awards')); + ulsWithPicture.forEach((ul) => ul.classList.add('hero2-awards')); renderNanoBlocks(block); From 2ad4338e898808b65b5b66e25b42c2c6ff47f022 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 23:39:45 +0100 Subject: [PATCH 12/30] feat: add hero2 block --- solutions/blocks/hero2/hero2.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index 2180790a6..718c2bb62 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -24,7 +24,7 @@ /* breadcrumbs */ -main .hero .hero-content .breadcrumb { +main .hero2 .hero2-content .breadcrumb { font-weight: var(--font-weight-bold); color: #dedede; min-height: 82px; From a87ca2746ab7b9fc315ecf4a90d8fd6b4d2fa10b Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 7 Feb 2024 23:41:18 +0100 Subject: [PATCH 13/30] feat: add hero2 block --- solutions/blocks/hero2/hero2.css | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index 718c2bb62..f37c775b8 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -32,7 +32,7 @@ main .hero2 .hero2-content .breadcrumb { margin-bottom: 12px; } -main .hero .hero-content .breadcrumb a { +main .hero2 .hero2-content .breadcrumb a { font-size: var(--breadcrumbs-font-size-s); font-weight: var(--font-weight-bold); color: var(--breadcrumb-text-color-dark-hover); @@ -41,13 +41,13 @@ main .hero .hero-content .breadcrumb a { letter-spacing: .96px; } -main .hero .hero-content .breadcrumb a:last-child { +main .hero2 .hero2-content .breadcrumb a:last-child { padding: 0; margin: 0; pointer-events: none; } -main .hero .hero-content .breadcrumb a::after { +main .hero2 .hero2-content .breadcrumb a::after { content: "/"; display: inline-block; color: var(--color-dark-gray); @@ -55,57 +55,57 @@ main .hero .hero-content .breadcrumb a::after { font-size: 9pt; } -main .hero .hero-content .breadcrumb a:hover { +main .hero2 .hero2-content .breadcrumb a:hover { color: var(--text-color); } -main .hero.black-background .hero-content .breadcrumb a { +main .hero2.black-background .hero2-content .breadcrumb a { color: var(--breadcrumb-text-color-dark); text-decoration: none; } -main .hero.black-background .hero-content .breadcrumb a::after { +main .hero2.black-background .hero2-content .breadcrumb a::after { color: #dedede; } -main .hero.black-background .hero-content .breadcrumb a:hover { +main .hero2.black-background .hero2-content .breadcrumb a:hover { color: var(--breadcrumb-text-color-dark-hover); } /* hero */ -main .hero-container > div { +main .hero2-container > div { max-width: unset; } -main .hero-container { +main .hero2-container { padding: 0; margin: 0 auto; } -main .hero .hero-content > div { +main .hero2 .hero2-content > div { width: 100%; } -main .hero-container .hero-wrapper { +main .hero2-container .hero2-wrapper { padding: 0; } -main .hero { +main .hero2 { position: relative; padding: 0; min-height: 300px; } -main .hero.black-background { +main .hero2.black-background { background-color: var(--dark-background-color); } -main .hero.comparison { +main .hero2.comparison { height: 600px; } -main .hero .hero-picture { +main .hero2 .hero2-picture { border: 1px solid #000; position: absolute; top: 0; From 54873afc317b52de782a90266511f547c0f58bbd Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Thu, 8 Feb 2024 10:10:16 +0100 Subject: [PATCH 14/30] Revert "feat: add hero2 block" This reverts commit a87ca2746ab7b9fc315ecf4a90d8fd6b4d2fa10b. --- solutions/blocks/hero2/hero2.css | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index f37c775b8..718c2bb62 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -32,7 +32,7 @@ main .hero2 .hero2-content .breadcrumb { margin-bottom: 12px; } -main .hero2 .hero2-content .breadcrumb a { +main .hero .hero-content .breadcrumb a { font-size: var(--breadcrumbs-font-size-s); font-weight: var(--font-weight-bold); color: var(--breadcrumb-text-color-dark-hover); @@ -41,13 +41,13 @@ main .hero2 .hero2-content .breadcrumb a { letter-spacing: .96px; } -main .hero2 .hero2-content .breadcrumb a:last-child { +main .hero .hero-content .breadcrumb a:last-child { padding: 0; margin: 0; pointer-events: none; } -main .hero2 .hero2-content .breadcrumb a::after { +main .hero .hero-content .breadcrumb a::after { content: "/"; display: inline-block; color: var(--color-dark-gray); @@ -55,57 +55,57 @@ main .hero2 .hero2-content .breadcrumb a::after { font-size: 9pt; } -main .hero2 .hero2-content .breadcrumb a:hover { +main .hero .hero-content .breadcrumb a:hover { color: var(--text-color); } -main .hero2.black-background .hero2-content .breadcrumb a { +main .hero.black-background .hero-content .breadcrumb a { color: var(--breadcrumb-text-color-dark); text-decoration: none; } -main .hero2.black-background .hero2-content .breadcrumb a::after { +main .hero.black-background .hero-content .breadcrumb a::after { color: #dedede; } -main .hero2.black-background .hero2-content .breadcrumb a:hover { +main .hero.black-background .hero-content .breadcrumb a:hover { color: var(--breadcrumb-text-color-dark-hover); } /* hero */ -main .hero2-container > div { +main .hero-container > div { max-width: unset; } -main .hero2-container { +main .hero-container { padding: 0; margin: 0 auto; } -main .hero2 .hero2-content > div { +main .hero .hero-content > div { width: 100%; } -main .hero2-container .hero2-wrapper { +main .hero-container .hero-wrapper { padding: 0; } -main .hero2 { +main .hero { position: relative; padding: 0; min-height: 300px; } -main .hero2.black-background { +main .hero.black-background { background-color: var(--dark-background-color); } -main .hero2.comparison { +main .hero.comparison { height: 600px; } -main .hero2 .hero2-picture { +main .hero .hero-picture { border: 1px solid #000; position: absolute; top: 0; From 7b38410dd0984717104bb242770cb85c87bde30f Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Thu, 8 Feb 2024 10:10:16 +0100 Subject: [PATCH 15/30] Revert "feat: add hero2 block" This reverts commit 2ad4338e898808b65b5b66e25b42c2c6ff47f022. --- solutions/blocks/hero2/hero2.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index 718c2bb62..2180790a6 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -24,7 +24,7 @@ /* breadcrumbs */ -main .hero2 .hero2-content .breadcrumb { +main .hero .hero-content .breadcrumb { font-weight: var(--font-weight-bold); color: #dedede; min-height: 82px; From 5cc97b3f3d6001eed71b30ef45f8a4cd6cdb4269 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Thu, 8 Feb 2024 10:10:16 +0100 Subject: [PATCH 16/30] Revert "feat: add hero2 block" This reverts commit ad6369f0576104e08d08e7641ffaa22299abf680. --- solutions/blocks/hero2/hero2.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js index ddaa837d9..7718e3ee6 100644 --- a/solutions/blocks/hero2/hero2.js +++ b/solutions/blocks/hero2/hero2.js @@ -24,7 +24,7 @@ function buildHeroBlock(element) { document.querySelector('div.hero2 div div:first-child').prepend(breadcrumb); const pictureEl = document.createElement('div'); - pictureEl.classList.add('hero2-picture'); + pictureEl.classList.add('hero-picture'); pictureEl.append(picture); section.prepend(pictureEl); @@ -77,7 +77,7 @@ export default async function decorate(block) { const ulsWithPicture = Array.from(document.querySelectorAll('ul')).filter((ul) => ul.querySelector('picture')); // Apply a CSS class to each selected
            element - ulsWithPicture.forEach((ul) => ul.classList.add('hero2-awards')); + ulsWithPicture.forEach((ul) => ul.classList.add('hero-awards')); renderNanoBlocks(block); From bccb9993797ce27615d793d771568a66e5c7d80b Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Thu, 8 Feb 2024 10:10:16 +0100 Subject: [PATCH 17/30] Revert "feat: add hero2 block" This reverts commit b990e8a02f1883e7f672d3781d7ed81ec58470ce. --- solutions/blocks/hero2/hero2.css | 128 +++++++++++++++---------------- solutions/blocks/hero2/hero2.js | 8 +- 2 files changed, 68 insertions(+), 68 deletions(-) diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css index 2180790a6..e500d46ef 100644 --- a/solutions/blocks/hero2/hero2.css +++ b/solutions/blocks/hero2/hero2.css @@ -114,7 +114,7 @@ main .hero .hero-picture { right: 0; } -main .hero2 .hero2-content { +main .hero .hero-content { display: flex; flex-direction: column; padding: 17px var(--body-padding) 56px; @@ -122,29 +122,29 @@ main .hero2 .hero2-content { position: relative; } -main .hero2 .hero2-content .right-col { +main .hero .hero-content .right-col { display: flex; justify-content: center; flex-direction: column; } -main .hero2.black-background .hero2-content { +main .hero.black-background .hero-content { background: linear-gradient(90deg, #000 0%, #000 15%, #fff0 100%); } -main .hero2.comparison .hero2-content { +main .hero.comparison .hero-content { height: 100%; padding: 40px; justify-content: center; flex-direction: column; } -main .hero2 h1 { +main .hero h1 { font-size: var(--hero-h1-font-size); margin: 0 0 25px; } -main .hero2 h2 { +main .hero h2 { font-size: 18px; color: var(--text-color); margin: 0 0 9px; @@ -152,24 +152,24 @@ main .hero2 h2 { letter-spacing: .003em; } -main .hero2 h2, -main .hero2 h4 { +main .hero h2, +main .hero h4 { padding: 0; letter-spacing: normal; margin: 0 0 9px; } -main .hero2.black-background h1, -main .hero2.black-background h2, -main .hero2.black-background h4 { +main .hero.black-background h1, +main .hero.black-background h2, +main .hero.black-background h4 { color: var(--text-dark-color); } -main .hero2.comparison h1 { +main .hero.comparison h1 { font-weight: var(--font-weight-regular); } -main .hero2 p { +main .hero p { color: var(--hero-p-color); font-size: var(--hero-font-size-xxxs); font-weight: var(--font-weight-regular); @@ -179,7 +179,7 @@ main .hero2 p { margin: 0; } -main .hero2 h1 + p { +main .hero h1 + p { margin: 8px 0 0; color: #616161; font-size: var(--hero-font-size-xxs); @@ -187,7 +187,7 @@ main .hero2 h1 + p { line-height: 1.5; } -main .hero2.comparison p { +main .hero.comparison p { font-size: 18px; font-weight: 400; font-stretch: normal; @@ -198,11 +198,11 @@ main .hero2.comparison p { margin: 24px 0 0; } -main .hero2.black-background h1 + p { +main .hero.black-background h1 + p { color: var(--text-dark-color); } -main .hero2 p.button-container { +main .hero p.button-container { margin: 0; padding: 10px 0; display: flex; @@ -212,40 +212,40 @@ main .hero2 p.button-container { gap: 2px; } -main .hero2 p.button-container.discount-bubble-container{ +main .hero p.button-container.discount-bubble-container{ padding-top: 0; } -main .hero2 img { +main .hero img { object-fit: cover; width: 100%; height: 100%; } -main .hero2 .hero2-picture picture img { +main .hero .hero-picture picture img { position: absolute; display: none; padding-left: 200px; } -main .hero2 a.button { +main .hero a.button { margin: 8px 13px 0 0; } -main .hero2 a.button.modal { +main .hero a.button.modal { padding: 0 28px 0 0; min-width: unset; } @media (min-width: 1400px){ - main .hero2 a.button { + main .hero a.button { min-width: 360px; justify-content: center; align-items: center; } } -main .hero2 a.button span.button-text { +main .hero a.button span.button-text { transition: all .25s cubic-bezier(.4,0,.2,1); display: inline-block; position: relative; @@ -254,7 +254,7 @@ main .hero2 a.button span.button-text { } -main .hero2 .discount-bubble { +main .hero .discount-bubble { background: #2cb43d; border-radius: 50%; width: 72px; @@ -270,7 +270,7 @@ main .hero2 .discount-bubble { position: relative; } -main .hero2 .discount-bubble .discount-bubble-0 { +main .hero .discount-bubble .discount-bubble-0 { font-size: 24px; color: #fff; font-weight: var(--font-weight-boldest); @@ -279,7 +279,7 @@ main .hero2 .discount-bubble .discount-bubble-0 { padding-top: 12px; } -main .hero2 .discount-bubble .discount-bubble-1 { +main .hero .discount-bubble .discount-bubble-1 { font-size: 11px; color: #fff; line-height: 1.71; @@ -288,7 +288,7 @@ main .hero2 .discount-bubble .discount-bubble-1 { text-decoration: none; } -main .hero2 .wrapper-plan-discount { +main .hero .wrapper-plan-discount { margin: 0 0 10px; display: -webkit-box; display: flex; @@ -298,14 +298,14 @@ main .hero2 .wrapper-plan-discount { align-items: center } -main .hero2 .hero2-content ul { +main .hero .hero-content ul { margin: 20px 0 0; padding: 0; text-align: left; list-style-type: none; } -main .hero2 .hero2-content ul li { +main .hero .hero-content ul li { font-size: var(--hero-font-size-xxxs); font-weight: var(--font-weight-regular); letter-spacing: 0.096px; @@ -317,11 +317,11 @@ main .hero2 .hero2-content ul li { list-style: none; } -main .hero2 .hero2-content ul li:first-child { +main .hero .hero-content ul li:first-child { margin: 9px 0 0; } -main .hero2 ul li::before { +main .hero ul li::before { content: ""; position: absolute; left: 0; @@ -333,7 +333,7 @@ main .hero2 ul li::before { z-index: 1; } -main .hero2 ul li::after { +main .hero ul li::after { content: ""; position: absolute; left: 5px; @@ -346,7 +346,7 @@ main .hero2 ul li::after { z-index: 2; } -main .hero2 ul.hero2-awards { +main .hero ul.hero-awards { display: flex; flex-flow: row wrap; align-items: center; @@ -356,7 +356,7 @@ main .hero2 ul.hero2-awards { text-align: left; } -main .hero2 .hero2-content ul.hero2-awards li { +main .hero .hero-content ul.hero-awards li { display: block; min-height: 20px; margin: 0 20px 30px 0; @@ -364,17 +364,17 @@ main .hero2 .hero2-content ul.hero2-awards li { width: auto; } -main .hero2 ul.hero2-awards li::before { +main .hero ul.hero-awards li::before { content: none; } -main .hero2 ul.hero2-awards li picture img { +main .hero ul.hero-awards li picture img { display: block; height: 80px; width: auto; } -main .hero2 .hero2-awards li::after { +main .hero .hero-awards li::after { content: none; } @@ -383,15 +383,15 @@ main .hero2 .hero2-awards li::after { --hero-h1-font-size: 42px; } - main .hero2 h2 { + main .hero h2 { font-size: 20px; } - main .hero2 .hero2-content .breadcrumb { + main .hero .hero-content .breadcrumb { min-height: 58px; } - main .hero2 .hero2-content .breadcrumb a::after { + main .hero .hero-content .breadcrumb a::after { margin: 0 9px; } @@ -399,25 +399,25 @@ main .hero2 .hero2-awards li::after { @media (min-width: 990px) { /* desktop */ - main .hero2 .hero2-content > div.left-col { + main .hero .hero-content > div.left-col { width: 50%; } - main .hero2 .hero2-content > div.right-col { + main .hero .hero-content > div.right-col { width: 50%; padding-left: 1.25rem; } - main .hero2 h2 { + main .hero h2 { font-size: 22px; margin-bottom: 10px; } - main .hero2 h1 { + main .hero h1 { font-size: 50px; } - main .hero2 .hero2-picture { + main .hero .hero-picture { position: absolute; top: 0; bottom: 0; @@ -425,17 +425,17 @@ main .hero2 .hero2-awards li::after { right: 0; } - main .hero2 p { + main .hero p { font-size: 14px; margin: 0; } - main .hero2 .hero2-picture picture img { + main .hero .hero-picture picture img { display: block; padding-left: 0; } - main .hero2 .hero2-content { + main .hero .hero-content { max-width: var(--section-desktop-max-width); min-height: unset; padding: 112px var(--section-desktop-padding) 54px var(--section-desktop-padding); @@ -444,26 +444,26 @@ main .hero2 .hero2-awards li::after { flex-direction: row; } - main .hero2 a.button.primary { + main .hero a.button.primary { min-width: 360px; } - main .hero2 .hero2-content > div { + main .hero .hero-content > div { width: 60%; padding: 0 20px 0 0; } - main .hero2.comparison .hero2-content > div { + main .hero.comparison .hero-content > div { width: 65%; padding: 40px 0 0; } - main .hero2 .hero2-content .breadcrumb a { + main .hero .hero-content .breadcrumb a { line-height: 1; letter-spacing: .96px; } - main .hero2 ul.hero2-awards { + main .hero ul.hero-awards { display: flex; flex-direction: row; align-items: center; @@ -472,7 +472,7 @@ main .hero2 .hero2-awards li::after { padding: 40px 0 0; } - main .hero2 ul.hero2-awards li { + main .hero ul.hero-awards li { display: block; min-height: 20px; margin: 9px 20px 0 0; @@ -483,7 +483,7 @@ main .hero2 .hero2-awards li::after { } @media (min-width: 1300px) { - main .hero2 .hero2-picture picture img { + main .hero .hero-picture picture img { padding-left: 20%; } } @@ -491,38 +491,38 @@ main .hero2 .hero2-awards li::after { @media (min-width: 1600px) { /* large desktop */ - main .hero2 .hero2-content .breadcrumb { + main .hero .hero-content .breadcrumb { padding: 9px 0; margin-bottom: 15px; } - main .hero2 h2 { + main .hero h2 { font-size: 24px; } - main .hero2 h1 { + main .hero h1 { font-size: 56px; } - main .hero2 .hero2-picture picture img { + main .hero .hero-picture picture img { display: block; padding-left: 25%; } - main .hero2 .discount-bubble { + main .hero .discount-bubble { width: 83px; height: 83px; } - main .hero2 .discount-bubble .discount-bubble-0 { + main .hero .discount-bubble .discount-bubble-0 { font-size: 32px; } - main .hero2 .discount-bubble .discount-bubble-1 { + main .hero .discount-bubble .discount-bubble-1 { font-size: 14px; } - main .hero2 .hero2-content { + main .hero .hero-content { min-height: 725px; max-width: var(--section-large-desktop-max-width); padding-left: var(--section-large-desktop-padding); diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js index 7718e3ee6..4ec77d913 100644 --- a/solutions/blocks/hero2/hero2.js +++ b/solutions/blocks/hero2/hero2.js @@ -16,12 +16,12 @@ function buildHeroBlock(element) { const pictureParent = picture ? picture.parentNode : false; // eslint-disable-next-line no-bitwise if (h1 && picture && (h1.compareDocumentPosition(picture) & Node.DOCUMENT_POSITION_PRECEDING)) { - const section = document.querySelector('div.hero2'); - const subSection = document.querySelector('div.hero2 div'); + const section = document.querySelector('div.hero'); + const subSection = document.querySelector('div.hero div'); subSection.classList.add('hero-content'); const breadcrumb = createTag('div', { class: 'breadcrumb' }); - document.querySelector('div.hero2 div div:first-child').prepend(breadcrumb); + document.querySelector('div.hero div div:first-child').prepend(breadcrumb); const pictureEl = document.createElement('div'); pictureEl.classList.add('hero-picture'); @@ -70,7 +70,7 @@ export default async function decorate(block) { [...block.querySelectorAll('img')].forEach((el) => el.setAttribute('loading', 'eager')); // get div class hero-content - const elementHeroContent = block.querySelector('.hero2 div.hero2-content div'); + const elementHeroContent = block.querySelector('.hero div.hero-content div'); if (elementHeroContent !== null) { // Select
              elements that contain a tag From 94138d1d65ed77f350b1caaeceb7d0205242e0f7 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Thu, 8 Feb 2024 10:10:16 +0100 Subject: [PATCH 18/30] Revert "feat: add hero2 block" This reverts commit 33c641bfa5c6250ac93bb33ca6e364d46d7a7112. --- solutions/blocks/hero2/hero2.css | 531 ------------------------------- solutions/blocks/hero2/hero2.js | 98 ------ 2 files changed, 629 deletions(-) delete mode 100644 solutions/blocks/hero2/hero2.css delete mode 100644 solutions/blocks/hero2/hero2.js diff --git a/solutions/blocks/hero2/hero2.css b/solutions/blocks/hero2/hero2.css deleted file mode 100644 index e500d46ef..000000000 --- a/solutions/blocks/hero2/hero2.css +++ /dev/null @@ -1,531 +0,0 @@ - /* block specific CSS goes here */ -:root { - /* hero font size */ - --hero-font-size-xxxl: 50px; - --hero-font-size-xxl: 48px; - --hero-font-size-xl: 40px; - --hero-font-size-l: 32px; - --hero-font-size-m: 22px; - --hero-font-size-s: 20px; - --hero-font-size-xs: 18px; - --hero-font-size-xxs: 16px; - --hero-font-size-xxxs: 14px; - --hero-h1-font-size: 32px; - --hero-h2-font-size: 24px; - --hero-botton-border-color: #616161; - --hero-p-color: #3c3c3c; - - /* breadcrumbs font size */ - --breadcrumb-text-color-dark: #c5c5c5; - --breadcrumb-text-color-dark-hover: #616161; - --breadcrumbs-font-size-s: 12px; -} - - -/* breadcrumbs */ - -main .hero .hero-content .breadcrumb { - font-weight: var(--font-weight-bold); - color: #dedede; - min-height: 82px; - padding: 12px 0; - margin-bottom: 12px; -} - -main .hero .hero-content .breadcrumb a { - font-size: var(--breadcrumbs-font-size-s); - font-weight: var(--font-weight-bold); - color: var(--breadcrumb-text-color-dark-hover); - text-decoration: none; - line-height: 1.7; - letter-spacing: .96px; -} - -main .hero .hero-content .breadcrumb a:last-child { - padding: 0; - margin: 0; - pointer-events: none; -} - -main .hero .hero-content .breadcrumb a::after { - content: "/"; - display: inline-block; - color: var(--color-dark-gray); - margin: 0 3px; - font-size: 9pt; -} - -main .hero .hero-content .breadcrumb a:hover { - color: var(--text-color); -} - -main .hero.black-background .hero-content .breadcrumb a { - color: var(--breadcrumb-text-color-dark); - text-decoration: none; -} - -main .hero.black-background .hero-content .breadcrumb a::after { - color: #dedede; -} - -main .hero.black-background .hero-content .breadcrumb a:hover { - color: var(--breadcrumb-text-color-dark-hover); -} - -/* hero */ - -main .hero-container > div { - max-width: unset; -} - -main .hero-container { - padding: 0; - margin: 0 auto; -} - -main .hero .hero-content > div { - width: 100%; -} - -main .hero-container .hero-wrapper { - padding: 0; -} - -main .hero { - position: relative; - padding: 0; - min-height: 300px; -} - -main .hero.black-background { - background-color: var(--dark-background-color); -} - -main .hero.comparison { - height: 600px; -} - -main .hero .hero-picture { - border: 1px solid #000; - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; -} - -main .hero .hero-content { - display: flex; - flex-direction: column; - padding: 17px var(--body-padding) 56px; - margin: 0 auto; - position: relative; -} - -main .hero .hero-content .right-col { - display: flex; - justify-content: center; - flex-direction: column; -} - -main .hero.black-background .hero-content { - background: linear-gradient(90deg, #000 0%, #000 15%, #fff0 100%); -} - -main .hero.comparison .hero-content { - height: 100%; - padding: 40px; - justify-content: center; - flex-direction: column; -} - -main .hero h1 { - font-size: var(--hero-h1-font-size); - margin: 0 0 25px; -} - -main .hero h2 { - font-size: 18px; - color: var(--text-color); - margin: 0 0 9px; - padding: 15px 0 0; - letter-spacing: .003em; -} - -main .hero h2, -main .hero h4 { - padding: 0; - letter-spacing: normal; - margin: 0 0 9px; -} - -main .hero.black-background h1, -main .hero.black-background h2, -main .hero.black-background h4 { - color: var(--text-dark-color); -} - -main .hero.comparison h1 { - font-weight: var(--font-weight-regular); -} - -main .hero p { - color: var(--hero-p-color); - font-size: var(--hero-font-size-xxxs); - font-weight: var(--font-weight-regular); - line-height: 1.5; - display: block; - letter-spacing: .006em; - margin: 0; -} - -main .hero h1 + p { - margin: 8px 0 0; - color: #616161; - font-size: var(--hero-font-size-xxs); - font-weight: var(--font-weight-bold); - line-height: 1.5; -} - -main .hero.comparison p { - font-size: 18px; - font-weight: 400; - font-stretch: normal; - font-style: normal; - line-height: 1.5; - letter-spacing: normal; - color: #fff; - margin: 24px 0 0; -} - -main .hero.black-background h1 + p { - color: var(--text-dark-color); -} - -main .hero p.button-container { - margin: 0; - padding: 10px 0; - display: flex; - flex-direction: row; - justify-content: flex-start; - align-items: center; - gap: 2px; -} - -main .hero p.button-container.discount-bubble-container{ - padding-top: 0; -} - -main .hero img { - object-fit: cover; - width: 100%; - height: 100%; -} - -main .hero .hero-picture picture img { - position: absolute; - display: none; - padding-left: 200px; -} - -main .hero a.button { - margin: 8px 13px 0 0; -} - -main .hero a.button.modal { - padding: 0 28px 0 0; - min-width: unset; -} - -@media (min-width: 1400px){ - main .hero a.button { - min-width: 360px; - justify-content: center; - align-items: center; - } -} - -main .hero a.button span.button-text { - transition: all .25s cubic-bezier(.4,0,.2,1); - display: inline-block; - position: relative; - font-size: var(--hero-font-size-xs); - font-weight: var(--font-weight-bold); -} - - -main .hero .discount-bubble { - background: #2cb43d; - border-radius: 50%; - width: 72px; - height: 72px; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - text-align: center; - gap: 2px; - bottom: -5px; - right: 0; - position: relative; -} - -main .hero .discount-bubble .discount-bubble-0 { - font-size: 24px; - color: #fff; - font-weight: var(--font-weight-boldest); - line-height: .8; - text-decoration: none; - padding-top: 12px; -} - -main .hero .discount-bubble .discount-bubble-1 { - font-size: 11px; - color: #fff; - line-height: 1.71; - font-weight: var(--font-weight-bold); - font-style: normal; - text-decoration: none; -} - -main .hero .wrapper-plan-discount { - margin: 0 0 10px; - display: -webkit-box; - display: flex; - flex-wrap: wrap; - -webkit-box-align: center; - -ms-flex-align: center; - align-items: center -} - -main .hero .hero-content ul { - margin: 20px 0 0; - padding: 0; - text-align: left; - list-style-type: none; -} - -main .hero .hero-content ul li { - font-size: var(--hero-font-size-xxxs); - font-weight: var(--font-weight-regular); - letter-spacing: 0.096px; - line-height: 1.5; - color: var(--hero-p-color); - margin: 13px 0 0; - padding: 0 0 0 20px; - position: relative; - list-style: none; -} - -main .hero .hero-content ul li:first-child { - margin: 9px 0 0; -} - -main .hero ul li::before { - content: ""; - position: absolute; - left: 0; - top: 3px; - width: 15px; - height: 15px; - background-color: var(--background-checkmark); - border-radius: 50%; - z-index: 1; -} - -main .hero ul li::after { - content: ""; - position: absolute; - left: 5px; - top: 5px; - width: 3px; - height: 7px; - border-bottom: 2px solid var( --white-color); - border-right: 2px solid var( --white-color); - transform: rotate(45deg); - z-index: 2; -} - -main .hero ul.hero-awards { - display: flex; - flex-flow: row wrap; - align-items: center; - justify-content: flex-start; - margin: 0; - padding: 40px 0 48px; - text-align: left; -} - -main .hero .hero-content ul.hero-awards li { - display: block; - min-height: 20px; - margin: 0 20px 30px 0; - padding: 0; - width: auto; -} - -main .hero ul.hero-awards li::before { - content: none; -} - -main .hero ul.hero-awards li picture img { - display: block; - height: 80px; - width: auto; -} - -main .hero .hero-awards li::after { - content: none; -} - -@media(min-width: 767px) { /* tablet */ - :root { - --hero-h1-font-size: 42px; - } - - main .hero h2 { - font-size: 20px; - } - - main .hero .hero-content .breadcrumb { - min-height: 58px; - } - - main .hero .hero-content .breadcrumb a::after { - margin: 0 9px; - } - -} - -@media (min-width: 990px) { /* desktop */ - - main .hero .hero-content > div.left-col { - width: 50%; - } - - main .hero .hero-content > div.right-col { - width: 50%; - padding-left: 1.25rem; - } - - main .hero h2 { - font-size: 22px; - margin-bottom: 10px; - } - - main .hero h1 { - font-size: 50px; - } - - main .hero .hero-picture { - position: absolute; - top: 0; - bottom: 0; - left: 0; - right: 0; - } - - main .hero p { - font-size: 14px; - margin: 0; - } - - main .hero .hero-picture picture img { - display: block; - padding-left: 0; - } - - main .hero .hero-content { - max-width: var(--section-desktop-max-width); - min-height: unset; - padding: 112px var(--section-desktop-padding) 54px var(--section-desktop-padding); - padding-top: 115px; - display: flex; - flex-direction: row; - } - - main .hero a.button.primary { - min-width: 360px; - } - - main .hero .hero-content > div { - width: 60%; - padding: 0 20px 0 0; - } - - main .hero.comparison .hero-content > div { - width: 65%; - padding: 40px 0 0; - } - - main .hero .hero-content .breadcrumb a { - line-height: 1; - letter-spacing: .96px; - } - - main .hero ul.hero-awards { - display: flex; - flex-direction: row; - align-items: center; - justify-content: flex-start; - margin: 0; - padding: 40px 0 0; - } - - main .hero ul.hero-awards li { - display: block; - min-height: 20px; - margin: 9px 20px 0 0; - padding: 0; - width: auto; - } - -} - -@media (min-width: 1300px) { - main .hero .hero-picture picture img { - padding-left: 20%; - } -} - -@media (min-width: 1600px) { /* large desktop */ - - - main .hero .hero-content .breadcrumb { - padding: 9px 0; - margin-bottom: 15px; - } - - main .hero h2 { - font-size: 24px; - } - - main .hero h1 { - font-size: 56px; - } - - main .hero .hero-picture picture img { - display: block; - padding-left: 25%; - } - - main .hero .discount-bubble { - width: 83px; - height: 83px; - } - - main .hero .discount-bubble .discount-bubble-0 { - font-size: 32px; - } - - main .hero .discount-bubble .discount-bubble-1 { - font-size: 14px; - } - - main .hero .hero-content { - min-height: 725px; - max-width: var(--section-large-desktop-max-width); - padding-left: var(--section-large-desktop-padding); - padding-right: var(--section-large-desktop-padding); - } -} diff --git a/solutions/blocks/hero2/hero2.js b/solutions/blocks/hero2/hero2.js deleted file mode 100644 index 4ec77d913..000000000 --- a/solutions/blocks/hero2/hero2.js +++ /dev/null @@ -1,98 +0,0 @@ -// Description: Hero block -import { - createTag, - createNanoBlock, - renderNanoBlocks, - fetchProduct, -} from '../../scripts/utils/utils.js'; - -/** - * Builds hero block and prepends to main in a new section. - * @param {Element} element The container element - */ -function buildHeroBlock(element) { - const h1 = element.querySelector('h1'); - const picture = element.querySelector('picture'); - const pictureParent = picture ? picture.parentNode : false; - // eslint-disable-next-line no-bitwise - if (h1 && picture && (h1.compareDocumentPosition(picture) & Node.DOCUMENT_POSITION_PRECEDING)) { - const section = document.querySelector('div.hero'); - const subSection = document.querySelector('div.hero div'); - subSection.classList.add('hero-content'); - - const breadcrumb = createTag('div', { class: 'breadcrumb' }); - document.querySelector('div.hero div div:first-child').prepend(breadcrumb); - - const pictureEl = document.createElement('div'); - pictureEl.classList.add('hero-picture'); - pictureEl.append(picture); - - section.prepend(pictureEl); - - pictureParent.remove(); - } -} - -createNanoBlock('discount', (code, variant) => { - const root = document.createElement('div'); - root.classList.add('discount-bubble'); - root.innerHTML = ` - --% - Discount - `; - - fetchProduct(code, variant) - .then((product) => { - if (product.discount) { - const discount = Math.round( - (1 - (product.discount.discounted_price) / product.price) * 100, - ); - root.querySelector('.discount-bubble-0').textContent = `${discount}%`; - } else { - // eslint-disable-next-line no-console - console.error('no discount available'); - } - }) - .catch((err) => { - // eslint-disable-next-line no-console - console.error(err); - }); - return root; -}); - -/** - * decorates hero block - * @param {Element} block The hero block element - */ -export default async function decorate(block) { - buildHeroBlock(block); - // Eager load images to improve LCP - [...block.querySelectorAll('img')].forEach((el) => el.setAttribute('loading', 'eager')); - - // get div class hero-content - const elementHeroContent = block.querySelector('.hero div.hero-content div'); - - if (elementHeroContent !== null) { - // Select
                elements that contain a tag - const ulsWithPicture = Array.from(document.querySelectorAll('ul')).filter((ul) => ul.querySelector('picture')); - - // Apply a CSS class to each selected
                  element - ulsWithPicture.forEach((ul) => ul.classList.add('hero-awards')); - - renderNanoBlocks(block); - - // move discount bubble inside the closest button - const bubble = block.querySelector('.discount-bubble'); - if (bubble) { - let sibling = bubble.previousElementSibling; - - while (sibling) { - if (sibling.matches('.button-container')) { - sibling.append(bubble); - break; - } - sibling = sibling.previousElementSibling; - } - } - } -} From 6ac41db277c87e1e22b24d4ec2ab032643e3e292 Mon Sep 17 00:00:00 2001 From: Dereje Dilnesaw Date: Thu, 8 Feb 2024 10:06:40 +0100 Subject: [PATCH 19/30] added css to highlight challenger change --- solutions/blocks/hero/hero.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/solutions/blocks/hero/hero.css b/solutions/blocks/hero/hero.css index 303265de0..bb652f8d5 100644 --- a/solutions/blocks/hero/hero.css +++ b/solutions/blocks/hero/hero.css @@ -91,6 +91,12 @@ main .hero-container .hero-wrapper { padding: 0; } +.two .hero-awards{ + border: red 10px solid; + display: flex; + flex-direction: column; +} + main .hero { position: relative; padding: 0; From f5843149eb2ec84e9e1984d0de4692722bd09c85 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Sun, 21 Apr 2024 02:22:01 +0200 Subject: [PATCH 20/30] feat: create audiences dynamically --- solutions/scripts/scripts.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 0a8fc2564..74413da85 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -52,9 +52,10 @@ const HREFLANG_MAP = [ ]; const targetPromise = (async () => { - const targetLocation = getMetadata('target-location'); + const targetLocation = getMetadata('experiment-target-location'); + console.log(`Resolving target audience for location: ${targetLocation}`); const randomString = Math.random().toString(36).substring(7); - const resp = await fetch(`/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { + const resp = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -75,14 +76,25 @@ const targetPromise = (async () => { }), }); const payload = await resp.json(); + console.log(`Received payload: ${JSON.stringify(payload)}`); const mbox = payload.execute.mboxes.find((mbox) => mbox.name === targetLocation); - const { audience } = mbox?.options[0].content ?? { audience: 'default' }; - console.log(`Resolved target audience: ${audience}`); - return audience; + console.log(`Received target offer: ${mbox?.options[0].content}`); + const { url } = mbox?.options[0].content ?? { url: null }; + console.log(`Resolved challenger url: ${url}`); + + if (url) { + // Add the current audience to the page + const link = document.createElement('meta'); + link.setAttribute('property', 'audience:current'); + link.content = url; + document.getElementsByTagName('head')[0].appendChild(link); + } + + return !!url; })(); const AUDIENCES = { - challenger1: () => targetPromise.then((audience) => audience === 'challenger1'), + current: () => targetPromise.then(() => true), }; window.hlx.plugins.add('rum-conversion', { From 66c393b3ff643a709c78df6195f847c2c7c7185e Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 11:27:00 +0200 Subject: [PATCH 21/30] feat: cleanup and refactoring --- head.html | 3 +- solutions/scripts/scripts.js | 49 +--------------------- solutions/scripts/target.js | 81 ++++++++++++++++++++++++++++++++++++ 3 files changed, 85 insertions(+), 48 deletions(-) create mode 100644 solutions/scripts/target.js diff --git a/head.html b/head.html index 14aab57a2..9f71a839c 100644 --- a/head.html +++ b/head.html @@ -2,5 +2,6 @@ + - \ No newline at end of file + diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index c86475c12..1f9d3a493 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -20,6 +20,7 @@ import { } from './utils.js'; import { loadAnalytics } from './analytics.js'; +import getTargetAudiences from './target.js'; const LCP_BLOCKS = ['hero']; // add your LCP blocks to the list const TRACKED_PRODUCTS = []; @@ -53,52 +54,6 @@ const HREFLANG_MAP = [ ['x-default', { baseUrl: 'https://www.bitdefender.com', pageType: '.html' }], ]; -const targetPromise = (async () => { - const targetLocation = getMetadata('experiment-target-location'); - console.log(`Resolving target audience for location: ${targetLocation}`); - const randomString = Math.random().toString(36).substring(7); - const resp = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${randomString}`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - context: { - channel: 'web', - }, - execute: { - pageLoad: {}, - mboxes: [ - { - name: targetLocation, - index: 0, - }, - ], - }, - }), - }); - const payload = await resp.json(); - console.log(`Received payload: ${JSON.stringify(payload)}`); - const mbox = payload.execute.mboxes.find((mbox) => mbox.name === targetLocation); - console.log(`Received target offer: ${mbox?.options[0].content}`); - const { url } = mbox?.options[0].content ?? { url: null }; - console.log(`Resolved challenger url: ${url}`); - - if (url) { - // Add the current audience to the page - const link = document.createElement('meta'); - link.setAttribute('property', 'audience:current'); - link.content = url; - document.getElementsByTagName('head')[0].appendChild(link); - } - - return !!url; -})(); - -const AUDIENCES = { - current: () => targetPromise.then(() => true), -}; - window.hlx.plugins.add('rum-conversion', { load: 'lazy', url: '../plugins/rum-conversion/src/index.js', @@ -107,7 +62,7 @@ window.hlx.plugins.add('rum-conversion', { window.hlx.plugins.add('experimentation', { options: { prodHost: 'www.bitdefender.com.au', - audiences: AUDIENCES, + audiences: getTargetAudiences(), }, url: '../plugins/experimentation/src/index.js', }); diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js new file mode 100644 index 000000000..013701d18 --- /dev/null +++ b/solutions/scripts/target.js @@ -0,0 +1,81 @@ +import { getMetadata } from './lib-franklin.js'; + +const TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId'; + +const DEFAULT_AUDIENCE = 'current'; + +/** + * Get or create a session id for the current user. + * @returns {string} + */ +function getOrCreateSessionId() { + let sessionId = localStorage.getItem(TARGET_SESSION_ID_PARAM); + if (!sessionId) { + sessionId = Math.random().toString(36).substring(7); + localStorage.setItem(TARGET_SESSION_ID_PARAM, sessionId); + } + return sessionId; +} + +/** + * Create a meta tag with the current url as the audience. + * @param url + */ +function createAudienceMetadata(url) { + const link = document.createElement('meta'); + link.setAttribute('property', `audience:${DEFAULT_AUDIENCE}`); + link.content = url; + document.getElementsByTagName('head')[0].appendChild(link); +} + +/** + * Fetch the target offers for the current location. + * @returns {Promise} + */ +async function fetchJsonOffers() { + const targetLocation = getMetadata('experiment-target-location'); + // eslint-disable-next-line no-console + console.debug(`Resolving target offers for location: ${targetLocation}`); + + const sessionId = getOrCreateSessionId(); + + const res = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${sessionId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + context: { + channel: 'web', + }, + execute: { + pageLoad: {}, + mboxes: [ + { + name: targetLocation, + index: 0, + }, + ], + }, + }), + }); + + const payload = await res.json(); + const mbox = payload.execute.mboxes.find((m) => m.name === targetLocation); + const { url } = mbox?.options[0].content ?? { url: null }; + + // eslint-disable-next-line no-console + console.debug(`Resolved challenger url: ${url}`); + + if (url) { + createAudienceMetadata(url); + } + + return !!url; +} + +export default function getTargetAudiences() { + return { + [DEFAULT_AUDIENCE]: () => fetchJsonOffers.then(() => true), + }; +} From b96e5c3ebe16ad4591e94a57f01d01b8f486ddd7 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 11:29:33 +0200 Subject: [PATCH 22/30] chore: log experiment details --- solutions/scripts/scripts.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 1f9d3a493..5ba8e2e3f 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -471,6 +471,8 @@ function pushPageLoadToDataLayer() { const tags = getTags(getMetadata(METADATA_ANALYTICS_TAGS)); const experimentDetails = getExperimentDetails(); + // eslint-disable-next-line no-console + console.debug(`Experiment details: ${JSON.stringify(experimentDetails)}`); pushToDataLayer('page load started', { pageInstanceID: environment, From 0d247f9012df975cc825c0e955c31961f24b9227 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 11:43:57 +0200 Subject: [PATCH 23/30] feat: expose target tenant param --- solutions/scripts/scripts.js | 4 +++- solutions/scripts/target.js | 20 ++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 5ba8e2e3f..a884cda55 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -33,6 +33,8 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANALYTICS_TAGS = 'analytics-tags'; +const TARGET_TENANT = 'sitesinternal'; + const HREFLANG_MAP = [ ['en-ro', { baseUrl: 'https://www.bitdefender.ro', pageType: '.html' }], ['de', { baseUrl: 'https://www.bitdefender.de', pageType: '.html' }], @@ -62,7 +64,7 @@ window.hlx.plugins.add('rum-conversion', { window.hlx.plugins.add('experimentation', { options: { prodHost: 'www.bitdefender.com.au', - audiences: getTargetAudiences(), + audiences: getTargetAudiences(TARGET_TENANT), }, url: '../plugins/experimentation/src/index.js', }); diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js index 013701d18..e91852e6f 100644 --- a/solutions/scripts/target.js +++ b/solutions/scripts/target.js @@ -32,14 +32,8 @@ function createAudienceMetadata(url) { * Fetch the target offers for the current location. * @returns {Promise} */ -async function fetchJsonOffers() { - const targetLocation = getMetadata('experiment-target-location'); - // eslint-disable-next-line no-console - console.debug(`Resolving target offers for location: ${targetLocation}`); - - const sessionId = getOrCreateSessionId(); - - const res = await fetch(`https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=${sessionId}`, { +async function fetchJsonOffers(tenant, targetLocation) { + const res = await fetch(`https://${tenant}.tt.omtrdc.net/rest/v1/delivery?client=${tenant}&sessionId=${getOrCreateSessionId()}`, { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -74,8 +68,14 @@ async function fetchJsonOffers() { return !!url; } -export default function getTargetAudiences() { +export default function getTargetAudiences(tenant) { + const targetLocation = getMetadata('experiment-target-location'); + if (!targetLocation) { + return {}; + } + // eslint-disable-next-line no-console + console.debug(`Setting up target audiences for location: ${targetLocation}`); return { - [DEFAULT_AUDIENCE]: () => fetchJsonOffers.then(() => true), + [DEFAULT_AUDIENCE]: () => fetchJsonOffers(tenant, targetLocation), }; } From 9c63997f9fccd02ebfa1e77675d1250a466dc475 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 14:10:26 +0200 Subject: [PATCH 24/30] feat: resolve configured audiences --- .../plugins/experimentation/src/index.js | 5 +- solutions/scripts/scripts.js | 4 +- solutions/scripts/target.js | 56 ++++++++++++------- 3 files changed, 41 insertions(+), 24 deletions(-) diff --git a/solutions/plugins/experimentation/src/index.js b/solutions/plugins/experimentation/src/index.js index 5a0ec71fd..50e47910b 100644 --- a/solutions/plugins/experimentation/src/index.js +++ b/solutions/plugins/experimentation/src/index.js @@ -529,7 +529,10 @@ export async function serveAudience(document, options, context) { } const pluginOptions = { ...DEFAULT_OPTIONS, ...(options || {}) }; - const configuredAudiences = context.getAllMetadata(pluginOptions.audiencesMetaTagPrefix); + + const configuredAudiences = pluginOptions.configuredAudiences + ? await pluginOptions.configuredAudiences + : context.getAllMetadata(pluginOptions.audiencesMetaTagPrefix); if (!Object.keys(configuredAudiences).length) { return false; } diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index a884cda55..60ee84d1b 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -20,7 +20,7 @@ import { } from './utils.js'; import { loadAnalytics } from './analytics.js'; -import getTargetAudiences from './target.js'; +import getTargetConfig from './target.js'; const LCP_BLOCKS = ['hero']; // add your LCP blocks to the list const TRACKED_PRODUCTS = []; @@ -64,7 +64,7 @@ window.hlx.plugins.add('rum-conversion', { window.hlx.plugins.add('experimentation', { options: { prodHost: 'www.bitdefender.com.au', - audiences: getTargetAudiences(TARGET_TENANT), + ...getTargetConfig(TARGET_TENANT), }, url: '../plugins/experimentation/src/index.js', }); diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js index e91852e6f..80abad46d 100644 --- a/solutions/scripts/target.js +++ b/solutions/scripts/target.js @@ -5,27 +5,33 @@ const TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId'; const DEFAULT_AUDIENCE = 'current'; /** - * Get or create a session id for the current user. + * Generate a random session id. + * @param length * @returns {string} */ -function getOrCreateSessionId() { - let sessionId = localStorage.getItem(TARGET_SESSION_ID_PARAM); - if (!sessionId) { - sessionId = Math.random().toString(36).substring(7); - localStorage.setItem(TARGET_SESSION_ID_PARAM, sessionId); +function generateSessionID(length = 16) { + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + let sessionID = ''; + for (let i = 0; i < length; i++) { + const randomIndex = Math.floor(Math.random() * characters.length); + sessionID += characters.charAt(randomIndex); } - return sessionId; + return sessionID; } /** - * Create a meta tag with the current url as the audience. - * @param url + * Get or create a session id for the current user. + * @returns {string} */ -function createAudienceMetadata(url) { - const link = document.createElement('meta'); - link.setAttribute('property', `audience:${DEFAULT_AUDIENCE}`); - link.content = url; - document.getElementsByTagName('head')[0].appendChild(link); +function getOrCreateSessionId() { + let sessionId = sessionStorage.getItem(TARGET_SESSION_ID_PARAM); + console.debug(`Session id: ${sessionId}`); + if (!sessionId) { + sessionId = generateSessionID(); + console.debug(`Generated new session id: ${sessionId}`); + sessionStorage.setItem(TARGET_SESSION_ID_PARAM, sessionId); + } + return sessionId; } /** @@ -33,6 +39,7 @@ function createAudienceMetadata(url) { * @returns {Promise} */ async function fetchJsonOffers(tenant, targetLocation) { + console.debug(`Fetching target offers for location: ${targetLocation}`); const res = await fetch(`https://${tenant}.tt.omtrdc.net/rest/v1/delivery?client=${tenant}&sessionId=${getOrCreateSessionId()}`, { method: 'POST', headers: { @@ -61,21 +68,28 @@ async function fetchJsonOffers(tenant, targetLocation) { // eslint-disable-next-line no-console console.debug(`Resolved challenger url: ${url}`); - if (url) { - createAudienceMetadata(url); - } - - return !!url; + return url; } -export default function getTargetAudiences(tenant) { +export default function getTargetConfig(tenant) { const targetLocation = getMetadata('experiment-target-location'); if (!targetLocation) { return {}; } // eslint-disable-next-line no-console console.debug(`Setting up target audiences for location: ${targetLocation}`); + async function audienceResolver() { + return fetchJsonOffers(tenant, targetLocation); + } return { - [DEFAULT_AUDIENCE]: () => fetchJsonOffers(tenant, targetLocation), + audiences: { + // eslint-disable-next-line max-len + [DEFAULT_AUDIENCE]: () => audienceResolver().then((url) => !!url).catch(() => false), + }, + configuredAudiences: audienceResolver().then((url) => { + return { + [DEFAULT_AUDIENCE]: url, + }; + }), }; } From 759466ea4e1b4bf5abe4c1f5180163aaf797c133 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 14:12:24 +0200 Subject: [PATCH 25/30] chore: remove temp files --- target.sh | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100755 target.sh diff --git a/target.sh b/target.sh deleted file mode 100755 index 1a4545007..000000000 --- a/target.sh +++ /dev/null @@ -1,14 +0,0 @@ -curl -vvv -X POST -H "Content-type: application/json" -d '{ - "context": { - "channel": "web" - }, - "execute": { - "pageLoad": {}, - "mboxes": [ - { - "name": "Experiment 1", - "index": 0 - } - ] - } - }' 'https://sitesinternal.tt.omtrdc.net/rest/v1/delivery?client=sitesinternal&sessionId=9' From fed24dc0bde6783efe77404f02ab76f0e63e7812 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Fri, 24 May 2024 14:13:40 +0200 Subject: [PATCH 26/30] chore: undo accidental change --- solutions/blocks/hero/hero.css | 6 ------ 1 file changed, 6 deletions(-) diff --git a/solutions/blocks/hero/hero.css b/solutions/blocks/hero/hero.css index bb652f8d5..303265de0 100644 --- a/solutions/blocks/hero/hero.css +++ b/solutions/blocks/hero/hero.css @@ -91,12 +91,6 @@ main .hero-container .hero-wrapper { padding: 0; } -.two .hero-awards{ - border: red 10px solid; - display: flex; - flex-direction: column; -} - main .hero { position: relative; padding: 0; From 70488a95b083aee335d5a02443c2524ebb9ee0f2 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Tue, 28 May 2024 13:49:16 +0200 Subject: [PATCH 27/30] feat: decouple from aem experimentation --- .../plugins/experimentation/src/index.js | 5 +- solutions/scripts/scripts.js | 12 ++- solutions/scripts/target.js | 99 ++++++++++++++----- 3 files changed, 81 insertions(+), 35 deletions(-) diff --git a/solutions/plugins/experimentation/src/index.js b/solutions/plugins/experimentation/src/index.js index 50e47910b..5a0ec71fd 100644 --- a/solutions/plugins/experimentation/src/index.js +++ b/solutions/plugins/experimentation/src/index.js @@ -529,10 +529,7 @@ export async function serveAudience(document, options, context) { } const pluginOptions = { ...DEFAULT_OPTIONS, ...(options || {}) }; - - const configuredAudiences = pluginOptions.configuredAudiences - ? await pluginOptions.configuredAudiences - : context.getAllMetadata(pluginOptions.audiencesMetaTagPrefix); + const configuredAudiences = context.getAllMetadata(pluginOptions.audiencesMetaTagPrefix); if (!Object.keys(configuredAudiences).length) { return false; } diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index 60ee84d1b..df4292395 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -20,7 +20,7 @@ import { } from './utils.js'; import { loadAnalytics } from './analytics.js'; -import getTargetConfig from './target.js'; +import runTargetExperiment from './target.js'; const LCP_BLOCKS = ['hero']; // add your LCP blocks to the list const TRACKED_PRODUCTS = []; @@ -62,9 +62,9 @@ window.hlx.plugins.add('rum-conversion', { }); window.hlx.plugins.add('experimentation', { + condition: () => getMetadata('experiment'), options: { prodHost: 'www.bitdefender.com.au', - ...getTargetConfig(TARGET_TENANT), }, url: '../plugins/experimentation/src/index.js', }); @@ -462,7 +462,7 @@ function getExperimentDetails() { return { experimentId, experimentVariant }; } -function pushPageLoadToDataLayer() { +function pushPageLoadToDataLayer(targetExperimentDetails) { const { hostname } = window.location; if (!hostname) { return; @@ -472,7 +472,7 @@ function pushPageLoadToDataLayer() { const environment = getEnvironment(hostname, languageCountry.country); const tags = getTags(getMetadata(METADATA_ANALYTICS_TAGS)); - const experimentDetails = getExperimentDetails(); + const experimentDetails = targetExperimentDetails ?? getExperimentDetails(); // eslint-disable-next-line no-console console.debug(`Experiment details: ${JSON.stringify(experimentDetails)}`); @@ -516,7 +516,9 @@ async function loadEager(doc) { await window.hlx.plugins.run('loadEager'); - pushPageLoadToDataLayer(); + const targetExperimentDetails = await runTargetExperiment(TARGET_TENANT); + + pushPageLoadToDataLayer(targetExperimentDetails); if (getMetadata('template') !== '') { loadCSS(`${window.hlx.codeBasePath}/styles/${getMetadata('template')}.css`); diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js index 80abad46d..91af10f2a 100644 --- a/solutions/scripts/target.js +++ b/solutions/scripts/target.js @@ -1,8 +1,20 @@ -import { getMetadata } from './lib-franklin.js'; +import { getMetadata, sampleRUM } from './lib-franklin.js'; -const TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId'; +const ADOBE_TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId'; -const DEFAULT_AUDIENCE = 'current'; +/** + * Convert a URL to a relative URL. + * @param url + * @returns {*|string} + */ +function toRelativeUrl(url) { + try { + const parsedUrl = new URL(url); + return parsedUrl.pathname + parsedUrl.search + parsedUrl.hash; + } catch (e) { + return url; + } +} /** * Generate a random session id. @@ -24,12 +36,12 @@ function generateSessionID(length = 16) { * @returns {string} */ function getOrCreateSessionId() { - let sessionId = sessionStorage.getItem(TARGET_SESSION_ID_PARAM); + let sessionId = sessionStorage.getItem(ADOBE_TARGET_SESSION_ID_PARAM); console.debug(`Session id: ${sessionId}`); if (!sessionId) { sessionId = generateSessionID(); console.debug(`Generated new session id: ${sessionId}`); - sessionStorage.setItem(TARGET_SESSION_ID_PARAM, sessionId); + sessionStorage.setItem(ADOBE_TARGET_SESSION_ID_PARAM, sessionId); } return sessionId; } @@ -38,7 +50,7 @@ function getOrCreateSessionId() { * Fetch the target offers for the current location. * @returns {Promise} */ -async function fetchJsonOffers(tenant, targetLocation) { +async function fetchChallengerPageUrl(tenant, targetLocation) { console.debug(`Fetching target offers for location: ${targetLocation}`); const res = await fetch(`https://${tenant}.tt.omtrdc.net/rest/v1/delivery?client=${tenant}&sessionId=${getOrCreateSessionId()}`, { method: 'POST', @@ -64,32 +76,67 @@ async function fetchJsonOffers(tenant, targetLocation) { const payload = await res.json(); const mbox = payload.execute.mboxes.find((m) => m.name === targetLocation); const { url } = mbox?.options[0].content ?? { url: null }; + if (!url) { + // eslint-disable-next-line no-console + console.error('No challenger url found'); + throw new Error('No challenger url found'); + } // eslint-disable-next-line no-console console.debug(`Resolved challenger url: ${url}`); - return url; } -export default function getTargetConfig(tenant) { - const targetLocation = getMetadata('experiment-target-location'); - if (!targetLocation) { - return {}; +/** + * Replace the current page with the challenger page. + * @param url The challenger page url. + * @returns {Promise} + */ +async function switchToChallengerPage(url) { + const relativePath = toRelativeUrl(url); + const plainPath = relativePath.endsWith('/') ? `${relativePath}index.plain.html` : `${relativePath}.plain.html`; + const resp = await fetch(plainPath); + if (!resp.ok) { + throw new Error(`Failed to fetch challenger page: ${resp.status}`); } - // eslint-disable-next-line no-console - console.debug(`Setting up target audiences for location: ${targetLocation}`); - async function audienceResolver() { - return fetchJsonOffers(tenant, targetLocation); + const mainElement = document.querySelector('main'); + if (!mainElement) { + throw new Error('Main element not found'); + } + mainElement.innerHTML = await resp.text(); +} + +export default async function runTargetExperiment(clientId) { + try { + const experimentId = getMetadata('target-experiment'); + const targetLocation = getMetadata('target-experiment-location'); + if (!experimentId || !targetLocation) { + // eslint-disable-next-line no-console + console.log('Experiment id or target location not found'); + return null; + } + + // eslint-disable-next-line no-console + console.debug(`Running Target experiment ${experimentId} at location ${targetLocation}`); + + const pageUrl = await fetchChallengerPageUrl(clientId, targetLocation); + // eslint-disable-next-line no-console + console.debug(`Challenger page url: ${pageUrl}`); + + await switchToChallengerPage(pageUrl); + + sampleRUM('target-experiment', { + source: `target:${experimentId}`, + target: pageUrl, + }); + + return { + experimentId, + experimentVariant: pageUrl, + }; + } catch (e) { + // eslint-disable-next-line no-console + console.error('Error running target experiment:', e); + return null; } - return { - audiences: { - // eslint-disable-next-line max-len - [DEFAULT_AUDIENCE]: () => audienceResolver().then((url) => !!url).catch(() => false), - }, - configuredAudiences: audienceResolver().then((url) => { - return { - [DEFAULT_AUDIENCE]: url, - }; - }), - }; } From ffdad8c26f4e80fb451302ff6da1e021367baf3f Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Tue, 28 May 2024 13:51:39 +0200 Subject: [PATCH 28/30] chore: linting --- solutions/scripts/target.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js index 91af10f2a..bd6858e4f 100644 --- a/solutions/scripts/target.js +++ b/solutions/scripts/target.js @@ -24,7 +24,7 @@ function toRelativeUrl(url) { function generateSessionID(length = 16) { const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; let sessionID = ''; - for (let i = 0; i < length; i++) { + for (let i = 0; i < length; i += 1) { const randomIndex = Math.floor(Math.random() * characters.length); sessionID += characters.charAt(randomIndex); } @@ -37,9 +37,11 @@ function generateSessionID(length = 16) { */ function getOrCreateSessionId() { let sessionId = sessionStorage.getItem(ADOBE_TARGET_SESSION_ID_PARAM); + // eslint-disable-next-line no-console console.debug(`Session id: ${sessionId}`); if (!sessionId) { sessionId = generateSessionID(); + // eslint-disable-next-line no-console console.debug(`Generated new session id: ${sessionId}`); sessionStorage.setItem(ADOBE_TARGET_SESSION_ID_PARAM, sessionId); } @@ -51,6 +53,7 @@ function getOrCreateSessionId() { * @returns {Promise} */ async function fetchChallengerPageUrl(tenant, targetLocation) { + // eslint-disable-next-line no-console console.debug(`Fetching target offers for location: ${targetLocation}`); const res = await fetch(`https://${tenant}.tt.omtrdc.net/rest/v1/delivery?client=${tenant}&sessionId=${getOrCreateSessionId()}`, { method: 'POST', From 84eb9d55fc2722ddf10101452d43a7b66d350989 Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 29 May 2024 18:08:50 +0200 Subject: [PATCH 29/30] feat: apply review feedback --- head.html | 1 - solutions/scripts/scripts.js | 7 +++++-- solutions/scripts/target.js | 27 +++++++++++++++------------ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/head.html b/head.html index 9f71a839c..3359cb012 100644 --- a/head.html +++ b/head.html @@ -2,6 +2,5 @@ - diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index df4292395..fef410943 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -20,7 +20,6 @@ import { } from './utils.js'; import { loadAnalytics } from './analytics.js'; -import runTargetExperiment from './target.js'; const LCP_BLOCKS = ['hero']; // add your LCP blocks to the list const TRACKED_PRODUCTS = []; @@ -516,7 +515,11 @@ async function loadEager(doc) { await window.hlx.plugins.run('loadEager'); - const targetExperimentDetails = await runTargetExperiment(TARGET_TENANT); + let targetExperimentDetails = null; + if (getMetadata('target-experiment') !== '') { + const { runTargetExperiment } = await import('./target.js'); + targetExperimentDetails = await runTargetExperiment(TARGET_TENANT); + } pushPageLoadToDataLayer(targetExperimentDetails); diff --git a/solutions/scripts/target.js b/solutions/scripts/target.js index bd6858e4f..f85d55906 100644 --- a/solutions/scripts/target.js +++ b/solutions/scripts/target.js @@ -7,13 +7,10 @@ const ADOBE_TARGET_SESSION_ID_PARAM = 'adobeTargetSessionId'; * @param url * @returns {*|string} */ -function toRelativeUrl(url) { - try { - const parsedUrl = new URL(url); - return parsedUrl.pathname + parsedUrl.search + parsedUrl.hash; - } catch (e) { - return url; - } +function getPlainPageUrl(url) { + const { pathname, search, hash } = new URL(url, window.location.href); + const plainPagePathname = pathname.endsWith('/') ? `${pathname}index.plain.html` : `${pathname}.plain.html`; + return `${plainPagePathname}${search}${hash}`; } /** @@ -95,21 +92,27 @@ async function fetchChallengerPageUrl(tenant, targetLocation) { * @param url The challenger page url. * @returns {Promise} */ -async function switchToChallengerPage(url) { - const relativePath = toRelativeUrl(url); - const plainPath = relativePath.endsWith('/') ? `${relativePath}index.plain.html` : `${relativePath}.plain.html`; +async function navigateToChallengerPage(url) { + const plainPath = getPlainPageUrl(url); + + // eslint-disable-next-line no-console + console.debug(`Navigating to challenger page: ${plainPath}`); + const resp = await fetch(plainPath); if (!resp.ok) { throw new Error(`Failed to fetch challenger page: ${resp.status}`); } + const mainElement = document.querySelector('main'); if (!mainElement) { throw new Error('Main element not found'); } + mainElement.innerHTML = await resp.text(); } -export default async function runTargetExperiment(clientId) { +// eslint-disable-next-line import/prefer-default-export +export async function runTargetExperiment(clientId) { try { const experimentId = getMetadata('target-experiment'); const targetLocation = getMetadata('target-experiment-location'); @@ -126,7 +129,7 @@ export default async function runTargetExperiment(clientId) { // eslint-disable-next-line no-console console.debug(`Challenger page url: ${pageUrl}`); - await switchToChallengerPage(pageUrl); + await navigateToChallengerPage(pageUrl); sampleRUM('target-experiment', { source: `target:${experimentId}`, From 19066e83da8030785a1acab2aec0377b87cd182f Mon Sep 17 00:00:00 2001 From: Vitaly Tsaplin Date: Wed, 29 May 2024 19:52:48 +0200 Subject: [PATCH 30/30] chore: change target tenant --- solutions/scripts/scripts.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solutions/scripts/scripts.js b/solutions/scripts/scripts.js index fef410943..83efc000a 100644 --- a/solutions/scripts/scripts.js +++ b/solutions/scripts/scripts.js @@ -32,7 +32,7 @@ export const DEFAULT_COUNTRY = 'au'; export const METADATA_ANALYTICS_TAGS = 'analytics-tags'; -const TARGET_TENANT = 'sitesinternal'; +const TARGET_TENANT = 'bitdefender'; const HREFLANG_MAP = [ ['en-ro', { baseUrl: 'https://www.bitdefender.ro', pageType: '.html' }],