projects/conversational-commerce-agent/conversational-agent-examples/assets/apparel-ui/static/local.html (332 lines of code) (raw):

<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="df-messenger-bernard.css"> <link rel="stylesheet" href="bernard-styles.css"> <script src="https://www.gstatic.com/dialogflow-console/fast/df-messenger/prod/v1/df-messenger.js"></script> <script src="helper.js"></script> <script> // Element for retail example. Contact: bpataki@google.com class RetailTemplate extends HTMLElement { constructor() { super(); this.dfPayload = null; this.dfResponseId = null; this.renderRoot = this.attachShadow({ mode: 'open' }); } /** Web component Lifecycle method. */ connectedCallback() { this.renderRoot.appendChild(this._renderStyles()); this.renderRoot.appendChild(this._renderContent()); } /** * Render styles. * @return {HTMLElement!} */ _renderStyles() { const styles = document.createElement('style'); styles.textContent = ` .wrapper { color: var(--df-messenger-default-text-color); } .title-link { text-decoration: none; color: var(--df-messenger-default-text-color); } .item-list { display: flex; width: 100%; gap: 15px; /* No flex wrap. */ overflow-x: auto; } .item { width: 50%; // background: #E8F0FE; border-radius: 15px; padding: 16px; } .item-title { margin-top: 0; } .item-price { font-size: 1.5em; margin-top: 20px; } .item-image-wrapper { position: relative; } .item-image { border-radius: 8px; width: 100%; box-shadow: 5px 0 20px 0 rgba(0, 0, 0, 0.1) } .item-description, .item-details { padding: 8px 0; } .item-table { font-size: var(--df-messenger-default-font-size); } .item-table td { padding: 2px 8px; } .title { display: none; } `; return styles; } /** * Render content. * @return {HTMLElement!} */ _renderContent() { const content = document.createElement('div'); content.classList.add('wrapper'); const itemList = document.createElement('div'); itemList.classList.add('item-list'); for (const item of this.dfPayload.items) { itemList.appendChild(this._renderItem(item)); } content.appendChild(itemList); return content; } /** * Render content. * @param {Object!} itemPayload * @return {HTMLElement!} */ _renderItem(itemPayload) { let item = document.createElement('div'); item.classList.add('item'); console.log(itemPayload); const itemData = itemPayload.product; // console.log(itemData); let title = document.createElement('h2'); title.classList.add('item-title'); title.textContent = itemData.title; let imageWrapper = document.createElement('div'); imageWrapper.classList.add('item-image-wrapper'); let image = document.createElement('img'); image.classList.add('item-image'); image.src = itemData.images[0].uri; imageWrapper.appendChild(image); let price = document.createElement('div'); price.classList.add('item-price'); if (itemData.priceInfo) { price.textContent = `${itemData.priceInfo.price} ${itemData.priceInfo.currencyCode || "$"}`; } let description; if (itemData.description) { description = document.createElement('div'); description.classList.add('item-description'); description.textContent = itemData.description; } let details; if (itemData.categories) { details = document.createElement('div'); details.classList.add('item-details'); details.textContent = itemData.categories; } item.appendChild(title); item.appendChild(imageWrapper); if (itemData.description) { // item.appendChild(description); // uncomment to show the description } if (itemData.categories) { item.appendChild(details); } if (itemData.priceInfo) { item.appendChild(price); } // item.appendChild(infoLink); return item; } } // Custom Template for rendering Customer Reviews. class ReviewTemplate extends HTMLElement { constructor() { super(); this.dfPayload = null; this.dfResponseId = null; this.renderRoot = this.attachShadow({ mode: 'open' }); } /** Web component Lifecycle method. */ connectedCallback() { this.renderRoot.appendChild(this._renderStyles()); this.renderRoot.appendChild(this._renderContent()); } /** * Render styles. * @return {HTMLElement!} */ _renderStyles() { const styles = document.createElement('style'); styles.textContent = ` .wrapper { color: var(--df-messenger-default-text-color); } .title-link { text-decoration: none; color: var(--df-messenger-default-text-color); } .item-list { display: flex; width: 100%; gap: 15px; /* No flex wrap. */ overflow-x: auto; } .item { width: 50%; background: #E8F0FE; border-radius: 15px; padding: 16px; } .review { background: #fff; border-radius: 15px; box-shadow: 0 4px 8px rgba(0,0,0,0.1); padding: 20px; // width: 30%; /* Adjust as necessary for your layout */ // margin: 10px; box-sizing: border-box; } .review-header { display: flex; align-items: center; margin-bottom: 15px; } .user-avatar { background-color: #0077CC; color: #fff; font-weight: bold; width: 50px; height: 50px; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-right: 10px; } .user-info { flex-grow: 1; } .user-name { font-size: 1.1em; color: #333; } .user-rating { display: flex; align-items: center; } .stars { color: #FFD700; font-size: 1em; } .rating-score { font-size: 0.8em; color: #777; margin-left: 5px; } .review-text { font-size: 0.9em; color: #555; } .review-title { font-size: 0.9em; font-weight: bold; color: #555; } .review-text a { color: #0077CC; text-decoration: none; } `; return styles; } /** * Render content. * @return {HTMLElement!} */ _renderContent() { const content = document.createElement('div'); content.classList.add('wrapper'); const itemList = document.createElement('div'); itemList.classList.add('item-list'); const numReviews = this.dfPayload.items.length for (const item of this.dfPayload.items) { itemList.appendChild(this._renderItem(item, numReviews)); } content.appendChild(itemList); return content; } /** * Render content. * @param {Object!} itemPayload * @param {Number!} numReviews * @return {HTMLElement!} */ _renderItem(itemPayload, numReviews) { const item = document.createElement('div'); console.log(itemPayload); // Clone our template node, replace the values, and re-insert into DOM. let revTemplate = document.getElementById('review-template').cloneNode(true); revTemplate.id = ''; revTemplate.style.display = 'block'; item.appendChild(revTemplate); let userAvatar = revTemplate.getElementsByClassName('user-avatar')[0]; userAvatar.textContent = itemPayload.user[0]; let userName = revTemplate.getElementsByClassName('user-name')[0]; userName.textContent = itemPayload.user; let userRating = revTemplate.getElementsByClassName('rating-score')[0]; userRating.textContent = '(' + itemPayload.rating + '/5)'; let userDesc = revTemplate.getElementsByClassName('review-text')[0]; userDesc.textContent = itemPayload.desc; let prodTitle = revTemplate.getElementsByClassName('review-title')[0]; prodTitle.textContent = 'Item: ' + itemPayload.title; let stars = revTemplate.getElementsByClassName('stars')[0]; let numFilled = itemPayload.rating; let numEmpty = 5 - numFilled; for (let i = 0; i < itemPayload.rating; i++) { stars.textContent += '★'; } for (let i = 0; i < numEmpty; i++) { stars.textContent += '☆'; } return item; } } // Enable custom elements. (function () { customElements.define('retail-template', RetailTemplate); customElements.define('review-template', ReviewTemplate); })(); </script> </head> <body> <div class="page"> <df-messenger agent-id="72555c64-01a0-4e26-a27c-d01ec9e368f1" project-id="kalschi-conv-commerce-5" location="us-central1" language-code="en" intent="WelcomeEvent" url-allowlist="https://gstatic.com/" storage-option="none"> <df-messenger-chat chat-title-icon="assets/title-Apparel.png" user-actor-image="assets/user.png" bot-actor-image="assets/actor.png"></df-messenger-chat> </df-messenger> </div> <!-- DOM element to clone for creating reviews. --> <div id="review-template" class="review-container" style="display:none"> <div class="review"> <div class="review-header"> <div class="user-avatar"></div> <div class="user-info"> <div class="user-name"></div> <div class="user-rating"> <span class="stars"></span> <span class="rating-score"></span> </div> </div> </div> <p class="review-text"></p> <p class="review-title"></p> </div> </body> </html>