diff --git a/nx2/blocks/chat-ao/artifacts/index.js b/nx2/blocks/chat-ao/artifacts/index.js index 164ee7f4c..ac382c473 100644 --- a/nx2/blocks/chat-ao/artifacts/index.js +++ b/nx2/blocks/chat-ao/artifacts/index.js @@ -6,6 +6,7 @@ import './column.js'; import './card.js'; import './data-table.js'; import './metric-card.js'; +import './page-evaluation.js'; import './code-block.js'; import './alert.js'; diff --git a/nx2/blocks/chat-ao/artifacts/page-evaluation.css b/nx2/blocks/chat-ao/artifacts/page-evaluation.css new file mode 100644 index 000000000..674d4a48f --- /dev/null +++ b/nx2/blocks/chat-ao/artifacts/page-evaluation.css @@ -0,0 +1,466 @@ +:host { + display: block; + font-family: var(--s2-font-family); + color: var(--s2-gray-800); + font-size: var(--s2-body-size-s); + line-height: normal; +} + +.ui-artifact-pe { + display: flex; + flex-direction: column; + gap: var(--s2-spacing-200); +} + +.ui-artifact-pe-icon { + display: inline-block; + flex-shrink: 0; + width: 20px; + height: 20px; + background-color: currentcolor; + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; +} + +.ui-artifact-pe-icon.ui-artifact-pe-tone-negative { + mask-image: url("/img/icons/s2-icon-closecircle-20-n.svg"); +} + +.ui-artifact-pe-icon.ui-artifact-pe-tone-positive { + mask-image: url("/img/icons/s2-icon-checkmarkcircle-20-n.svg"); +} + +.ui-artifact-pe-icon.ui-artifact-pe-tone-neutral { + mask-image: url("/img/icons/s2-icon-removecircle-20-n.svg"); +} + +.ui-artifact-pe-icon.ui-artifact-pe-tone-informative { + mask-image: url("/img/icons/s2-icon-infocircle-20-n.svg"); +} + +/* --- tone text colors --- */ + +.ui-artifact-pe-tone-negative { color: var(--s2-orange-900); } +.ui-artifact-pe-tone-positive { color: var(--s2-green-900); } +.ui-artifact-pe-tone-neutral { color: var(--s2-gray-800); } + +/* --- tone chip backgrounds --- */ + +.ui-artifact-pe-tone-negative-bg { + background: var(--s2-orange-100); + color: var(--s2-orange-900); +} + +.ui-artifact-pe-tone-positive-bg { + background: var(--s2-green-100); + color: var(--s2-green-900); +} + +.ui-artifact-pe-tone-neutral-bg { + background: var(--s2-gray-100); + color: var(--s2-gray-800); +} + +/* --- summary tiles --- */ + +.ui-artifact-pe-summary { + display: flex; + overflow: hidden; +} + +.ui-artifact-pe-tile { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--s2-spacing-75); + padding: var(--s2-spacing-300); + + & + & { + border-left: 1px solid var(--s2-gray-200); + } +} + +.ui-artifact-pe-tile-label { + font-size: var(--s2-body-size-xs); + color: var(--s2-gray-800); +} + +.ui-artifact-pe-tile-value { + font-size: var(--s2-heading-size-s); + font-weight: var(--s2-heading-font-weight); + line-height: var(--s2-heading-line-height); +} + +.ui-artifact-pe-tile-desc { + font-size: var(--s2-body-size-xs); + color: var(--s2-gray-600); +} + +/* --- collapsible sections --- */ + +.ui-artifact-pe-section { + border: 1px solid var(--s2-gray-200); + border-radius: var(--s2-corner-radius-300); + overflow: hidden; + margin: 0; +} + +.ui-artifact-pe-section-header { + display: flex; + align-items: center; + gap: var(--s2-spacing-200); + padding: var(--s2-spacing-200) var(--s2-spacing-300); + cursor: pointer; + user-select: none; + list-style: none; + + &::marker, + &::-webkit-details-marker { + display: none; + } +} + +.ui-artifact-pe-section-chip { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + border-radius: var(--s2-corner-radius-300); + flex-shrink: 0; +} + +.ui-artifact-pe-section-labels { + flex: 1; + display: flex; + flex-direction: column; + gap: var(--s2-spacing-50); + min-width: 0; +} + +.ui-artifact-pe-section-label { + font-size: var(--s2-body-size-s); + font-weight: bold; + color: var(--s2-gray-900); +} + +.ui-artifact-pe-section-sublabel { + font-size: var(--s2-body-size-xs); + color: var(--s2-gray-600); +} + +.ui-artifact-pe-chevron { + width: 16px; + height: 16px; + flex-shrink: 0; + background-color: var(--s2-gray-600); + mask-image: url("/img/icons/s2-icon-chevronup-20-n.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; + transform: rotate(180deg); + transition: transform 0.15s ease; +} + +.ui-artifact-pe-section[open] > .ui-artifact-pe-section-header > .ui-artifact-pe-chevron { + transform: rotate(0deg); +} + +/* --- item rows --- */ + +.ui-artifact-pe-item-chip { + display: flex; + align-items: center; + justify-content: center; + width: 40px; + height: 40px; + flex-shrink: 0; +} + +.ui-artifact-pe-item { + display: flex; + align-items: flex-start; + gap: var(--s2-spacing-200); + padding: var(--s2-spacing-200) var(--s2-spacing-300); + + &[hidden] { + display: none; + } +} + +.ui-artifact-pe-item-body { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + gap: var(--s2-spacing-50); +} + +.ui-artifact-pe-item-title { + font-size: var(--s2-body-size-s); + font-weight: bold; + color: var(--s2-gray-900); +} + +.ui-artifact-pe-item-desc { + font-size: var(--s2-body-size-xs); + color: var(--s2-gray-600); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.ui-artifact-pe-item-action { + flex-shrink: 0; + align-self: center; + font-size: var(--s2-body-size-xs); + font-weight: 500; + color: var(--s2-gray-900); + background: none; + border: 1px solid var(--s2-gray-300); + border-radius: var(--s2-corner-radius-200); + padding: var(--s2-spacing-50) var(--s2-spacing-100); + cursor: pointer; + white-space: nowrap; + + &:hover { + background: var(--s2-gray-100); + } +} + +/* --- pagination --- */ + +.ui-artifact-pe-paging { + display: flex; + align-items: center; + justify-content: center; + gap: var(--s2-spacing-100); + padding: var(--s2-spacing-100) var(--s2-spacing-300) var(--s2-spacing-200); +} + +.ui-artifact-pe-paging-label { + font-size: var(--s2-body-size-xs); + font-weight: bold; + color: var(--s2-gray-800); +} + +.ui-artifact-pe-paging-btn { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border: none; + border-radius: var(--s2-corner-radius-200); + background: none; + cursor: pointer; + color: var(--s2-gray-600); + padding: 0; + + &:disabled { + opacity: 0.4; + cursor: default; + } + + &:hover:not(:disabled) { + background: var(--s2-gray-100); + } + + &::after { + content: ""; + display: block; + width: 14px; + height: 14px; + background-color: currentcolor; + mask-image: url("/img/icons/s2-icon-chevronup-20-n.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; + } +} + +.ui-artifact-pe-paging-prev::after { + transform: rotate(-90deg); +} + +.ui-artifact-pe-paging-next::after { + transform: rotate(90deg); +} + +/* --- modal --- */ + +/* The modal spec carries several off-token-scale values (13px, 20px, 28px, 6px + gap, 10px, 12px radius, 1.6 line-height); those stay raw to match the design. */ + +.ui-artifact-pe-modal-content { + font-family: var(--s2-font-family, 'Adobe Clean', adobe-clean, sans-serif); +} + +.ui-artifact-pe-modal-asset-label { + font-size: var(--s2-body-size-l); + font-weight: bold; + color: var(--s2-gray-900); + margin: 0 0 var(--s2-spacing-300); +} + +.ui-artifact-pe-modal-section { + margin-bottom: 20px; +} + +.ui-artifact-pe-modal-heading { + display: flex; + align-items: center; + gap: var(--s2-spacing-100); + margin-bottom: var(--s2-spacing-100); +} + +.ui-artifact-pe-modal-heading-icon { + width: 20px; + height: 20px; + flex-shrink: 0; + background-color: currentcolor; + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; +} + +.ui-artifact-pe-modal-heading-icon.issue { + color: var(--s2-orange-900); + mask-image: url("/img/icons/s2-icon-closecircle-20-n.svg"); +} + +.ui-artifact-pe-modal-heading-icon.fix { + color: var(--s2-green-900); + mask-image: url("/img/icons/s2-icon-checkmarkcircle-20-n.svg"); +} + +.ui-artifact-pe-modal-heading-text { + font-weight: bold; + font-size: var(--s2-body-size-s); + color: var(--s2-gray-900); +} + +.ui-artifact-pe-modal-body { + font-size: var(--s2-body-size-s); + line-height: 1.6; + color: var(--s2-gray-800); + margin: 0; +} + +.ui-artifact-pe-modal-copy { + display: inline-flex; + align-items: center; + gap: 6px; + font-size: 13px; + color: var(--s2-gray-800); + background: none; + border: none; + cursor: pointer; + padding: var(--s2-spacing-75) 0; + margin-top: var(--s2-spacing-75); + + &:hover { + color: var(--s2-gray-900); + } +} + +.ui-artifact-pe-modal-copy-icon { + width: 16px; + height: 16px; + flex-shrink: 0; + background-color: currentcolor; + mask-image: url("/img/icons/s2-icon-copy-20-n.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; +} + +.ui-artifact-pe-modal-context-title { + font-size: var(--s2-body-size-m); + font-weight: bold; + color: var(--s2-gray-900); + margin: var(--s2-spacing-400) 0 var(--s2-spacing-200); +} + +.ui-artifact-pe-modal-context-card { + border: 1px solid var(--s2-gray-200); + border-radius: 12px; + padding: var(--s2-spacing-300); +} + +.ui-artifact-pe-modal-chip { + display: inline-block; + background: var(--s2-gray-100); + border-radius: var(--s2-corner-radius-100); + padding: var(--s2-spacing-50) 10px; + font-size: var(--s2-body-size-xs); + color: var(--s2-gray-800); + margin-bottom: var(--s2-spacing-200); +} + +.ui-artifact-pe-modal-context-desc { + font-size: var(--s2-body-size-s); + line-height: 1.6; + color: var(--s2-gray-800); + margin: 0; +} + +.ui-artifact-pe-modal-paging { + display: flex; + justify-content: center; + align-items: center; + gap: var(--s2-spacing-200); + margin-top: 20px; + padding-top: var(--s2-spacing-300); + border-top: 1px solid var(--s2-gray-200); +} + +.ui-artifact-pe-modal-paging-btn { + display: flex; + align-items: center; + justify-content: center; + width: 28px; + height: 28px; + border: none; + border-radius: var(--s2-corner-radius-300); + background: none; + cursor: pointer; + color: var(--s2-gray-600); + padding: 0; + + &:disabled { + opacity: 0.3; + cursor: default; + } + + &:hover:not(:disabled) { + background: var(--s2-gray-100); + } + + &::after { + content: ""; + display: block; + width: 16px; + height: 16px; + background-color: currentcolor; + mask-image: url("/img/icons/s2-icon-chevronup-20-n.svg"); + mask-size: contain; + mask-repeat: no-repeat; + mask-position: center; + } +} + +.ui-artifact-pe-modal-paging-prev::after { + transform: rotate(-90deg); +} + +.ui-artifact-pe-modal-paging-next::after { + transform: rotate(90deg); +} + +.ui-artifact-pe-modal-paging-label { + font-size: 13px; + font-weight: bold; + color: var(--s2-gray-800); +} diff --git a/nx2/blocks/chat-ao/artifacts/page-evaluation.js b/nx2/blocks/chat-ao/artifacts/page-evaluation.js new file mode 100644 index 000000000..8650573aa --- /dev/null +++ b/nx2/blocks/chat-ao/artifacts/page-evaluation.js @@ -0,0 +1,305 @@ +/* + * Copyright 2026 Adobe. All rights reserved. + * This file is licensed to you under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. You may obtain a copy + * of the License at http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under + * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS + * OF ANY KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ + +import { LitElement, html, nothing } from 'da-lit'; +import { loadStyle } from '../../../utils/utils.js'; +import { registerArtifact } from './registry.js'; + +const styles = await loadStyle(import.meta.url); + +const PAGE_SIZE = 5; + +const TONE_MAP = { + negative: { cls: 'negative' }, + positive: { cls: 'positive' }, + neutral: { cls: 'neutral' }, +}; +const TONE_FALLBACK = { cls: 'informative' }; + +const toneOf = (tone) => TONE_MAP[tone] ?? TONE_FALLBACK; + +const toneIcon = (tone) => { + const { cls } = toneOf(tone); + return html``; +}; + +/* ---- summary ---- */ + +function renderTile({ label = '', value = '', description = '', tone }) { + const { cls } = toneOf(tone); + return html` +
${context.description}
` : nothing} +${suggestion.issue}
` : nothing} +${suggestion.suggested}
` : nothing} + +${item.description}
+