From e58bba54c6450be4a7a7dd36fd35e6f4dff4068b Mon Sep 17 00:00:00 2001 From: James Tsay Date: Mon, 16 Sep 2024 07:42:40 -0700 Subject: [PATCH 1/6] Prompt Card Draft --- acrobat/blocks/prompt-card/prompt-card.css | 157 ++++++++++++++++++ acrobat/blocks/prompt-card/prompt-card.js | 99 +++++++++++ acrobat/img/icons/aichat.svg | 7 + test/blocks/prompt-card/mocks/body-block.html | 28 ++++ test/blocks/prompt-card/mocks/body-group.html | 64 +++++++ .../prompt-card/mocks/body-section.html | 144 ++++++++++++++++ .../mocks/body-template-group.html | 63 +++++++ .../prompt-card/mocks/body-template.html | 85 ++++++++++ test/blocks/prompt-card/mocks/head-block.html | 4 + test/blocks/prompt-card/mocks/head.html | 3 + .../prompt-card/prompt-card-group.test.js | 17 ++ .../prompt-card/prompt-card-section.test.js | 17 ++ .../prompt-card-template-group.test.js | 17 ++ .../prompt-card/prompt-card-template.test.js | 17 ++ test/blocks/prompt-card/prompt-card.test.js | 44 +++++ 15 files changed, 766 insertions(+) create mode 100644 acrobat/blocks/prompt-card/prompt-card.css create mode 100644 acrobat/blocks/prompt-card/prompt-card.js create mode 100644 acrobat/img/icons/aichat.svg create mode 100644 test/blocks/prompt-card/mocks/body-block.html create mode 100644 test/blocks/prompt-card/mocks/body-group.html create mode 100644 test/blocks/prompt-card/mocks/body-section.html create mode 100644 test/blocks/prompt-card/mocks/body-template-group.html create mode 100644 test/blocks/prompt-card/mocks/body-template.html create mode 100644 test/blocks/prompt-card/mocks/head-block.html create mode 100644 test/blocks/prompt-card/mocks/head.html create mode 100644 test/blocks/prompt-card/prompt-card-group.test.js create mode 100644 test/blocks/prompt-card/prompt-card-section.test.js create mode 100644 test/blocks/prompt-card/prompt-card-template-group.test.js create mode 100644 test/blocks/prompt-card/prompt-card-template.test.js create mode 100644 test/blocks/prompt-card/prompt-card.test.js diff --git a/acrobat/blocks/prompt-card/prompt-card.css b/acrobat/blocks/prompt-card/prompt-card.css new file mode 100644 index 00000000..ebf646d1 --- /dev/null +++ b/acrobat/blocks/prompt-card/prompt-card.css @@ -0,0 +1,157 @@ +#prompt { + display: none +} + +.prompt-toast { + font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + 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: 1; + z-index: 11 +} + +.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-left: 10px; + margin-top: 7px; + min-width: 12px; + width: 12px +} + +.prompt-blade { + align-items: center; + 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; +} + +.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-right: 5px; + position: relative; + top: 5px +} + +.prompt-prefix { + color: #6d6d6d; + font-size: 12px; + padding: 0 0 16px; + text-transform: uppercase +} + +.prompt-prefix, +.prompt-title { + font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + font-style: normal; + font-weight: 700; + line-height: 125% +} + +.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: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + 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 +} diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js new file mode 100644 index 00000000..783381eb --- /dev/null +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -0,0 +1,99 @@ +import { setLibs } from '../../scripts/utils.js'; + +const miloLibs = setLibs('/libs'); +const { createTag } = await import(`${miloLibs}/utils/utils.js`); + +const classToastShow = 'prompt-toast--show'; + +async function createBlock(element, cfg) { + const blade = createTag('div', { class: 'prompt-blade' }); + const prefix = createTag('div', { class: 'prompt-prefix' }); + const icon = createTag('img', { class: 'prompt-icon', src: `/acrobat/img/icons/${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); + const toast = createTag('div', { class: 'prompt-toast' }, cfg.toast); + const toastClose = createTag('i', { class: 'prompt-close' }); + toast.appendChild(toastClose); + element.appendChild(toast); + + const copyPrompt = () => { + prompt.select(); + prompt.setSelectionRange(0, 99999); + navigator.clipboard.writeText(prompt.value); + toast.classList.add(classToastShow); + setTimeout(() => toast.classList.remove(classToastShow), 5000); + }; + + copyBtn.addEventListener('click', () => { + copyPrompt(); + }); + + copyBtn.addEventListener('keypress', (e) => { + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + copyPrompt(); + } + }); + + toastClose.addEventListener('click', (e) => { + e.currentTarget.parentNode.classList.remove(classToastShow); + }); +} + +async function processGroup(element, startIndex, templateCfg) { + const 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); + }); + for (const cfg of blockArray) { + const blockEl = createTag('div', { class: 'prompt-card' }); + await createBlock(blockEl, { ...templateCfg, ...cfg }); + element.parentNode.insertBefore(blockEl, element.nextSibling); + } + element.remove(); +} + +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, Object.keys(cfg).length + 1, cfg); + return; + } + + if (element.classList.contains('group')) { + await processGroup(element, 0, window.promptCardTemplate); + return; + } + + let cfg = readKeyValueSet(element); + + if (element.classList.contains('template')) { + window.promptCardTemplate = cfg; + element.remove(); + 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..a6e8260d --- /dev/null +++ b/acrobat/img/icons/aichat.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file 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..4f448e53 --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-block.html @@ -0,0 +1,28 @@ +
+
+
+
Icon
+
aichat.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-group.html b/test/blocks/prompt-card/mocks/body-group.html new file mode 100644 index 00000000..23f884ef --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-group.html @@ -0,0 +1,64 @@ +
+
+
+
+
Icon
+
aichat.svg
+
+
+
Prefix
+
Ask
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard!
+
+
+
+
+
+
+
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-section.html b/test/blocks/prompt-card/mocks/body-section.html new file mode 100644 index 00000000..3832d44d --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-section.html @@ -0,0 +1,144 @@ +
+
+
+
+
Icon
+
aichat.svg
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard
+
+
+
Prefix
+
Ask
+
+
+
Title
+
Sum it up
+
+
+
Prompt
+
Summarize this document in 3 sentences.
+
+
+
+
+
Icon
+
aichat.svg
+
+
+
Button
+
Copy
+
+
+
Toast
+
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.
+
+
+
+
+
Icon
+
aichat.svg
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard
+
+
+
Prefix
+
Brainstorm
+
+
+
Title
+
Refresh your memory.
+
+
+
Prompt
+
Provide 10 sample test questions that my professor could ask me.
+
+
+
+
+
Icon
+
aichat.svg
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard
+
+
+
Prefix
+
Analyze
+
+
+
Title
+
Point out tech advantages
+
+
+
Prompt
+
What are the key benefits for users of this proposed technology solution?
+
+
+
+
+
Icon
+
aichat.svg
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard
+
+
+
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..79bb91ab --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-template-group.html @@ -0,0 +1,63 @@ +
+
+
+
+
Icon
+
aichat.svg
+
+
+
Prefix
+
Ask
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard!
+
+
+
+
+
+
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..e346b3ab --- /dev/null +++ b/test/blocks/prompt-card/mocks/body-template.html @@ -0,0 +1,85 @@ +
+
+
+
+
Icon
+
aichat.svg
+
+
+
Prefix
+
Ask
+
+
+
Button
+
Copy
+
+
+
Toast
+
Copied to Clipboard!
+
+
+
+
+
+
+
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/prompt-card-group.test.js b/test/blocks/prompt-card/prompt-card-group.test.js new file mode 100644 index 00000000..979b1239 --- /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 a prompt-card block', async () => { + const blades = document.querySelectorAll('.prompt-blade'); + expect([...blades].length).to.equal(6); + }); +}); 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..ebb9137e --- /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 a prompt-card block', 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..86a324ca --- /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 a prompt-card block', 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..3a46c87c --- /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 a prompt-card block', 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..19647f85 --- /dev/null +++ b/test/blocks/prompt-card/prompt-card.test.js @@ -0,0 +1,44 @@ +import { readFile } from '@web/test-runner-commands'; +import { expect } from '@esm-bundle/chai'; + +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', () => { + 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); + }); + + 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 () => { + expect(document.querySelector('.prompt-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 copy button is clicked', async () => { + expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + document.querySelector('.prompt-copy-btn').dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter' })); + 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; + }); +}); From c145decd4dadf18053c0049d9e0b45dec0f48de3 Mon Sep 17 00:00:00 2001 From: James Tsay Date: Mon, 16 Sep 2024 14:28:31 -0700 Subject: [PATCH 2/6] Prompt card is clickable --- acrobat/blocks/prompt-card/prompt-card.js | 4 +-- test/blocks/prompt-card/prompt-card.test.js | 37 +++++++++++++++++++-- 2 files changed, 37 insertions(+), 4 deletions(-) diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js index 783381eb..117c4b47 100644 --- a/acrobat/blocks/prompt-card/prompt-card.js +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -32,9 +32,9 @@ async function createBlock(element, cfg) { setTimeout(() => toast.classList.remove(classToastShow), 5000); }; - copyBtn.addEventListener('click', () => { + [copyBtn, blade].forEach((el) => el.addEventListener('click', () => { copyPrompt(); - }); + })); copyBtn.addEventListener('keypress', (e) => { if (e.key === 'Enter' || e.key === ' ') { diff --git a/test/blocks/prompt-card/prompt-card.test.js b/test/blocks/prompt-card/prompt-card.test.js index 19647f85..0f10b97e 100644 --- a/test/blocks/prompt-card/prompt-card.test.js +++ b/test/blocks/prompt-card/prompt-card.test.js @@ -1,5 +1,6 @@ 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' }); @@ -8,6 +9,8 @@ const { default: init } = await import( ); describe('prompt-card block', () => { + let clock; + before(async () => { document.head.innerHTML = head; document.body.innerHTML = await readFile({ path: './mocks/body-block.html' }); @@ -15,6 +18,14 @@ describe('prompt-card block', () => { 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; @@ -33,12 +44,34 @@ describe('prompt-card block', () => { expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; }); - it('copies the prompt when copy button is clicked', async () => { + it('copies the prompt when key press ENTER/SPACE on copy button', () => { + const keys = ['Enter', ' ']; + keys.forEach((key) => { + expect(document.querySelector('.prompt-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-copy-btn').dispatchEvent(new KeyboardEvent('keypress', { key: 'Enter' })); + 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; + }); }); From 8ee1b20cb6d764606fe4e99623487d3804e64ede Mon Sep 17 00:00:00 2001 From: James Tsay Date: Tue, 17 Sep 2024 21:00:13 -0700 Subject: [PATCH 3/6] Placeholder, Icon, Toast Updates --- acrobat/blocks/prompt-card/prompt-card.css | 9 +-- acrobat/blocks/prompt-card/prompt-card.js | 68 ++++++++++++------- acrobat/img/icons/aichat.svg | 28 ++++++-- .../prompt-card/mocks/body-block-icon.html | 28 ++++++++ test/blocks/prompt-card/mocks/body-block.html | 4 -- .../mocks/body-group-placeholder.html | 52 ++++++++++++++ test/blocks/prompt-card/mocks/body-group.html | 14 +--- .../prompt-card/mocks/body-section.html | 56 +-------------- .../mocks/body-template-group.html | 12 ---- .../prompt-card/mocks/body-template.html | 12 ---- .../blocks/prompt-card/mocks/placeholder.json | 11 +++ .../prompt-card-group-placeholder.test.js | 25 +++++++ .../prompt-card/prompt-card-icon.test.js | 34 ++++++++++ test/blocks/prompt-card/prompt-card.test.js | 10 ++- 14 files changed, 231 insertions(+), 132 deletions(-) create mode 100644 test/blocks/prompt-card/mocks/body-block-icon.html create mode 100644 test/blocks/prompt-card/mocks/body-group-placeholder.html create mode 100644 test/blocks/prompt-card/mocks/placeholder.json create mode 100644 test/blocks/prompt-card/prompt-card-group-placeholder.test.js create mode 100644 test/blocks/prompt-card/prompt-card-icon.test.js diff --git a/acrobat/blocks/prompt-card/prompt-card.css b/acrobat/blocks/prompt-card/prompt-card.css index ebf646d1..9d3988c6 100644 --- a/acrobat/blocks/prompt-card/prompt-card.css +++ b/acrobat/blocks/prompt-card/prompt-card.css @@ -15,8 +15,7 @@ position: fixed; top: 110px; transform: translate(-50%, -50%); - z-index: 1; - z-index: 11 + z-index: 9999 } .prompt-toast--show { @@ -61,6 +60,7 @@ padding: 20px 20px 24px; transition-delay: 3s; transition-property: border; + max-width: 276px; } .prompt-blade:hover { @@ -73,7 +73,7 @@ } .prompt-icon { - margin-right: 5px; + margin-inline-end: 5px; position: relative; top: 5px } @@ -153,5 +153,6 @@ min-width: 18px; position: relative; top: 5px; - width: 18px + width: 18px; + margin-inline-start: 8px } diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js index 117c4b47..c9414fd3 100644 --- a/acrobat/blocks/prompt-card/prompt-card.js +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -4,11 +4,47 @@ 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) { - const blade = createTag('div', { class: 'prompt-blade' }); + 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', src: `/acrobat/img/icons/${cfg.icon}`, width: 18, height: 18 }); + 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 }); @@ -19,33 +55,17 @@ async function createBlock(element, cfg) { prefix.appendChild(createTag('span', null, cfg.prefix)); blade.append(prefix, title, copy, prompt, wrapper); element.replaceChildren(blade); - const toast = createTag('div', { class: 'prompt-toast' }, cfg.toast); - const toastClose = createTag('i', { class: 'prompt-close' }); - toast.appendChild(toastClose); - element.appendChild(toast); - - const copyPrompt = () => { - prompt.select(); - prompt.setSelectionRange(0, 99999); - navigator.clipboard.writeText(prompt.value); - toast.classList.add(classToastShow); - setTimeout(() => toast.classList.remove(classToastShow), 5000); - }; - - [copyBtn, blade].forEach((el) => el.addEventListener('click', () => { - copyPrompt(); - })); + + blade.addEventListener('click', () => { + copyPrompt(cfg); + }); copyBtn.addEventListener('keypress', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); - copyPrompt(); + copyPrompt(cfg); } }); - - toastClose.addEventListener('click', (e) => { - e.currentTarget.parentNode.classList.remove(classToastShow); - }); } async function processGroup(element, startIndex, templateCfg) { @@ -59,7 +79,7 @@ async function processGroup(element, startIndex, templateCfg) { for (const cfg of blockArray) { const blockEl = createTag('div', { class: 'prompt-card' }); await createBlock(blockEl, { ...templateCfg, ...cfg }); - element.parentNode.insertBefore(blockEl, element.nextSibling); + element.parentNode.insertBefore(blockEl, element.previousSibling); } element.remove(); } diff --git a/acrobat/img/icons/aichat.svg b/acrobat/img/icons/aichat.svg index a6e8260d..7d027e09 100644 --- a/acrobat/img/icons/aichat.svg +++ b/acrobat/img/icons/aichat.svg @@ -1,7 +1,21 @@ - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + 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 index 4f448e53..6d5ea8c0 100644 --- a/test/blocks/prompt-card/mocks/body-block.html +++ b/test/blocks/prompt-card/mocks/body-block.html @@ -1,9 +1,5 @@
-
-
Icon
-
aichat.svg
-
Prefix
Ask
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 index 23f884ef..af38e0ef 100644 --- a/test/blocks/prompt-card/mocks/body-group.html +++ b/test/blocks/prompt-card/mocks/body-group.html @@ -1,22 +1,10 @@
-
-
Icon
-
aichat.svg
-
Prefix
Ask
-
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard!
-
+
diff --git a/test/blocks/prompt-card/mocks/body-section.html b/test/blocks/prompt-card/mocks/body-section.html index 3832d44d..71c1c088 100644 --- a/test/blocks/prompt-card/mocks/body-section.html +++ b/test/blocks/prompt-card/mocks/body-section.html @@ -1,18 +1,6 @@
-
-
Icon
-
aichat.svg
-
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard
-
Prefix
Ask
@@ -27,17 +15,13 @@
-
-
Icon
-
aichat.svg
-
Button
-
Copy
+
My Copy
Toast
-
Copied to Clipboard
+
My Copied to Clipboard
Prefix
@@ -53,18 +37,6 @@
-
-
Icon
-
aichat.svg
-
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard
-
Prefix
Brainstorm
@@ -79,18 +51,6 @@
-
-
Icon
-
aichat.svg
-
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard
-
Prefix
Analyze
@@ -105,18 +65,6 @@
-
-
Icon
-
aichat.svg
-
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard
-
Prefix
Modify
diff --git a/test/blocks/prompt-card/mocks/body-template-group.html b/test/blocks/prompt-card/mocks/body-template-group.html index 79bb91ab..67d6c0e3 100644 --- a/test/blocks/prompt-card/mocks/body-template-group.html +++ b/test/blocks/prompt-card/mocks/body-template-group.html @@ -1,22 +1,10 @@
-
-
Icon
-
aichat.svg
-
Prefix
Ask
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard!
-
diff --git a/test/blocks/prompt-card/mocks/body-template.html b/test/blocks/prompt-card/mocks/body-template.html index e346b3ab..8fd42370 100644 --- a/test/blocks/prompt-card/mocks/body-template.html +++ b/test/blocks/prompt-card/mocks/body-template.html @@ -1,22 +1,10 @@
-
-
Icon
-
aichat.svg
-
Prefix
Ask
-
-
Button
-
Copy
-
-
-
Toast
-
Copied to Clipboard!
-
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/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-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.test.js b/test/blocks/prompt-card/prompt-card.test.js index 0f10b97e..9bb94d13 100644 --- a/test/blocks/prompt-card/prompt-card.test.js +++ b/test/blocks/prompt-card/prompt-card.test.js @@ -36,7 +36,10 @@ describe('prompt-card block', () => { }); it('copies the prompt when copy button is clicked', async () => { - expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + 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; @@ -47,7 +50,10 @@ describe('prompt-card block', () => { it('copies the prompt when key press ENTER/SPACE on copy button', () => { const keys = ['Enter', ' ']; keys.forEach((key) => { - expect(document.querySelector('.prompt-toast').checkVisibility()).to.be.false; + 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; From c3c764e36a88f4868b9a0e183c149b354231c5cb Mon Sep 17 00:00:00 2001 From: James Tsay Date: Mon, 23 Sep 2024 09:42:53 -0700 Subject: [PATCH 4/6] Support prompt cards in json --- acrobat/blocks/prompt-card/prompt-card.js | 46 ++++++++++++++----- test/blocks/prompt-card/mocks/body-json.html | 29 ++++++++++++ .../blocks/prompt-card/mocks/promptcards.json | 14 ++++++ .../prompt-card/prompt-card-group.test.js | 2 +- .../prompt-card-json-error.test.js | 26 +++++++++++ .../prompt-card/prompt-card-json.test.js | 27 +++++++++++ .../prompt-card/prompt-card-section.test.js | 2 +- .../prompt-card-template-group.test.js | 2 +- .../prompt-card/prompt-card-template.test.js | 2 +- 9 files changed, 135 insertions(+), 15 deletions(-) create mode 100644 test/blocks/prompt-card/mocks/body-json.html create mode 100644 test/blocks/prompt-card/mocks/promptcards.json create mode 100644 test/blocks/prompt-card/prompt-card-json-error.test.js create mode 100644 test/blocks/prompt-card/prompt-card-json.test.js diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js index c9414fd3..c240c3d3 100644 --- a/acrobat/blocks/prompt-card/prompt-card.js +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -68,22 +68,41 @@ async function createBlock(element, cfg) { }); } -async function processGroup(element, startIndex, templateCfg) { - const 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); - }); +async function createBlocks(element, blockArray, templateCfg) { + const { parentNode } = element; for (const cfg of blockArray) { const blockEl = createTag('div', { class: 'prompt-card' }); await createBlock(blockEl, { ...templateCfg, ...cfg }); - element.parentNode.insertBefore(blockEl, element.previousSibling); + parentNode.insertBefore(blockEl, element.previousSibling); } element.remove(); } +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'].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]) { @@ -96,12 +115,12 @@ function readKeyValueSet(element) { export default async function init(element) { if (element.classList.contains('template') && element.classList.contains('group')) { const cfg = readKeyValueSet(element); - await processGroup(element, Object.keys(cfg).length + 1, cfg); + await processGroup(element, cfg, Object.keys(cfg).length + 1); return; } if (element.classList.contains('group')) { - await processGroup(element, 0, window.promptCardTemplate); + await processGroup(element, window.promptCardTemplate, 0); return; } @@ -113,6 +132,11 @@ export default async function init(element) { return; } + if (element.classList.contains('json')) { + await processGroup(element, cfg, -1); + return; + } + cfg = { ...window.promptCardTemplate, ...cfg }; await createBlock(element, cfg); 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/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.test.js b/test/blocks/prompt-card/prompt-card-group.test.js index 979b1239..06cd82f7 100644 --- a/test/blocks/prompt-card/prompt-card-group.test.js +++ b/test/blocks/prompt-card/prompt-card-group.test.js @@ -10,7 +10,7 @@ describe('prompt-cards in a section using the group feature', () => { await waitForElement('.prompt-blade'); }); - it('creates a prompt-card block', async () => { + 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-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.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 index ebb9137e..a94639f6 100644 --- a/test/blocks/prompt-card/prompt-card-section.test.js +++ b/test/blocks/prompt-card/prompt-card-section.test.js @@ -10,7 +10,7 @@ describe('prompt-cards in a section', () => { await waitForElement('.prompt-blade'); }); - it('creates a prompt-card block', async () => { + 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 index 86a324ca..5aad1268 100644 --- a/test/blocks/prompt-card/prompt-card-template-group.test.js +++ b/test/blocks/prompt-card/prompt-card-template-group.test.js @@ -10,7 +10,7 @@ describe('prompt-cards using the template and group features', () => { await waitForElement('.prompt-blade'); }); - it('creates a prompt-card block', async () => { + 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 index 3a46c87c..1f6bf437 100644 --- a/test/blocks/prompt-card/prompt-card-template.test.js +++ b/test/blocks/prompt-card/prompt-card-template.test.js @@ -10,7 +10,7 @@ describe('prompt-cards in a section using a template', () => { await waitForElement('.prompt-blade'); }); - it('creates a prompt-card block', async () => { + it('creates prompt cards', async () => { const blades = document.querySelectorAll('.prompt-blade'); expect([...blades].length).to.equal(5); }); From 74a5eae9273a37d1f060b09174193d75717fb67c Mon Sep 17 00:00:00 2001 From: James Tsay Date: Mon, 23 Sep 2024 15:08:29 -0700 Subject: [PATCH 5/6] Support view all --- acrobat/blocks/prompt-card/prompt-card.css | 10 +++++ acrobat/blocks/prompt-card/prompt-card.js | 34 ++++++++++++++++- .../mocks/body-json-more-less.html | 29 ++++++++++++++ .../prompt-card/mocks/body-json-more.html | 25 ++++++++++++ .../prompt-card-json-more-less.test.js | 30 +++++++++++++++ .../prompt-card/prompt-card-json-more.test.js | 38 +++++++++++++++++++ 6 files changed, 164 insertions(+), 2 deletions(-) create mode 100644 test/blocks/prompt-card/mocks/body-json-more-less.html create mode 100644 test/blocks/prompt-card/mocks/body-json-more.html create mode 100644 test/blocks/prompt-card/prompt-card-json-more-less.test.js create mode 100644 test/blocks/prompt-card/prompt-card-json-more.test.js diff --git a/acrobat/blocks/prompt-card/prompt-card.css b/acrobat/blocks/prompt-card/prompt-card.css index 9d3988c6..cf1ee914 100644 --- a/acrobat/blocks/prompt-card/prompt-card.css +++ b/acrobat/blocks/prompt-card/prompt-card.css @@ -2,6 +2,16 @@ display: none } +.prompt-card.hidden { + display: none; +} + +.view-all { + grid-column: 1 / -1; + display: flex; + justify-content: center; +} + .prompt-toast { font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; align-items: flex-start; diff --git a/acrobat/blocks/prompt-card/prompt-card.js b/acrobat/blocks/prompt-card/prompt-card.js index c240c3d3..a591e071 100644 --- a/acrobat/blocks/prompt-card/prompt-card.js +++ b/acrobat/blocks/prompt-card/prompt-card.js @@ -1,3 +1,4 @@ +/* eslint-disable compat/compat */ import { setLibs } from '../../scripts/utils.js'; const miloLibs = setLibs('/libs'); @@ -70,12 +71,41 @@ async function createBlock(element, cfg) { async function createBlocks(element, blockArray, templateCfg) { const { parentNode } = element; - for (const cfg of blockArray) { + 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) { @@ -95,7 +125,7 @@ async function processGroup(element, cfg, startIndex) { return; } const json = await resp.json(); - const keys = Object.keys(cfg).filter((k) => !['json'].includes(k)); + 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), ); 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/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; + }); +}); From edc06d6e988edf65119587ade008415cd58d85fb Mon Sep 17 00:00:00 2001 From: James Tsay Date: Wed, 25 Sep 2024 10:32:51 -0700 Subject: [PATCH 6/6] Update CSS --- acrobat/blocks/prompt-card/prompt-card.css | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/acrobat/blocks/prompt-card/prompt-card.css b/acrobat/blocks/prompt-card/prompt-card.css index cf1ee914..95406622 100644 --- a/acrobat/blocks/prompt-card/prompt-card.css +++ b/acrobat/blocks/prompt-card/prompt-card.css @@ -1,3 +1,7 @@ +:root { + --common-font: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; +} + #prompt { display: none } @@ -13,7 +17,7 @@ } .prompt-toast { - font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + font-family: var(--common-font); align-items: flex-start; background: #05834e; border-radius: 10px; @@ -49,14 +53,12 @@ background-size: contain; content: ""; height: 12px; - margin-left: 10px; + margin-inline-start: 10px; margin-top: 7px; - min-width: 12px; width: 12px } .prompt-blade { - align-items: center; align-items: flex-start; align-self: stretch; background-color: #fff; @@ -85,14 +87,15 @@ .prompt-icon { margin-inline-end: 5px; position: relative; - top: 5px } .prompt-prefix { color: #6d6d6d; font-size: 12px; padding: 0 0 16px; - text-transform: uppercase + text-transform: uppercase; + display: flex; + align-items: center; } .prompt-prefix, @@ -100,7 +103,7 @@ font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; font-style: normal; font-weight: 700; - line-height: 125% + line-height: 1.25 } .prompt-title { @@ -145,7 +148,7 @@ .prompt-copy-btn { color: #686868; cursor: pointer; - font-family: "Adobe Clean", adobe-clean, "Trebuchet MS", sans-serif; + font-family: var(--common-font); font-size: 14px; font-style: normal; font-weight: 400;