UNPKG

@humanos/assistant

Version:

HumanOS assistant for enterprises

266 lines (242 loc) 14 kB
var ChatWidget=function(){"use strict";var s=Object.defineProperty;var p=(i,e,a)=>e in i?s(i,e,{enumerable:!0,configurable:!0,writable:!0,value:a}):i[e]=a;var o=(i,e,a)=>p(i,typeof e!="symbol"?e+"":e,a);const e=class e{constructor(t={}){o(this,"container");o(this,"isOpen",!1);o(this,"messages",[]);o(this,"theme");o(this,"font");o(this,"STORAGE_KEY","chat_messages");o(this,"TIMEOUT_DURATION",6e4);o(this,"LOGO_URL_LIGHT","https://res.cloudinary.com/dsiqtt2lb/image/upload/w_1000,c_fill,ar_1:1,g_auto,r_max,bo_5px_solid_red,b_rgb:262c35/v1735304645/human_logo_dark_akvtvi.svg");o(this,"LOGO_URL_DARK","https://res.cloudinary.com/dsiqtt2lb/image/upload/w_1000,c_fill,ar_1:1,g_auto,r_max,bo_5px_solid_red,b_rgb:262c35/v1735303222/widget/dsr92v45uphhjudlui43.svg");o(this,"USER_ICON_URL","https://res.cloudinary.com/dsiqtt2lb/image/upload/widget/user_icon.png");o(this,"FONTS",{"System Default":'-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',Inter:"Inter, sans-serif",Roboto:"Roboto, sans-serif","Open Sans":'"Open Sans", sans-serif',Poppins:"Poppins, sans-serif"});e.instance&&e.instance.destroy(),this.theme=this.getTheme(t.theme||"dark"),this.font=this.FONTS[t.font||"Poppins"],this.createContainer(),this.setupGlobalInstance(),this.loadMessages(),this.render(),e.instance=this}getTheme(t){return{light:{widget:{background:"#ffffff",textColor:"#333333"},header:{background:"#f8f9fa",textColor:"#333333"},messages:{background:"#ffffff",textColor:"#333333"},input:{background:"#ffffff",textColor:"#333333",borderColor:"#e0e0e0",placeholderColor:"#999999"},sendButton:{background:"#f8f9fa",hoverBackground:"#e9ecef",iconColor:"#333333"}},dark:{widget:{background:"#2d2d2d",textColor:"#ffffff"},header:{background:"#1a1a1a",textColor:"#ffffff"},messages:{background:"#ffffff",textColor:"#333333"},input:{background:"#ffffff",textColor:"#333333",borderColor:"#e0e0e0",placeholderColor:"#999999"},sendButton:{background:"#1a1a1a",hoverBackground:"#2d2d2d",iconColor:"#ffffff"}},blue:{widget:{background:"#2196f3",textColor:"#ffffff"},header:{background:"#1e88e5",textColor:"#ffffff"},messages:{background:"#ffffff",textColor:"#333333"},input:{background:"#ffffff",textColor:"#333333",borderColor:"#e3f2fd",placeholderColor:"#90caf9"},sendButton:{background:"#1e88e5",hoverBackground:"#1976d2",iconColor:"#ffffff"}},green:{widget:{background:"#2e7d32",textColor:"#ffffff"},header:{background:"#1b5e20",textColor:"#ffffff"},messages:{background:"#ffffff",textColor:"#333333"},input:{background:"#ffffff",textColor:"#333333",borderColor:"#e0e0e0",placeholderColor:"#999999"},sendButton:{background:"#1b5e20",hoverBackground:"#2e7d32",iconColor:"#ffffff"}}}[t]}createContainer(){this.container=document.createElement("div"),this.container.className="chat-widget-container",document.body.appendChild(this.container),this.addStyles()}addStyles(){const t=document.getElementById("chat-widget-styles");t&&t.remove();const n=document.createElement("style");n.id="chat-widget-styles",n.textContent=` @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Open+Sans:wght@400;600&family=Poppins:wght@400;500;600&family=Roboto:wght@400;500&display=swap'); .chat-widget-container { font-family: ${this.font} !important; position: fixed !important; bottom: 20px !important; right: 20px !important; width: 150px !important; height: 54px !important; background: ${this.theme.widget.background} !important; border-radius: 25px !important; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important; transition: all 0.3s ease !important; z-index: 999999 !important; overflow: hidden !important; } .chat-widget-container.chat-widget-container--open { width: 300px !important; height: 400px !important; border-radius: 12px !important; background: ${this.theme.messages.background} !important; } .chat-header { padding: 8px !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: flex-start !important; gap: 8px !important; background: ${this.theme==="light"?"#e8e8e8":this.theme.header.background} !important; color: ${this.theme.header.textColor} !important; height: 54px !important; box-sizing: border-box !important; border-bottom: 2px solid ${this.theme==="light"?"#e0e0e0":"rgba(255,255,255,0.1)"} !important; } .chat-icon { width: 38px !important; height: 38px !important; display: flex !important; align-items: center !important; justify-content: center !important; flex-shrink: 0 !important; background: ${this.theme.header.background} !important; } .chat-icon img { width: 28px !important; height: 28px !important; object-fit: contain !important; display: block !important; filter: brightness(1) !important; } .chat-text { font-size: 15px !important; font-weight: 600 !important; color: ${this.theme.header.textColor} !important; white-space: nowrap !important; overflow: hidden !important; text-overflow: ellipsis !important; line-height: 1.2 !important; } .chat-content { height: calc(100% - 54px) !important; display: flex !important; flex-direction: column !important; background: ${this.theme.messages.background} !important; } .messages { flex-grow: 1 !important; padding: 16px !important; overflow-y: auto !important; display: flex !important; flex-direction: column !important; scrollbar-width: none !important; -ms-overflow-style: none !important; &::-webkit-scrollbar { display: none !important; } } .message { display: flex !important; align-items: flex-start !important; gap: 8px !important; margin-bottom: 12px !important; width: fit-content !important; max-width: 80% !important; } .message-avatar { width: 24px !important; height: 24px !important; flex-shrink: 0 !important; border-radius: 50% !important; overflow: hidden !important; display: flex !important; align-items: center !important; justify-content: center !important; background: transparent !important; } .message-avatar img { width: 22px !important; height: 22px !important; object-fit: cover !important; display: block !important; border-radius: 50% !important; } .message-content { padding: 8px 12px !important; border-radius: 12px !important; word-wrap: break-word !important; font-size: 14px !important; box-shadow: 0 1px 2px rgba(0,0,0,0.1) !important; max-width: 200px !important; } .message--user, .message--bot { justify-content: flex-start !important; } .message--user .message-content { background: ${this.theme.header.background} !important; color: ${this.theme.header.textColor} !important; border-bottom-right-radius: 4px !important; } .message--user .message-avatar { background-image: url('${this.USER_ICON_URL}') !important; background-color: transparent !important; background-size: contain !important; background-position: center !important; background-repeat: no-repeat !important; border: none !important; } .message--bot { justify-content: flex-start !important; } .message--bot .message-content { background: ${this.theme==="dark"?"#f8f9fa":"#f0f0f0"} !important; color: #333333 !important; border-bottom-left-radius: 4px !important; } .message--bot .message-avatar { background-image: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%23333333"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></svg>') !important; background-color: #f0f0f0 !important; } .chat-input { padding: 12px !important; border-top: 1px solid ${this.theme.input.borderColor} !important; display: flex !important; gap: 8px !important; background: ${this.theme.input.background} !important; border-radius: 0 0 12px 12px !important; align-items: center !important; } .chat-input textarea { flex-grow: 1 !important; padding: 8px 12px !important; border: 1px solid ${this.theme.input.borderColor} !important; border-radius: 8px !important; outline: none !important; font-size: 14px !important; line-height: 20px !important; color: ${this.theme.input.textColor} !important; background: ${this.theme==="dark"?"#f8f9fa":"#ffffff"} !important; resize: none !important; height: 20px !important; max-height: 120px !important; padding-top: 8px !important; padding-bottom: 8px !important; font-family: inherit !important; box-sizing: content-box !important; overflow-y: auto !important; scrollbar-width: none !important; -ms-overflow-style: none !important; box-shadow: ${this.theme==="light"?"0 2px 4px rgba(0,0,0,0.05)":"none"} !important; &::-webkit-scrollbar { display: none !important; } } .chat-input textarea:focus { border-color: ${this.theme.sendButton.background} !important; box-shadow: 0 0 0 2px ${this.theme.sendButton.background}33 !important; } .chat-input button { padding: 8px !important; background: ${this.theme.sendButton.background} !important; color: ${this.theme.sendButton.iconColor} !important; border: none !important; border-radius: 8px !important; cursor: pointer !important; display: flex !important; align-items: center !important; justify-content: center !important; width: 36px !important; height: 36px !important; flex-shrink: 0 !important; align-self: flex-end !important; } .chat-input button:hover { background: ${this.theme.sendButton.hoverBackground} !important; } `,document.head.appendChild(n)}scrollToBottom(){const t=this.container.querySelector(".messages");t&&(t.scrollTop=t.scrollHeight)}render(){const n=`<img src="${this.theme.header.background===this.getTheme("light").header.background?this.LOGO_URL_LIGHT:this.LOGO_URL_DARK}" alt="Chat Icon" width="28" height="28" style="object-fit: contain !important; display: block !important;" />`;this.container.innerHTML=` <div class="chat-header" onclick="window.chatWidget.toggleChat()"> <div class="chat-icon"> ${n} </div> <span class="chat-text"> ${this.isOpen?"Ask Assistant":"Questions"} </span> </div> ${this.isOpen?` <div class="chat-content"> <div class="messages"> ${this.messages.map(r=>` <div class="message message--${r.sender}"> <div class="message-avatar"> ${r.sender==="user"?`<img src="${this.USER_ICON_URL}" alt="User" style="width: 100%; height: 100%; border-radius: 50%;">`:""} </div> <div class="message-content"> ${r.text} </div> </div> `).join("")} </div> <div class="chat-input"> <textarea placeholder="Type your message..." oninput="this.style.height = ''; this.style.height = this.scrollHeight + 'px'" onkeypress="if(event.key === 'Enter' && !event.shiftKey) { event.preventDefault(); window.chatWidget.sendMessage(this.value); this.style.height = 'auto'; }" ></textarea> <button onclick="window.chatWidget.sendMessage(this.previousElementSibling.value)"> <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M22 2L11 13" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> <path d="M22 2L15 22L11 13L2 9L22 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </button> </div> </div> `:""} `,this.isOpen?this.container.classList.add("chat-widget-container--open"):this.container.classList.remove("chat-widget-container--open"),this.isOpen&&setTimeout(()=>this.scrollToBottom(),0)}loadMessages(){}saveMessages(){localStorage.setItem(this.STORAGE_KEY,JSON.stringify(this.messages))}sendMessage(t){if(!t.trim())return;const n={id:Date.now().toString(),text:t.trim(),sender:"user",timestamp:Date.now()};this.messages.push(n),this.saveMessages(),this.render();const r=this.container.querySelector("input");r&&(r.value=""),this.scrollToBottom()}toggleChat(){this.isOpen=!this.isOpen,this.render(),this.isOpen&&setTimeout(()=>this.scrollToBottom(),0)}static init(t){return new e(t)}setupGlobalInstance(){window.chatWidget=this}destroy(){this.container&&this.container.parentNode&&this.container.parentNode.removeChild(this.container);const t=document.getElementById("chat-widget-styles");t&&t.remove()}};o(e,"instance",null);let i=e;return window.ChatWidget=i,i}();