aptolix_chatbot 1.0.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.
Files changed (40) hide show
  1. package/.vs/Aptolix-Chatbot/CopilotIndices/17.14.995.13737/CodeChunks.db +0 -0
  2. package/.vs/Aptolix-Chatbot/CopilotIndices/17.14.995.13737/SemanticSymbols.db +0 -0
  3. package/.vs/Aptolix-Chatbot/FileContentIndex/7a6184fc-93ec-4d74-9ae5-f42762df27b5.vsidx +0 -0
  4. package/.vs/Aptolix-Chatbot/FileContentIndex/812b8a98-dfb2-4448-bf14-4ed36d2c34f3.vsidx +0 -0
  5. package/.vs/Aptolix-Chatbot/FileContentIndex/98c498ee-ddc5-46fc-82d9-ed30a218b641.vsidx +0 -0
  6. package/.vs/Aptolix-Chatbot/FileContentIndex/9f4cf152-a82c-4f20-97b4-5c50ab636d6f.vsidx +0 -0
  7. package/.vs/Aptolix-Chatbot/FileContentIndex/c402a8e1-cb87-4b94-8c7f-298a59a5fb1b.vsidx +0 -0
  8. package/.vs/Aptolix-Chatbot/config/applicationhost.config +1011 -0
  9. package/.vs/Aptolix-Chatbot/copilot-chat/c320fb0f/sessions/48c7360b-028f-426c-b850-39c47706c316 +0 -0
  10. package/.vs/Aptolix-Chatbot/v17/.wsuo +0 -0
  11. package/.vs/Aptolix-Chatbot/v17/DocumentLayout.backup.json +62 -0
  12. package/.vs/Aptolix-Chatbot/v17/DocumentLayout.json +62 -0
  13. package/.vs/Aptolix-Chatbot-Widget/CopilotIndices/17.14.995.13737/CodeChunks.db +0 -0
  14. package/.vs/Aptolix-Chatbot-Widget/CopilotIndices/17.14.995.13737/SemanticSymbols.db +0 -0
  15. package/.vs/Aptolix-Chatbot-Widget/FileContentIndex/5d6b4f41-52da-4119-be44-2b20a4cefcd3.vsidx +0 -0
  16. package/.vs/Aptolix-Chatbot-Widget/FileContentIndex/c0c65d68-1df0-4f38-a40a-82ac4f5b0852.vsidx +0 -0
  17. package/.vs/Aptolix-Chatbot-Widget/FileContentIndex/c92407ec-f2a5-4d8d-a76e-b5b00ad5bb95.vsidx +0 -0
  18. package/.vs/Aptolix-Chatbot-Widget/FileContentIndex/cabcefbd-2c41-4e7f-817f-d3eb21b99197.vsidx +0 -0
  19. package/.vs/Aptolix-Chatbot-Widget/FileContentIndex/ebb08769-a636-4f23-aa30-03ee4e0170df.vsidx +0 -0
  20. package/.vs/Aptolix-Chatbot-Widget/config/applicationhost.config +1011 -0
  21. package/.vs/Aptolix-Chatbot-Widget/copilot-chat/c320fb0f/sessions/3189df6f-a527-48b1-8a59-6cbda8035079 +0 -0
  22. package/.vs/Aptolix-Chatbot-Widget/copilot-chat/c320fb0f/sessions/71a58fcf-f873-4b3b-96f4-7c23ed9008ff +0 -0
  23. package/.vs/Aptolix-Chatbot-Widget/v17/.wsuo +0 -0
  24. package/.vs/Aptolix-Chatbot-Widget/v17/DocumentLayout.backup.json +94 -0
  25. package/.vs/Aptolix-Chatbot-Widget/v17/DocumentLayout.json +93 -0
  26. package/.vs/Aptolix_Chatbot/CopilotIndices/17.14.995.13737/CodeChunks.db +0 -0
  27. package/.vs/Aptolix_Chatbot/CopilotIndices/17.14.995.13737/SemanticSymbols.db +0 -0
  28. package/.vs/Aptolix_Chatbot/FileContentIndex/8eb4f5c8-369a-4933-85d5-514cb280a707.vsidx +0 -0
  29. package/.vs/Aptolix_Chatbot/config/applicationhost.config +1011 -0
  30. package/.vs/Aptolix_Chatbot/copilot-chat/c320fb0f/sessions/a1e2cdd1-6164-49e1-930a-45581363790b +0 -0
  31. package/.vs/Aptolix_Chatbot/v17/.wsuo +0 -0
  32. package/.vs/Aptolix_Chatbot/v17/DocumentLayout.json +79 -0
  33. package/.vs/VSWorkspaceState.json +9 -0
  34. package/.vs/slnx.sqlite +0 -0
  35. package/dist/web.mjs +2 -0
  36. package/dist/web.mjs.map +1 -0
  37. package/package.json +18 -0
  38. package/rollup.config.js +22 -0
  39. package/src/chatbotstyle.css +384 -0
  40. package/src/index.js +282 -0
@@ -0,0 +1,384 @@
1
+ /* =========================
2
+ COMMON STYLES
3
+ ========================= */
4
+ #aptolix-chat-window {
5
+ font-family: 'Inter', sans-serif;
6
+ display: flex;
7
+ flex-direction: column;
8
+ overflow: hidden;
9
+ box-sizing: border-box;
10
+ background: #f6f3ff;
11
+ width: 100%;
12
+ height: 100%;
13
+ min-width: 0;
14
+ min-height: 0;
15
+ max-width: 100%;
16
+ max-height: 100%;
17
+ margin: 0;
18
+ border-radius: 16px;
19
+ box-shadow: 0 12px 40px rgba(167, 139, 250, 0.12);
20
+ border: 2.5px solid #9333ea;
21
+ }
22
+
23
+ #aptolix-chat-header {
24
+ font-weight: 600;
25
+ padding: 18px 16px 16px 16px;
26
+ font-size: 1.15rem;
27
+ border-bottom: 2px solid #ede9fe;
28
+ display: flex;
29
+ align-items: center;
30
+ justify-content: space-between;
31
+ background: #9333ea;
32
+ color: #fff;
33
+ }
34
+
35
+ .aptolix-header-title {
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: 2px;
39
+ justify-content: center;
40
+ }
41
+
42
+ .aptolix-header-subtitle {
43
+ font-size: 0.95rem;
44
+ color: #ede9fe;
45
+ font-weight: 400;
46
+ margin-top: 2px;
47
+ }
48
+
49
+ .aptolix-header-actions {
50
+ display: flex;
51
+ gap: 12px;
52
+ align-items: center; /* ensure buttons are vertically centered */
53
+ margin-top: 0; /* remove any margin that could push it down */
54
+ }
55
+
56
+ .aptolix-header-flex {
57
+ display: flex;
58
+ justify-content: space-between;
59
+ align-items: center;
60
+ width: 100%;
61
+ }
62
+
63
+ #aptolix-chat-messages {
64
+ flex: 1 1 auto;
65
+ min-height: 120px;
66
+ overflow-y: auto;
67
+ padding: 18px 16px 16px 16px;
68
+ background: #f6f3ff;
69
+ display: flex;
70
+ flex-direction: column;
71
+ gap: 6px;
72
+ }
73
+
74
+ .aptolix-powered-by {
75
+ text-align: center;
76
+ font-size: 0.95rem;
77
+ color: #a78bfa;
78
+ padding: 10px 0 8px 0;
79
+ background: transparent;
80
+ font-weight: 500;
81
+ letter-spacing: 0.02em;
82
+ }
83
+
84
+ .aptolix-powered-by .aptolix-link {
85
+ color: #9333ea;
86
+ text-decoration: underline;
87
+ font-weight: 600;
88
+ }
89
+
90
+ #aptolix-chat-input {
91
+ display: flex;
92
+ align-items: center;
93
+ gap: 8px;
94
+ padding: 14px 12px;
95
+ border-top: 2px solid #ede9fe;
96
+ background: #fff;
97
+ min-height: 56px;
98
+ }
99
+
100
+ #aptolix-chat-input input {
101
+ flex: 1 1 auto;
102
+ padding: 10px 14px;
103
+ border: 1.5px solid #d1d5db;
104
+ border-radius: 10px;
105
+ font-size: 1rem;
106
+ background: #f6f3ff;
107
+ color: #7c3aed;
108
+ transition: border 0.2s;
109
+ min-width: 0;
110
+ }
111
+
112
+ #aptolix-chat-input input:focus {
113
+ border-color: #a78bfa;
114
+ outline: none;
115
+ }
116
+
117
+ #aptolix-chat-input button {
118
+ background: #a78bfa;
119
+ color: #fff;
120
+ border: none;
121
+ border-radius: 10px;
122
+ padding: 8px 18px;
123
+ font-size: 1rem;
124
+ cursor: pointer;
125
+ font-weight: 600;
126
+ box-shadow: 0 2px 8px rgba(167, 139, 250, 0.10);
127
+ transition: background 0.2s, box-shadow 0.2s;
128
+ flex-shrink: 0;
129
+ }
130
+
131
+ #aptolix-chat-input button:hover {
132
+ background: #7c3aed;
133
+ box-shadow: 0 4px 16px rgba(124, 62, 237, 0.18);
134
+ }
135
+
136
+ #aptolix-chat-input button:not(:first-child) {
137
+ padding: 8px 12px;
138
+ font-size: 1.1rem;
139
+ background: rgba(167,139,250,0.12);
140
+ color: #9333ea;
141
+ border-radius: 8px;
142
+ box-shadow: none;
143
+ font-weight: 500;
144
+ }
145
+
146
+ #aptolix-chat-input button:not(:first-child):hover {
147
+ background: rgba(167,139,250,0.22);
148
+ color: #4b5563;
149
+ }
150
+
151
+ /* Message bubbles */
152
+ .message.user,
153
+ .message.bot {
154
+ display: block;
155
+ word-break: break-word;
156
+ max-width: 90%;
157
+ margin-bottom: 0;
158
+ font-family: 'Inter', sans-serif;
159
+ }
160
+
161
+ .message.user {
162
+ align-self: flex-end;
163
+ text-align: right;
164
+ color: #fff;
165
+ background: #a78bfa;
166
+ padding: 8px 14px;
167
+ border-radius: 14px 14px 4px 14px;
168
+ font-weight: 500;
169
+ box-shadow: 0 2px 8px rgba(167, 139, 250, 0.10);
170
+ }
171
+
172
+ .message.bot {
173
+ align-self: flex-start;
174
+ text-align: left;
175
+ color: #4b5563;
176
+ background: #ede9fe;
177
+ padding: 8px 14px;
178
+ border-radius: 14px 14px 14px 4px;
179
+ font-weight: 500;
180
+ box-shadow: 0 2px 8px rgba(167, 139, 250, 0.08);
181
+ }
182
+
183
+ .message.bot a {
184
+ color: #7c3aed;
185
+ text-decoration: underline;
186
+ word-break: break-all;
187
+ }
188
+
189
+ .message.bot strong, .message.bot b {
190
+ font-weight: 700;
191
+ color: #312e81;
192
+ }
193
+
194
+ .message.bot h1, .message.bot h2, .message.bot h3 {
195
+ margin: 10px 0 6px 0;
196
+ font-size: 1.3rem;
197
+ line-height: 1.2;
198
+ }
199
+ .message.bot h2 { font-size: 1.15rem; }
200
+ .message.bot h3 { font-size: 1.05rem; }
201
+
202
+ .message.bot p {
203
+ margin: 10px 0;
204
+ }
205
+
206
+ .message.bot ul, .message.bot ol {
207
+ margin: 8px 0 8px 18px;
208
+ padding-left: 18px;
209
+ }
210
+
211
+ .message.bot ul {
212
+ list-style: none;
213
+ padding-left: 0;
214
+ }
215
+
216
+ .message.bot ul li {
217
+ position: relative;
218
+ padding-left: 1.3em;
219
+ margin-bottom: 4px;
220
+ }
221
+
222
+ .message.bot ul li::before {
223
+ content: '';
224
+ position: absolute;
225
+ left: 0.3em;
226
+ top: 0.7em;
227
+ width: 0.5em;
228
+ height: 0.5em;
229
+ background: #9333ea;
230
+ border-radius: 50%;
231
+ display: inline-block;
232
+ }
233
+
234
+ .message.bot li {
235
+ margin-bottom: 4px;
236
+ }
237
+
238
+ .message.bot pre, .message.bot code {
239
+ margin: 8px 0;
240
+ padding: 4px 10px;
241
+ background: #f3f4f6;
242
+ border-radius: 6px;
243
+ font-size: 1em;
244
+ font-family: 'Fira Mono', 'Consolas', 'Monaco', monospace;
245
+ color: #7c3aed;
246
+ }
247
+ .message.bot pre {
248
+ padding: 12px 16px;
249
+ overflow-x: auto;
250
+ }
251
+
252
+ /* Typing indicator */
253
+ .typing-dots span {
254
+ animation: blink 1.2s infinite;
255
+ opacity: 0.5;
256
+ font-size: 1.5em;
257
+ margin-right: 2px;
258
+ }
259
+ .typing-dots span:nth-child(2) { animation-delay: 0.2s; }
260
+ .typing-dots span:nth-child(3) { animation-delay: 0.4s; }
261
+ @keyframes blink { 0%, 100% { opacity: 0.2; } 50% { opacity: 1; } }
262
+
263
+ /* =========================
264
+ BUBBLE MODE STYLES
265
+ ========================= */
266
+ #aptolix-chat-bubble {
267
+ position: fixed;
268
+ bottom: 32px;
269
+ right: 32px;
270
+ width: 56px;
271
+ height: 56px;
272
+ background: #9333ea;
273
+ color: #fff;
274
+ font-size: 2rem;
275
+ border-radius: 50%;
276
+ box-shadow: 0 6px 24px rgba(167, 139, 250, 0.18);
277
+ display: flex;
278
+ align-items: center;
279
+ justify-content: center;
280
+ cursor: pointer;
281
+ z-index: 9999;
282
+ transition: background 0.2s, box-shadow 0.2s;
283
+ }
284
+
285
+ #aptolix-chat-bubble:hover {
286
+ background: #7c3aed;
287
+ box-shadow: 0 8px 32px rgba(124, 62, 237, 0.28);
288
+ }
289
+
290
+ #aptolix-chat-window.bubble-mode {
291
+ position: fixed;
292
+ bottom: 100px;
293
+ right: 32px;
294
+ width: 400px;
295
+ height: 595px;
296
+ min-height: 595px;
297
+ max-height: 80vh;
298
+ border-radius: 16px;
299
+ z-index: 9999;
300
+ }
301
+
302
+ /* =========================
303
+ SECTION MODE STYLES
304
+ ========================= */
305
+ #aptolix-chat-window.section-mode {
306
+ position: static !important;
307
+ width: 100%;
308
+ height: 100%;
309
+ max-width: 100%;
310
+ max-height: 100%;
311
+ border-radius: 18px;
312
+ box-shadow: 0 4px 24px rgba(167, 139, 250, 0.10);
313
+ border: 2px solid #a78bfa;
314
+ }
315
+
316
+ #aptolix-chat-window.section-mode #aptolix-chat-header {
317
+ background: #9333ea;
318
+ color: #fff;
319
+ }
320
+
321
+ /* Hide bubble and controls in section mode */
322
+ #aptolix-chat-window.section-mode ~ #aptolix-chat-bubble,
323
+ #aptolix-chat-window.section-mode #aptolix-chat-close,
324
+ #aptolix-chat-window.section-mode #aptolix-chat-expand {
325
+ display: none !important;
326
+ }
327
+
328
+ /* Section mode message tweaks */
329
+ #aptolix-chat-window.section-mode .message.user {
330
+ background: #a78bfa;
331
+ color: #fff;
332
+ }
333
+ #aptolix-chat-window.section-mode .message.bot {
334
+ background: #ede9fe;
335
+ color: #4b5563;
336
+ }
337
+
338
+ /* Section mode messages area */
339
+ #aptolix-chat-window.section-mode #aptolix-chat-messages {
340
+ background: #f6f3ff;
341
+ padding: 20px 18px 18px 18px;
342
+ }
343
+
344
+ /* =========================
345
+ RESPONSIVE
346
+ ========================= */
347
+ @media (max-width: 600px) {
348
+ #aptolix-chat-window,
349
+ #aptolix-chat-window.section-mode,
350
+ #aptolix-chat-window.bubble-mode {
351
+ border-radius: 12px;
352
+ padding: 0;
353
+ min-height: 180px;
354
+ width: 100vw;
355
+ max-width: 100vw;
356
+ }
357
+ #aptolix-chat-header {
358
+ font-size: 1rem;
359
+ padding: 10px 6px 8px 6px;
360
+ }
361
+ #aptolix-chat-messages {
362
+ padding: 8px 4px 6px 4px;
363
+ }
364
+ #aptolix-chat-input {
365
+ padding: 6px 2px;
366
+ }
367
+ }
368
+
369
+ .aptolix-retry-btn {
370
+ margin-top: 8px;
371
+ padding: 4px 12px;
372
+ background: #ede9fe;
373
+ color: #7c3aed;
374
+ border: none;
375
+ border-radius: 6px;
376
+ cursor: pointer;
377
+ font-weight: 600;
378
+ }
379
+ .aptolix-retry-btn:hover {
380
+ background: #d8b4fe;
381
+ }
382
+
383
+
384
+
package/src/index.js ADDED
@@ -0,0 +1,282 @@
1
+ import { marked } from "marked";
2
+ import './chatbotstyle.css';
3
+
4
+ const AptolixChatbot = {
5
+ init: ({ apiHost, chatflowid, title, subtitle, greeting, mode = "bubble", target }) => {
6
+
7
+ const modeClass = mode === "section" ? "section-mode" : "bubble-mode";
8
+
9
+ let bubble;
10
+ if (mode === "bubble") {
11
+ bubble = document.createElement('div');
12
+ bubble.id = "aptolix-chat-bubble";
13
+ bubble.innerText = "💬";
14
+ document.body.appendChild(bubble);
15
+ }
16
+
17
+ const chatWindow = document.createElement('div');
18
+ chatWindow.id = "aptolix-chat-window";
19
+ chatWindow.classList.add(modeClass);
20
+ chatWindow.style.display = mode === "section" ? "flex" : "none";
21
+
22
+ if (mode === "section" && target) {
23
+ const targetEl = typeof target === "string" ? document.querySelector(target) : target;
24
+ if (targetEl) targetEl.appendChild(chatWindow);
25
+ else document.body.appendChild(chatWindow);
26
+ } else {
27
+ document.body.appendChild(chatWindow);
28
+ }
29
+
30
+ chatWindow.innerHTML = `
31
+ <div id="aptolix-chat-header">
32
+ <div class="aptolix-header-flex">
33
+ <div class="aptolix-header-title">
34
+ <strong>${title || "Assistant"}</strong>
35
+ ${subtitle ? `<div class="aptolix-header-subtitle">${subtitle}</div>` : ""}
36
+ </div>
37
+ <div class="aptolix-header-actions">
38
+ <button id="aptolix-chat-reset" title="Clear chat" aria-label="Clear chat">⟲</button>
39
+ <button id="aptolix-chat-expand" title="Expand/Collapse" aria-label="Expand/Collapse">
40
+ <span id="aptolix-chat-expand-icon">⤢</span>
41
+ </button>
42
+ <button id="aptolix-chat-close" title="Close chat" aria-label="Close chat">×</button>
43
+ </div>
44
+ </div>
45
+ </div>
46
+ <div id="aptolix-chat-messages"></div>
47
+ <div id="aptolix-chat-input">
48
+ <textarea id="aptolix-chat-inputbox" rows="1" placeholder="Type your message..." style="resize:none"></textarea>
49
+ <button>Send</button>
50
+ </div>
51
+ <div class="aptolix-powered-by">
52
+ Powered by <a href="https://aptolix.com" target="_blank" rel="noopener" class="aptolix-link">Aptolix</a>
53
+ </div>
54
+ `;
55
+
56
+ const closeBtn = chatWindow.querySelector("#aptolix-chat-close");
57
+ const resetBtn = chatWindow.querySelector("#aptolix-chat-reset");
58
+ const expandBtn = chatWindow.querySelector("#aptolix-chat-expand");
59
+ const expandIcon = chatWindow.querySelector("#aptolix-chat-expand-icon");
60
+ const input = chatWindow.querySelector("#aptolix-chat-inputbox");
61
+ const sendButton = chatWindow.querySelector("button");
62
+ const messagesDiv = chatWindow.querySelector("#aptolix-chat-messages");
63
+
64
+ if (mode === "bubble") {
65
+ closeBtn.addEventListener("click", () => {
66
+ chatWindow.style.display = "none";
67
+ });
68
+ }
69
+
70
+ resetBtn.addEventListener("click", () => {
71
+ messagesDiv.innerHTML = "";
72
+ input.value = "";
73
+ showGreeting(); // Show greeting after reset
74
+ });
75
+
76
+ if (mode === "bubble" && bubble) {
77
+ bubble.addEventListener("click", () => {
78
+ const wasClosed = chatWindow.style.display === "none";
79
+ chatWindow.style.display = wasClosed ? "flex" : "none";
80
+ bubble.removeAttribute("data-unread");
81
+ if (wasClosed) showGreeting();
82
+ });
83
+ }
84
+
85
+ if (mode === "bubble") {
86
+ document.addEventListener("mousedown", function onOutsideClick(event) {
87
+ if (chatWindow.style.display !== "none") {
88
+ if (
89
+ !chatWindow.contains(event.target) &&
90
+ !bubble.contains(event.target)
91
+ ) {
92
+ chatWindow.style.display = "none";
93
+ }
94
+ }
95
+ });
96
+ }
97
+
98
+ async function sendMessage(isRetry = false, previousText = null) {
99
+ const userText = previousText || input.value.trim();
100
+ if (!userText) return;
101
+ if (!isRetry) input.value = "";
102
+
103
+ if (!isRetry) {
104
+ const userMsg = document.createElement("div");
105
+ userMsg.className = "message user";
106
+ userMsg.innerText = userText;
107
+ messagesDiv.appendChild(userMsg);
108
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
109
+ }
110
+
111
+ const typingMsg = document.createElement("div");
112
+ typingMsg.className = "message bot typing";
113
+ typingMsg.innerHTML = `<span class="typing-dots"><span>.</span><span>.</span><span>.</span></span>`;
114
+ messagesDiv.appendChild(typingMsg);
115
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
116
+
117
+ function showError() {
118
+ typingMsg.remove();
119
+ const errorMsg = document.createElement("div");
120
+ errorMsg.className = "message bot error";
121
+ errorMsg.innerHTML = `
122
+ <div>
123
+ <strong>⚠️ Unable to connect to the assistant.</strong><br>
124
+ Please check your internet connection or try again later.
125
+ </div>
126
+ <button class="aptolix-retry-btn">Retry</button>
127
+ `;
128
+ messagesDiv.appendChild(errorMsg);
129
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
130
+
131
+ const retryBtn = errorMsg.querySelector('.aptolix-retry-btn');
132
+ if (retryBtn) {
133
+ retryBtn.addEventListener('click', () => {
134
+ errorMsg.remove();
135
+ sendMessage(true, userText);
136
+ });
137
+ }
138
+ }
139
+
140
+ try {
141
+ const res = await fetch(`${apiHost}${chatflowid}`, {
142
+ method: "POST",
143
+ headers: { "Content-Type": "application/json" },
144
+ body: JSON.stringify({ question: userText }),
145
+ });
146
+ const data = await res.json();
147
+
148
+ typingMsg.remove();
149
+
150
+ const botMsg = document.createElement("div");
151
+ botMsg.className = "message bot";
152
+ botMsg.innerHTML = marked.parse(data.text || "[No response]");
153
+ messagesDiv.appendChild(botMsg);
154
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
155
+
156
+ if (mode === "bubble" && chatWindow.style.display === "none") {
157
+ bubble.setAttribute("data-unread", "true");
158
+ }
159
+ } catch (err) {
160
+ showError();
161
+ if (mode === "bubble" && chatWindow.style.display === "none") {
162
+ bubble.setAttribute("data-unread", "true");
163
+ }
164
+ }
165
+ }
166
+
167
+ // Limit to 5 lines
168
+ input.addEventListener("keydown", (e) => {
169
+ const lines = input.value.split('\n');
170
+ if (e.key === "Enter") {
171
+ if (lines.length >= 5) {
172
+ e.preventDefault();
173
+ }
174
+ }
175
+ });
176
+
177
+ // Send on Ctrl+Enter or button click
178
+ sendButton.addEventListener("click", () => sendMessage());
179
+ input.addEventListener("keydown", (e) => {
180
+ const lines = input.value.split('\n');
181
+ if ((e.key === "Enter" && e.ctrlKey) || (e.key === "Enter" && lines.length >= 5)) {
182
+ e.preventDefault();
183
+ sendMessage();
184
+ }
185
+ });
186
+
187
+ let expanded = false;
188
+ if (mode === "bubble") {
189
+ expandBtn.addEventListener("click", () => {
190
+ expanded = !expanded;
191
+ if (expanded) {
192
+ chatWindow.style.width = "600px";
193
+ chatWindow.style.height = "80vh";
194
+ expandIcon.textContent = "⤡";
195
+ } else {
196
+ chatWindow.style.width = "400px";
197
+ chatWindow.style.height = "595px";
198
+ expandIcon.textContent = "⤢";
199
+ }
200
+ });
201
+ }
202
+
203
+ function showGreeting() {
204
+ // Remove any previous greeting messages
205
+ messagesDiv.querySelectorAll('.message.greeting').forEach(el => el.remove());
206
+ const greetMsg = greeting || "<strong>👋 Howdy, </strong>How can I help you today?";
207
+ const greetingDiv = document.createElement("div");
208
+ greetingDiv.className = "message bot greeting";
209
+ greetingDiv.innerHTML = greetMsg;
210
+ messagesDiv.appendChild(greetingDiv);
211
+ messagesDiv.scrollTop = messagesDiv.scrollHeight;
212
+ }
213
+ setTimeout(showGreeting, 100);
214
+ },
215
+ initFull: function(options) {
216
+ let el = document.querySelector('aptolix-chatbot');
217
+ if (!el) {
218
+ console.warn('No <aptolix-chatbot> element found in the DOM.');
219
+ return;
220
+ }
221
+ Object.entries(options).forEach(([key, value]) => {
222
+ el.setAttribute(key, value);
223
+ });
224
+ }
225
+ };
226
+
227
+ // Custom element for section embedding
228
+ class AptolixChatbotElement extends HTMLElement {
229
+ static get observedAttributes() {
230
+ return ['apiHost', 'chatflowid', 'title', 'greeting', 'subtitle', 'target'];
231
+ }
232
+
233
+ connectedCallback() {
234
+ this.tryInit();
235
+ }
236
+
237
+ attributeChangedCallback() {
238
+ // Remove previous chat window if present
239
+ const existingChatWindow = this.querySelector('#aptolix-chat-window');
240
+ if (existingChatWindow) existingChatWindow.remove();
241
+ // Re-initialize to update greeting and other attributes
242
+ this._initialized = false;
243
+ this.tryInit();
244
+ }
245
+
246
+ tryInit() {
247
+ const apiHost = this.getAttribute('apiHost');
248
+ const chatflowid = this.getAttribute('chatflowid');
249
+ if (!apiHost || !chatflowid) return;
250
+
251
+ const title = this.getAttribute('title') || "Aptolix Assistant";
252
+ const greeting = this.getAttribute('greeting');
253
+ const subtitle = this.getAttribute('subtitle');
254
+ const targetAttr = this.getAttribute('target');
255
+ let target = this;
256
+ if (targetAttr) {
257
+ const found = document.querySelector(targetAttr);
258
+ if (found) target = found;
259
+ }
260
+
261
+ if (this._initialized) return;
262
+ this._initialized = true;
263
+
264
+ AptolixChatbot.init({
265
+ apiHost,
266
+ chatflowid,
267
+ title,
268
+ subtitle,
269
+ greeting,
270
+ mode: "section",
271
+ target
272
+ });
273
+ }
274
+ }
275
+ customElements.define('aptolix-chatbot', AptolixChatbotElement);
276
+
277
+ // Export as default so consumers use Chatbot.init and Chatbot.initFull
278
+ export default AptolixChatbot;
279
+
280
+
281
+
282
+