diff --git a/express/code/blocks/floating-panel/floating-panel.css b/express/code/blocks/floating-panel/floating-panel.css new file mode 100644 index 00000000..be8b775c --- /dev/null +++ b/express/code/blocks/floating-panel/floating-panel.css @@ -0,0 +1,66 @@ +.floating-panel { + line-height: 130%; + padding: 16px; + border-radius: 16px; + box-shadow: 0px 0px 12px 0px rgba(0, 0, 0, 0.16); + position: fixed; + z-index: 2; + bottom: 100px; + box-sizing: border-box; + width: 343px; + left: 50%; + transform: translateX(-50%); +} + +.floating-panel.dark { + color: var(--color-white); + background-color: #000b1d; +} + +.floating-panel .header { + font-weight: 700; + font-size: var(--body-font-size-l); + display: flex; + justify-content: space-between; + align-items: center; + padding-bottom: 8px;; +} +.floating-panel .header .icon{ + width: 10px; + height: 10px; + padding: 7px; +} + +.floating-panel .subheader { + font-weight: 400; + font-size: var(--body-font-size-s); + padding-bottom: 16px; +} + +.floating-panel .link-rows-container { + display: flex; + flex-direction: column; + gap: 8px; +} + +.floating-panel-link-row { + display: flex; + justify-content: space-between; +} + +.floating-panel-link-row div { + display: flex; + gap: 8px; + align-items: center; +} + +.floating-panel-link-row .icon { + width: 22px; + height: 22px; + gap: 4px; +} + +.floating-panel .floating-panel-link-row a.con-button { + /* min-width: 100px; */ + margin: 0; +} diff --git a/express/code/blocks/floating-panel/floating-panel.js b/express/code/blocks/floating-panel/floating-panel.js new file mode 100644 index 00000000..0bf97828 --- /dev/null +++ b/express/code/blocks/floating-panel/floating-panel.js @@ -0,0 +1,28 @@ +import { getLibs, getIconElementDeprecated } from '../../scripts/utils.js'; + +const iconRegex = /icon-\s*([^\s]+)/; +let decorateButtons; let createTag; + +export default async function init(el) { + [{ decorateButtons }, { createTag }] = await Promise.all([import(`${getLibs()}/utils/decorate.js`), import(`${getLibs()}/utils/utils.js`)]); + + decorateButtons(el); + const rows = [...el.children]; + const [header, subheader, ...linkRows] = rows; + header.classList.add('header'); + header.append(getIconElementDeprecated('close-white')); + subheader.classList.add('subheader'); + + const linkRowsContainer = createTag('div', { class: 'link-rows-container' }); + linkRows.forEach((link) => { + link.classList.add('floating-panel-link-row'); + const icon = link.querySelector('.icon'); + const match = icon && iconRegex.exec(icon.className); + if (match?.[1]) { + icon.append(getIconElementDeprecated(match[1])); + } + linkRowsContainer.append(link); + }); + el.append(linkRowsContainer); + return el; +} diff --git a/express/code/blocks/frictionless-quick-action/frictionless-quick-action.js b/express/code/blocks/frictionless-quick-action/frictionless-quick-action.js index 29f1b0d1..7efb10c2 100644 --- a/express/code/blocks/frictionless-quick-action/frictionless-quick-action.js +++ b/express/code/blocks/frictionless-quick-action/frictionless-quick-action.js @@ -7,7 +7,8 @@ import { buildFreePlanWidget } from '../../scripts/widgets/free-plan.js'; import { sendFrictionlessEventToAdobeAnaltics } from '../../scripts/instrument.js'; let createTag; let getConfig; -let loadScript; let getMetadata; +let getMetadata; +let loadScript; let globalNavSelector; let ccEverywhere; let quickActionContainer; @@ -40,6 +41,10 @@ const QA_CONFIGS = { ...getBaseImgCfg(JPG, JPEG, PNG), input_check: () => true, }, + 'qa-in-product-variant1': { ...getBaseImgCfg(JPG, JPEG, PNG) }, + 'qa-in-product-variant2': { ...getBaseImgCfg(JPG, JPEG, PNG) }, + 'qa-in-product-control': { ...getBaseImgCfg(JPG, JPEG, PNG) }, + 'qa-nba': { ...getBaseImgCfg(JPG, JPEG, PNG) }, }; function fade(element, action) { @@ -61,6 +66,40 @@ function selectElementByTagPrefix(p) { return Array.from(allEls).find((e) => e.tagName.toLowerCase().startsWith(p.toLowerCase())); } +function frictionlessQAExperiment(quickAction, docConfig, appConfig, exportConfig, contConfig) { + const urlParams = new URLSearchParams(window.location.search); + const urlVariant = urlParams.get('variant'); + const isStage = urlParams.get('hzenv') === 'stage'; + const variant = isStage && urlVariant ? urlVariant : quickAction; + appConfig.metaData.variant = variant; + switch (variant) { + case 'qa-nba': + ccEverywhere.quickAction.removeBackground(docConfig, appConfig, exportConfig, contConfig); + break; + case 'qa-in-product-control': + ccEverywhere.quickAction.removeBackground(docConfig, appConfig, exportConfig, contConfig); + break; + case 'qa-in-product-variant1': + appConfig.metaData.isFrictionlessQa = false; + document.querySelector(`${globalNavSelector}.ready`).style.display = 'none'; + ccEverywhere.editor.createWithAsset(docConfig, appConfig, exportConfig, { + ...contConfig, + mode: 'modal', + }); + break; + case 'qa-in-product-variant2': + appConfig.metaData.isFrictionlessQa = false; + document.querySelector(`${globalNavSelector}.ready`).style.display = 'none'; + ccEverywhere.editor.createWithAsset(docConfig, appConfig, exportConfig, { + ...contConfig, + mode: 'modal', + }); + break; + default: + break; + } +} + // eslint-disable-next-line default-param-last export function runQuickAction(quickAction, data, block) { // TODO: need the button labels from the placeholders sheet if the SDK default doens't work. @@ -101,6 +140,7 @@ export function runQuickAction(quickAction, data, block) { parentElementId: `${quickAction}-container`, backgroundColor: 'transparent', hideCloseButton: true, + padding: 0, }; const docConfig = { @@ -110,6 +150,7 @@ export function runQuickAction(quickAction, data, block) { type: 'image', }, }; + const appConfig = { metaData: { isFrictionlessQa: 'true' }, receiveQuickActionErrors: false, @@ -132,6 +173,10 @@ export function runQuickAction(quickAction, data, block) { }, }; + const urlParams = new URLSearchParams(window.location.search); + const variant = urlParams.get('variant'); + const isStage = urlParams.get('hzenv') === 'stage'; + if (!ccEverywhere) return; switch (quickAction) { case 'convert-to-jpg': @@ -151,11 +196,30 @@ export function runQuickAction(quickAction, data, block) { ccEverywhere.quickAction.resizeImage(docConfig, appConfig, exportConfig, contConfig); break; case 'remove-background': + + if (variant && isStage) { + frictionlessQAExperiment(variant, docConfig, appConfig, exportConfig, contConfig); + break; + } + ccEverywhere.quickAction.removeBackground(docConfig, appConfig, exportConfig, contConfig); break; case 'generate-qr-code': ccEverywhere.quickAction.generateQRCode({}, appConfig, exportConfig, contConfig); break; + // Experiment code, remove after done + case 'qa-nba': + frictionlessQAExperiment(quickAction, docConfig, appConfig, exportConfig, contConfig); + break; + case 'qa-in-product-control': + frictionlessQAExperiment(quickAction, docConfig, appConfig, exportConfig, contConfig); + break; + case 'qa-in-product-variant1': + frictionlessQAExperiment(quickAction, docConfig, appConfig, exportConfig, contConfig); + break; + case 'qa-in-product-variant2': + frictionlessQAExperiment(quickAction, docConfig, appConfig, exportConfig, contConfig); + break; default: break; } } @@ -186,7 +250,10 @@ async function startSDK(data = '', quickAction, block) { if (country) ietf = getConfig().locales[country]?.ietf; if (ietf === 'zh-Hant-TW') ietf = 'tw-TW'; else if (ietf === 'zh-Hans-CN') ietf = 'cn-CN'; - + // query parameter URL for overriding the cc everywhere + // iframe source URL, used for testing new experiences + const isStageEnv = urlParams.get('hzenv') === 'stage'; + const baseQA = new URLSearchParams(window.location.search).get('base-qa'); const ccEverywhereConfig = { hostInfo: { clientId, @@ -194,7 +261,8 @@ async function startSDK(data = '', quickAction, block) { }, configParams: { locale: ietf?.replace('-', '_'), - env: urlParams.get('hzenv') === 'stage' ? 'stage' : 'prod', + env: isStageEnv ? 'stage' : 'prod', + urlOverride: isStageEnv ? baseQA : undefined, }, authOption: () => ({ mode: 'delayed' }), }; @@ -248,9 +316,12 @@ async function startSDKWithUnconvertedFile(file, quickAction, block) { } export default async function decorate(block) { - await Promise.all([import(`${getLibs()}/utils/utils.js`), decorateButtonsDeprecated(block)]).then(([utils]) => { - ({ createTag, getConfig, loadScript, getMetadata } = utils); - }); + const [utils, gNavUtils] = await Promise.all([import(`${getLibs()}/utils/utils.js`), + import(`${getLibs()}/blocks/global-navigation/utilities/utilities.js`), + decorateButtonsDeprecated(block)]); + ({ createTag, getMetadata, loadScript, getConfig } = utils); + globalNavSelector = gNavUtils?.selectors.globalNav; + const rows = Array.from(block.children); rows[1].classList.add('fqa-container'); const quickActionRow = rows.filter((r) => r.children && r.children[0].textContent.toLowerCase().trim() === 'quick-action'); diff --git a/express/code/blocks/login-page/login-page.css b/express/code/blocks/login-page/login-page.css new file mode 100644 index 00000000..af67fbed --- /dev/null +++ b/express/code/blocks/login-page/login-page.css @@ -0,0 +1,62 @@ +/* make susi-light in the same ax-login-page section hover */ +.section.ax-login-page { + display: flex; + justify-content: center; + align-items: center; +} + +.login-page .background img { + display: none; + width: 100vw; /* not needed if authored right images */ +} + +@media (min-width: 768px) { + .login-page .background .m-background { + display: block; + } +} + +@media (min-width: 1024px) { + .login-page .background .m-background { + display: none; + } + .login-page .background .tablet-background { + display: block; + } +} + +@media (min-width: 1280px) { + .login-page .background .tablet-background { + display: none; + } + .login-page .background .l-background { + display: block; + } +} + +@media (min-width: 1440px) { + .login-page .background .l-background { + display: none; + } + .login-page .background .desktop-background { + display: block; + } +} + +@media (min-width: 1680px) { + .login-page .background .desktop-background { + display: none; + } + .login-page .background .xl-background { + display: block; + } +} + +@media (min-width: 1920px) { + .login-page .background .xl-background { + display: none; + } + .login-page .background .xxl-background { + display: block; + } +} diff --git a/express/code/blocks/login-page/login-page.js b/express/code/blocks/login-page/login-page.js new file mode 100644 index 00000000..6ac238af --- /dev/null +++ b/express/code/blocks/login-page/login-page.js @@ -0,0 +1,10 @@ +// 768/1024/1280/1440/1600/1920 +const breakpoints = ['m', 'tablet', 'l', 'desktop', 'xl', 'xxl']; +export default async function init(el) { + const background = el.children[0]; + background.classList.add('background'); + const imgs = [...background.querySelectorAll('img')]; + imgs.forEach((img, index) => { + img.classList.add(`${breakpoints[index]}-background`); + }); +} diff --git a/express/code/blocks/susi-light/susi-light.css b/express/code/blocks/susi-light/susi-light.css index 649cfff3..92040a9a 100644 --- a/express/code/blocks/susi-light/susi-light.css +++ b/express/code/blocks/susi-light/susi-light.css @@ -3,3 +3,142 @@ width: 360px; min-height: 462px; } + +.susi-light { + display: flex; + align-items: center; + justify-content: center; +} + +.susi-tabs { + text-align: center; + display: flex; + flex-direction: column; + align-items: center; +} + +.susi-tabs .express-logo { + width: unset; + height: 24px; + padding-top: 32px; +} + +.susi-tabs .title { + font-size: var(--heading-font-size-s); + line-height: 28.6px; + font-weight: 900; + padding-top: 12px; + text-align: center; +} + +.susi-tabs [role='tablist'] { + background-color: #e6e6e6; + border-radius: 8px; + display: flex; + gap: 4px; + padding: 4px; + margin-top: 16px; +} + +.susi-tabs [role='tablist']:has(:first-child:last-child) { + display: none; +} + +.susi-tabs [role='tab'] { + background-color: #e6e6e6; + color: #222222; + border: initial; + font-family: var(--body-font-family); + font-size: var(--body-font-size-xs); + font-weight: 700; + padding: 8px 12px 10px; + line-height: 130%; + cursor: pointer; +} + +.susi-tabs [role='tab'][aria-selected='true'] { + background-color: var(--color-white); + border-radius: 6px; +} + +.susi-tabs [role='tabpanel'] { + width: 400px; + max-width: 95vw; +} + +.susi-tabs [role='tabpanel'].hide { + display: none; +} + +/* reduce CLS */ +.susi-tabs [role='tabpanel'].standard .susi-wrapper { + min-height: 457.5px; +} + +.susi-tabs [role='tabpanel'].edu-express .susi-wrapper { + min-height: 366.5px; +} + +.susi-tabs .footer { + font-size: var(--body-font-size-s); + text-align: center; + padding: 16px 0; + font-weight: 700; + color: #292929; + line-height: 20.8px; +} + +.susi-tabs .footer a { + text-decoration: underline; + color: initial; + font-weight: 500; +} + +.susi-tabs .footer.susi-banner { + background-color: #f3f3f3; +} + +.susi-tabs .footer.susi-bubbles h2 { + font-size: var(--body-font-size-l); + font-weight: 700; +} + +.susi-tabs .footer .susi-bubble-container { + display: flex; + gap: 12px; + justify-content: center; + padding-top: 8px; +} + +.susi-tabs .footer .susi-bubble { + font-size: var(--body-font-size-s); + background-color: #f3f3f3; + display: flex; + flex-direction: column; + padding: 12px 24px; + border-radius: 8px; + margin: 0; +} + +/* ax-login-page section metadata styles */ +.section.ax-login-page .susi-tabs { + background-color: var(--color-white); + border-radius: 16px; +} + +.section.ax-login-page .susi-light { + padding-bottom: 32px; +} +.section.ax-login-page .susi-tabs .footer { + border-radius: 8px; +} + +@media (min-width: 768px) { + .section.ax-login-page .susi-light { + position: absolute; + padding-top: 30px; + } + .section.ax-login-page .susi-tabs .footer { + border-radius: 0 0 16px 16px; + } +} diff --git a/express/code/blocks/susi-light/susi-light.js b/express/code/blocks/susi-light/susi-light.js index 9fdfffa4..fc3d4b2e 100644 --- a/express/code/blocks/susi-light/susi-light.js +++ b/express/code/blocks/susi-light/susi-light.js @@ -1,12 +1,14 @@ /* eslint-disable no-underscore-dangle */ /* eslint-disable camelcase */ -import { getLibs } from '../../scripts/utils.js'; +import { getLibs, getIconElementDeprecated } from '../../scripts/utils.js'; let createTag; let loadScript; let getConfig; let isStage; let loadIms; -const variant = 'edu-express'; +const DCTX_ID_STAGE = 'v:2,s,dcp-r,bg:express2024,bf31d610-dd5f-11ee-abfd-ebac9468bc58'; +const DCTX_ID_PROD = 'v:2,s,dcp-r,bg:express2024,45faecb0-e687-11ee-a865-f545a8ca5d2c'; + const usp = new URLSearchParams(window.location.search); const onRedirect = (e) => { @@ -21,7 +23,7 @@ const onError = (e) => { window.lana?.log('on error:', e); }; -export function loadWrapper() { +export function loadSUSIScripts() { const CDN_URL = `https://auth-light.identity${isStage ? '-stage' : ''}.adobe.com/sentry/wrapper.js`; return loadScript(CDN_URL); } @@ -40,58 +42,154 @@ function getDestURL(url) { return destURL.toString(); } -export default async function init(el) { - ({ createTag, loadScript, getConfig, loadIms } = await import(`${getLibs()}/utils/utils.js`)); - isStage = (usp.get('env') && usp.get('env') !== 'prod') || getConfig().env.name !== 'prod'; - const rows = el.querySelectorAll(':scope> div > div'); - const redirectUrl = rows[0]?.textContent?.trim().toLowerCase(); - // eslint-disable-next-line camelcase - const client_id = rows[1]?.textContent?.trim() || 'AdobeExpressWeb'; - const title = rows[2]?.textContent?.trim(); - const authParams = { - dt: false, - locale: getConfig().locale.ietf.toLowerCase(), - response_type: 'code', - client_id, - scope: 'AdobeID,openid', - }; - function sendEventToAnalytics(type, eventName) { - const sendEvent = () => { - window._satellite.track('event', { - xdm: {}, - data: { - eventType: 'web.webinteraction.linkClicks', - web: { - webInteraction: { - name: eventName, - linkClicks: { value: 1 }, - type, +function sendEventToAnalytics(type, eventName, client_id) { + const sendEvent = () => { + window._satellite.track('event', { + xdm: {}, + data: { + eventType: 'web.webinteraction.linkClicks', + web: { + webInteraction: { + name: eventName, + linkClicks: { + value: 1, }, + type, }, - /* eslint-disable object-curly-newline */ - _adobe_corpnew: { - digitalData: { - primaryEvent: { - eventInfo: { - eventName, - client_id, - }, + }, + _adobe_corpnew: { + digitalData: { + primaryEvent: { + eventInfo: { + eventName, + client_id, }, }, }, - /* eslint-enable object-curly-newline */ }, - }); - }; - if (window._satellite?.track) { + }, + }); + }; + if (window._satellite?.track) { + sendEvent(); + } else { + window.addEventListener('alloy_sendEvent', () => { sendEvent(); - } else { - window.addEventListener('alloy_sendEvent', () => { - sendEvent(); - }, { once: true }); - } + }, { once: true }); } - const destURL = getDestURL(redirectUrl); +} + +function createSUSIComponent({ variant, config, authParams, destURL }) { + const susi = createTag('susi-sentry-light'); + susi.authParams = authParams; + susi.authParams.redirect_uri = destURL; + susi.authParams.dctx_id = isStage ? DCTX_ID_STAGE : DCTX_ID_PROD; + susi.config = config; + if (isStage) susi.stage = 'true'; + susi.variant = variant; + const onAnalytics = (e) => { + const { type, event } = e.detail; + sendEventToAnalytics(type, event, authParams.client_id); + }; + susi.addEventListener('redirect', onRedirect); + susi.addEventListener('on-error', onError); + susi.addEventListener('on-analytics', onAnalytics); + return susi; +} + +function buildSUSIParams({ client_id, variant, destURL, locale, title, hideIcon }) { + const params = { + variant, + authParams: { + dt: false, + locale, + response_type: 'code', + client_id, + scope: 'AdobeID,openid', + }, + destURL, + config: { + consentProfile: 'free', + fullWidth: true, + }, + }; + if (title !== undefined) { + params.config.title = title; + } + if (hideIcon) { + params.config.hideIcon = true; + } + return params; +} + +function sanitizeId(input) { + return input + .toLowerCase() + .trim() + .replace(/\s+/g, '-') + .replace(/[^\w-]/g, ''); +} + +let tabsId = 0; +function buildSUSITabs(el, options) { + tabsId += 1; + const rows = [...el.children]; + const wrapper = createTag('div', { class: 'susi-tabs' }); + const tabList = createTag('div', { role: 'tablist' }); + const susiScriptReady = loadSUSIScripts(); + const panels = options.map((option, i) => { + const { footer, tabName, variant } = option; + const susiWrapper = createTag('div', { class: 'susi-wrapper' }); + const panel = createTag('div', { role: 'tabpanel', class: variant }, susiWrapper); + susiScriptReady.then(() => susiWrapper.append(createSUSIComponent(option))); + + if (footer) { + footer.classList.add('footer'); + if (footer.querySelector('h2')) { + footer.classList.add('susi-bubbles'); + const bubbleContainer = createTag('div', { class: 'susi-bubble-container' }); + [...footer.querySelectorAll('p')].forEach((p) => { + p.classList.add('susi-bubble'); + bubbleContainer.append(p); + }); + footer.append(bubbleContainer); + } else { + footer.classList.add('susi-banner'); + } + panel.append(footer); + } + + const id = sanitizeId(`${tabName}-${tabsId}`); + panel.setAttribute('aria-labelledby', `tab-${id}`); + panel.id = `panel-${id}`; + i > 0 && panel.classList.add('hide'); + const tab = createTag('button', { + role: 'tab', + 'aria-selected': i === 0, + 'aria-controls': `panel-${id}`, + id: `tab-${id}`, + }, tabName); + tab.addEventListener('click', () => { + tabList.querySelector('[aria-selected=true]')?.setAttribute('aria-selected', false); + tab.setAttribute('aria-selected', true); + panels.forEach((p) => { + p !== panel ? p.classList.add('hide') : p.classList.remove('hide'); + }); + }); + tabList.append(tab); + return panel; + }); + + const logo = getIconElementDeprecated('adobe-express-logo'); + logo.classList.add('express-logo'); + logo.height = 24; + const title = rows[0].textContent?.trim(); + const titleDiv = createTag('div', { class: 'title' }, title); + wrapper.append(logo, titleDiv, tabList, ...panels); + return wrapper; +} + +function redirectIfLoggedIn(destURL) { const goDest = () => { sendEventToAnalytics('redirect', 'logged-in-auto-redirect'); window.location.assign(destURL); @@ -106,23 +204,55 @@ export default async function init(el) { }) .catch((e) => { window.lana?.log(`Unable to load IMS in susi-light: ${e}`); }); } - el.innerHTML = ''; - await loadWrapper(); - const config = { consentProfile: 'free' }; - if (title) { config.title = title; } - const susi = createTag('susi-sentry-light'); - susi.authParams = authParams; - susi.authParams.redirect_uri = destURL; - susi.config = config; - if (isStage) susi.stage = 'true'; - susi.variant = variant; +} - const onAnalytics = (e) => { - const { type, event } = e.detail; - sendEventToAnalytics(type, event); - }; - susi.addEventListener('redirect', onRedirect); - susi.addEventListener('on-error', onError); - susi.addEventListener('on-analytics', onAnalytics); - el.append(susi); +export default async function init(el) { + ({ createTag, loadScript, getConfig, loadIms } = await import(`${getLibs()}/utils/utils.js`)); + isStage = (usp.get('env') && usp.get('env') !== 'prod') || getConfig().env.name !== 'prod'; + const locale = getConfig().locale.ietf.toLowerCase(); + const { imsClientId } = getConfig(); + + const isTabs = el.classList.contains('tabs'); + const noRedirect = el.classList.contains('no-redirect'); + + // only edu variant shows single + if (!isTabs) { + const rows = el.querySelectorAll(':scope > div > div'); + const redirectUrl = rows[0]?.textContent?.trim().toLowerCase(); + const client_id = rows[1]?.textContent?.trim() || (imsClientId ?? 'AdobeExpressWeb'); + const title = rows[2]?.textContent?.trim(); + const variant = 'edu-express'; + const params = buildSUSIParams({ + client_id, variant, destURL: getDestURL(redirectUrl), locale, title, + }); + if (!noRedirect) { + redirectIfLoggedIn(params.destURL); + } + await loadSUSIScripts(); + el.replaceChildren(createSUSIComponent(params)); + return; + } + const rows = [...el.children]; + const tabNames = [...rows[1].querySelectorAll('div')].map((div) => div.textContent); + const variants = [...rows[2].querySelectorAll('div')].map((div) => div.textContent?.trim().toLowerCase()); + const redirectUrls = [...rows[3].querySelectorAll('div')].map((div) => div.textContent?.trim().toLowerCase()); + const client_ids = [...rows[4].querySelectorAll('div')].map((div) => div.textContent?.trim() || (imsClientId ?? 'AdobeExpressWeb')); + const footers = rows[5] ? [...rows[5].querySelectorAll('div')] : []; + const tabParams = tabNames.map((tabName, index) => ({ + tabName, + ...buildSUSIParams({ + client_id: client_ids[index], + variant: variants[index], + destURL: getDestURL(redirectUrls[index]), + locale, + title: '', // rm titles + hideIcon: true, + }), + footer: footers[index] ?? null, + })); + if (!noRedirect) { + // redirect to first one if logged in + redirectIfLoggedIn(tabParams[0].destURL); + } + el.replaceChildren(buildSUSITabs(el, tabParams)); } diff --git a/express/code/icons/ax-badge-dark.svg b/express/code/icons/ax-badge-dark.svg new file mode 100644 index 00000000..5ca9c5ff --- /dev/null +++ b/express/code/icons/ax-badge-dark.svg @@ -0,0 +1,25 @@ + diff --git a/express/code/icons/ax-globe.svg b/express/code/icons/ax-globe.svg new file mode 100644 index 00000000..b3d1da31 --- /dev/null +++ b/express/code/icons/ax-globe.svg @@ -0,0 +1,10 @@ + diff --git a/express/code/icons/ax-web-dark.svg b/express/code/icons/ax-web-dark.svg new file mode 100644 index 00000000..7346ef1a --- /dev/null +++ b/express/code/icons/ax-web-dark.svg @@ -0,0 +1,10 @@ + diff --git a/express/code/scripts/express-delayed.js b/express/code/scripts/express-delayed.js index 8e7cc96d..a59afef2 100644 --- a/express/code/scripts/express-delayed.js +++ b/express/code/scripts/express-delayed.js @@ -21,7 +21,7 @@ function preloadSUSILight() { preloadTag.setAttribute('data-stage', 'true'); } import('../blocks/susi-light/susi-light.js') - .then((mod) => mod.loadWrapper()) + .then((mod) => mod.loadSUSIScripts()) .then(() => { document.head.append(preloadTag); }); diff --git a/test/blocks/floating-panel/floating-panel.test.js b/test/blocks/floating-panel/floating-panel.test.js new file mode 100644 index 00000000..db0aa101 --- /dev/null +++ b/test/blocks/floating-panel/floating-panel.test.js @@ -0,0 +1,39 @@ +/* eslint-env mocha */ +/* eslint-disable no-unused-vars */ + +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { mockRes } from '../test-utilities.js'; + +const locales = { '': { ietf: 'en-US', tk: 'hah7vzn.css' } }; +document.body.innerHTML = await readFile({ path: './mocks/body.html' }); +const originalFetch = window.fetch; + +const [{ getLibs }, _, { default: decorate }] = await Promise.all([import('../../../express/code/scripts/utils.js'), import('../../../express/code/scripts/scripts.js'), import( + '../../../express/code/blocks/floating-panel/floating-panel.js' +)]); +await import(`${getLibs()}/utils/utils.js`).then((mod) => { + const conf = { locales }; + mod.setConfig(conf); +}); + +describe('Floating-panel', async () => { + const block = document.querySelector('.floating-panel'); + before(() => { + window.fetch = sinon.stub().callsFake(() => mockRes({})); + }); + + after(() => { + window.fetch = originalFetch; + }); + + it('decorates all required content', async () => { + expect(block).to.exist; + await decorate(block); + expect(block.querySelector('.header')).to.exist; + expect(block.querySelector('.subheader')).to.exist; + expect(block.querySelector('.link-rows-container')).to.exist; + expect(block.querySelectorAll('.floating-panel-link-row').length).to.equal(2); + }); +}); diff --git a/test/blocks/floating-panel/mocks/body.html b/test/blocks/floating-panel/mocks/body.html new file mode 100644 index 00000000..19fb074a --- /dev/null +++ b/test/blocks/floating-panel/mocks/body.html @@ -0,0 +1,18 @@ +
+
Get started in the all-in-one editor
@@ -39,10 +39,10 @@
+
Edit your media in one click
@@ -68,10 +68,10 @@
+
Create fast with generative AI
@@ -89,10 +89,10 @@
+
Explore amazing content
diff --git a/test/blocks/login-page/login-page.test.js b/test/blocks/login-page/login-page.test.js new file mode 100644 index 00000000..9e342717 --- /dev/null +++ b/test/blocks/login-page/login-page.test.js @@ -0,0 +1,24 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; + +const imports = await Promise.all([import('../../../express/code/scripts/utils.js'), import('../../../express/code/scripts/scripts.js')]); +const { getLibs } = imports[0]; +await import(`${getLibs()}/utils/utils.js`).then((mod) => { + const conf = {}; + mod.setConfig(conf); +}); +const [{ default: decorate }] = await Promise.all([import('../../../express/code/blocks/login-page/login-page.js')]); +document.body.innerHTML = await readFile({ path: './mocks/body.html' }); +describe('login-page', () => { + let block; + before(async () => { + block = document.querySelector('.login-page'); + decorate(block); + }); + it('has a background image', async () => { + expect(block.querySelector('img.m-background')).to.exist; + expect(block.querySelector('img.l-background')).to.exist; + expect(block.querySelector('img.xl-background')).to.exist; + expect(block.querySelector('img.xxl-background')).to.exist; + }); +}); diff --git a/test/blocks/login-page/mocks/body.html b/test/blocks/login-page/mocks/body.html new file mode 100644 index 00000000..52deeaf8 --- /dev/null +++ b/test/blocks/login-page/mocks/body.html @@ -0,0 +1,79 @@ +