diff --git a/acrobat/blocks/prompt-card/prompt-card.css b/acrobat/blocks/prompt-card/prompt-card.css new file mode 100644 index 00000000..95406622 --- /dev/null +++ b/acrobat/blocks/prompt-card/prompt-card.css @@ -0,0 +1,171 @@ +:root { + --common-font: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; +} + +#prompt { + display: none +} + +.prompt-card.hidden { + display: none; +} + +.view-all { + grid-column: 1 / -1; + display: flex; + justify-content: center; +} + +.prompt-toast { + font-family: var(--common-font); + align-items: flex-start; + background: #05834e; + border-radius: 10px; + color: #fff; + display: none; + gap: 10px; + left: 50%; + padding: 20px 16px; + position: fixed; + top: 110px; + transform: translate(-50%, -50%); + z-index: 9999 +} + +.prompt-toast--show { + display: inline-flex +} + +.prompt-toast:before { + background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iI2ZmZiI+PHBhdGggZD0iTTEwIDE4Ljc1Yy00LjgyNSAwLTguNzUtMy45MjUtOC43NS04Ljc1UzUuMTc1IDEuMjUgMTAgMS4yNXM4Ljc1IDMuOTI1IDguNzUgOC43NS0zLjkyNSA4Ljc1LTguNzUgOC43NVptMC0xNkE3LjI1OCA3LjI1OCAwIDAgMCAyLjc1IDEwYzAgMy45OTggMy4yNTIgNy4yNSA3LjI1IDcuMjVzNy4yNS0zLjI1MiA3LjI1LTcuMjVTMTMuOTk4IDIuNzUgMTAgMi43NVoiLz48cGF0aCBkPSJNOS4xODMgMTMuOTQzYS43NTEuNzUxIDAgMCAxLS41NTgtLjI0OGwtMi42NDMtMi45NGEuNzUuNzUgMCAwIDEgMS4xMTUtMS4wMDNsMi4wMjYgMi4yNTQgMy43LTUuMDQ2YS43NS43NSAwIDEgMSAxLjIwOS44ODdsLTQuMjQ1IDUuNzlhLjc0NS43NDUgMCAwIDEtLjU2Ny4zMDVsLS4wMzcuMDAxWiIvPjwvZz48L3N2Zz4="); + background-repeat: no-repeat; + background-size: contain; + content: ""; + height: 20px; + margin-top: 3px; + min-width: 20px; + width: 20px +} + +.prompt-close { + background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTIiIGhlaWdodD0iMTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2EpIj48cGF0aCBkPSJtNy4zNDIgNiAzLjM5Ni0zLjM5NmEuOTUuOTUgMCAwIDAtMS4zNDMtMS4zNDJMNiA0LjY1OCAyLjYwNCAxLjI2MmEuOTUuOTUgMCAxIDAtMS4zNDMgMS4zNDJMNC42NTcgNiAxLjI2MSA5LjM5NmEuOTUuOTUgMCAxIDAgMS4zNDMgMS4zNDJMNiA3LjM0MmwzLjM5NSAzLjM5NmEuOTQ2Ljk0NiAwIDAgMCAxLjM0My4wMDEuOTUuOTUgMCAwIDAgMC0xLjM0M0w3LjM0MiA2WiIgZmlsbD0iI2ZmZiIvPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImEiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0wIDBoMTJ2MTJIMHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4="); + background-repeat: no-repeat; + background-size: contain; + content: ""; + height: 12px; + margin-inline-start: 10px; + margin-top: 7px; + width: 12px +} + +.prompt-blade { + align-items: flex-start; + align-self: stretch; + background-color: #fff; + border: 1px solid #e8e8e8; + border-radius: 10px; + cursor: pointer; + display: flow; + flex: 1 0 0; + flex-direction: column; + justify-content: space-between; + padding: 20px 20px 24px; + transition-delay: 3s; + transition-property: border; + max-width: 276px; +} + +.prompt-blade:hover { + box-shadow: 3px 6px 6px 0 rgba(0, 0, 0, .16) +} + +.prompt-blade:active { + border: 1px solid #095aba; + transition-delay: 0s +} + +.prompt-icon { + margin-inline-end: 5px; + position: relative; +} + +.prompt-prefix { + color: #6d6d6d; + font-size: 12px; + padding: 0 0 16px; + text-transform: uppercase; + display: flex; + align-items: center; +} + +.prompt-prefix, +.prompt-title { + font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + font-style: normal; + font-weight: 700; + line-height: 1.25 +} + +.prompt-title { + align-self: stretch; + color: #2c2c2c; + font-size: 18px +} + +.prompt-copy { + -webkit-line-clamp: 5; + -webkit-box-orient: vertical; + background: #f8f8f8; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + color: #696969; + display: -webkit-box; + flex: 1 0 0; + font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + font-size: 20px; + font-style: normal; + font-weight: 400; + height: 155px; + line-height: 150%; + margin-top: 16px; + overflow: hidden; + padding: 8px 16px 0 +} + +.prompt-copy-btn-wrapper { + align-items: center; + align-self: stretch; + background: #f8f8f8; + border-bottom-left-radius: 8px; + border-bottom-right-radius: 8px; + display: flex; + gap: 8px; + justify-content: flex-end; + padding-bottom: 16px; + padding-top: 5px +} + +.prompt-copy-btn { + color: #686868; + cursor: pointer; + font-family: var(--common-font); + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 150%; + padding: 2px 8px +} + +.prompt-copy-btn:after { + background: url("data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTkiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0iIzI0MjQyNCI+PHBhdGggZD0iTTE2Ljc1IDExLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTE2Ljc1IDkuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41YS4yNS4yNSAwIDAgMCAuMjUtLjI1di0uNWEuMjUuMjUgMCAwIDAtLjI1LS4yNVpNMTYuNzUgNy41aC0uNWEuMjUuMjUgMCAwIDAtLjI1LjI1di41YzAgLjEzOC4xMTIuMjUuMjUuMjVoLjVhLjI1LjI1IDAgMCAwIC4yNS0uMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk0xNi43NSA1LjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTE2Ljc1IDMuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41YS4yNS4yNSAwIDAgMCAuMjUtLjI1di0uNWEuMjUuMjUgMCAwIDAtLjI1LS4yNVpNMTYuNzUgMS41aC0uNWEuMjUuMjUgMCAwIDAtLjI1LjI1di41YzAgLjEzOC4xMTIuMjUuMjUuMjVoLjVhLjI1LjI1IDAgMCAwIC4yNS0uMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk0xNC43NSAxLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTEyLjc1IDEuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41YS4yNS4yNSAwIDAgMCAuMjUtLjI1di0uNWEuMjUuMjUgMCAwIDAtLjI1LS4yNVpNMTAuNzUgMS41aC0uNWEuMjUuMjUgMCAwIDAtLjI1LjI1di41YzAgLjEzOC4xMTIuMjUuMjUuMjVoLjVhLjI1LjI1IDAgMCAwIC4yNS0uMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk04Ljc1IDEuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41QS4yNS4yNSAwIDAgMCA5IDIuMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk02Ljc1IDEuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41QS4yNS4yNSAwIDAgMCA3IDIuMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk02Ljc1IDMuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41QS4yNS4yNSAwIDAgMCA3IDQuMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk02Ljc1IDUuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41QS4yNS4yNSAwIDAgMCA3IDYuMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk02Ljc1IDcuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41QS4yNS4yNSAwIDAgMCA3IDguMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk02Ljc1IDkuNWgtLjVhLjI1LjI1IDAgMCAwLS4yNS4yNXYuNWMwIC4xMzguMTEyLjI1LjI1LjI1aC41YS4yNS4yNSAwIDAgMCAuMjUtLjI1di0uNWEuMjUuMjUgMCAwIDAtLjI1LS4yNVpNNi43NSAxMS41aC0uNWEuMjUuMjUgMCAwIDAtLjI1LjI1di41YzAgLjEzOC4xMTIuMjUuMjUuMjVoLjVhLjI1LjI1IDAgMCAwIC4yNS0uMjV2LS41YS4yNS4yNSAwIDAgMC0uMjUtLjI1Wk04Ljc1IDExLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTEwLjc1IDExLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTEyLjc1IDExLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaTTE0Ljc1IDExLjVoLS41YS4yNS4yNSAwIDAgMC0uMjUuMjV2LjVjMCAuMTM4LjExMi4yNS4yNS4yNWguNWEuMjUuMjUgMCAwIDAgLjI1LS4yNXYtLjVhLjI1LjI1IDAgMCAwLS4yNS0uMjVaIi8+PHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik01IDYuNUgxLjVBLjUuNSAwIDAgMCAxIDd2MTBhLjUuNSAwIDAgMCAuNS41aDEwYS41LjUgMCAwIDAgLjUtLjV2LTMuNUg1LjVBLjUuNSAwIDAgMSA1IDEzVjYuNVoiLz48L2c+PC9zdmc+"); + background-repeat: no-repeat; + background-size: contain; + content: ""; + display: inline-block; + height: 18px; + min-width: 18px; + position: relative; + top: 5px; + width: 18px; + margin-inline-start: 8px +} diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js new file mode 100644 index 00000000..a591e071 --- /dev/null +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -0,0 +1,173 @@ +/* eslint-disable compat/compat */ +import { setLibs } from '../../scripts/utils.js'; + +const miloLibs = setLibs('/libs'); +const { createTag } = await import(`${miloLibs}/utils/utils.js`); + +const classToastShow = 'prompt-toast--show'; +const getPlaceHolder = (x) => (window.mph?.[x] || x); + +function copyPrompt(cfg) { + navigator.clipboard.writeText(cfg.prompt); + + let toast = document.querySelector('.prompt-toast'); + if (!toast) { + toast = createTag('div', { class: 'prompt-toast' }, cfg.toast); + const toastClose = createTag('i', { class: 'prompt-close' }); + toast.appendChild(toastClose); + document.body.appendChild(toast); + + toastClose.addEventListener('click', () => { + toast.classList.remove(classToastShow); + }); + } + toast.childNodes[0].textContent = cfg.toast; + toast.classList.add(classToastShow); + + setTimeout(() => toast.classList.remove(classToastShow), 5000); +} + +async function createBlock(element, cfg) { + cfg.icon = cfg.icon || '/acrobat/img/icons/aichat.svg'; + cfg.button = cfg.button || getPlaceHolder('Copy'); + cfg.toast = cfg.toast || getPlaceHolder('Copied to clipboard'); + const blade = createTag('div', { + class: 'prompt-blade', + title: cfg.prompt, + 'data-toast': cfg.toast, + 'daa-im': true, + 'daa-lh': 'Featured prompts | Executive summary', + }); + const prefix = createTag('div', { class: 'prompt-prefix' }); + const icon = createTag('img', { + class: 'prompt-icon', + alt: 'AI Assistant Icon', + src: cfg.icon, + width: 18, + height: 18, + }); + const title = createTag('div', { class: 'prompt-title' }, cfg.title); + const copy = createTag('div', { class: 'prompt-copy' }, cfg.prompt); + const prompt = createTag('input', { id: 'prompt', value: cfg.prompt }); + const wrapper = createTag('div', { class: 'prompt-copy-btn-wrapper' }); + const copyBtn = createTag('span', { class: 'prompt-copy-btn', role: 'button', tabindex: 0, 'aria-label': 'Copy button' }, cfg.button); + wrapper.append(copyBtn); + prefix.appendChild(icon); + prefix.appendChild(createTag('span', null, cfg.prefix)); + blade.append(prefix, title, copy, prompt, wrapper); + element.replaceChildren(blade); + + blade.addEventListener('click', () => { + copyPrompt(cfg); + }); + + copyBtn.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + copyPrompt(cfg); + } + }); +} + +async function createBlocks(element, blockArray, templateCfg) { + const { parentNode } = element; + for (const [i, cfg] of blockArray.entries()) { + const blockEl = createTag('div', { class: 'prompt-card' }); + if (templateCfg.rows && i > 0) blockEl.classList.add('hidden'); + await createBlock(blockEl, { ...templateCfg, ...cfg }); + parentNode.insertBefore(blockEl, element.previousSibling); + } + element.remove(); + + if (templateCfg.rows && parentNode.classList.contains('section')) { + const resizeObserver = new ResizeObserver(() => { + const computedStyle = window.getComputedStyle(parentNode); + if (/^(\d+(\.\d+)?(px|fr|em|rem|%))( (\d+(\.\d+)?(px|fr|em|rem|%)))*$/.test(computedStyle.gridTemplateColumns)) { + const visibleCnt = computedStyle.gridTemplateColumns.split(' ').length * templateCfg.rows; + const promptcards = [...parentNode.querySelectorAll('.prompt-card')]; + if (promptcards.length <= visibleCnt) { + parentNode.querySelector('.view-all')?.remove(); + resizeObserver.disconnect(); + } + promptcards.forEach( + (x, i) => (i < visibleCnt ? x.classList.remove('hidden') : x.classList.add('hidden')), + ); + } + }); + resizeObserver.observe(parentNode); + + const viewMore = createTag('div', { class: 'view-all' }); + const moreBtn = createTag('div', { class: 'con-button outline' }, getPlaceHolder('View all')); + moreBtn.addEventListener('click', (e) => { + resizeObserver.disconnect(); + [...parentNode.querySelectorAll('.prompt-card')].forEach((x) => x.classList.remove('hidden')); + e.target.parentNode.remove(); + }); + viewMore.appendChild(moreBtn); + parentNode.appendChild(viewMore); + } +} + +async function processGroup(element, cfg, startIndex) { + let blockArray; + if (startIndex > -1) { + blockArray = []; + const keys = [...element.children[startIndex].children].map((x) => x.textContent.toLowerCase()); + [...element.children].slice(startIndex + 1).forEach((x) => { + const values = [...x.children].map((y) => y.textContent); + const block = keys.reduce((obj, key, index) => ({ ...obj, [key]: values[index] }), {}); + blockArray.push(block); + }); + } else { + const resp = await fetch(cfg.json); + if (!resp.ok) { + element.remove(); + return; + } + const json = await resp.json(); + const keys = Object.keys(cfg).filter((k) => !['json', 'rows'].includes(k)); + blockArray = json.data.filter( + (x) => keys.reduce((a, k) => a && cfg[k] === x[k], true), + ); + } + await createBlocks(element, blockArray, cfg); +} + +function readKeyValueSet(element) { + const cfg = {}; + for (const x of [...element.children]) { + if (x.children.length < 2) break; + cfg[x.children[0].textContent.toLowerCase()] = x.children[1].textContent; + } + return cfg; +} + +export default async function init(element) { + if (element.classList.contains('template') && element.classList.contains('group')) { + const cfg = readKeyValueSet(element); + await processGroup(element, cfg, Object.keys(cfg).length + 1); + return; + } + + if (element.classList.contains('group')) { + await processGroup(element, window.promptCardTemplate, 0); + return; + } + + let cfg = readKeyValueSet(element); + + if (element.classList.contains('template')) { + window.promptCardTemplate = cfg; + element.remove(); + return; + } + + if (element.classList.contains('json')) { + await processGroup(element, cfg, -1); + return; + } + + cfg = { ...window.promptCardTemplate, ...cfg }; + + await createBlock(element, cfg); +} diff --git a/acrobat/img/icons/aichat.svg b/acrobat/img/icons/aichat.svg new file mode 100644 index 00000000..7d027e09 --- /dev/null +++ b/acrobat/img/icons/aichat.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/test/blocks/prompt-card/mocks/body-block-icon.html b/test/blocks/prompt-card/mocks/body-block-icon.html new file mode 100644 index 00000000..e8ad0016 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-block-icon.html @@ -0,0 +1,28 @@ +
+
+
+
Icon
+
https://main--dc--adobecom.hlx.live/dc-shared/assets/images/frictionless/verb-footer-images/word-to-pdf.svg
+
+
+
Prefix
+
Ask
+
+
+
Title
+
Sum it up
+
+
+
Prompt
+
Summarize this document in 3 sentences.
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to clipboard
+
+
+
diff --git a/test/blocks/prompt-card/mocks/body-block.html b/test/blocks/prompt-card/mocks/body-block.html new file mode 100644 index 00000000..6d5ea8c0 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-block.html @@ -0,0 +1,24 @@ +
+
+
+
Prefix
+
Ask
+
+
+
Title
+
Sum it up
+
+
+
Prompt
+
Summarize this document in 3 sentences.
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to clipboard
+
+
+
diff --git a/test/blocks/prompt-card/mocks/body-group-placeholder.html b/test/blocks/prompt-card/mocks/body-group-placeholder.html new file mode 100644 index 00000000..75afff64 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-group-placeholder.html @@ -0,0 +1,52 @@ +
+
+
+
+
Prefix
+
{{Ask}}
+
+
+
+
+
+
+
Title
+
Prompt
+
+
+
Sum it up
+
Summarize this document in 3 sentences.
+
+
+
Organize your thoughts
+
Suggest a few essay topics based on this reading that can help me get started.
+
+
+
Refresh your memory.
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Shorten up the intro
+
Rewrite the introduction so it has only 200 words and a Flesch reading score above 50.
+
+
+ +
+
\ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-group.html b/test/blocks/prompt-card/mocks/body-group.html new file mode 100644 index 00000000..af38e0ef --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-group.html @@ -0,0 +1,52 @@ +
+
+
+
+
Prefix
+
Ask
+
+
+
+
+
+
+
Title
+
Prompt
+
+
+
Sum it up
+
Summarize this document in 3 sentences.
+
+
+
Organize your thoughts
+
Suggest a few essay topics based on this reading that can help me get started.
+
+
+
Refresh your memory.
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Shorten up the intro
+
Rewrite the introduction so it has only 200 words and a Flesch reading score above 50.
+
+
+ +
+
\ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-json-more-less.html b/test/blocks/prompt-card/mocks/body-json-more-less.html new file mode 100644 index 00000000..692c4847 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-json-more-less.html @@ -0,0 +1,29 @@ +
+
+
+
+
Json
+
https://www.adobe.com/dc-shared/promptcard.json
+
+
+
Prefix
+
Analyze
+
+
+
Rows
+
1
+
+
+ +
+
+ \ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-json-more.html b/test/blocks/prompt-card/mocks/body-json-more.html new file mode 100644 index 00000000..ba702fef --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-json-more.html @@ -0,0 +1,25 @@ +
+
+
+
+
Json
+
https://www.adobe.com/dc-shared/promptcard.json
+
+
+
Rows
+
1
+
+
+ +
+
+ \ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-json.html b/test/blocks/prompt-card/mocks/body-json.html new file mode 100644 index 00000000..832cb91b --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-json.html @@ -0,0 +1,29 @@ +
+
+
+
+
Json
+
https://www.adobe.com/dc-shared/promptcard.json
+
+
+
Page
+
B
+
+
+
Prefix
+
Analyze
+
+
+ +
+
+ \ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-section.html b/test/blocks/prompt-card/mocks/body-section.html new file mode 100644 index 00000000..71c1c088 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-section.html @@ -0,0 +1,92 @@ +
+
+
+
+
Prefix
+
Ask
+
+
+
Title
+
Sum it up
+
+
+
Prompt
+
Summarize this document in 3 sentences.
+
+
+
+
+
Button
+
My Copy
+
+
+
Toast
+
My Copied to Clipboard
+
+
+
Prefix
+
Generate
+
+
+
Title
+
Organize your thoughts.
+
+
+
Prompt
+
Suggest a few essay topics based on this reading that can help me get started.
+
+
+
+
+
Prefix
+
Brainstorm
+
+
+
Title
+
Refresh your memory.
+
+
+
Prompt
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
+
+
Prefix
+
Analyze
+
+
+
Title
+
Point out tech advantages
+
+
+
Prompt
+
What are the key benefits for users of this proposed technology solution?
+
+
+
+
+
Prefix
+
Modify
+
+
+
Title
+
Shorten up the intro
+
+
+
Prompt
+
Rewrite the introduction so it has only 200 words and a Flesch reading score above 50.
+
+
+ +
+
\ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-template-group.html b/test/blocks/prompt-card/mocks/body-template-group.html new file mode 100644 index 00000000..67d6c0e3 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-template-group.html @@ -0,0 +1,51 @@ +
+
+
+
+
Prefix
+
Ask
+
+
+
+
+
+
Title
+
Prompt
+
+
+
Sum it up
+
Summarize this document in 3 sentences.
+
+
+
Organize your thoughts
+
Suggest a few essay topics based on this reading that can help me get started.
+
+
+
Refresh your memory.
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Point out tech advantages
+
What are the key benefits for users of this proposed technology solution?
+
+
+
Shorten up the intro
+
Rewrite the introduction so it has only 200 words and a Flesch reading score above 50.
+
+
+ +
+
\ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/body-template.html b/test/blocks/prompt-card/mocks/body-template.html new file mode 100644 index 00000000..8fd42370 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-template.html @@ -0,0 +1,73 @@ +
+
+
+
+
Prefix
+
Ask
+
+
+
+
+
+
+
Title
+
Sum it up
+
+
+
Prompt
+
Summarize this document in 3 sentences.
+
+
+
+
+
Title
+
Organize your thoughts.
+
+
+
Prompt
+
Suggest a few essay topics based on this reading that can help me get started.
+
+
+
+
+
Title
+
Refresh your memory.
+
+
+
Prompt
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
+
+
Title
+
Point out tech advantages
+
+
+
Prompt
+
What are the key benefits for users of this proposed technology solution?
+
+
+
+
+
Title
+
Shorten up the intro
+
+
+
Prompt
+
Rewrite the introduction so it has only 200 words and a Flesch reading score above 50.
+
+
+ +
+
+ \ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/head-block.html b/test/blocks/prompt-card/mocks/head-block.html new file mode 100644 index 00000000..8f4d0513 --- /dev/null +++ b/test/blocks/prompt-card/mocks/head-block.html @@ -0,0 +1,4 @@ + + + + diff --git a/test/blocks/prompt-card/mocks/head.html b/test/blocks/prompt-card/mocks/head.html new file mode 100644 index 00000000..8ca44032 --- /dev/null +++ b/test/blocks/prompt-card/mocks/head.html @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/test/blocks/prompt-card/mocks/placeholder.json b/test/blocks/prompt-card/mocks/placeholder.json new file mode 100644 index 00000000..558fcdad --- /dev/null +++ b/test/blocks/prompt-card/mocks/placeholder.json @@ -0,0 +1,11 @@ +{ + "total": 2, + "offset": 0, + "limit": 2, + "data": [ + { "key": "Ask", "value": "聞く"}, + { "key": "Copy", "value": "コピー" }, + { "key": "Copied to clipboard", "value": "クリップボードにコピーされました" } + ], + ":type": "sheet" +} diff --git a/test/blocks/prompt-card/mocks/promptcards.json b/test/blocks/prompt-card/mocks/promptcards.json new file mode 100644 index 00000000..0b9ee932 --- /dev/null +++ b/test/blocks/prompt-card/mocks/promptcards.json @@ -0,0 +1,14 @@ +{ + "total": 2, + "offset": 0, + "limit": 2, + "data": [ + { "page": "A", "prefix": "Ask", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."}, + { "page": "A", "prefix": "Ask", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."}, + { "page": "A", "prefix": "Ask", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."}, + { "page": "B", "prefix": "Analyze", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."}, + { "page": "B", "prefix": "Ask", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."}, + { "page": "B", "prefix": "Analyze", "title": "Sum it up", "prompt": "Summarize this document in 3 sentences."} + ], + ":type": "sheet" +} diff --git a/test/blocks/prompt-card/prompt-card-group-placeholder.test.js b/test/blocks/prompt-card/prompt-card-group-placeholder.test.js new file mode 100644 index 00000000..d8aea259 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-group-placeholder.test.js @@ -0,0 +1,25 @@ +/* eslint-disable compat/compat */ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards in a section using the group feature', () => { + before(async () => { + const placeholder = await readFile({ path: './mocks/placeholder.json' }); + sinon.stub(window, 'fetch'); + const res = new window.Response(placeholder, { status: 200 }); + window.fetch.returns(Promise.resolve(res)); + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-group-placeholder.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + it('shows replaced placeholder text', async () => { + const prefix = document.querySelector('.prompt-prefix'); + expect(prefix.textContent).to.equal('聞く'); + const button = document.querySelector('.prompt-copy-btn'); + expect(button.textContent).to.equal('コピー'); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-group.test.js b/test/blocks/prompt-card/prompt-card-group.test.js new file mode 100644 index 00000000..06cd82f7 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-group.test.js @@ -0,0 +1,17 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards in a section using the group feature', () => { + before(async () => { + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-group.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + it('creates prompt cards', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(6); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-icon.test.js b/test/blocks/prompt-card/prompt-card-icon.test.js new file mode 100644 index 00000000..bb9d7686 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-icon.test.js @@ -0,0 +1,34 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; + +const head = await readFile({ path: './mocks/head-block.html' }); + +const { default: init } = await import( + '../../../acrobat/blocks/prompt-card/prompt-card.js' +); + +describe('prompt-card block', () => { + let clock; + + before(async () => { + document.head.innerHTML = head; + document.body.innerHTML = await readFile({ path: './mocks/body-block-icon.html' }); + const block = document.querySelector('.prompt-card'); + await init(block); + }); + + beforeEach(() => { + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); + }); + + it('has a customized icon', async () => { + const icon = document.querySelector('.prompt-icon'); + expect(icon).to.be.exist; + expect(icon.src).to.contains('word-to-pdf.svg'); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-json-error.test.js b/test/blocks/prompt-card/prompt-card-json-error.test.js new file mode 100644 index 00000000..ad75f217 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-json-error.test.js @@ -0,0 +1,26 @@ +/* eslint-disable compat/compat */ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { delay } from '../../helpers/waitfor.js'; + +describe('prompt-cards using json feature', () => { + before(async () => { + sinon.stub(window, 'fetch'); + const res = new window.Response('Not Found', { status: 404 }); + window.fetch.returns(Promise.resolve(res)); + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-json.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await delay(500); + }); + + after(() => { + sinon.restore(); + }); + + it('shows no prompt card', async () => { + const promptcard = document.querySelector('.prompt-card'); + expect(promptcard).to.not.exist; + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-json-more-less.test.js b/test/blocks/prompt-card/prompt-card-json-more-less.test.js new file mode 100644 index 00000000..80a8855c --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-json-more-less.test.js @@ -0,0 +1,30 @@ +/* eslint-disable compat/compat */ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { waitForElement, delay } from '../../helpers/waitfor.js'; + +describe('prompt-cards view all feature', () => { + before(async () => { + const promptcards = await readFile({ path: './mocks/promptcards.json' }); + sinon.stub(window, 'fetch'); + const res = new window.Response(promptcards, { status: 200 }); + window.fetch.returns(Promise.resolve(res)); + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-json-more-less.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await delay(500); + await new Promise((resolve) => requestAnimationFrame(resolve)); + }); + + after(() => { + sinon.restore(); + }); + + it('has no a view-all button if no more items', () => { + const promptcards = document.querySelectorAll('.prompt-card:not(.hidden)'); + expect([...promptcards].length).to.equal(2); + const button = document.querySelector('.view-all .con-button'); + expect(button).to.not.exist; + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-json-more.test.js b/test/blocks/prompt-card/prompt-card-json-more.test.js new file mode 100644 index 00000000..20b1e7af --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-json-more.test.js @@ -0,0 +1,38 @@ +/* eslint-disable compat/compat */ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { waitForElement, delay } from '../../helpers/waitfor.js'; + +describe('prompt-cards view all feature', () => { + before(async () => { + const promptcards = await readFile({ path: './mocks/promptcards.json' }); + sinon.stub(window, 'fetch'); + const res = new window.Response(promptcards, { status: 200 }); + window.fetch.returns(Promise.resolve(res)); + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-json-more.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await delay(500); + await new Promise((resolve) => requestAnimationFrame(resolve)); + }); + + after(() => { + sinon.restore(); + }); + + it('creates prompt cards on rows 1 with a view-all button', async () => { + const promptcards = document.querySelectorAll('.prompt-card:not(.hidden)'); + expect([...promptcards].length).to.equal(2); + }); + + it('click the view-all button', () => { + const button = document.querySelector('.view-all .con-button'); + button.click(); + const promptcards = document.querySelectorAll('.prompt-card:not(.hidden)'); + expect([...promptcards].length).to.equal(6); + const hiddencards = document.querySelectorAll('.hidden'); + expect([...hiddencards].length).to.equal(0); + expect(document.querySelector('.view-all .con-button')).to.not.exist; + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-json.test.js b/test/blocks/prompt-card/prompt-card-json.test.js new file mode 100644 index 00000000..fb594cd3 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-json.test.js @@ -0,0 +1,27 @@ +/* eslint-disable compat/compat */ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards using json feature', () => { + before(async () => { + const promptcards = await readFile({ path: './mocks/promptcards.json' }); + sinon.stub(window, 'fetch'); + const res = new window.Response(promptcards, { status: 200 }); + window.fetch.returns(Promise.resolve(res)); + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-json.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + after(() => { + sinon.restore(); + }); + + it('creates prompt cards', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(2); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-section.test.js b/test/blocks/prompt-card/prompt-card-section.test.js new file mode 100644 index 00000000..a94639f6 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-section.test.js @@ -0,0 +1,17 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards in a section', () => { + before(async () => { + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-section.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + it('creates prompt cards', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(5); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-template-group.test.js b/test/blocks/prompt-card/prompt-card-template-group.test.js new file mode 100644 index 00000000..5aad1268 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-template-group.test.js @@ -0,0 +1,17 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards using the template and group features', () => { + before(async () => { + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-template-group.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + it('creates prompt cards', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(6); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card-template.test.js b/test/blocks/prompt-card/prompt-card-template.test.js new file mode 100644 index 00000000..1f6bf437 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card-template.test.js @@ -0,0 +1,17 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import { waitForElement } from '../../helpers/waitfor.js'; + +describe('prompt-cards in a section using a template', () => { + before(async () => { + document.head.innerHTML = await readFile({ path: './mocks/head.html' }); + document.body.innerHTML = await readFile({ path: './mocks/body-template.html' }); + await import('../../../acrobat/scripts/scripts.js'); + await waitForElement('.prompt-blade'); + }); + + it('creates prompt cards', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(5); + }); +}); diff --git a/test/blocks/prompt-card/prompt-card.test.js b/test/blocks/prompt-card/prompt-card.test.js new file mode 100644 index 00000000..9bb94d13 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card.test.js @@ -0,0 +1,83 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; +import sinon from 'sinon'; + +const head = await readFile({ path: './mocks/head-block.html' }); + +const { default: init } = await import( + '../../../acrobat/blocks/prompt-card/prompt-card.js' +); + +describe('prompt-card block', () => { + let clock; + + before(async () => { + document.head.innerHTML = head; + document.body.innerHTML = await readFile({ path: './mocks/body-block.html' }); + const block = document.querySelector('.prompt-card'); + await init(block); + }); + + beforeEach(() => { + clock = sinon.useFakeTimers(); + }); + + afterEach(() => { + clock.restore(); + }); + + it('creates a prompt-card block', async () => { + expect(document.querySelector('.prompt-icon')).to.be.exist; + expect(document.querySelector('.prompt-prefix span')).to.be.exist; + expect(document.querySelector('.prompt-title')).to.be.exist; + expect(document.querySelector('.prompt-copy')).to.be.exist; + expect(document.querySelector('#prompt')).to.be.exist; + expect(document.querySelector('.prompt-copy-btn')).to.be.exist; + }); + + it('copies the prompt when copy button is clicked', async () => { + const toast = document.querySelector('.prompt-toast'); + if (toast) { + expect(toast.checkVisibility()).to.be.false; + } + document.querySelector('.prompt-copy-btn').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.true; + expect(document.querySelector('.prompt-close')).to.be.exist; + document.querySelector('.prompt-close').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + }); + + it('copies the prompt when key press ENTER/SPACE on copy button', () => { + const keys = ['Enter', ' ']; + keys.forEach((key) => { + const toast = document.querySelector('.prompt-toast'); + if (toast) { + expect(toast.checkVisibility()).to.be.false; + } + document.querySelector('.prompt-copy-btn').dispatchEvent(new KeyboardEvent('keypress', { key })); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.true; + expect(document.querySelector('.prompt-close')).to.be.exist; + document.querySelector('.prompt-close').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + }); + }); + + it('copies the prompt when prompt card is clicked', () => { + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + document.querySelector('.prompt-blade').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.true; + expect(document.querySelector('.prompt-close')).to.be.exist; + document.querySelector('.prompt-close').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + }); + + it('Prompt toast automatically dismissed after 5 seconds', () => { + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + document.querySelector('.prompt-copy-btn').click(); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.true; + clock.tick(4000); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.true; + clock.tick(1100); + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + }); +});