mini-chat-bot-widget 0.2.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-widget.esm.js +65 -20
- package/dist/chat-widget.esm.min.js +1 -1
- package/dist/chat-widget.umd.js +65 -20
- package/dist/chat-widget.umd.min.js +1 -1
- package/package.json +1 -1
- package/src/chat-widget.js +426 -87
package/dist/chat-widget.esm.js
CHANGED
|
@@ -34,15 +34,17 @@ function getDefaultExportFromCjs (x) {
|
|
|
34
34
|
var chatWidget = {exports: {}};
|
|
35
35
|
|
|
36
36
|
(function (module) {
|
|
37
|
-
// chat-widget.js - vanilla JS chat bot widget
|
|
37
|
+
// chat-widget.js - Modern vanilla JS chat bot widget
|
|
38
38
|
var ChatWidget = /*#__PURE__*/function () {
|
|
39
39
|
function ChatWidget() {
|
|
40
40
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
41
41
|
_classCallCheck(this, ChatWidget);
|
|
42
|
-
this.title = options.title || "Chat
|
|
43
|
-
this.placeholder = options.placeholder || "Type
|
|
42
|
+
this.title = options.title || "Chat Assistant";
|
|
43
|
+
this.placeholder = options.placeholder || "Type your message...";
|
|
44
|
+
this.primaryColor = options.primaryColor || "#6366f1";
|
|
44
45
|
this.container = null;
|
|
45
46
|
this.messages = [];
|
|
47
|
+
this.isMinimized = false;
|
|
46
48
|
this._init();
|
|
47
49
|
}
|
|
48
50
|
return _createClass(ChatWidget, [{
|
|
@@ -51,7 +53,7 @@ var chatWidget = {exports: {}};
|
|
|
51
53
|
// Create container
|
|
52
54
|
this.container = document.createElement("div");
|
|
53
55
|
this.container.id = "chat-widget-container";
|
|
54
|
-
this.container.innerHTML = "\n <div class=\"chat-header\">".concat(this.title, "</div>\n
|
|
56
|
+
this.container.innerHTML = "\n <div class=\"chat-widget-minimized\" id=\"chat-toggle\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </div>\n <div class=\"chat-widget-expanded\" id=\"chat-expanded\">\n <div class=\"chat-header\">\n <div class=\"chat-header-content\">\n <div class=\"chat-avatar\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n </svg>\n </div>\n <div class=\"chat-header-text\">\n <div class=\"chat-title\">".concat(this.title, "</div>\n <div class=\"chat-status\">\u25CF Online</div>\n </div>\n </div>\n <button class=\"chat-close\" id=\"chat-close\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n <div class=\"chat-messages\" id=\"chat-messages\">\n <div class=\"chat-welcome\">\n <div class=\"welcome-icon\">\uD83D\uDC4B</div>\n <div class=\"welcome-text\">Hello! How can I help you today?</div>\n </div>\n </div>\n <div class=\"chat-input-wrapper\">\n <input type=\"text\" id=\"chat-input\" placeholder=\"").concat(this.placeholder, "\" autocomplete=\"off\" />\n <button id=\"chat-send\" disabled>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n ");
|
|
55
57
|
document.body.appendChild(this.container);
|
|
56
58
|
this._applyStyles();
|
|
57
59
|
this._bindEvents();
|
|
@@ -60,40 +62,83 @@ var chatWidget = {exports: {}};
|
|
|
60
62
|
key: "_applyStyles",
|
|
61
63
|
value: function _applyStyles() {
|
|
62
64
|
var style = document.createElement("style");
|
|
63
|
-
style.textContent = "\n #chat-widget-container {\n position: fixed;\n bottom:
|
|
65
|
+
style.textContent = "\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');\n \n #chat-widget-container {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10000;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n .chat-widget-minimized {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: linear-gradient(135deg, ".concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n animation: pulse 2s infinite;\n }\n\n .chat-widget-minimized:hover {\n transform: scale(1.1);\n box-shadow: 0 12px 32px rgba(99, 102, 241, 0.5);\n }\n\n @keyframes pulse {\n 0%, 100% { box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4); }\n 50% { box-shadow: 0 8px 32px rgba(99, 102, 241, 0.6); }\n }\n\n .chat-widget-expanded {\n width: 380px;\n height: 600px;\n background: white;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);\n display: none;\n flex-direction: column;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .chat-widget-expanded.visible {\n display: flex;\n }\n\n .chat-header {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n padding: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .chat-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .chat-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(10px);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .chat-title {\n font-weight: 600;\n font-size: 16px;\n }\n\n .chat-status {\n font-size: 12px;\n opacity: 0.9;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .chat-close {\n background: transparent;\n border: none;\n color: white;\n cursor: pointer;\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n .chat-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n\n .chat-messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background: #f9fafb;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .chat-messages::-webkit-scrollbar {\n width: 6px;\n }\n\n .chat-messages::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chat-messages::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n }\n\n .chat-welcome {\n text-align: center;\n padding: 40px 20px;\n color: #64748b;\n }\n\n .welcome-icon {\n font-size: 48px;\n margin-bottom: 12px;\n }\n\n .welcome-text {\n font-size: 15px;\n font-weight: 500;\n color: #475569;\n }\n\n .chat-message {\n display: flex;\n gap: 8px;\n animation: messageSlide 0.3s ease-out;\n }\n\n @keyframes messageSlide {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .chat-message.user {\n flex-direction: row-reverse;\n }\n\n .message-bubble {\n max-width: 75%;\n padding: 12px 16px;\n border-radius: 16px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .chat-message.user .message-bubble {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .chat-message.bot .message-bubble {\n background: white;\n color: #1e293b;\n border-bottom-left-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-indicator {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n background: white;\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n max-width: 60px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #94a3b8;\n animation: typing 1.4s infinite;\n }\n\n .typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n }\n\n .typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n }\n\n @keyframes typing {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.7;\n }\n 30% {\n transform: translateY(-10px);\n opacity: 1;\n }\n }\n\n .chat-input-wrapper {\n display: flex;\n padding: 16px;\n gap: 8px;\n background: white;\n border-top: 1px solid #e2e8f0;\n }\n\n #chat-input {\n flex: 1;\n border: 2px solid #e2e8f0;\n border-radius: 12px;\n padding: 12px 16px;\n font-size: 14px;\n outline: none;\n transition: all 0.2s;\n font-family: inherit;\n }\n\n #chat-input:focus {\n border-color: ").concat(this.primaryColor, ";\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n\n #chat-send {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n border: none;\n border-radius: 12px;\n padding: 12px 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n #chat-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n #chat-send:not(:disabled):hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n }\n\n #chat-send:not(:disabled):active {\n transform: scale(0.95);\n }\n ");
|
|
64
66
|
document.head.appendChild(style);
|
|
65
67
|
}
|
|
66
68
|
}, {
|
|
67
69
|
key: "_bindEvents",
|
|
68
70
|
value: function _bindEvents() {
|
|
69
71
|
var _this = this;
|
|
72
|
+
var toggle = this.container.querySelector("#chat-toggle");
|
|
73
|
+
var closeBtn = this.container.querySelector("#chat-close");
|
|
74
|
+
var expanded = this.container.querySelector("#chat-expanded");
|
|
70
75
|
var input = this.container.querySelector("#chat-input");
|
|
71
76
|
var sendBtn = this.container.querySelector("#chat-send");
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
77
|
+
toggle.addEventListener("click", function () {
|
|
78
|
+
toggle.style.display = "none";
|
|
79
|
+
expanded.classList.add("visible");
|
|
80
|
+
input.focus();
|
|
81
|
+
});
|
|
82
|
+
closeBtn.addEventListener("click", function () {
|
|
83
|
+
expanded.classList.remove("visible");
|
|
84
|
+
toggle.style.display = "flex";
|
|
85
|
+
});
|
|
86
|
+
input.addEventListener("input", function () {
|
|
87
|
+
sendBtn.disabled = !input.value.trim();
|
|
88
|
+
});
|
|
82
89
|
var send = function send() {
|
|
83
90
|
var text = input.value.trim();
|
|
84
91
|
if (!text) return;
|
|
85
|
-
|
|
92
|
+
_this._addMessage(text, true);
|
|
86
93
|
input.value = "";
|
|
87
|
-
|
|
94
|
+
sendBtn.disabled = true;
|
|
95
|
+
_this._showTypingIndicator();
|
|
88
96
|
setTimeout(function () {
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
_this._hideTypingIndicator();
|
|
98
|
+
_this._addMessage("Thanks for your message! You said: \"".concat(text, "\""), false);
|
|
99
|
+
}, 1000 + Math.random() * 1000);
|
|
91
100
|
};
|
|
92
101
|
sendBtn.addEventListener("click", send);
|
|
93
102
|
input.addEventListener("keypress", function (e) {
|
|
94
|
-
if (e.key === "Enter") send();
|
|
103
|
+
if (e.key === "Enter" && !sendBtn.disabled) send();
|
|
95
104
|
});
|
|
96
105
|
}
|
|
106
|
+
}, {
|
|
107
|
+
key: "_addMessage",
|
|
108
|
+
value: function _addMessage(text, isUser) {
|
|
109
|
+
var messagesContainer = this.container.querySelector("#chat-messages");
|
|
110
|
+
var welcome = messagesContainer.querySelector(".chat-welcome");
|
|
111
|
+
if (welcome) welcome.remove();
|
|
112
|
+
var messageEl = document.createElement("div");
|
|
113
|
+
messageEl.className = "chat-message ".concat(isUser ? "user" : "bot");
|
|
114
|
+
messageEl.innerHTML = "<div class=\"message-bubble\">".concat(this._escapeHtml(text), "</div>");
|
|
115
|
+
messagesContainer.appendChild(messageEl);
|
|
116
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
117
|
+
}
|
|
118
|
+
}, {
|
|
119
|
+
key: "_showTypingIndicator",
|
|
120
|
+
value: function _showTypingIndicator() {
|
|
121
|
+
var messagesContainer = this.container.querySelector("#chat-messages");
|
|
122
|
+
var indicator = document.createElement("div");
|
|
123
|
+
indicator.className = "chat-message bot";
|
|
124
|
+
indicator.id = "typing-indicator";
|
|
125
|
+
indicator.innerHTML = "\n <div class=\"typing-indicator\">\n <div class=\"typing-dot\"></div>\n <div class=\"typing-dot\"></div>\n <div class=\"typing-dot\"></div>\n </div>\n ";
|
|
126
|
+
messagesContainer.appendChild(indicator);
|
|
127
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
128
|
+
}
|
|
129
|
+
}, {
|
|
130
|
+
key: "_hideTypingIndicator",
|
|
131
|
+
value: function _hideTypingIndicator() {
|
|
132
|
+
var indicator = this.container.querySelector("#typing-indicator");
|
|
133
|
+
if (indicator) indicator.remove();
|
|
134
|
+
}
|
|
135
|
+
}, {
|
|
136
|
+
key: "_escapeHtml",
|
|
137
|
+
value: function _escapeHtml(text) {
|
|
138
|
+
var div = document.createElement("div");
|
|
139
|
+
div.textContent = text;
|
|
140
|
+
return div.innerHTML;
|
|
141
|
+
}
|
|
97
142
|
}]);
|
|
98
143
|
}(); // Export as UMD and ESM compatible
|
|
99
144
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function n(n,t,i){return t&&function(n,t){for(var i=0;i<t.length;i++){var r=t[i];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(n,e(r.key),r)}}(n.prototype,t),Object.defineProperty(n,"prototype",{writable:!1}),n}function e(n){var e=function(n,e){if("object"!=typeof n||!n)return n;var t=n[Symbol.toPrimitive];if(void 0!==t){var i=t.call(n,e);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(n)}(n,"string");return"symbol"==typeof e?e:e+""}function t(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}var i,r,a={exports:{}};i=a,r=function(){return n(function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),this.title=e.title||"Chat Bot",this.placeholder=e.placeholder||"Type a message...",this.container=null,this.messages=[],this._init()},[{key:"_init",value:function(){this.container=document.createElement("div"),this.container.id="chat-widget-container",this.container.innerHTML='\n <div class="chat-header">'.concat(this.title,'</div>\n <div class="chat-messages" id="chat-messages"></div>\n <div class="chat-input-wrapper">\n <input type="text" id="chat-input" placeholder="').concat(this.placeholder,'" />\n <button id="chat-send">Send</button>\n </div>\n '),document.body.appendChild(this.container),this._applyStyles(),this._bindEvents()}},{key:"_applyStyles",value:function(){var n=document.createElement("style");n.textContent="\n #chat-widget-container {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 300px;\n max-height: 400px;\n background: rgba(255,255,255,0.95);\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n font-family: 'Inter', sans-serif;\n overflow: hidden;\n z-index: 10000;\n }\n #chat-widget-container .chat-header {\n background: linear-gradient(135deg, #6a5acd, #00bfff);\n color: white;\n padding: 8px 12px;\n font-weight: 600;\n text-align: center;\n }\n #chat-widget-container .chat-messages {\n flex: 1;\n padding: 8px 12px;\n overflow-y: auto;\n font-size: 0.9rem;\n color: #333;\n }\n #chat-widget-container .chat-input-wrapper {\n display: flex;\n border-top: 1px solid #ddd;\n }\n #chat-widget-container #chat-input {\n flex: 1;\n border: none;\n padding: 8px;\n font-size: 0.9rem;\n outline: none;\n }\n #chat-widget-container #chat-send {\n background: #6a5acd;\n color: white;\n border: none;\n padding: 0 12px;\n cursor: pointer;\n font-weight: 600;\n }\n #chat-widget-container #chat-send:hover {\n background: #5a4acb;\n }\n ",document.head.appendChild(n)}},{key:"_bindEvents",value:function(){var n=this,e=this.container.querySelector("#chat-input"),t=this.container.querySelector("#chat-send"),i=function(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=document.createElement("div");i.textContent=e,i.style.marginBottom="6px",i.style.textAlign=t?"right":"left",i.style.color=t?"#0066cc":"#333",n.container.querySelector("#chat-messages").appendChild(i),n.container.querySelector("#chat-messages").scrollTop=9999},r=function(){var n=e.value.trim();n&&(i(n,!0),e.value="",setTimeout(function(){return i("You said: "+n,!1)},500))};t.addEventListener("click",r),e.addEventListener("keypress",function(n){"Enter"===n.key&&r()})}}])}(),i.exports=r;var o=t(a.exports);export{o as default};
|
|
1
|
+
function n(n,t,i){return t&&function(n,t){for(var i=0;i<t.length;i++){var a=t[i];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(n,e(a.key),a)}}(n.prototype,t),Object.defineProperty(n,"prototype",{writable:!1}),n}function e(n){var e=function(n,e){if("object"!=typeof n||!n)return n;var t=n[Symbol.toPrimitive];if(void 0!==t){var i=t.call(n,e);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(n)}(n,"string");return"symbol"==typeof e?e:e+""}function t(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}var i,a,o={exports:{}};i=o,a=function(){return n(function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),this.title=e.title||"Chat Assistant",this.placeholder=e.placeholder||"Type your message...",this.primaryColor=e.primaryColor||"#6366f1",this.container=null,this.messages=[],this.isMinimized=!1,this._init()},[{key:"_init",value:function(){this.container=document.createElement("div"),this.container.id="chat-widget-container",this.container.innerHTML='\n <div class="chat-widget-minimized" id="chat-toggle">\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>\n </svg>\n </div>\n <div class="chat-widget-expanded" id="chat-expanded">\n <div class="chat-header">\n <div class="chat-header-content">\n <div class="chat-avatar">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path>\n <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>\n </svg>\n </div>\n <div class="chat-header-text">\n <div class="chat-title">'.concat(this.title,'</div>\n <div class="chat-status">● Online</div>\n </div>\n </div>\n <button class="chat-close" id="chat-close">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <line x1="18" y1="6" x2="6" y2="18"></line>\n <line x1="6" y1="6" x2="18" y2="18"></line>\n </svg>\n </button>\n </div>\n <div class="chat-messages" id="chat-messages">\n <div class="chat-welcome">\n <div class="welcome-icon">👋</div>\n <div class="welcome-text">Hello! How can I help you today?</div>\n </div>\n </div>\n <div class="chat-input-wrapper">\n <input type="text" id="chat-input" placeholder="').concat(this.placeholder,'" autocomplete="off" />\n <button id="chat-send" disabled>\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <line x1="22" y1="2" x2="11" y2="13"></line>\n <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>\n </svg>\n </button>\n </div>\n </div>\n '),document.body.appendChild(this.container),this._applyStyles(),this._bindEvents()}},{key:"_applyStyles",value:function(){var n=document.createElement("style");n.textContent="\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');\n \n #chat-widget-container {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10000;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n .chat-widget-minimized {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: linear-gradient(135deg, ".concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n animation: pulse 2s infinite;\n }\n\n .chat-widget-minimized:hover {\n transform: scale(1.1);\n box-shadow: 0 12px 32px rgba(99, 102, 241, 0.5);\n }\n\n @keyframes pulse {\n 0%, 100% { box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4); }\n 50% { box-shadow: 0 8px 32px rgba(99, 102, 241, 0.6); }\n }\n\n .chat-widget-expanded {\n width: 380px;\n height: 600px;\n background: white;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);\n display: none;\n flex-direction: column;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .chat-widget-expanded.visible {\n display: flex;\n }\n\n .chat-header {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n padding: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .chat-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .chat-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(10px);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .chat-title {\n font-weight: 600;\n font-size: 16px;\n }\n\n .chat-status {\n font-size: 12px;\n opacity: 0.9;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .chat-close {\n background: transparent;\n border: none;\n color: white;\n cursor: pointer;\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n .chat-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n\n .chat-messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background: #f9fafb;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .chat-messages::-webkit-scrollbar {\n width: 6px;\n }\n\n .chat-messages::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chat-messages::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n }\n\n .chat-welcome {\n text-align: center;\n padding: 40px 20px;\n color: #64748b;\n }\n\n .welcome-icon {\n font-size: 48px;\n margin-bottom: 12px;\n }\n\n .welcome-text {\n font-size: 15px;\n font-weight: 500;\n color: #475569;\n }\n\n .chat-message {\n display: flex;\n gap: 8px;\n animation: messageSlide 0.3s ease-out;\n }\n\n @keyframes messageSlide {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .chat-message.user {\n flex-direction: row-reverse;\n }\n\n .message-bubble {\n max-width: 75%;\n padding: 12px 16px;\n border-radius: 16px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .chat-message.user .message-bubble {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .chat-message.bot .message-bubble {\n background: white;\n color: #1e293b;\n border-bottom-left-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-indicator {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n background: white;\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n max-width: 60px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #94a3b8;\n animation: typing 1.4s infinite;\n }\n\n .typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n }\n\n .typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n }\n\n @keyframes typing {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.7;\n }\n 30% {\n transform: translateY(-10px);\n opacity: 1;\n }\n }\n\n .chat-input-wrapper {\n display: flex;\n padding: 16px;\n gap: 8px;\n background: white;\n border-top: 1px solid #e2e8f0;\n }\n\n #chat-input {\n flex: 1;\n border: 2px solid #e2e8f0;\n border-radius: 12px;\n padding: 12px 16px;\n font-size: 14px;\n outline: none;\n transition: all 0.2s;\n font-family: inherit;\n }\n\n #chat-input:focus {\n border-color: ").concat(this.primaryColor,";\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n\n #chat-send {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n border: none;\n border-radius: 12px;\n padding: 12px 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n #chat-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n #chat-send:not(:disabled):hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n }\n\n #chat-send:not(:disabled):active {\n transform: scale(0.95);\n }\n "),document.head.appendChild(n)}},{key:"_bindEvents",value:function(){var n=this,e=this.container.querySelector("#chat-toggle"),t=this.container.querySelector("#chat-close"),i=this.container.querySelector("#chat-expanded"),a=this.container.querySelector("#chat-input"),o=this.container.querySelector("#chat-send");e.addEventListener("click",function(){e.style.display="none",i.classList.add("visible"),a.focus()}),t.addEventListener("click",function(){i.classList.remove("visible"),e.style.display="flex"}),a.addEventListener("input",function(){o.disabled=!a.value.trim()});var r=function(){var e=a.value.trim();e&&(n._addMessage(e,!0),a.value="",o.disabled=!0,n._showTypingIndicator(),setTimeout(function(){n._hideTypingIndicator(),n._addMessage('Thanks for your message! You said: "'.concat(e,'"'),!1)},1e3+1e3*Math.random()))};o.addEventListener("click",r),a.addEventListener("keypress",function(n){"Enter"!==n.key||o.disabled||r()})}},{key:"_addMessage",value:function(n,e){var t=this.container.querySelector("#chat-messages"),i=t.querySelector(".chat-welcome");i&&i.remove();var a=document.createElement("div");a.className="chat-message ".concat(e?"user":"bot"),a.innerHTML='<div class="message-bubble">'.concat(this._escapeHtml(n),"</div>"),t.appendChild(a),t.scrollTop=t.scrollHeight}},{key:"_showTypingIndicator",value:function(){var n=this.container.querySelector("#chat-messages"),e=document.createElement("div");e.className="chat-message bot",e.id="typing-indicator",e.innerHTML='\n <div class="typing-indicator">\n <div class="typing-dot"></div>\n <div class="typing-dot"></div>\n <div class="typing-dot"></div>\n </div>\n ',n.appendChild(e),n.scrollTop=n.scrollHeight}},{key:"_hideTypingIndicator",value:function(){var n=this.container.querySelector("#typing-indicator");n&&n.remove()}},{key:"_escapeHtml",value:function(n){var e=document.createElement("div");return e.textContent=n,e.innerHTML}}])}(),i.exports=a;var r=t(o.exports);export{r as default};
|
package/dist/chat-widget.umd.js
CHANGED
|
@@ -40,15 +40,17 @@
|
|
|
40
40
|
var chatWidget = {exports: {}};
|
|
41
41
|
|
|
42
42
|
(function (module) {
|
|
43
|
-
// chat-widget.js - vanilla JS chat bot widget
|
|
43
|
+
// chat-widget.js - Modern vanilla JS chat bot widget
|
|
44
44
|
var ChatWidget = /*#__PURE__*/function () {
|
|
45
45
|
function ChatWidget() {
|
|
46
46
|
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
47
47
|
_classCallCheck(this, ChatWidget);
|
|
48
|
-
this.title = options.title || "Chat
|
|
49
|
-
this.placeholder = options.placeholder || "Type
|
|
48
|
+
this.title = options.title || "Chat Assistant";
|
|
49
|
+
this.placeholder = options.placeholder || "Type your message...";
|
|
50
|
+
this.primaryColor = options.primaryColor || "#6366f1";
|
|
50
51
|
this.container = null;
|
|
51
52
|
this.messages = [];
|
|
53
|
+
this.isMinimized = false;
|
|
52
54
|
this._init();
|
|
53
55
|
}
|
|
54
56
|
return _createClass(ChatWidget, [{
|
|
@@ -57,7 +59,7 @@
|
|
|
57
59
|
// Create container
|
|
58
60
|
this.container = document.createElement("div");
|
|
59
61
|
this.container.id = "chat-widget-container";
|
|
60
|
-
this.container.innerHTML = "\n <div class=\"chat-header\">".concat(this.title, "</div>\n
|
|
62
|
+
this.container.innerHTML = "\n <div class=\"chat-widget-minimized\" id=\"chat-toggle\">\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"></path>\n </svg>\n </div>\n <div class=\"chat-widget-expanded\" id=\"chat-expanded\">\n <div class=\"chat-header\">\n <div class=\"chat-header-content\">\n <div class=\"chat-avatar\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"></path>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"></path>\n </svg>\n </div>\n <div class=\"chat-header-text\">\n <div class=\"chat-title\">".concat(this.title, "</div>\n <div class=\"chat-status\">\u25CF Online</div>\n </div>\n </div>\n <button class=\"chat-close\" id=\"chat-close\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"></line>\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"></line>\n </svg>\n </button>\n </div>\n <div class=\"chat-messages\" id=\"chat-messages\">\n <div class=\"chat-welcome\">\n <div class=\"welcome-icon\">\uD83D\uDC4B</div>\n <div class=\"welcome-text\">Hello! How can I help you today?</div>\n </div>\n </div>\n <div class=\"chat-input-wrapper\">\n <input type=\"text\" id=\"chat-input\" placeholder=\"").concat(this.placeholder, "\" autocomplete=\"off\" />\n <button id=\"chat-send\" disabled>\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"></line>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"></polygon>\n </svg>\n </button>\n </div>\n </div>\n ");
|
|
61
63
|
document.body.appendChild(this.container);
|
|
62
64
|
this._applyStyles();
|
|
63
65
|
this._bindEvents();
|
|
@@ -66,40 +68,83 @@
|
|
|
66
68
|
key: "_applyStyles",
|
|
67
69
|
value: function _applyStyles() {
|
|
68
70
|
var style = document.createElement("style");
|
|
69
|
-
style.textContent = "\n #chat-widget-container {\n position: fixed;\n bottom:
|
|
71
|
+
style.textContent = "\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');\n \n #chat-widget-container {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10000;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n .chat-widget-minimized {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: linear-gradient(135deg, ".concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n animation: pulse 2s infinite;\n }\n\n .chat-widget-minimized:hover {\n transform: scale(1.1);\n box-shadow: 0 12px 32px rgba(99, 102, 241, 0.5);\n }\n\n @keyframes pulse {\n 0%, 100% { box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4); }\n 50% { box-shadow: 0 8px 32px rgba(99, 102, 241, 0.6); }\n }\n\n .chat-widget-expanded {\n width: 380px;\n height: 600px;\n background: white;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);\n display: none;\n flex-direction: column;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .chat-widget-expanded.visible {\n display: flex;\n }\n\n .chat-header {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n padding: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .chat-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .chat-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(10px);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .chat-title {\n font-weight: 600;\n font-size: 16px;\n }\n\n .chat-status {\n font-size: 12px;\n opacity: 0.9;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .chat-close {\n background: transparent;\n border: none;\n color: white;\n cursor: pointer;\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n .chat-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n\n .chat-messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background: #f9fafb;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .chat-messages::-webkit-scrollbar {\n width: 6px;\n }\n\n .chat-messages::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chat-messages::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n }\n\n .chat-welcome {\n text-align: center;\n padding: 40px 20px;\n color: #64748b;\n }\n\n .welcome-icon {\n font-size: 48px;\n margin-bottom: 12px;\n }\n\n .welcome-text {\n font-size: 15px;\n font-weight: 500;\n color: #475569;\n }\n\n .chat-message {\n display: flex;\n gap: 8px;\n animation: messageSlide 0.3s ease-out;\n }\n\n @keyframes messageSlide {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .chat-message.user {\n flex-direction: row-reverse;\n }\n\n .message-bubble {\n max-width: 75%;\n padding: 12px 16px;\n border-radius: 16px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .chat-message.user .message-bubble {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .chat-message.bot .message-bubble {\n background: white;\n color: #1e293b;\n border-bottom-left-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-indicator {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n background: white;\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n max-width: 60px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #94a3b8;\n animation: typing 1.4s infinite;\n }\n\n .typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n }\n\n .typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n }\n\n @keyframes typing {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.7;\n }\n 30% {\n transform: translateY(-10px);\n opacity: 1;\n }\n }\n\n .chat-input-wrapper {\n display: flex;\n padding: 16px;\n gap: 8px;\n background: white;\n border-top: 1px solid #e2e8f0;\n }\n\n #chat-input {\n flex: 1;\n border: 2px solid #e2e8f0;\n border-radius: 12px;\n padding: 12px 16px;\n font-size: 14px;\n outline: none;\n transition: all 0.2s;\n font-family: inherit;\n }\n\n #chat-input:focus {\n border-color: ").concat(this.primaryColor, ";\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n\n #chat-send {\n background: linear-gradient(135deg, ").concat(this.primaryColor, " 0%, #8b5cf6 100%);\n color: white;\n border: none;\n border-radius: 12px;\n padding: 12px 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n #chat-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n #chat-send:not(:disabled):hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n }\n\n #chat-send:not(:disabled):active {\n transform: scale(0.95);\n }\n ");
|
|
70
72
|
document.head.appendChild(style);
|
|
71
73
|
}
|
|
72
74
|
}, {
|
|
73
75
|
key: "_bindEvents",
|
|
74
76
|
value: function _bindEvents() {
|
|
75
77
|
var _this = this;
|
|
78
|
+
var toggle = this.container.querySelector("#chat-toggle");
|
|
79
|
+
var closeBtn = this.container.querySelector("#chat-close");
|
|
80
|
+
var expanded = this.container.querySelector("#chat-expanded");
|
|
76
81
|
var input = this.container.querySelector("#chat-input");
|
|
77
82
|
var sendBtn = this.container.querySelector("#chat-send");
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
toggle.addEventListener("click", function () {
|
|
84
|
+
toggle.style.display = "none";
|
|
85
|
+
expanded.classList.add("visible");
|
|
86
|
+
input.focus();
|
|
87
|
+
});
|
|
88
|
+
closeBtn.addEventListener("click", function () {
|
|
89
|
+
expanded.classList.remove("visible");
|
|
90
|
+
toggle.style.display = "flex";
|
|
91
|
+
});
|
|
92
|
+
input.addEventListener("input", function () {
|
|
93
|
+
sendBtn.disabled = !input.value.trim();
|
|
94
|
+
});
|
|
88
95
|
var send = function send() {
|
|
89
96
|
var text = input.value.trim();
|
|
90
97
|
if (!text) return;
|
|
91
|
-
|
|
98
|
+
_this._addMessage(text, true);
|
|
92
99
|
input.value = "";
|
|
93
|
-
|
|
100
|
+
sendBtn.disabled = true;
|
|
101
|
+
_this._showTypingIndicator();
|
|
94
102
|
setTimeout(function () {
|
|
95
|
-
|
|
96
|
-
|
|
103
|
+
_this._hideTypingIndicator();
|
|
104
|
+
_this._addMessage("Thanks for your message! You said: \"".concat(text, "\""), false);
|
|
105
|
+
}, 1000 + Math.random() * 1000);
|
|
97
106
|
};
|
|
98
107
|
sendBtn.addEventListener("click", send);
|
|
99
108
|
input.addEventListener("keypress", function (e) {
|
|
100
|
-
if (e.key === "Enter") send();
|
|
109
|
+
if (e.key === "Enter" && !sendBtn.disabled) send();
|
|
101
110
|
});
|
|
102
111
|
}
|
|
112
|
+
}, {
|
|
113
|
+
key: "_addMessage",
|
|
114
|
+
value: function _addMessage(text, isUser) {
|
|
115
|
+
var messagesContainer = this.container.querySelector("#chat-messages");
|
|
116
|
+
var welcome = messagesContainer.querySelector(".chat-welcome");
|
|
117
|
+
if (welcome) welcome.remove();
|
|
118
|
+
var messageEl = document.createElement("div");
|
|
119
|
+
messageEl.className = "chat-message ".concat(isUser ? "user" : "bot");
|
|
120
|
+
messageEl.innerHTML = "<div class=\"message-bubble\">".concat(this._escapeHtml(text), "</div>");
|
|
121
|
+
messagesContainer.appendChild(messageEl);
|
|
122
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
123
|
+
}
|
|
124
|
+
}, {
|
|
125
|
+
key: "_showTypingIndicator",
|
|
126
|
+
value: function _showTypingIndicator() {
|
|
127
|
+
var messagesContainer = this.container.querySelector("#chat-messages");
|
|
128
|
+
var indicator = document.createElement("div");
|
|
129
|
+
indicator.className = "chat-message bot";
|
|
130
|
+
indicator.id = "typing-indicator";
|
|
131
|
+
indicator.innerHTML = "\n <div class=\"typing-indicator\">\n <div class=\"typing-dot\"></div>\n <div class=\"typing-dot\"></div>\n <div class=\"typing-dot\"></div>\n </div>\n ";
|
|
132
|
+
messagesContainer.appendChild(indicator);
|
|
133
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
134
|
+
}
|
|
135
|
+
}, {
|
|
136
|
+
key: "_hideTypingIndicator",
|
|
137
|
+
value: function _hideTypingIndicator() {
|
|
138
|
+
var indicator = this.container.querySelector("#typing-indicator");
|
|
139
|
+
if (indicator) indicator.remove();
|
|
140
|
+
}
|
|
141
|
+
}, {
|
|
142
|
+
key: "_escapeHtml",
|
|
143
|
+
value: function _escapeHtml(text) {
|
|
144
|
+
var div = document.createElement("div");
|
|
145
|
+
div.textContent = text;
|
|
146
|
+
return div.innerHTML;
|
|
147
|
+
}
|
|
103
148
|
}]);
|
|
104
149
|
}(); // Export as UMD and ESM compatible
|
|
105
150
|
{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(e="undefined"!=typeof globalThis?globalThis:e||self).ChatWidget=n()}(this,function(){"use strict";function e(e,t,i){return t&&function(e,t){for(var i=0;i<t.length;i++){var o=t[i];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(e,n(o.key),o)}}(e.prototype,t),Object.defineProperty(e,"prototype",{writable:!1}),e}function n(e){var n=function(e,n){if("object"!=typeof e||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var i=t.call(e,n);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e,"string");return"symbol"==typeof n?n:n+""}function t(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var i={exports:{}};return function(n){var t=function(){return e(function e(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e),this.title=n.title||"Chat Bot",this.placeholder=n.placeholder||"Type a message...",this.container=null,this.messages=[],this._init()},[{key:"_init",value:function(){this.container=document.createElement("div"),this.container.id="chat-widget-container",this.container.innerHTML='\n <div class="chat-header">'.concat(this.title,'</div>\n <div class="chat-messages" id="chat-messages"></div>\n <div class="chat-input-wrapper">\n <input type="text" id="chat-input" placeholder="').concat(this.placeholder,'" />\n <button id="chat-send">Send</button>\n </div>\n '),document.body.appendChild(this.container),this._applyStyles(),this._bindEvents()}},{key:"_applyStyles",value:function(){var e=document.createElement("style");e.textContent="\n #chat-widget-container {\n position: fixed;\n bottom: 20px;\n right: 20px;\n width: 300px;\n max-height: 400px;\n background: rgba(255,255,255,0.95);\n box-shadow: 0 4px 12px rgba(0,0,0,0.15);\n border-radius: 12px;\n display: flex;\n flex-direction: column;\n font-family: 'Inter', sans-serif;\n overflow: hidden;\n z-index: 10000;\n }\n #chat-widget-container .chat-header {\n background: linear-gradient(135deg, #6a5acd, #00bfff);\n color: white;\n padding: 8px 12px;\n font-weight: 600;\n text-align: center;\n }\n #chat-widget-container .chat-messages {\n flex: 1;\n padding: 8px 12px;\n overflow-y: auto;\n font-size: 0.9rem;\n color: #333;\n }\n #chat-widget-container .chat-input-wrapper {\n display: flex;\n border-top: 1px solid #ddd;\n }\n #chat-widget-container #chat-input {\n flex: 1;\n border: none;\n padding: 8px;\n font-size: 0.9rem;\n outline: none;\n }\n #chat-widget-container #chat-send {\n background: #6a5acd;\n color: white;\n border: none;\n padding: 0 12px;\n cursor: pointer;\n font-weight: 600;\n }\n #chat-widget-container #chat-send:hover {\n background: #5a4acb;\n }\n ",document.head.appendChild(e)}},{key:"_bindEvents",value:function(){var e=this,n=this.container.querySelector("#chat-input"),t=this.container.querySelector("#chat-send"),i=function(n){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1],i=document.createElement("div");i.textContent=n,i.style.marginBottom="6px",i.style.textAlign=t?"right":"left",i.style.color=t?"#0066cc":"#333",e.container.querySelector("#chat-messages").appendChild(i),e.container.querySelector("#chat-messages").scrollTop=9999},o=function(){var e=n.value.trim();e&&(i(e,!0),n.value="",setTimeout(function(){return i("You said: "+e,!1)},500))};t.addEventListener("click",o),n.addEventListener("keypress",function(e){"Enter"===e.key&&o()})}}])}();n.exports=t}(i),t(i.exports)});
|
|
1
|
+
!function(n,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(n="undefined"!=typeof globalThis?globalThis:n||self).ChatWidget=e()}(this,function(){"use strict";function n(n,t,i){return t&&function(n,t){for(var i=0;i<t.length;i++){var a=t[i];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(n,e(a.key),a)}}(n.prototype,t),Object.defineProperty(n,"prototype",{writable:!1}),n}function e(n){var e=function(n,e){if("object"!=typeof n||!n)return n;var t=n[Symbol.toPrimitive];if(void 0!==t){var i=t.call(n,e);if("object"!=typeof i)return i;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(n)}(n,"string");return"symbol"==typeof e?e:e+""}function t(n){return n&&n.__esModule&&Object.prototype.hasOwnProperty.call(n,"default")?n.default:n}var i={exports:{}};return function(e){var t=function(){return n(function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};!function(n,e){if(!(n instanceof e))throw new TypeError("Cannot call a class as a function")}(this,n),this.title=e.title||"Chat Assistant",this.placeholder=e.placeholder||"Type your message...",this.primaryColor=e.primaryColor||"#6366f1",this.container=null,this.messages=[],this.isMinimized=!1,this._init()},[{key:"_init",value:function(){this.container=document.createElement("div"),this.container.id="chat-widget-container",this.container.innerHTML='\n <div class="chat-widget-minimized" id="chat-toggle">\n <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>\n </svg>\n </div>\n <div class="chat-widget-expanded" id="chat-expanded">\n <div class="chat-header">\n <div class="chat-header-content">\n <div class="chat-avatar">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path>\n <path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>\n </svg>\n </div>\n <div class="chat-header-text">\n <div class="chat-title">'.concat(this.title,'</div>\n <div class="chat-status">● Online</div>\n </div>\n </div>\n <button class="chat-close" id="chat-close">\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <line x1="18" y1="6" x2="6" y2="18"></line>\n <line x1="6" y1="6" x2="18" y2="18"></line>\n </svg>\n </button>\n </div>\n <div class="chat-messages" id="chat-messages">\n <div class="chat-welcome">\n <div class="welcome-icon">👋</div>\n <div class="welcome-text">Hello! How can I help you today?</div>\n </div>\n </div>\n <div class="chat-input-wrapper">\n <input type="text" id="chat-input" placeholder="').concat(this.placeholder,'" autocomplete="off" />\n <button id="chat-send" disabled>\n <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">\n <line x1="22" y1="2" x2="11" y2="13"></line>\n <polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>\n </svg>\n </button>\n </div>\n </div>\n '),document.body.appendChild(this.container),this._applyStyles(),this._bindEvents()}},{key:"_applyStyles",value:function(){var n=document.createElement("style");n.textContent="\n @import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');\n \n #chat-widget-container {\n position: fixed;\n bottom: 24px;\n right: 24px;\n z-index: 10000;\n font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n }\n\n .chat-widget-minimized {\n width: 60px;\n height: 60px;\n border-radius: 50%;\n background: linear-gradient(135deg, ".concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: pointer;\n box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4);\n transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n animation: pulse 2s infinite;\n }\n\n .chat-widget-minimized:hover {\n transform: scale(1.1);\n box-shadow: 0 12px 32px rgba(99, 102, 241, 0.5);\n }\n\n @keyframes pulse {\n 0%, 100% { box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4); }\n 50% { box-shadow: 0 8px 32px rgba(99, 102, 241, 0.6); }\n }\n\n .chat-widget-expanded {\n width: 380px;\n height: 600px;\n background: white;\n border-radius: 16px;\n box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);\n display: none;\n flex-direction: column;\n overflow: hidden;\n animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);\n }\n\n @keyframes slideUp {\n from {\n opacity: 0;\n transform: translateY(20px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n }\n\n .chat-widget-expanded.visible {\n display: flex;\n }\n\n .chat-header {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n padding: 20px;\n display: flex;\n align-items: center;\n justify-content: space-between;\n }\n\n .chat-header-content {\n display: flex;\n align-items: center;\n gap: 12px;\n }\n\n .chat-avatar {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.2);\n backdrop-filter: blur(10px);\n display: flex;\n align-items: center;\n justify-content: center;\n }\n\n .chat-header-text {\n display: flex;\n flex-direction: column;\n gap: 2px;\n }\n\n .chat-title {\n font-weight: 600;\n font-size: 16px;\n }\n\n .chat-status {\n font-size: 12px;\n opacity: 0.9;\n display: flex;\n align-items: center;\n gap: 4px;\n }\n\n .chat-close {\n background: transparent;\n border: none;\n color: white;\n cursor: pointer;\n padding: 8px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n .chat-close:hover {\n background: rgba(255, 255, 255, 0.15);\n }\n\n .chat-messages {\n flex: 1;\n padding: 20px;\n overflow-y: auto;\n background: #f9fafb;\n display: flex;\n flex-direction: column;\n gap: 12px;\n }\n\n .chat-messages::-webkit-scrollbar {\n width: 6px;\n }\n\n .chat-messages::-webkit-scrollbar-track {\n background: transparent;\n }\n\n .chat-messages::-webkit-scrollbar-thumb {\n background: #cbd5e1;\n border-radius: 3px;\n }\n\n .chat-welcome {\n text-align: center;\n padding: 40px 20px;\n color: #64748b;\n }\n\n .welcome-icon {\n font-size: 48px;\n margin-bottom: 12px;\n }\n\n .welcome-text {\n font-size: 15px;\n font-weight: 500;\n color: #475569;\n }\n\n .chat-message {\n display: flex;\n gap: 8px;\n animation: messageSlide 0.3s ease-out;\n }\n\n @keyframes messageSlide {\n from {\n opacity: 0;\n transform: translateY(10px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n }\n\n .chat-message.user {\n flex-direction: row-reverse;\n }\n\n .message-bubble {\n max-width: 75%;\n padding: 12px 16px;\n border-radius: 16px;\n font-size: 14px;\n line-height: 1.5;\n word-wrap: break-word;\n }\n\n .chat-message.user .message-bubble {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n border-bottom-right-radius: 4px;\n }\n\n .chat-message.bot .message-bubble {\n background: white;\n color: #1e293b;\n border-bottom-left-radius: 4px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-indicator {\n display: flex;\n gap: 4px;\n padding: 12px 16px;\n background: white;\n border-radius: 16px;\n border-bottom-left-radius: 4px;\n max-width: 60px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);\n }\n\n .typing-dot {\n width: 8px;\n height: 8px;\n border-radius: 50%;\n background: #94a3b8;\n animation: typing 1.4s infinite;\n }\n\n .typing-dot:nth-child(2) {\n animation-delay: 0.2s;\n }\n\n .typing-dot:nth-child(3) {\n animation-delay: 0.4s;\n }\n\n @keyframes typing {\n 0%, 60%, 100% {\n transform: translateY(0);\n opacity: 0.7;\n }\n 30% {\n transform: translateY(-10px);\n opacity: 1;\n }\n }\n\n .chat-input-wrapper {\n display: flex;\n padding: 16px;\n gap: 8px;\n background: white;\n border-top: 1px solid #e2e8f0;\n }\n\n #chat-input {\n flex: 1;\n border: 2px solid #e2e8f0;\n border-radius: 12px;\n padding: 12px 16px;\n font-size: 14px;\n outline: none;\n transition: all 0.2s;\n font-family: inherit;\n }\n\n #chat-input:focus {\n border-color: ").concat(this.primaryColor,";\n box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);\n }\n\n #chat-send {\n background: linear-gradient(135deg, ").concat(this.primaryColor," 0%, #8b5cf6 100%);\n color: white;\n border: none;\n border-radius: 12px;\n padding: 12px 16px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: all 0.2s;\n }\n\n #chat-send:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n #chat-send:not(:disabled):hover {\n transform: scale(1.05);\n box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);\n }\n\n #chat-send:not(:disabled):active {\n transform: scale(0.95);\n }\n "),document.head.appendChild(n)}},{key:"_bindEvents",value:function(){var n=this,e=this.container.querySelector("#chat-toggle"),t=this.container.querySelector("#chat-close"),i=this.container.querySelector("#chat-expanded"),a=this.container.querySelector("#chat-input"),o=this.container.querySelector("#chat-send");e.addEventListener("click",function(){e.style.display="none",i.classList.add("visible"),a.focus()}),t.addEventListener("click",function(){i.classList.remove("visible"),e.style.display="flex"}),a.addEventListener("input",function(){o.disabled=!a.value.trim()});var r=function(){var e=a.value.trim();e&&(n._addMessage(e,!0),a.value="",o.disabled=!0,n._showTypingIndicator(),setTimeout(function(){n._hideTypingIndicator(),n._addMessage('Thanks for your message! You said: "'.concat(e,'"'),!1)},1e3+1e3*Math.random()))};o.addEventListener("click",r),a.addEventListener("keypress",function(n){"Enter"!==n.key||o.disabled||r()})}},{key:"_addMessage",value:function(n,e){var t=this.container.querySelector("#chat-messages"),i=t.querySelector(".chat-welcome");i&&i.remove();var a=document.createElement("div");a.className="chat-message ".concat(e?"user":"bot"),a.innerHTML='<div class="message-bubble">'.concat(this._escapeHtml(n),"</div>"),t.appendChild(a),t.scrollTop=t.scrollHeight}},{key:"_showTypingIndicator",value:function(){var n=this.container.querySelector("#chat-messages"),e=document.createElement("div");e.className="chat-message bot",e.id="typing-indicator",e.innerHTML='\n <div class="typing-indicator">\n <div class="typing-dot"></div>\n <div class="typing-dot"></div>\n <div class="typing-dot"></div>\n </div>\n ',n.appendChild(e),n.scrollTop=n.scrollHeight}},{key:"_hideTypingIndicator",value:function(){var n=this.container.querySelector("#typing-indicator");n&&n.remove()}},{key:"_escapeHtml",value:function(n){var e=document.createElement("div");return e.textContent=n,e.innerHTML}}])}();e.exports=t}(i),t(i.exports)});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mini-chat-bot-widget",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "A tiny chat bot widget fixed at bottom right, distributable via npm and usable with a <script> tag.",
|
|
5
5
|
"main": "dist/chat-widget.umd.js",
|
|
6
6
|
"module": "dist/chat-widget.esm.js",
|
package/src/chat-widget.js
CHANGED
|
@@ -1,119 +1,458 @@
|
|
|
1
|
-
// chat-widget.js - vanilla JS chat bot widget
|
|
1
|
+
// chat-widget.js - Modern vanilla JS chat bot widget
|
|
2
2
|
|
|
3
3
|
class ChatWidget {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
<div class="chat-
|
|
20
|
-
<
|
|
21
|
-
|
|
4
|
+
constructor(options = {}) {
|
|
5
|
+
this.title = options.title || "Chat Assistant";
|
|
6
|
+
this.placeholder = options.placeholder || "Type your message...";
|
|
7
|
+
this.primaryColor = options.primaryColor || "#6366f1";
|
|
8
|
+
this.container = null;
|
|
9
|
+
this.messages = [];
|
|
10
|
+
this.isMinimized = false;
|
|
11
|
+
this._init();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
_init() {
|
|
15
|
+
// Create container
|
|
16
|
+
this.container = document.createElement("div");
|
|
17
|
+
this.container.id = "chat-widget-container";
|
|
18
|
+
this.container.innerHTML = `
|
|
19
|
+
<div class="chat-widget-minimized" id="chat-toggle">
|
|
20
|
+
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
21
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
22
|
+
</svg>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="chat-widget-expanded" id="chat-expanded">
|
|
25
|
+
<div class="chat-header">
|
|
26
|
+
<div class="chat-header-content">
|
|
27
|
+
<div class="chat-avatar">
|
|
28
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
29
|
+
<path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path>
|
|
30
|
+
<path d="M19 10v2a7 7 0 0 1-14 0v-2"></path>
|
|
31
|
+
</svg>
|
|
32
|
+
</div>
|
|
33
|
+
<div class="chat-header-text">
|
|
34
|
+
<div class="chat-title">${this.title}</div>
|
|
35
|
+
<div class="chat-status">● Online</div>
|
|
36
|
+
</div>
|
|
37
|
+
</div>
|
|
38
|
+
<button class="chat-close" id="chat-close">
|
|
39
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
40
|
+
<line x1="18" y1="6" x2="6" y2="18"></line>
|
|
41
|
+
<line x1="6" y1="6" x2="18" y2="18"></line>
|
|
42
|
+
</svg>
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
<div class="chat-messages" id="chat-messages">
|
|
46
|
+
<div class="chat-welcome">
|
|
47
|
+
<div class="welcome-icon">👋</div>
|
|
48
|
+
<div class="welcome-text">Hello! How can I help you today?</div>
|
|
49
|
+
</div>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="chat-input-wrapper">
|
|
52
|
+
<input type="text" id="chat-input" placeholder="${this.placeholder}" autocomplete="off" />
|
|
53
|
+
<button id="chat-send" disabled>
|
|
54
|
+
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
55
|
+
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
56
|
+
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
57
|
+
</svg>
|
|
58
|
+
</button>
|
|
59
|
+
</div>
|
|
22
60
|
</div>
|
|
23
61
|
`;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
62
|
+
document.body.appendChild(this.container);
|
|
63
|
+
this._applyStyles();
|
|
64
|
+
this._bindEvents();
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_applyStyles() {
|
|
68
|
+
const style = document.createElement("style");
|
|
69
|
+
style.textContent = `
|
|
70
|
+
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap');
|
|
71
|
+
|
|
32
72
|
#chat-widget-container {
|
|
33
73
|
position: fixed;
|
|
34
|
-
bottom:
|
|
35
|
-
right:
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
74
|
+
bottom: 24px;
|
|
75
|
+
right: 24px;
|
|
76
|
+
z-index: 10000;
|
|
77
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.chat-widget-minimized {
|
|
81
|
+
width: 60px;
|
|
82
|
+
height: 60px;
|
|
83
|
+
border-radius: 50%;
|
|
84
|
+
background: linear-gradient(135deg, ${this.primaryColor} 0%, #8b5cf6 100%);
|
|
85
|
+
color: white;
|
|
41
86
|
display: flex;
|
|
87
|
+
align-items: center;
|
|
88
|
+
justify-content: center;
|
|
89
|
+
cursor: pointer;
|
|
90
|
+
box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4);
|
|
91
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
92
|
+
animation: pulse 2s infinite;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.chat-widget-minimized:hover {
|
|
96
|
+
transform: scale(1.1);
|
|
97
|
+
box-shadow: 0 12px 32px rgba(99, 102, 241, 0.5);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
@keyframes pulse {
|
|
101
|
+
0%, 100% { box-shadow: 0 8px 24px rgba(99, 102, 241, 0.4); }
|
|
102
|
+
50% { box-shadow: 0 8px 32px rgba(99, 102, 241, 0.6); }
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.chat-widget-expanded {
|
|
106
|
+
width: 380px;
|
|
107
|
+
height: 600px;
|
|
108
|
+
background: white;
|
|
109
|
+
border-radius: 16px;
|
|
110
|
+
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.15);
|
|
111
|
+
display: none;
|
|
42
112
|
flex-direction: column;
|
|
43
|
-
font-family: 'Inter', sans-serif;
|
|
44
113
|
overflow: hidden;
|
|
45
|
-
|
|
114
|
+
animation: slideUp 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
46
115
|
}
|
|
47
|
-
|
|
48
|
-
|
|
116
|
+
|
|
117
|
+
@keyframes slideUp {
|
|
118
|
+
from {
|
|
119
|
+
opacity: 0;
|
|
120
|
+
transform: translateY(20px) scale(0.95);
|
|
121
|
+
}
|
|
122
|
+
to {
|
|
123
|
+
opacity: 1;
|
|
124
|
+
transform: translateY(0) scale(1);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.chat-widget-expanded.visible {
|
|
129
|
+
display: flex;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.chat-header {
|
|
133
|
+
background: linear-gradient(135deg, ${this.primaryColor} 0%, #8b5cf6 100%);
|
|
49
134
|
color: white;
|
|
50
|
-
padding:
|
|
135
|
+
padding: 20px;
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: space-between;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.chat-header-content {
|
|
142
|
+
display: flex;
|
|
143
|
+
align-items: center;
|
|
144
|
+
gap: 12px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.chat-avatar {
|
|
148
|
+
width: 40px;
|
|
149
|
+
height: 40px;
|
|
150
|
+
border-radius: 50%;
|
|
151
|
+
background: rgba(255, 255, 255, 0.2);
|
|
152
|
+
backdrop-filter: blur(10px);
|
|
153
|
+
display: flex;
|
|
154
|
+
align-items: center;
|
|
155
|
+
justify-content: center;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.chat-header-text {
|
|
159
|
+
display: flex;
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
gap: 2px;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.chat-title {
|
|
51
165
|
font-weight: 600;
|
|
52
|
-
|
|
166
|
+
font-size: 16px;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.chat-status {
|
|
170
|
+
font-size: 12px;
|
|
171
|
+
opacity: 0.9;
|
|
172
|
+
display: flex;
|
|
173
|
+
align-items: center;
|
|
174
|
+
gap: 4px;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.chat-close {
|
|
178
|
+
background: transparent;
|
|
179
|
+
border: none;
|
|
180
|
+
color: white;
|
|
181
|
+
cursor: pointer;
|
|
182
|
+
padding: 8px;
|
|
183
|
+
border-radius: 8px;
|
|
184
|
+
display: flex;
|
|
185
|
+
align-items: center;
|
|
186
|
+
justify-content: center;
|
|
187
|
+
transition: all 0.2s;
|
|
53
188
|
}
|
|
54
|
-
|
|
189
|
+
|
|
190
|
+
.chat-close:hover {
|
|
191
|
+
background: rgba(255, 255, 255, 0.15);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.chat-messages {
|
|
55
195
|
flex: 1;
|
|
56
|
-
padding:
|
|
196
|
+
padding: 20px;
|
|
57
197
|
overflow-y: auto;
|
|
58
|
-
|
|
59
|
-
|
|
198
|
+
background: #f9fafb;
|
|
199
|
+
display: flex;
|
|
200
|
+
flex-direction: column;
|
|
201
|
+
gap: 12px;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.chat-messages::-webkit-scrollbar {
|
|
205
|
+
width: 6px;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
.chat-messages::-webkit-scrollbar-track {
|
|
209
|
+
background: transparent;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
.chat-messages::-webkit-scrollbar-thumb {
|
|
213
|
+
background: #cbd5e1;
|
|
214
|
+
border-radius: 3px;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.chat-welcome {
|
|
218
|
+
text-align: center;
|
|
219
|
+
padding: 40px 20px;
|
|
220
|
+
color: #64748b;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.welcome-icon {
|
|
224
|
+
font-size: 48px;
|
|
225
|
+
margin-bottom: 12px;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.welcome-text {
|
|
229
|
+
font-size: 15px;
|
|
230
|
+
font-weight: 500;
|
|
231
|
+
color: #475569;
|
|
60
232
|
}
|
|
61
|
-
|
|
233
|
+
|
|
234
|
+
.chat-message {
|
|
62
235
|
display: flex;
|
|
63
|
-
|
|
236
|
+
gap: 8px;
|
|
237
|
+
animation: messageSlide 0.3s ease-out;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
@keyframes messageSlide {
|
|
241
|
+
from {
|
|
242
|
+
opacity: 0;
|
|
243
|
+
transform: translateY(10px);
|
|
244
|
+
}
|
|
245
|
+
to {
|
|
246
|
+
opacity: 1;
|
|
247
|
+
transform: translateY(0);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.chat-message.user {
|
|
252
|
+
flex-direction: row-reverse;
|
|
64
253
|
}
|
|
65
|
-
|
|
254
|
+
|
|
255
|
+
.message-bubble {
|
|
256
|
+
max-width: 75%;
|
|
257
|
+
padding: 12px 16px;
|
|
258
|
+
border-radius: 16px;
|
|
259
|
+
font-size: 14px;
|
|
260
|
+
line-height: 1.5;
|
|
261
|
+
word-wrap: break-word;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.chat-message.user .message-bubble {
|
|
265
|
+
background: linear-gradient(135deg, ${this.primaryColor} 0%, #8b5cf6 100%);
|
|
266
|
+
color: white;
|
|
267
|
+
border-bottom-right-radius: 4px;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.chat-message.bot .message-bubble {
|
|
271
|
+
background: white;
|
|
272
|
+
color: #1e293b;
|
|
273
|
+
border-bottom-left-radius: 4px;
|
|
274
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.typing-indicator {
|
|
278
|
+
display: flex;
|
|
279
|
+
gap: 4px;
|
|
280
|
+
padding: 12px 16px;
|
|
281
|
+
background: white;
|
|
282
|
+
border-radius: 16px;
|
|
283
|
+
border-bottom-left-radius: 4px;
|
|
284
|
+
max-width: 60px;
|
|
285
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.typing-dot {
|
|
289
|
+
width: 8px;
|
|
290
|
+
height: 8px;
|
|
291
|
+
border-radius: 50%;
|
|
292
|
+
background: #94a3b8;
|
|
293
|
+
animation: typing 1.4s infinite;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.typing-dot:nth-child(2) {
|
|
297
|
+
animation-delay: 0.2s;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.typing-dot:nth-child(3) {
|
|
301
|
+
animation-delay: 0.4s;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
@keyframes typing {
|
|
305
|
+
0%, 60%, 100% {
|
|
306
|
+
transform: translateY(0);
|
|
307
|
+
opacity: 0.7;
|
|
308
|
+
}
|
|
309
|
+
30% {
|
|
310
|
+
transform: translateY(-10px);
|
|
311
|
+
opacity: 1;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
.chat-input-wrapper {
|
|
316
|
+
display: flex;
|
|
317
|
+
padding: 16px;
|
|
318
|
+
gap: 8px;
|
|
319
|
+
background: white;
|
|
320
|
+
border-top: 1px solid #e2e8f0;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
#chat-input {
|
|
66
324
|
flex: 1;
|
|
67
|
-
border:
|
|
68
|
-
|
|
69
|
-
|
|
325
|
+
border: 2px solid #e2e8f0;
|
|
326
|
+
border-radius: 12px;
|
|
327
|
+
padding: 12px 16px;
|
|
328
|
+
font-size: 14px;
|
|
70
329
|
outline: none;
|
|
330
|
+
transition: all 0.2s;
|
|
331
|
+
font-family: inherit;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
#chat-input:focus {
|
|
335
|
+
border-color: ${this.primaryColor};
|
|
336
|
+
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
|
|
71
337
|
}
|
|
72
|
-
|
|
73
|
-
|
|
338
|
+
|
|
339
|
+
#chat-send {
|
|
340
|
+
background: linear-gradient(135deg, ${this.primaryColor} 0%, #8b5cf6 100%);
|
|
74
341
|
color: white;
|
|
75
342
|
border: none;
|
|
76
|
-
|
|
343
|
+
border-radius: 12px;
|
|
344
|
+
padding: 12px 16px;
|
|
77
345
|
cursor: pointer;
|
|
78
|
-
|
|
346
|
+
display: flex;
|
|
347
|
+
align-items: center;
|
|
348
|
+
justify-content: center;
|
|
349
|
+
transition: all 0.2s;
|
|
79
350
|
}
|
|
80
|
-
|
|
81
|
-
|
|
351
|
+
|
|
352
|
+
#chat-send:disabled {
|
|
353
|
+
opacity: 0.5;
|
|
354
|
+
cursor: not-allowed;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
#chat-send:not(:disabled):hover {
|
|
358
|
+
transform: scale(1.05);
|
|
359
|
+
box-shadow: 0 4px 12px rgba(99, 102, 241, 0.3);
|
|
82
360
|
}
|
|
361
|
+
|
|
362
|
+
#chat-send:not(:disabled):active {
|
|
363
|
+
transform: scale(0.95);
|
|
364
|
+
}
|
|
365
|
+
`;
|
|
366
|
+
document.head.appendChild(style);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
_bindEvents() {
|
|
370
|
+
const toggle = this.container.querySelector("#chat-toggle");
|
|
371
|
+
const closeBtn = this.container.querySelector("#chat-close");
|
|
372
|
+
const expanded = this.container.querySelector("#chat-expanded");
|
|
373
|
+
const input = this.container.querySelector("#chat-input");
|
|
374
|
+
const sendBtn = this.container.querySelector("#chat-send");
|
|
375
|
+
|
|
376
|
+
toggle.addEventListener("click", () => {
|
|
377
|
+
toggle.style.display = "none";
|
|
378
|
+
expanded.classList.add("visible");
|
|
379
|
+
input.focus();
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
closeBtn.addEventListener("click", () => {
|
|
383
|
+
expanded.classList.remove("visible");
|
|
384
|
+
toggle.style.display = "flex";
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
input.addEventListener("input", () => {
|
|
388
|
+
sendBtn.disabled = !input.value.trim();
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
const send = () => {
|
|
392
|
+
const text = input.value.trim();
|
|
393
|
+
if (!text) return;
|
|
394
|
+
|
|
395
|
+
this._addMessage(text, true);
|
|
396
|
+
input.value = "";
|
|
397
|
+
sendBtn.disabled = true;
|
|
398
|
+
|
|
399
|
+
this._showTypingIndicator();
|
|
400
|
+
|
|
401
|
+
setTimeout(() => {
|
|
402
|
+
this._hideTypingIndicator();
|
|
403
|
+
this._addMessage(`Thanks for your message! You said: "${text}"`, false);
|
|
404
|
+
}, 1000 + Math.random() * 1000);
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
sendBtn.addEventListener("click", send);
|
|
408
|
+
input.addEventListener("keypress", (e) => {
|
|
409
|
+
if (e.key === "Enter" && !sendBtn.disabled) send();
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
_addMessage(text, isUser) {
|
|
414
|
+
const messagesContainer = this.container.querySelector("#chat-messages");
|
|
415
|
+
const welcome = messagesContainer.querySelector(".chat-welcome");
|
|
416
|
+
if (welcome) welcome.remove();
|
|
417
|
+
|
|
418
|
+
const messageEl = document.createElement("div");
|
|
419
|
+
messageEl.className = `chat-message ${isUser ? "user" : "bot"}`;
|
|
420
|
+
messageEl.innerHTML = `<div class="message-bubble">${this._escapeHtml(text)}</div>`;
|
|
421
|
+
messagesContainer.appendChild(messageEl);
|
|
422
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
_showTypingIndicator() {
|
|
426
|
+
const messagesContainer = this.container.querySelector("#chat-messages");
|
|
427
|
+
const indicator = document.createElement("div");
|
|
428
|
+
indicator.className = "chat-message bot";
|
|
429
|
+
indicator.id = "typing-indicator";
|
|
430
|
+
indicator.innerHTML = `
|
|
431
|
+
<div class="typing-indicator">
|
|
432
|
+
<div class="typing-dot"></div>
|
|
433
|
+
<div class="typing-dot"></div>
|
|
434
|
+
<div class="typing-dot"></div>
|
|
435
|
+
</div>
|
|
83
436
|
`;
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
const send = () => {
|
|
100
|
-
const text = input.value.trim();
|
|
101
|
-
if (!text) return;
|
|
102
|
-
addMessage(text, true);
|
|
103
|
-
input.value = "";
|
|
104
|
-
// Simple echo bot – replace with real logic or API call
|
|
105
|
-
setTimeout(() => addMessage("You said: " + text, false), 500);
|
|
106
|
-
};
|
|
107
|
-
sendBtn.addEventListener("click", send);
|
|
108
|
-
input.addEventListener("keypress", (e) => {
|
|
109
|
-
if (e.key === "Enter") send();
|
|
110
|
-
});
|
|
111
|
-
}
|
|
437
|
+
messagesContainer.appendChild(indicator);
|
|
438
|
+
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
_hideTypingIndicator() {
|
|
442
|
+
const indicator = this.container.querySelector("#typing-indicator");
|
|
443
|
+
if (indicator) indicator.remove();
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
_escapeHtml(text) {
|
|
447
|
+
const div = document.createElement("div");
|
|
448
|
+
div.textContent = text;
|
|
449
|
+
return div.innerHTML;
|
|
450
|
+
}
|
|
112
451
|
}
|
|
113
452
|
|
|
114
453
|
// Export as UMD and ESM compatible
|
|
115
454
|
if (typeof module !== "undefined" && typeof module.exports !== "undefined") {
|
|
116
|
-
|
|
455
|
+
module.exports = ChatWidget;
|
|
117
456
|
} else {
|
|
118
|
-
|
|
119
|
-
}
|
|
457
|
+
window.ChatWidget = ChatWidget;
|
|
458
|
+
}
|