wakz-chat-widget 2.2.0 → 4.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.
- package/index.js +834 -456
- package/package.json +1 -38
- package/README.md +0 -71
package/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WAKZ Chat Widget
|
|
2
|
+
* WAKZ Chat Widget v4.0.0
|
|
3
3
|
* ─────────────────────────────────────────────────────────────────
|
|
4
4
|
* A production-grade, self-contained chat widget using Shadow DOM.
|
|
5
|
-
*
|
|
5
|
+
* Liquid Glass design — pill header, floating input, dark user bubbles.
|
|
6
6
|
*
|
|
7
7
|
* Embed: <script src="/wakz-widget.js" data-api-key="xxx" data-server="https://..." async></script>
|
|
8
8
|
*
|
|
@@ -127,17 +127,24 @@
|
|
|
127
127
|
return fetch(url, merged).finally(function () { clearTimeout(timer); });
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
+
/** XSS-safe: escape HTML entities */
|
|
131
|
+
function _escapeHTML(str) {
|
|
132
|
+
var div = document.createElement('div');
|
|
133
|
+
div.appendChild(document.createTextNode(str));
|
|
134
|
+
return div.innerHTML;
|
|
135
|
+
}
|
|
136
|
+
|
|
130
137
|
/* ════════════════════════════════════════════════════════════════
|
|
131
138
|
SVG ICONS (inline for zero-dependency)
|
|
132
139
|
════════════════════════════════════════════════════════════════ */
|
|
133
140
|
|
|
134
141
|
var _ICONS = {
|
|
135
142
|
chatBubble:
|
|
136
|
-
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21
|
|
143
|
+
'<svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>',
|
|
137
144
|
send:
|
|
138
|
-
'<svg viewBox="0 0 24 24" fill="
|
|
145
|
+
'<svg width="18" height="18" viewBox="0 0 24 24" fill="none"><path d="M19 12H5M5 12L11 6M5 12L11 18" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg>',
|
|
139
146
|
close:
|
|
140
|
-
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"
|
|
147
|
+
'<svg width="14" height="14" viewBox="0 0 24 24" fill="none"><line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/><line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="2.5" stroke-linecap="round"/></svg>',
|
|
141
148
|
error:
|
|
142
149
|
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/></svg>'
|
|
143
150
|
};
|
|
@@ -149,7 +156,7 @@
|
|
|
149
156
|
var _I18N = {
|
|
150
157
|
ar: {
|
|
151
158
|
placeholder: 'اكتب رسالتك...',
|
|
152
|
-
online: 'متصل',
|
|
159
|
+
online: 'متصل الآن',
|
|
153
160
|
offline: 'غير متصل',
|
|
154
161
|
errorMsg: 'حدث خطأ في الاتصال. يرجى المحاولة مرة أخرى.',
|
|
155
162
|
retry: 'إعادة المحاولة',
|
|
@@ -157,7 +164,8 @@
|
|
|
157
164
|
openChat: 'فتح المحادثة',
|
|
158
165
|
closeChat: 'إغلاق المحادثة',
|
|
159
166
|
sendMessage: 'إرسال',
|
|
160
|
-
humanBadge: '
|
|
167
|
+
humanBadge: 'فريق الدعم',
|
|
168
|
+
defaultSubtitle: 'المساعد الذكي'
|
|
161
169
|
},
|
|
162
170
|
en: {
|
|
163
171
|
placeholder: 'Type your message...',
|
|
@@ -169,7 +177,8 @@
|
|
|
169
177
|
openChat: 'Open chat',
|
|
170
178
|
closeChat: 'Close chat',
|
|
171
179
|
sendMessage: 'Send',
|
|
172
|
-
humanBadge: '
|
|
180
|
+
humanBadge: 'Support Team',
|
|
181
|
+
defaultSubtitle: 'Smart Assistant'
|
|
173
182
|
},
|
|
174
183
|
fr: {
|
|
175
184
|
placeholder: 'Tapez votre message...',
|
|
@@ -181,7 +190,8 @@
|
|
|
181
190
|
openChat: 'Ouvrir le chat',
|
|
182
191
|
closeChat: 'Fermer le chat',
|
|
183
192
|
sendMessage: 'Envoyer',
|
|
184
|
-
humanBadge: '
|
|
193
|
+
humanBadge: 'Équipe de support',
|
|
194
|
+
defaultSubtitle: 'Assistant intelligent'
|
|
185
195
|
}
|
|
186
196
|
};
|
|
187
197
|
|
|
@@ -195,10 +205,11 @@
|
|
|
195
205
|
|
|
196
206
|
var _DEFAULTS = {
|
|
197
207
|
botName: 'WAKZ',
|
|
208
|
+
botSubtitle: '',
|
|
198
209
|
welcomeMessage: '',
|
|
199
|
-
primaryColor: '#
|
|
200
|
-
chatBg: '#
|
|
201
|
-
btnColor: '#
|
|
210
|
+
primaryColor: '#111111',
|
|
211
|
+
chatBg: '#ffffff',
|
|
212
|
+
btnColor: '#111111',
|
|
202
213
|
widgetBg: '#ffffff',
|
|
203
214
|
position: 'bottom-right',
|
|
204
215
|
language: 'en',
|
|
@@ -222,7 +233,7 @@
|
|
|
222
233
|
self.apiKey = attrs.apiKey;
|
|
223
234
|
self.server = attrs.server;
|
|
224
235
|
self.visitorId = _getVisitorId();
|
|
225
|
-
self._deviceInfo = _getDeviceInfo();
|
|
236
|
+
self._deviceInfo = _getDeviceInfo();
|
|
226
237
|
|
|
227
238
|
/* ── Runtime state ── */
|
|
228
239
|
self.config = Object.assign({}, _DEFAULTS);
|
|
@@ -235,22 +246,28 @@
|
|
|
235
246
|
self._configError = false;
|
|
236
247
|
self._pollTimer = null;
|
|
237
248
|
self._lastPollTime = null;
|
|
238
|
-
self._POLL_INTERVAL = 4000;
|
|
239
|
-
self._knownMessageIds = {};
|
|
240
|
-
self._pendingReply = false;
|
|
249
|
+
self._POLL_INTERVAL = 4000;
|
|
250
|
+
self._knownMessageIds = {};
|
|
251
|
+
self._pendingReply = false;
|
|
241
252
|
|
|
242
253
|
/* ── DOM refs (populated after mount) ── */
|
|
243
254
|
self._host = null;
|
|
244
255
|
self._shadow = null;
|
|
245
256
|
self._root = null;
|
|
257
|
+
self._overlay = null;
|
|
246
258
|
self._chatWindow = null;
|
|
247
|
-
self.
|
|
259
|
+
self._messagesInner = null;
|
|
260
|
+
self._inputWrap = null;
|
|
248
261
|
self._inputEl = null;
|
|
249
262
|
self._sendBtn = null;
|
|
250
263
|
self._toggleBtn = null;
|
|
251
264
|
self._statusDot = null;
|
|
265
|
+
self._headerTitleEl = null;
|
|
266
|
+
self._headerSubtitleEl = null;
|
|
267
|
+
self._headerStatusPill = null;
|
|
252
268
|
self._headerStatusDot = null;
|
|
253
269
|
self._headerStatusText = null;
|
|
270
|
+
self._closeBtn = null;
|
|
254
271
|
|
|
255
272
|
/* ── Bootstrap ── */
|
|
256
273
|
self._injectCSS();
|
|
@@ -261,7 +278,7 @@
|
|
|
261
278
|
}
|
|
262
279
|
|
|
263
280
|
/* ════════════════════════════════════════════════════════════════
|
|
264
|
-
CSS — Complete
|
|
281
|
+
CSS — Complete Liquid Glass design (v4.0.0)
|
|
265
282
|
════════════════════════════════════════════════════════════════ */
|
|
266
283
|
|
|
267
284
|
WAKZWidget.prototype._injectCSS = function () {
|
|
@@ -271,21 +288,12 @@
|
|
|
271
288
|
self._styleEl.textContent = [
|
|
272
289
|
/* ── CSS Custom Properties (theming) ── */
|
|
273
290
|
':host {',
|
|
274
|
-
' --wakz-primary: #
|
|
275
|
-
' --wakz-btn: #
|
|
276
|
-
' --wakz-chat-bg: #
|
|
291
|
+
' --wakz-primary: #111111;',
|
|
292
|
+
' --wakz-btn: #111111;',
|
|
293
|
+
' --wakz-chat-bg: #ffffff;',
|
|
277
294
|
' --wakz-widget-bg: #ffffff;',
|
|
278
|
-
' --wakz-radius-window: 16px;',
|
|
279
|
-
' --wakz-radius-bubble: 16px;',
|
|
280
|
-
' --wakz-radius-fab: 28px;',
|
|
281
|
-
' --wakz-shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);',
|
|
282
|
-
' --wakz-shadow-md: 0 4px 12px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06);',
|
|
283
|
-
' --wakz-shadow-lg: 0 12px 40px rgba(0,0,0,.15), 0 4px 12px rgba(0,0,0,.1);',
|
|
284
|
-
' --wakz-shadow-xl: 0 20px 60px rgba(0,0,0,.2), 0 8px 20px rgba(0,0,0,.12);',
|
|
285
|
-
' --wakz-transition: 200ms ease;',
|
|
286
|
-
' --wakz-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;',
|
|
287
295
|
' all: initial;',
|
|
288
|
-
' font-family:
|
|
296
|
+
' font-family: "Cairo", "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;',
|
|
289
297
|
'}',
|
|
290
298
|
|
|
291
299
|
/* ── Reset ── */
|
|
@@ -296,312 +304,486 @@
|
|
|
296
304
|
'}',
|
|
297
305
|
|
|
298
306
|
/* ══════════════════════════════════════════════════
|
|
299
|
-
|
|
307
|
+
ANIMATIONS
|
|
308
|
+
══════════════════════════════════════════════════ */
|
|
309
|
+
'@keyframes wakz-fade-slide-up {',
|
|
310
|
+
' from { opacity: 0; transform: translateY(6px); }',
|
|
311
|
+
' to { opacity: 1; transform: translateY(0); }',
|
|
312
|
+
'}',
|
|
313
|
+
|
|
314
|
+
'@keyframes wakz-typing-bounce {',
|
|
315
|
+
' 0%, 60%, 100% { transform: translateY(0); opacity: 0.35; }',
|
|
316
|
+
' 30% { transform: translateY(-4px); opacity: 1; }',
|
|
317
|
+
'}',
|
|
318
|
+
|
|
319
|
+
'@keyframes wakz-pulse-green {',
|
|
320
|
+
' 0%, 100% { box-shadow: 0 0 0 2px rgba(34,197,94,0.2); }',
|
|
321
|
+
' 50% { box-shadow: 0 0 0 4px rgba(34,197,94,0.08); }',
|
|
322
|
+
'}',
|
|
323
|
+
|
|
324
|
+
'@keyframes wakz-fab-enter {',
|
|
325
|
+
' 0% { opacity: 0; transform: scale(0.3); }',
|
|
326
|
+
' 50% { opacity: 1; transform: scale(1.12); }',
|
|
327
|
+
' 70% { transform: scale(0.92); }',
|
|
328
|
+
' 100% { transform: scale(1); }',
|
|
329
|
+
'}',
|
|
330
|
+
|
|
331
|
+
/* ══════════════════════════════════════════════════
|
|
332
|
+
FLOATING ACTION BUTTON (FAB) — 56px black circle
|
|
300
333
|
══════════════════════════════════════════════════ */
|
|
301
334
|
'.wakz-fab {',
|
|
302
335
|
' position: fixed;',
|
|
303
336
|
' z-index: 2147483647;',
|
|
304
337
|
' width: 56px;',
|
|
305
338
|
' height: 56px;',
|
|
306
|
-
' border-radius:
|
|
339
|
+
' border-radius: 50%;',
|
|
307
340
|
' border: none;',
|
|
308
341
|
' cursor: pointer;',
|
|
309
342
|
' display: flex;',
|
|
310
343
|
' align-items: center;',
|
|
311
344
|
' justify-content: center;',
|
|
312
|
-
'
|
|
313
|
-
'
|
|
345
|
+
' color: #ffffff;',
|
|
346
|
+
' background: var(--wakz-btn);',
|
|
347
|
+
' box-shadow: 0 4px 20px rgba(0,0,0,0.2), 0 1px 6px rgba(0,0,0,0.12);',
|
|
348
|
+
' transition: transform 0.3s cubic-bezier(0.22,1,0.36,1), box-shadow 0.3s cubic-bezier(0.22,1,0.36,1);',
|
|
314
349
|
' outline: none;',
|
|
315
350
|
' -webkit-tap-highlight-color: transparent;',
|
|
316
|
-
' background: var(--wakz-btn);',
|
|
317
351
|
'}',
|
|
318
352
|
'.wakz-fab:hover {',
|
|
319
|
-
' transform: scale(1.
|
|
320
|
-
' box-shadow:
|
|
321
|
-
'}',
|
|
322
|
-
'.wakz-fab:active {',
|
|
323
|
-
' transform: scale(0.96);',
|
|
324
|
-
'}',
|
|
325
|
-
'.wakz-fab svg {',
|
|
326
|
-
' width: 26px;',
|
|
327
|
-
' height: 26px;',
|
|
328
|
-
' color: #ffffff;',
|
|
329
|
-
' pointer-events: none;',
|
|
353
|
+
' transform: scale(1.1);',
|
|
354
|
+
' box-shadow: 0 6px 28px rgba(0,0,0,0.25), 0 2px 8px rgba(0,0,0,0.15);',
|
|
330
355
|
'}',
|
|
356
|
+
'.wakz-fab:active { transform: scale(0.93); }',
|
|
357
|
+
'.wakz-fab svg { width: 26px; height: 26px; color: #fff; pointer-events: none; }',
|
|
331
358
|
|
|
332
359
|
/* ── FAB Positioning ── */
|
|
333
360
|
'.wakz-fab-pos-br { bottom: 24px; right: 24px; }',
|
|
334
361
|
'.wakz-fab-pos-bl { bottom: 24px; left: 24px; }',
|
|
335
362
|
|
|
336
|
-
/* ── FAB
|
|
337
|
-
'
|
|
338
|
-
'
|
|
339
|
-
'
|
|
340
|
-
' 70% { transform: scale(0.92); }',
|
|
341
|
-
' 100% { transform: scale(1); }',
|
|
363
|
+
/* ── Hide FAB when chat is open ── */
|
|
364
|
+
'.wakz-window.wakz-visible ~ .wakz-fab,',
|
|
365
|
+
'.wakz-fab.wakz-fab-hidden {',
|
|
366
|
+
' display: none !important;',
|
|
342
367
|
'}',
|
|
368
|
+
|
|
369
|
+
/* ── FAB Entrance Bounce ── */
|
|
343
370
|
'.wakz-fab-enter {',
|
|
344
|
-
' animation: wakz-fab-enter 0.6s cubic-bezier(0.34,
|
|
371
|
+
' animation: wakz-fab-enter 0.6s cubic-bezier(0.34,1.56,0.64,1) forwards;',
|
|
345
372
|
'}',
|
|
346
373
|
|
|
347
374
|
/* ══════════════════════════════════════════════════
|
|
348
|
-
STATUS DOT (on FAB)
|
|
375
|
+
STATUS DOT (on FAB) — 10px, top-right
|
|
349
376
|
══════════════════════════════════════════════════ */
|
|
350
377
|
'.wakz-fab-dot {',
|
|
351
378
|
' position: absolute;',
|
|
352
|
-
' top:
|
|
353
|
-
' right:
|
|
354
|
-
' width:
|
|
355
|
-
' height:
|
|
379
|
+
' top: -1px;',
|
|
380
|
+
' right: -1px;',
|
|
381
|
+
' width: 10px;',
|
|
382
|
+
' height: 10px;',
|
|
356
383
|
' border-radius: 50%;',
|
|
357
|
-
' border:
|
|
384
|
+
' border: 2px solid #ffffff;',
|
|
358
385
|
' z-index: 2;',
|
|
359
386
|
' transition: background 0.3s ease;',
|
|
360
387
|
'}',
|
|
361
|
-
'.wakz-fab-pos-bl .wakz-fab-dot {',
|
|
362
|
-
' right: auto;',
|
|
363
|
-
' left: 0px;',
|
|
364
|
-
'}',
|
|
365
|
-
|
|
366
|
-
/* ── Online (green pulse) ── */
|
|
388
|
+
'.wakz-fab-pos-bl .wakz-fab-dot { right: auto; left: -1px; }',
|
|
367
389
|
'.wakz-fab-dot.online {',
|
|
368
390
|
' background: #22c55e;',
|
|
391
|
+
' animation: wakz-pulse-green 2.5s ease-in-out infinite;',
|
|
369
392
|
'}',
|
|
370
|
-
'@keyframes wakz-dot-pulse {',
|
|
371
|
-
' 0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.5); }',
|
|
372
|
-
' 50% { box-shadow: 0 0 0 6px rgba(34,197,94,0); }',
|
|
373
|
-
'}',
|
|
374
|
-
'.wakz-fab-dot.online {',
|
|
375
|
-
' animation: wakz-dot-pulse 2s ease-in-out infinite;',
|
|
376
|
-
'}',
|
|
377
|
-
|
|
378
|
-
/* ── Offline (red, no pulse) ── */
|
|
379
393
|
'.wakz-fab-dot.offline {',
|
|
380
394
|
' background: #ef4444;',
|
|
381
395
|
' animation: none;',
|
|
382
396
|
'}',
|
|
383
397
|
|
|
384
|
-
/*
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
'
|
|
398
|
+
/* ══════════════════════════════════════════════════
|
|
399
|
+
OVERLAY / BACKDROP — blur behind modal
|
|
400
|
+
══════════════════════════════════════════════════ */
|
|
401
|
+
'.wakz-overlay {',
|
|
402
|
+
' position: fixed;',
|
|
403
|
+
' inset: 0;',
|
|
404
|
+
' z-index: 2147483645;',
|
|
405
|
+
' background: rgba(0,0,0,0.25);',
|
|
406
|
+
' backdrop-filter: blur(4px);',
|
|
407
|
+
' -webkit-backdrop-filter: blur(4px);',
|
|
408
|
+
' opacity: 0;',
|
|
409
|
+
' pointer-events: none;',
|
|
410
|
+
' transition: opacity 0.3s cubic-bezier(0.4,0,0.2,1);',
|
|
411
|
+
'}',
|
|
412
|
+
'.wakz-overlay.wakz-visible {',
|
|
413
|
+
' opacity: 1;',
|
|
414
|
+
' pointer-events: auto;',
|
|
388
415
|
'}',
|
|
389
416
|
|
|
390
417
|
/* ══════════════════════════════════════════════════
|
|
391
|
-
CHAT WINDOW
|
|
418
|
+
CHAT WINDOW — Centered, 420x560, 24px radius
|
|
392
419
|
══════════════════════════════════════════════════ */
|
|
393
420
|
'.wakz-window {',
|
|
394
421
|
' position: fixed;',
|
|
395
422
|
' z-index: 2147483646;',
|
|
396
|
-
'
|
|
397
|
-
'
|
|
398
|
-
'
|
|
399
|
-
'
|
|
423
|
+
' top: 50%;',
|
|
424
|
+
' left: 50%;',
|
|
425
|
+
' transform: translate(-50%, -50%) scale(0.95);',
|
|
426
|
+
' width: 420px;',
|
|
427
|
+
' height: 560px;',
|
|
428
|
+
' max-width: calc(100vw - 24px);',
|
|
429
|
+
' max-height: calc(100vh - 24px);',
|
|
430
|
+
' border-radius: 24px;',
|
|
400
431
|
' overflow: hidden;',
|
|
401
432
|
' display: flex;',
|
|
402
433
|
' flex-direction: column;',
|
|
403
434
|
' background: var(--wakz-widget-bg);',
|
|
404
|
-
' box-shadow:
|
|
435
|
+
' box-shadow:',
|
|
436
|
+
' 0 0 0 0.5px rgba(0,0,0,0.06),',
|
|
437
|
+
' 0 8px 40px rgba(0,0,0,0.08),',
|
|
438
|
+
' 0 2px 12px rgba(0,0,0,0.04);',
|
|
405
439
|
' opacity: 0;',
|
|
406
|
-
' transform: translateY(20px) scale(0.95);',
|
|
407
440
|
' pointer-events: none;',
|
|
408
|
-
' transition: opacity 0.3s cubic-bezier(0.4,
|
|
409
|
-
' transform 0.3s cubic-bezier(0.4,
|
|
441
|
+
' transition: opacity 0.3s cubic-bezier(0.4,0,0.2,1),',
|
|
442
|
+
' transform 0.3s cubic-bezier(0.4,0,0.2,1);',
|
|
410
443
|
'}',
|
|
411
444
|
'.wakz-window.wakz-visible {',
|
|
412
445
|
' opacity: 1;',
|
|
413
|
-
' transform:
|
|
446
|
+
' transform: translate(-50%, -50%) scale(1);',
|
|
414
447
|
' pointer-events: auto;',
|
|
415
448
|
'}',
|
|
416
449
|
|
|
417
|
-
/* ── Window Positioning ── */
|
|
418
|
-
'.wakz-win-pos-br { bottom: 92px; right: 24px; }',
|
|
419
|
-
'.wakz-win-pos-bl { bottom: 92px; left: 24px; }',
|
|
420
|
-
|
|
421
450
|
/* ══════════════════════════════════════════════════
|
|
422
|
-
HEADER
|
|
451
|
+
FLOATING HEADER WRAP — absolute over messages
|
|
423
452
|
══════════════════════════════════════════════════ */
|
|
424
|
-
'.wakz-
|
|
425
|
-
'
|
|
426
|
-
'
|
|
453
|
+
'.wakz-header-wrap {',
|
|
454
|
+
' position: absolute;',
|
|
455
|
+
' top: 12px;',
|
|
456
|
+
' right: 12px;',
|
|
457
|
+
' left: 12px;',
|
|
458
|
+
' z-index: 100;',
|
|
459
|
+
' pointer-events: none;',
|
|
460
|
+
'}',
|
|
461
|
+
|
|
462
|
+
/* ── HEADER — Liquid Glass Pill ── */
|
|
463
|
+
'.wakz-header {',
|
|
464
|
+
' pointer-events: all;',
|
|
427
465
|
' display: flex;',
|
|
428
466
|
' align-items: center;',
|
|
429
467
|
' justify-content: space-between;',
|
|
430
|
-
'
|
|
431
|
-
'
|
|
432
|
-
'
|
|
433
|
-
'
|
|
468
|
+
' position: relative;',
|
|
469
|
+
' overflow: hidden;',
|
|
470
|
+
' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
471
|
+
' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
472
|
+
' background: rgba(255,255,255,0.82);',
|
|
473
|
+
' border: 0.5px solid rgba(255,255,255,0.7);',
|
|
474
|
+
' border-radius: 9999px;',
|
|
475
|
+
' box-shadow:',
|
|
476
|
+
' inset 0 1px 0 0 rgba(255,255,255,0.9),',
|
|
477
|
+
' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
|
|
478
|
+
' 0 0 0 0.5px rgba(0,0,0,0.06),',
|
|
479
|
+
' 0 8px 32px rgba(0,0,0,0.08),',
|
|
480
|
+
' 0 2px 8px rgba(0,0,0,0.04);',
|
|
481
|
+
' padding: 8px 8px 8px 12px;',
|
|
482
|
+
' gap: 12px;',
|
|
434
483
|
'}',
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
'
|
|
438
|
-
'
|
|
439
|
-
'
|
|
484
|
+
|
|
485
|
+
/* ── Specular Highlight (real DOM element, not ::before) ── */
|
|
486
|
+
'.wakz-specular {',
|
|
487
|
+
' position: absolute;',
|
|
488
|
+
' top: 0;',
|
|
489
|
+
' left: 15%;',
|
|
490
|
+
' right: 15%;',
|
|
491
|
+
' height: 1px;',
|
|
492
|
+
' background: linear-gradient(',
|
|
493
|
+
' 90deg,',
|
|
494
|
+
' transparent,',
|
|
495
|
+
' rgba(255,255,255,0.6) 20%,',
|
|
496
|
+
' rgba(255,255,255,0.95) 50%,',
|
|
497
|
+
' rgba(255,255,255,0.6) 80%,',
|
|
498
|
+
' transparent',
|
|
499
|
+
' );',
|
|
500
|
+
' border-radius: inherit;',
|
|
501
|
+
' pointer-events: none;',
|
|
502
|
+
' z-index: 1;',
|
|
440
503
|
'}',
|
|
441
504
|
|
|
442
|
-
/* ──
|
|
443
|
-
'.wakz-
|
|
444
|
-
' width: 38px;',
|
|
445
|
-
' height: 38px;',
|
|
446
|
-
' border-radius: 50%;',
|
|
447
|
-
' background: rgba(255,255,255,0.18);',
|
|
505
|
+
/* ── Brand (right side in RTL) ── */
|
|
506
|
+
'.wakz-hdr-brand {',
|
|
448
507
|
' display: flex;',
|
|
449
508
|
' align-items: center;',
|
|
450
|
-
' justify-content: center;',
|
|
451
|
-
' font-weight: 700;',
|
|
452
|
-
' font-size: 16px;',
|
|
453
509
|
' flex-shrink: 0;',
|
|
454
|
-
'
|
|
510
|
+
' padding: 0 6px;',
|
|
455
511
|
'}',
|
|
456
|
-
|
|
457
|
-
/* ── Header Info ── */
|
|
458
512
|
'.wakz-hdr-info {',
|
|
459
513
|
' display: flex;',
|
|
460
514
|
' flex-direction: column;',
|
|
461
|
-
'
|
|
515
|
+
' gap: 1px;',
|
|
462
516
|
'}',
|
|
463
|
-
'.wakz-hdr-
|
|
517
|
+
'.wakz-hdr-title {',
|
|
464
518
|
' font-size: 15px;',
|
|
465
|
-
' font-weight:
|
|
466
|
-
'
|
|
467
|
-
'
|
|
468
|
-
'
|
|
469
|
-
'
|
|
519
|
+
' font-weight: 900;',
|
|
520
|
+
' color: #0a0a0a;',
|
|
521
|
+
' letter-spacing: -0.2px;',
|
|
522
|
+
' line-height: 1.2;',
|
|
523
|
+
' font-family: "Cairo", sans-serif;',
|
|
470
524
|
'}',
|
|
471
|
-
'.wakz-hdr-
|
|
472
|
-
' font-size:
|
|
473
|
-
'
|
|
525
|
+
'.wakz-hdr-subtitle {',
|
|
526
|
+
' font-size: 11px;',
|
|
527
|
+
' font-weight: 500;',
|
|
528
|
+
' color: #999;',
|
|
529
|
+
' line-height: 1.2;',
|
|
530
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
531
|
+
'}',
|
|
532
|
+
|
|
533
|
+
/* ── Actions (left side in RTL) ── */
|
|
534
|
+
'.wakz-hdr-actions {',
|
|
474
535
|
' display: flex;',
|
|
475
536
|
' align-items: center;',
|
|
537
|
+
' gap: 8px;',
|
|
538
|
+
' flex-shrink: 0;',
|
|
539
|
+
'}',
|
|
540
|
+
|
|
541
|
+
/* ── Status Pill ── */
|
|
542
|
+
'.wakz-status-pill {',
|
|
543
|
+
' display: inline-flex;',
|
|
544
|
+
' align-items: center;',
|
|
476
545
|
' gap: 5px;',
|
|
477
|
-
'
|
|
546
|
+
' padding: 4px 10px;',
|
|
547
|
+
' border-radius: 50px;',
|
|
548
|
+
' font-size: 11px;',
|
|
549
|
+
' font-weight: 600;',
|
|
550
|
+
' font-family: "Cairo", sans-serif;',
|
|
551
|
+
' white-space: nowrap;',
|
|
552
|
+
' transition: all 0.3s ease;',
|
|
553
|
+
'}',
|
|
554
|
+
'.wakz-status-pill--online {',
|
|
555
|
+
' background: rgba(34,197,94,0.08);',
|
|
556
|
+
' color: #16a34a;',
|
|
557
|
+
' border: 1px solid rgba(34,197,94,0.15);',
|
|
478
558
|
'}',
|
|
479
|
-
'.wakz-
|
|
480
|
-
'
|
|
481
|
-
'
|
|
559
|
+
'.wakz-status-pill--offline {',
|
|
560
|
+
' background: rgba(156,163,175,0.1);',
|
|
561
|
+
' color: #6b7280;',
|
|
562
|
+
' border: 1px solid rgba(156,163,175,0.15);',
|
|
563
|
+
'}',
|
|
564
|
+
|
|
565
|
+
/* ── Status Dot inside pill (6px) ── */
|
|
566
|
+
'.wakz-status-dot {',
|
|
567
|
+
' width: 6px;',
|
|
568
|
+
' height: 6px;',
|
|
482
569
|
' border-radius: 50%;',
|
|
483
|
-
' display: inline-block;',
|
|
484
570
|
' flex-shrink: 0;',
|
|
485
|
-
' transition: background 0.3s ease;',
|
|
486
571
|
'}',
|
|
487
|
-
'.wakz-
|
|
488
|
-
'
|
|
572
|
+
'.wakz-status-pill--online .wakz-status-dot {',
|
|
573
|
+
' background: #22c55e;',
|
|
574
|
+
' animation: wakz-pulse-green 2.5s ease-in-out infinite;',
|
|
575
|
+
'}',
|
|
576
|
+
'.wakz-status-pill--offline .wakz-status-dot {',
|
|
577
|
+
' background: #9ca3af;',
|
|
578
|
+
'}',
|
|
489
579
|
|
|
490
|
-
/* ── Close Button ── */
|
|
580
|
+
/* ── Close Button (glass circle) ── */
|
|
491
581
|
'.wakz-close {',
|
|
492
|
-
' width:
|
|
493
|
-
' height:
|
|
582
|
+
' width: 30px;',
|
|
583
|
+
' height: 30px;',
|
|
584
|
+
' min-width: 30px;',
|
|
585
|
+
' min-height: 30px;',
|
|
494
586
|
' border-radius: 50%;',
|
|
495
587
|
' border: none;',
|
|
496
|
-
' background: rgba(255,255,255,0.12);',
|
|
497
|
-
' color: #ffffff;',
|
|
498
588
|
' cursor: pointer;',
|
|
499
589
|
' display: flex;',
|
|
500
590
|
' align-items: center;',
|
|
501
591
|
' justify-content: center;',
|
|
502
|
-
'
|
|
592
|
+
' color: #888;',
|
|
593
|
+
' position: relative;',
|
|
594
|
+
' overflow: hidden;',
|
|
595
|
+
' backdrop-filter: blur(20px) saturate(180%);',
|
|
596
|
+
' -webkit-backdrop-filter: blur(20px) saturate(180%);',
|
|
597
|
+
' background: rgba(255,255,255,0.6);',
|
|
598
|
+
' border: 0.5px solid rgba(255,255,255,0.6);',
|
|
599
|
+
' box-shadow:',
|
|
600
|
+
' inset 0 1px 0 0 rgba(255,255,255,0.8),',
|
|
601
|
+
' 0 1px 4px rgba(0,0,0,0.04);',
|
|
602
|
+
' transition: all 0.2s cubic-bezier(0.22,1,0.36,1);',
|
|
503
603
|
' outline: none;',
|
|
504
|
-
' flex-shrink: 0;',
|
|
505
604
|
'}',
|
|
506
605
|
'.wakz-close:hover {',
|
|
507
|
-
' background: rgba(255,
|
|
508
|
-
'
|
|
509
|
-
'.
|
|
510
|
-
'
|
|
511
|
-
'
|
|
606
|
+
' background: rgba(255,80,80,0.08);',
|
|
607
|
+
' color: #ef4444;',
|
|
608
|
+
' transform: scale(1.1);',
|
|
609
|
+
' box-shadow:',
|
|
610
|
+
' inset 0 1px 0 0 rgba(255,255,255,0.8),',
|
|
611
|
+
' 0 2px 8px rgba(239,68,68,0.1);',
|
|
512
612
|
'}',
|
|
613
|
+
'.wakz-close:active { transform: scale(0.92); }',
|
|
614
|
+
'.wakz-close svg { width: 14px; height: 14px; }',
|
|
513
615
|
|
|
514
616
|
/* ══════════════════════════════════════════════════
|
|
515
|
-
MESSAGES AREA
|
|
617
|
+
MESSAGES AREA — scrollable
|
|
516
618
|
══════════════════════════════════════════════════ */
|
|
517
619
|
'.wakz-msgs {',
|
|
518
620
|
' flex: 1;',
|
|
519
621
|
' overflow-y: auto;',
|
|
520
622
|
' overflow-x: hidden;',
|
|
521
|
-
' padding:
|
|
522
|
-
'
|
|
523
|
-
'
|
|
524
|
-
'
|
|
623
|
+
' padding: 0;',
|
|
624
|
+
' padding-top: 76px;',
|
|
625
|
+
' padding-bottom: 100px;',
|
|
626
|
+
' padding-right: 14px;',
|
|
627
|
+
' padding-left: 14px;',
|
|
525
628
|
' scroll-behavior: smooth;',
|
|
526
|
-
'
|
|
629
|
+
' position: relative;',
|
|
527
630
|
'}',
|
|
528
|
-
'.wakz-msgs::-webkit-scrollbar { width:
|
|
631
|
+
'.wakz-msgs::-webkit-scrollbar { width: 3px; }',
|
|
529
632
|
'.wakz-msgs::-webkit-scrollbar-track { background: transparent; }',
|
|
530
633
|
'.wakz-msgs::-webkit-scrollbar-thumb {',
|
|
531
|
-
' background: rgba(0,0,0,0.
|
|
532
|
-
' border-radius:
|
|
634
|
+
' background: rgba(0,0,0,0.08);',
|
|
635
|
+
' border-radius: 99px;',
|
|
636
|
+
'}',
|
|
637
|
+
|
|
638
|
+
'.wakz-msgs-inner {',
|
|
639
|
+
' display: flex;',
|
|
640
|
+
' flex-direction: column;',
|
|
641
|
+
' gap: 6px;',
|
|
533
642
|
'}',
|
|
534
643
|
|
|
535
644
|
/* ══════════════════════════════════════════════════
|
|
536
|
-
MESSAGE
|
|
645
|
+
MESSAGE ROWS
|
|
537
646
|
══════════════════════════════════════════════════ */
|
|
538
647
|
'.wakz-msg-row {',
|
|
539
648
|
' display: flex;',
|
|
540
|
-
'
|
|
541
|
-
'
|
|
649
|
+
' align-items: flex-end;',
|
|
650
|
+
' width: 100%;',
|
|
651
|
+
' animation: wakz-fade-slide-up 0.3s cubic-bezier(0.22,1,0.36,1) both;',
|
|
542
652
|
'}',
|
|
543
|
-
'.wakz-msg-row.bot { align-self: flex-start; }',
|
|
544
|
-
'.wakz-msg-row.user { align-self: flex-end; }',
|
|
545
653
|
|
|
546
|
-
|
|
547
|
-
'
|
|
548
|
-
'
|
|
654
|
+
/* ── USER MESSAGE — dark bubble ── */
|
|
655
|
+
'.wakz-msg-row--user { justify-content: flex-end; }',
|
|
656
|
+
'.wakz-user-card {',
|
|
657
|
+
' max-width: 78%;',
|
|
658
|
+
' padding: 10px 14px 8px;',
|
|
659
|
+
' background: #111111;',
|
|
660
|
+
' color: #ffffff;',
|
|
661
|
+
' border-radius: 18px 18px 5px 18px;',
|
|
662
|
+
' box-shadow: 0 2px 10px rgba(0,0,0,0.06), 0 1px 3px rgba(0,0,0,0.03);',
|
|
549
663
|
'}',
|
|
550
|
-
|
|
551
|
-
'
|
|
552
|
-
'
|
|
553
|
-
'
|
|
554
|
-
' line-height: 1.55;',
|
|
555
|
-
' word-wrap: break-word;',
|
|
556
|
-
' overflow-wrap: break-word;',
|
|
664
|
+
'.wakz-user-text {',
|
|
665
|
+
' font-size: 13.5px;',
|
|
666
|
+
' font-weight: 400;',
|
|
667
|
+
' line-height: 1.7;',
|
|
557
668
|
' white-space: pre-wrap;',
|
|
558
|
-
'
|
|
559
|
-
'
|
|
669
|
+
' word-break: break-word;',
|
|
670
|
+
' text-align: right;',
|
|
671
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
560
672
|
'}',
|
|
561
|
-
'.wakz-
|
|
562
|
-
'
|
|
563
|
-
' color:
|
|
564
|
-
'
|
|
565
|
-
'
|
|
673
|
+
'.wakz-user-time {',
|
|
674
|
+
' font-size: 9.5px;',
|
|
675
|
+
' color: rgba(255,255,255,0.4);',
|
|
676
|
+
' display: block;',
|
|
677
|
+
' margin-top: 4px;',
|
|
678
|
+
' text-align: left;',
|
|
679
|
+
' font-family: "Tajawal", sans-serif;',
|
|
566
680
|
'}',
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
'
|
|
570
|
-
'
|
|
681
|
+
|
|
682
|
+
/* ── BOT MESSAGE — no bubble, on background ── */
|
|
683
|
+
'.wakz-msg-row--bot { justify-content: flex-start; }',
|
|
684
|
+
'.wakz-bot-content {',
|
|
685
|
+
' max-width: 78%;',
|
|
686
|
+
' display: flex;',
|
|
687
|
+
' flex-direction: column;',
|
|
688
|
+
' align-items: flex-end;',
|
|
689
|
+
' gap: 1px;',
|
|
571
690
|
'}',
|
|
572
|
-
'.wakz-
|
|
573
|
-
'
|
|
574
|
-
'
|
|
575
|
-
'
|
|
576
|
-
'
|
|
577
|
-
'
|
|
691
|
+
'.wakz-bot-label {',
|
|
692
|
+
' font-size: 10px;',
|
|
693
|
+
' font-weight: 700;',
|
|
694
|
+
' color: #aaa;',
|
|
695
|
+
' letter-spacing: 0.1px;',
|
|
696
|
+
' padding: 0 4px;',
|
|
697
|
+
' font-family: "Cairo", sans-serif;',
|
|
578
698
|
'}',
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
'
|
|
699
|
+
'.wakz-bot-text {',
|
|
700
|
+
' font-size: 13.5px;',
|
|
701
|
+
' font-weight: 400;',
|
|
702
|
+
' line-height: 1.75;',
|
|
703
|
+
' color: #333333;',
|
|
704
|
+
' white-space: pre-wrap;',
|
|
705
|
+
' word-break: break-word;',
|
|
706
|
+
' text-align: right;',
|
|
707
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
708
|
+
' padding: 0 4px;',
|
|
709
|
+
'}',
|
|
710
|
+
'.wakz-bot-time {',
|
|
711
|
+
' font-size: 9.5px;',
|
|
712
|
+
' color: #cccccc;',
|
|
582
713
|
' display: block;',
|
|
583
|
-
'
|
|
584
|
-
'
|
|
585
|
-
'
|
|
714
|
+
' margin-top: 1px;',
|
|
715
|
+
' text-align: left;',
|
|
716
|
+
' padding-left: 4px;',
|
|
717
|
+
' font-family: "Tajawal", sans-serif;',
|
|
718
|
+
'}',
|
|
719
|
+
|
|
720
|
+
/* ── SUPPORT MESSAGE — green accent ── */
|
|
721
|
+
'.wakz-msg-row--support { justify-content: flex-start; }',
|
|
722
|
+
'.wakz-support-content {',
|
|
723
|
+
' max-width: 78%;',
|
|
724
|
+
' display: flex;',
|
|
725
|
+
' flex-direction: column;',
|
|
726
|
+
' align-items: flex-end;',
|
|
727
|
+
' gap: 1px;',
|
|
728
|
+
' border-right: 2.5px solid #22c55e;',
|
|
729
|
+
' padding-right: 10px;',
|
|
730
|
+
'}',
|
|
731
|
+
'.wakz-support-label {',
|
|
732
|
+
' font-size: 10px;',
|
|
733
|
+
' font-weight: 700;',
|
|
734
|
+
' color: #16a34a;',
|
|
735
|
+
' letter-spacing: 0.1px;',
|
|
736
|
+
' padding: 0 4px;',
|
|
737
|
+
' font-family: "Cairo", sans-serif;',
|
|
738
|
+
' display: flex;',
|
|
739
|
+
' align-items: center;',
|
|
740
|
+
' gap: 4px;',
|
|
741
|
+
'}',
|
|
742
|
+
'.wakz-support-label-dot {',
|
|
743
|
+
' width: 4px;',
|
|
744
|
+
' height: 4px;',
|
|
745
|
+
' border-radius: 50%;',
|
|
746
|
+
' background: #22c55e;',
|
|
747
|
+
' flex-shrink: 0;',
|
|
586
748
|
'}',
|
|
587
|
-
'.wakz-
|
|
749
|
+
'.wakz-support-text {',
|
|
750
|
+
' font-size: 13.5px;',
|
|
751
|
+
' font-weight: 400;',
|
|
752
|
+
' line-height: 1.75;',
|
|
753
|
+
' color: #333333;',
|
|
754
|
+
' white-space: pre-wrap;',
|
|
755
|
+
' word-break: break-word;',
|
|
588
756
|
' text-align: right;',
|
|
757
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
758
|
+
' padding: 0 4px;',
|
|
759
|
+
'}',
|
|
760
|
+
'.wakz-support-time {',
|
|
761
|
+
' font-size: 9.5px;',
|
|
762
|
+
' color: #cccccc;',
|
|
763
|
+
' display: block;',
|
|
764
|
+
' margin-top: 1px;',
|
|
765
|
+
' text-align: left;',
|
|
766
|
+
' padding-left: 4px;',
|
|
767
|
+
' font-family: "Tajawal", sans-serif;',
|
|
589
768
|
'}',
|
|
590
769
|
|
|
591
|
-
/* ──
|
|
592
|
-
'.wakz-
|
|
593
|
-
'
|
|
594
|
-
'
|
|
595
|
-
'
|
|
596
|
-
'
|
|
597
|
-
'
|
|
598
|
-
'
|
|
599
|
-
'
|
|
600
|
-
'
|
|
601
|
-
'
|
|
770
|
+
/* ── Error Messages ── */
|
|
771
|
+
'.wakz-error-bubble {',
|
|
772
|
+
' max-width: 78%;',
|
|
773
|
+
' padding: 10px 14px;',
|
|
774
|
+
' font-size: 13.5px;',
|
|
775
|
+
' line-height: 1.6;',
|
|
776
|
+
' white-space: pre-wrap;',
|
|
777
|
+
' word-break: break-word;',
|
|
778
|
+
' border-radius: 14px;',
|
|
779
|
+
' border-bottom-left-radius: 4px;',
|
|
780
|
+
' background: #FEF2F2;',
|
|
781
|
+
' color: #DC2626;',
|
|
782
|
+
' border: 1px solid #FECACA;',
|
|
783
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
602
784
|
'}',
|
|
603
785
|
|
|
604
|
-
/* ── Retry Button
|
|
786
|
+
/* ── Retry Button ── */
|
|
605
787
|
'.wakz-retry {',
|
|
606
788
|
' display: inline-flex;',
|
|
607
789
|
' align-items: center;',
|
|
@@ -615,183 +797,226 @@
|
|
|
615
797
|
' background: #ffffff;',
|
|
616
798
|
' color: #dc2626;',
|
|
617
799
|
' cursor: pointer;',
|
|
618
|
-
' font-family:
|
|
619
|
-
' transition: background
|
|
800
|
+
' font-family: "Cairo", "Tajawal", sans-serif;',
|
|
801
|
+
' transition: background 0.2s ease, border-color 0.2s ease;',
|
|
620
802
|
' outline: none;',
|
|
621
803
|
'}',
|
|
622
|
-
'.wakz-retry:hover {',
|
|
623
|
-
' background: #fef2f2;',
|
|
624
|
-
' border-color: #f87171;',
|
|
625
|
-
'}',
|
|
804
|
+
'.wakz-retry:hover { background: #fef2f2; border-color: #f87171; }',
|
|
626
805
|
|
|
627
806
|
/* ══════════════════════════════════════════════════
|
|
628
807
|
TYPING INDICATOR
|
|
629
808
|
══════════════════════════════════════════════════ */
|
|
630
|
-
'.wakz-typing {',
|
|
809
|
+
'.wakz-typing-row {',
|
|
810
|
+
' display: flex;',
|
|
811
|
+
' align-items: flex-end;',
|
|
812
|
+
' justify-content: flex-start;',
|
|
813
|
+
' width: 100%;',
|
|
814
|
+
' animation: wakz-fade-slide-up 0.25s ease both;',
|
|
815
|
+
'}',
|
|
816
|
+
'.wakz-typing-content {',
|
|
817
|
+
' display: flex;',
|
|
818
|
+
' flex-direction: column;',
|
|
819
|
+
' align-items: flex-end;',
|
|
820
|
+
' gap: 3px;',
|
|
821
|
+
'}',
|
|
822
|
+
'.wakz-typing-label {',
|
|
823
|
+
' font-size: 10px;',
|
|
824
|
+
' font-weight: 700;',
|
|
825
|
+
' color: #aaa;',
|
|
826
|
+
' padding: 0 4px;',
|
|
827
|
+
' font-family: "Cairo", sans-serif;',
|
|
828
|
+
'}',
|
|
829
|
+
'.wakz-typing-dots {',
|
|
631
830
|
' display: flex;',
|
|
632
831
|
' align-items: center;',
|
|
633
832
|
' gap: 4px;',
|
|
634
|
-
' padding:
|
|
635
|
-
' background: #ffffff;',
|
|
636
|
-
' border-radius: var(--wakz-radius-bubble);',
|
|
637
|
-
' border-bottom-left-radius: 4px;',
|
|
638
|
-
' box-shadow: var(--wakz-shadow-sm);',
|
|
833
|
+
' padding: 8px 12px;',
|
|
639
834
|
'}',
|
|
640
|
-
'.wakz-typing-
|
|
641
|
-
' width:
|
|
642
|
-
' height:
|
|
835
|
+
'.wakz-typing-dots span {',
|
|
836
|
+
' width: 6px;',
|
|
837
|
+
' height: 6px;',
|
|
643
838
|
' border-radius: 50%;',
|
|
644
|
-
' background: #
|
|
645
|
-
' animation: wakz-bounce
|
|
646
|
-
'}',
|
|
647
|
-
'.wakz-typing-dot:nth-child(2) { animation-delay: 0.16s; }',
|
|
648
|
-
'.wakz-typing-dot:nth-child(3) { animation-delay: 0.32s; }',
|
|
649
|
-
'@keyframes wakz-bounce-dot {',
|
|
650
|
-
' 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }',
|
|
651
|
-
' 30% { transform: translateY(-7px); opacity: 1; }',
|
|
839
|
+
' background: #bbb;',
|
|
840
|
+
' animation: wakz-typing-bounce 1.4s ease-in-out infinite;',
|
|
652
841
|
'}',
|
|
842
|
+
'.wakz-typing-dots span:nth-child(1) { animation-delay: 0s; }',
|
|
843
|
+
'.wakz-typing-dots span:nth-child(2) { animation-delay: 0.18s; }',
|
|
844
|
+
'.wakz-typing-dots span:nth-child(3) { animation-delay: 0.36s; }',
|
|
653
845
|
|
|
654
846
|
/* ══════════════════════════════════════════════════
|
|
655
|
-
INPUT
|
|
847
|
+
FLOATING INPUT WRAP — absolute bottom
|
|
656
848
|
══════════════════════════════════════════════════ */
|
|
657
849
|
'.wakz-input-wrap {',
|
|
658
|
-
'
|
|
659
|
-
'
|
|
660
|
-
'
|
|
661
|
-
'
|
|
850
|
+
' position: absolute;',
|
|
851
|
+
' bottom: 12px;',
|
|
852
|
+
' right: 12px;',
|
|
853
|
+
' left: 12px;',
|
|
854
|
+
' z-index: 100;',
|
|
855
|
+
' pointer-events: none;',
|
|
856
|
+
'}',
|
|
857
|
+
'.wakz-input-row {',
|
|
858
|
+
' pointer-events: all;',
|
|
859
|
+
' width: 100%;',
|
|
662
860
|
' display: flex;',
|
|
663
|
-
' align-items:
|
|
861
|
+
' align-items: center;',
|
|
664
862
|
' gap: 8px;',
|
|
665
863
|
'}',
|
|
864
|
+
|
|
865
|
+
/* ── Input Glass Pill ── */
|
|
866
|
+
'.wakz-input-glass {',
|
|
867
|
+
' flex: 1;',
|
|
868
|
+
' display: flex;',
|
|
869
|
+
' align-items: center;',
|
|
870
|
+
' position: relative;',
|
|
871
|
+
' overflow: hidden;',
|
|
872
|
+
' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
873
|
+
' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
874
|
+
' background: rgba(255,255,255,0.85);',
|
|
875
|
+
' border: 0.5px solid rgba(255,255,255,0.7);',
|
|
876
|
+
' border-radius: 9999px;',
|
|
877
|
+
' box-shadow:',
|
|
878
|
+
' inset 0 1px 0 0 rgba(255,255,255,0.9),',
|
|
879
|
+
' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
|
|
880
|
+
' 0 0 0 0.5px rgba(0,0,0,0.06),',
|
|
881
|
+
' 0 8px 32px rgba(0,0,0,0.08),',
|
|
882
|
+
' 0 2px 8px rgba(0,0,0,0.04);',
|
|
883
|
+
' padding: 8px 16px;',
|
|
884
|
+
'}',
|
|
885
|
+
|
|
886
|
+
/* ── Input specular highlight ── */
|
|
887
|
+
'.wakz-input-specular {',
|
|
888
|
+
' position: absolute;',
|
|
889
|
+
' top: 0;',
|
|
890
|
+
' left: 10%;',
|
|
891
|
+
' right: 10%;',
|
|
892
|
+
' height: 1px;',
|
|
893
|
+
' background: linear-gradient(',
|
|
894
|
+
' 90deg,',
|
|
895
|
+
' transparent,',
|
|
896
|
+
' rgba(255,255,255,0.5) 20%,',
|
|
897
|
+
' rgba(255,255,255,0.8) 50%,',
|
|
898
|
+
' rgba(255,255,255,0.5) 80%,',
|
|
899
|
+
' transparent',
|
|
900
|
+
' );',
|
|
901
|
+
' border-radius: inherit;',
|
|
902
|
+
' pointer-events: none;',
|
|
903
|
+
' z-index: 1;',
|
|
904
|
+
'}',
|
|
905
|
+
|
|
906
|
+
/* ── Textarea ── */
|
|
666
907
|
'.wakz-input {',
|
|
667
908
|
' flex: 1;',
|
|
668
|
-
' border: 1.5px solid #e5e7eb;',
|
|
669
|
-
' border-radius: 22px;',
|
|
670
|
-
' padding: 10px 16px;',
|
|
671
|
-
' font-size: 14px;',
|
|
672
|
-
' line-height: 1.4;',
|
|
673
|
-
' outline: none;',
|
|
674
|
-
' font-family: var(--wakz-font);',
|
|
675
|
-
' transition: border-color var(--wakz-transition);',
|
|
676
909
|
' resize: none;',
|
|
677
|
-
'
|
|
910
|
+
' border: none;',
|
|
911
|
+
' outline: none;',
|
|
912
|
+
' background: transparent;',
|
|
913
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
914
|
+
' font-size: 13.5px;',
|
|
915
|
+
' font-weight: 400;',
|
|
916
|
+
' color: #111;',
|
|
917
|
+
' line-height: 1.5;',
|
|
918
|
+
' padding: 1px 4px;',
|
|
919
|
+
' max-height: 48px;',
|
|
678
920
|
' overflow-y: auto;',
|
|
679
|
-
'
|
|
680
|
-
' color: #111827;',
|
|
681
|
-
'}',
|
|
682
|
-
'.wakz-input:focus {',
|
|
683
|
-
' border-color: var(--wakz-primary);',
|
|
684
|
-
' background: #ffffff;',
|
|
921
|
+
' align-self: center;',
|
|
685
922
|
'}',
|
|
686
923
|
'.wakz-input::placeholder {',
|
|
687
|
-
' color: #
|
|
924
|
+
' color: #bbb;',
|
|
925
|
+
' font-weight: 400;',
|
|
926
|
+
' font-family: "Cairo", "Tajawal", sans-serif;',
|
|
688
927
|
'}',
|
|
928
|
+
'.wakz-input:focus { outline: none; }',
|
|
929
|
+
'.wakz-input::-webkit-scrollbar { width: 3px; }',
|
|
930
|
+
'.wakz-input::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.1); border-radius: 99px; }',
|
|
689
931
|
|
|
690
|
-
/* ── Send Button ── */
|
|
932
|
+
/* ── Send Button — 40px circle, separate ── */
|
|
691
933
|
'.wakz-send {',
|
|
934
|
+
' flex-shrink: 0;',
|
|
692
935
|
' width: 40px;',
|
|
693
936
|
' height: 40px;',
|
|
937
|
+
' min-width: 40px;',
|
|
938
|
+
' min-height: 40px;',
|
|
694
939
|
' border-radius: 50%;',
|
|
695
940
|
' border: none;',
|
|
696
|
-
' color: #ffffff;',
|
|
697
941
|
' cursor: pointer;',
|
|
698
942
|
' display: flex;',
|
|
699
943
|
' align-items: center;',
|
|
700
944
|
' justify-content: center;',
|
|
701
|
-
'
|
|
702
|
-
'
|
|
945
|
+
' position: relative;',
|
|
946
|
+
' overflow: hidden;',
|
|
947
|
+
' transition: all 0.25s cubic-bezier(0.22,1,0.36,1);',
|
|
703
948
|
' outline: none;',
|
|
704
|
-
'
|
|
705
|
-
'
|
|
706
|
-
'
|
|
707
|
-
'.
|
|
708
|
-
' box-shadow:
|
|
709
|
-
'
|
|
710
|
-
'
|
|
711
|
-
'
|
|
712
|
-
'
|
|
713
|
-
'
|
|
714
|
-
'.wakz-send:not(:disabled):active {',
|
|
715
|
-
' transform: scale(0.88);',
|
|
949
|
+
' backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
950
|
+
' -webkit-backdrop-filter: blur(40px) saturate(180%) brightness(102%);',
|
|
951
|
+
' background: rgba(255,255,255,0.82);',
|
|
952
|
+
' border: 0.5px solid rgba(255,255,255,0.7);',
|
|
953
|
+
' box-shadow:',
|
|
954
|
+
' inset 0 1px 0 0 rgba(255,255,255,0.9),',
|
|
955
|
+
' inset 0 -1px 0 0 rgba(0,0,0,0.04),',
|
|
956
|
+
' 0 0 0 0.5px rgba(0,0,0,0.06),',
|
|
957
|
+
' 0 4px 16px rgba(0,0,0,0.06);',
|
|
958
|
+
' color: #bbb;',
|
|
716
959
|
'}',
|
|
960
|
+
'.wakz-send:disabled { cursor: default; }',
|
|
717
961
|
'.wakz-send svg {',
|
|
718
962
|
' width: 18px;',
|
|
719
963
|
' height: 18px;',
|
|
720
964
|
' pointer-events: none;',
|
|
721
965
|
'}',
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
'.wakz-welcome-wrap {',
|
|
727
|
-
' display: flex;',
|
|
728
|
-
' gap: 8px;',
|
|
729
|
-
' max-width: 88%;',
|
|
730
|
-
' align-self: flex-start;',
|
|
731
|
-
' animation: wakz-msg-in 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
|
|
732
|
-
'}',
|
|
733
|
-
'.wakz-welcome-avatar {',
|
|
734
|
-
' width: 28px;',
|
|
735
|
-
' height: 28px;',
|
|
736
|
-
' border-radius: 50%;',
|
|
737
|
-
' background: var(--wakz-primary);',
|
|
738
|
-
' display: flex;',
|
|
739
|
-
' align-items: center;',
|
|
740
|
-
' justify-content: center;',
|
|
966
|
+
/* ── Send Active State ── */
|
|
967
|
+
'.wakz-send--active {',
|
|
968
|
+
' background: #111111;',
|
|
969
|
+
' border-color: #111111;',
|
|
741
970
|
' color: #ffffff;',
|
|
742
|
-
'
|
|
743
|
-
'
|
|
744
|
-
'
|
|
745
|
-
'
|
|
746
|
-
'
|
|
971
|
+
' filter: none;',
|
|
972
|
+
' backdrop-filter: none;',
|
|
973
|
+
' -webkit-backdrop-filter: none;',
|
|
974
|
+
' box-shadow: 0 4px 20px rgba(0,0,0,0.22), 0 1px 6px rgba(0,0,0,0.12);',
|
|
975
|
+
'}',
|
|
976
|
+
'.wakz-send--active:hover:not(:disabled) {',
|
|
977
|
+
' background: #222;',
|
|
978
|
+
' transform: scale(1.08);',
|
|
979
|
+
' box-shadow: 0 6px 24px rgba(0,0,0,0.28), 0 2px 8px rgba(0,0,0,0.14);',
|
|
747
980
|
'}',
|
|
981
|
+
'.wakz-send--active:active:not(:disabled) { transform: scale(0.93); }',
|
|
748
982
|
|
|
749
983
|
/* ══════════════════════════════════════════════════
|
|
750
984
|
RTL SUPPORT
|
|
751
985
|
══════════════════════════════════════════════════ */
|
|
752
986
|
'.wakz-rtl { direction: rtl; }',
|
|
753
|
-
'.wakz-rtl .wakz-
|
|
754
|
-
' border-
|
|
755
|
-
' border-bottom-right-radius: 4px;',
|
|
987
|
+
'.wakz-rtl .wakz-user-card {',
|
|
988
|
+
' border-radius: 18px 18px 18px 5px;',
|
|
756
989
|
'}',
|
|
757
|
-
'.wakz-rtl .wakz-bubble
|
|
758
|
-
' border-bottom-
|
|
759
|
-
' border-bottom-left-radius: 4px;',
|
|
760
|
-
'}',
|
|
761
|
-
'.wakz-rtl .wakz-typing {',
|
|
762
|
-
' border-bottom-left-radius: var(--wakz-radius-bubble);',
|
|
990
|
+
'.wakz-rtl .wakz-error-bubble {',
|
|
991
|
+
' border-bottom-left-radius: 14px;',
|
|
763
992
|
' border-bottom-right-radius: 4px;',
|
|
764
993
|
'}',
|
|
765
|
-
'.wakz-rtl .wakz-bubble.user .wakz-ts {',
|
|
766
|
-
' text-align: left;',
|
|
767
|
-
'}',
|
|
768
994
|
|
|
769
995
|
/* ══════════════════════════════════════════════════
|
|
770
|
-
|
|
996
|
+
RESPONSIVE
|
|
771
997
|
══════════════════════════════════════════════════ */
|
|
772
|
-
'@media (max-width:
|
|
998
|
+
'@media (max-width: 440px) {',
|
|
773
999
|
' .wakz-window {',
|
|
774
|
-
' width:
|
|
775
|
-
' height:
|
|
776
|
-
'
|
|
777
|
-
' max-height:
|
|
778
|
-
' bottom: 0 !important;',
|
|
779
|
-
' top: 0 !important;',
|
|
780
|
-
' right: 0 !important;',
|
|
781
|
-
' left: 0 !important;',
|
|
1000
|
+
' width: 100% !important;',
|
|
1001
|
+
' height: 100% !important;',
|
|
1002
|
+
' max-width: 100% !important;',
|
|
1003
|
+
' max-height: 100% !important;',
|
|
782
1004
|
' border-radius: 0 !important;',
|
|
1005
|
+
' box-shadow: none !important;',
|
|
783
1006
|
' }',
|
|
784
|
-
'
|
|
785
|
-
'
|
|
786
|
-
' }',
|
|
787
|
-
' .wakz-
|
|
788
|
-
' .wakz-
|
|
1007
|
+
'}',
|
|
1008
|
+
'@media (max-width: 380px) {',
|
|
1009
|
+
' .wakz-hdr-title { font-size: 13px; }',
|
|
1010
|
+
' .wakz-status-pill span:last-child { display: none; }',
|
|
1011
|
+
' .wakz-status-pill { padding: 4px 8px; }',
|
|
1012
|
+
' .wakz-send { width: 36px; height: 36px; min-width: 36px; min-height: 36px; }',
|
|
1013
|
+
' .wakz-close { width: 26px; height: 26px; min-width: 26px; min-height: 26px; }',
|
|
789
1014
|
'}'
|
|
790
1015
|
].join('\n');
|
|
791
1016
|
};
|
|
792
1017
|
|
|
793
1018
|
/* ════════════════════════════════════════════════════════════════
|
|
794
|
-
DOM CREATION
|
|
1019
|
+
DOM CREATION — v4.0.0 Liquid Glass structure
|
|
795
1020
|
════════════════════════════════════════════════════════════════ */
|
|
796
1021
|
|
|
797
1022
|
WAKZWidget.prototype._createDOM = function () {
|
|
@@ -805,58 +1030,98 @@
|
|
|
805
1030
|
document.body.appendChild(self._host);
|
|
806
1031
|
self._shadow = self._host.attachShadow({ mode: 'closed' });
|
|
807
1032
|
|
|
1033
|
+
/* ── Google Fonts link (injected into shadow root) ── */
|
|
1034
|
+
var fontsLink = _el('link', {
|
|
1035
|
+
rel: 'stylesheet',
|
|
1036
|
+
href: 'https://fonts.googleapis.com/css2?family=Cairo:wght@400;600;700;900&family=Tajawal:wght@300;400;500;700&display=swap'
|
|
1037
|
+
});
|
|
1038
|
+
self._shadow.appendChild(fontsLink);
|
|
1039
|
+
|
|
808
1040
|
/* ── Root wrapper ── */
|
|
809
1041
|
self._root = _el('div', { className: 'wakz' + (isRtl ? ' wakz-rtl' : '') });
|
|
810
1042
|
self._shadow.appendChild(self._styleEl);
|
|
811
1043
|
self._shadow.appendChild(self._root);
|
|
812
1044
|
|
|
813
|
-
/* ══════════════ FLOATING ACTION BUTTON ══════════════ */
|
|
1045
|
+
/* ══════════════ FLOATING ACTION BUTTON (FAB) ══════════════ */
|
|
814
1046
|
self._toggleBtn = _el('button', {
|
|
815
1047
|
className: 'wakz-fab wakz-fab-pos-' + posClass,
|
|
816
1048
|
'aria-label': str.openChat
|
|
817
1049
|
});
|
|
818
1050
|
self._toggleBtn.innerHTML = _ICONS.chatBubble;
|
|
819
1051
|
|
|
820
|
-
/* Status dot on FAB */
|
|
1052
|
+
/* Status dot on FAB (10px) */
|
|
821
1053
|
self._statusDot = _el('span', { className: 'wakz-fab-dot ' + (self.config.online ? 'online' : 'offline') });
|
|
822
1054
|
self._statusDot.style.display = self.config.showStatus ? '' : 'none';
|
|
823
1055
|
self._toggleBtn.appendChild(self._statusDot);
|
|
824
1056
|
self._root.appendChild(self._toggleBtn);
|
|
825
1057
|
|
|
1058
|
+
/* ══════════════ OVERLAY / BACKDROP ══════════════ */
|
|
1059
|
+
self._overlay = _el('div', { className: 'wakz-overlay' });
|
|
1060
|
+
self._root.appendChild(self._overlay);
|
|
1061
|
+
|
|
826
1062
|
/* ══════════════ CHAT WINDOW ══════════════ */
|
|
827
|
-
self._chatWindow = _el('div', { className: 'wakz-window
|
|
1063
|
+
self._chatWindow = _el('div', { className: 'wakz-window' });
|
|
828
1064
|
|
|
829
|
-
/* ──
|
|
830
|
-
|
|
1065
|
+
/* ── Messages Container (with floating header + input inside) ── */
|
|
1066
|
+
self._messagesContainer = _el('div', { className: 'wakz-msgs' });
|
|
831
1067
|
|
|
832
|
-
|
|
833
|
-
var
|
|
834
|
-
|
|
1068
|
+
/* ══════════════ FLOATING HEADER (pill, absolute over messages) ══════════════ */
|
|
1069
|
+
var headerWrap = _el('div', { className: 'wakz-header-wrap' });
|
|
1070
|
+
var header = _el('div', { className: 'wakz-header' });
|
|
835
1071
|
|
|
836
|
-
|
|
837
|
-
|
|
1072
|
+
/* Specular highlight (real DOM element, not ::before) */
|
|
1073
|
+
header.appendChild(_el('div', { className: 'wakz-specular' }));
|
|
838
1074
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
self.
|
|
843
|
-
|
|
844
|
-
headerInfo.appendChild(statusLine);
|
|
1075
|
+
/* Brand side (right in RTL) */
|
|
1076
|
+
var brand = _el('div', { className: 'wakz-hdr-brand' });
|
|
1077
|
+
var info = _el('div', { className: 'wakz-hdr-info' });
|
|
1078
|
+
self._headerTitleEl = _el('span', { className: 'wakz-hdr-title' }, [self.config.botName]);
|
|
1079
|
+
info.appendChild(self._headerTitleEl);
|
|
845
1080
|
|
|
846
|
-
|
|
847
|
-
|
|
1081
|
+
var subtitleText = self.config.botSubtitle || str.defaultSubtitle || '';
|
|
1082
|
+
self._headerSubtitleEl = _el('span', { className: 'wakz-hdr-subtitle' }, [subtitleText]);
|
|
1083
|
+
info.appendChild(self._headerSubtitleEl);
|
|
848
1084
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
headerEl.appendChild(closeBtn);
|
|
852
|
-
self._chatWindow.appendChild(headerEl);
|
|
1085
|
+
brand.appendChild(info);
|
|
1086
|
+
header.appendChild(brand);
|
|
853
1087
|
|
|
854
|
-
/*
|
|
855
|
-
|
|
856
|
-
|
|
1088
|
+
/* Actions side (left in RTL) */
|
|
1089
|
+
var actions = _el('div', { className: 'wakz-hdr-actions' });
|
|
1090
|
+
|
|
1091
|
+
/* Status pill */
|
|
1092
|
+
self._headerStatusPill = _el('div', {
|
|
1093
|
+
className: 'wakz-status-pill ' + (self.config.online ? 'wakz-status-pill--online' : 'wakz-status-pill--offline')
|
|
1094
|
+
});
|
|
1095
|
+
if (self.config.showStatus) {
|
|
1096
|
+
self._headerStatusDot = _el('span', { className: 'wakz-status-dot' });
|
|
1097
|
+
self._headerStatusPill.appendChild(self._headerStatusDot);
|
|
1098
|
+
self._headerStatusText = document.createTextNode(self.config.online ? str.online : str.offline);
|
|
1099
|
+
self._headerStatusPill.appendChild(self._headerStatusText);
|
|
1100
|
+
}
|
|
1101
|
+
actions.appendChild(self._headerStatusPill);
|
|
1102
|
+
|
|
1103
|
+
/* Close button (glass circle) */
|
|
1104
|
+
self._closeBtn = _el('button', { className: 'wakz-close', 'aria-label': str.closeChat });
|
|
1105
|
+
self._closeBtn.innerHTML = _ICONS.close;
|
|
1106
|
+
actions.appendChild(self._closeBtn);
|
|
1107
|
+
|
|
1108
|
+
header.appendChild(actions);
|
|
1109
|
+
headerWrap.appendChild(header);
|
|
1110
|
+
self._messagesContainer.appendChild(headerWrap);
|
|
1111
|
+
|
|
1112
|
+
/* ── Messages inner (scrollable content) ── */
|
|
1113
|
+
self._messagesInner = _el('div', { className: 'wakz-msgs-inner' });
|
|
1114
|
+
self._messagesContainer.appendChild(self._messagesInner);
|
|
1115
|
+
|
|
1116
|
+
/* ══════════════ FLOATING INPUT (pill, absolute bottom) ══════════════ */
|
|
1117
|
+
self._inputWrap = _el('div', { className: 'wakz-input-wrap' });
|
|
1118
|
+
var inputRow = _el('div', { className: 'wakz-input-row' });
|
|
857
1119
|
|
|
858
|
-
/*
|
|
859
|
-
var
|
|
1120
|
+
/* Input glass pill */
|
|
1121
|
+
var inputGlass = _el('div', { className: 'wakz-input-glass' });
|
|
1122
|
+
|
|
1123
|
+
/* Specular highlight for input glass */
|
|
1124
|
+
inputGlass.appendChild(_el('div', { className: 'wakz-input-specular' }));
|
|
860
1125
|
|
|
861
1126
|
self._inputEl = _el('textarea', {
|
|
862
1127
|
className: 'wakz-input',
|
|
@@ -864,16 +1129,21 @@
|
|
|
864
1129
|
rows: 1,
|
|
865
1130
|
dir: isRtl ? 'rtl' : 'ltr'
|
|
866
1131
|
});
|
|
867
|
-
|
|
1132
|
+
inputGlass.appendChild(self._inputEl);
|
|
1133
|
+
inputRow.appendChild(inputGlass);
|
|
868
1134
|
|
|
1135
|
+
/* Send button (40px circle, separate from input) */
|
|
869
1136
|
self._sendBtn = _el('button', {
|
|
870
1137
|
className: 'wakz-send',
|
|
871
1138
|
'aria-label': str.sendMessage
|
|
872
1139
|
});
|
|
873
1140
|
self._sendBtn.innerHTML = _ICONS.send;
|
|
874
|
-
|
|
875
|
-
|
|
1141
|
+
inputRow.appendChild(self._sendBtn);
|
|
1142
|
+
|
|
1143
|
+
self._inputWrap.appendChild(inputRow);
|
|
1144
|
+
self._messagesContainer.appendChild(self._inputWrap);
|
|
876
1145
|
|
|
1146
|
+
self._chatWindow.appendChild(self._messagesContainer);
|
|
877
1147
|
self._root.appendChild(self._chatWindow);
|
|
878
1148
|
};
|
|
879
1149
|
|
|
@@ -889,8 +1159,13 @@
|
|
|
889
1159
|
self.toggleChat(!self.isOpen);
|
|
890
1160
|
});
|
|
891
1161
|
|
|
1162
|
+
/* Overlay click to close */
|
|
1163
|
+
self._overlay.addEventListener('click', function () {
|
|
1164
|
+
self.toggleChat(false);
|
|
1165
|
+
});
|
|
1166
|
+
|
|
892
1167
|
/* Close button click */
|
|
893
|
-
self.
|
|
1168
|
+
self._closeBtn.addEventListener('click', function () {
|
|
894
1169
|
self.toggleChat(false);
|
|
895
1170
|
});
|
|
896
1171
|
|
|
@@ -907,10 +1182,16 @@
|
|
|
907
1182
|
}
|
|
908
1183
|
});
|
|
909
1184
|
|
|
910
|
-
/* Auto-resize textarea */
|
|
1185
|
+
/* Auto-resize textarea (max 48px) + toggle send active state */
|
|
911
1186
|
self._inputEl.addEventListener('input', function () {
|
|
912
1187
|
self._inputEl.style.height = 'auto';
|
|
913
|
-
self._inputEl.style.height = Math.min(self._inputEl.scrollHeight,
|
|
1188
|
+
self._inputEl.style.height = Math.min(self._inputEl.scrollHeight, 48) + 'px';
|
|
1189
|
+
var hasText = (self._inputEl.value || '').trim().length > 0;
|
|
1190
|
+
if (hasText) {
|
|
1191
|
+
self._sendBtn.classList.add('wakz-send--active');
|
|
1192
|
+
} else {
|
|
1193
|
+
self._sendBtn.classList.remove('wakz-send--active');
|
|
1194
|
+
}
|
|
914
1195
|
});
|
|
915
1196
|
|
|
916
1197
|
/* Escape to close */
|
|
@@ -925,7 +1206,6 @@
|
|
|
925
1206
|
|
|
926
1207
|
WAKZWidget.prototype._playFabEntrance = function () {
|
|
927
1208
|
var self = this;
|
|
928
|
-
/* Start invisible, then animate after a brief delay */
|
|
929
1209
|
self._toggleBtn.style.opacity = '0';
|
|
930
1210
|
setTimeout(function () {
|
|
931
1211
|
self._toggleBtn.style.opacity = '';
|
|
@@ -942,6 +1222,8 @@
|
|
|
942
1222
|
self.isOpen = open;
|
|
943
1223
|
if (open) {
|
|
944
1224
|
self._chatWindow.classList.add('wakz-visible');
|
|
1225
|
+
self._overlay.classList.add('wakz-visible');
|
|
1226
|
+
self._toggleBtn.classList.add('wakz-fab-hidden');
|
|
945
1227
|
/* Fetch history on first open (after config is loaded) */
|
|
946
1228
|
if (self._configLoaded && !self._hasFetchedHistory) {
|
|
947
1229
|
self._fetchHistory();
|
|
@@ -955,6 +1237,8 @@
|
|
|
955
1237
|
setTimeout(function () { self._inputEl.focus(); }, 320);
|
|
956
1238
|
} else {
|
|
957
1239
|
self._chatWindow.classList.remove('wakz-visible');
|
|
1240
|
+
self._overlay.classList.remove('wakz-visible');
|
|
1241
|
+
self._toggleBtn.classList.remove('wakz-fab-hidden');
|
|
958
1242
|
/* Stop polling when chat is closed */
|
|
959
1243
|
self._stopPolling();
|
|
960
1244
|
}
|
|
@@ -988,7 +1272,6 @@
|
|
|
988
1272
|
}
|
|
989
1273
|
})
|
|
990
1274
|
.catch(function (err) {
|
|
991
|
-
/* AbortError means timeout */
|
|
992
1275
|
self._handleConfigError();
|
|
993
1276
|
});
|
|
994
1277
|
};
|
|
@@ -1004,9 +1287,13 @@
|
|
|
1004
1287
|
self._statusDot.className = 'wakz-fab-dot offline';
|
|
1005
1288
|
self._statusDot.style.display = '';
|
|
1006
1289
|
}
|
|
1007
|
-
/* Update header status */
|
|
1290
|
+
/* Update header status pill to offline */
|
|
1291
|
+
if (self._headerStatusPill) {
|
|
1292
|
+
self._headerStatusPill.className = 'wakz-status-pill wakz-status-pill--offline';
|
|
1293
|
+
self._headerStatusPill.style.display = '';
|
|
1294
|
+
}
|
|
1008
1295
|
if (self._headerStatusDot) {
|
|
1009
|
-
self._headerStatusDot.className = 'wakz-
|
|
1296
|
+
self._headerStatusDot.className = 'wakz-status-dot';
|
|
1010
1297
|
}
|
|
1011
1298
|
if (self._headerStatusText) {
|
|
1012
1299
|
self._headerStatusText.textContent = _strings(self.config.language).offline;
|
|
@@ -1033,33 +1320,37 @@
|
|
|
1033
1320
|
else self._root.classList.remove('wakz-rtl');
|
|
1034
1321
|
|
|
1035
1322
|
/* ── FAB ── */
|
|
1036
|
-
self._toggleBtn.className = 'wakz-fab wakz-fab-pos-' + posClass + ' wakz-fab-enter';
|
|
1323
|
+
self._toggleBtn.className = 'wakz-fab wakz-fab-pos-' + posClass + ' wakz-fab-enter' + (self.isOpen ? ' wakz-fab-hidden' : '');
|
|
1037
1324
|
self._toggleBtn.setAttribute('aria-label', str.openChat);
|
|
1038
1325
|
|
|
1039
1326
|
/* ── FAB Status Dot ── */
|
|
1040
1327
|
self._statusDot.className = 'wakz-fab-dot ' + (cfg.online ? 'online' : 'offline');
|
|
1041
1328
|
self._statusDot.style.display = cfg.showStatus ? '' : 'none';
|
|
1042
1329
|
|
|
1043
|
-
/* ── Window
|
|
1044
|
-
self._chatWindow.className = 'wakz-window
|
|
1330
|
+
/* ── Window ── */
|
|
1331
|
+
self._chatWindow.className = 'wakz-window' + (self.isOpen ? ' wakz-visible' : '');
|
|
1045
1332
|
|
|
1046
|
-
/* ──
|
|
1047
|
-
|
|
1048
|
-
if (headerEl) headerEl.style.background = cfg.primaryColor;
|
|
1333
|
+
/* ── Overlay ── */
|
|
1334
|
+
self._overlay.className = 'wakz-overlay' + (self.isOpen ? ' wakz-visible' : '');
|
|
1049
1335
|
|
|
1050
|
-
/* ──
|
|
1051
|
-
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
/* ── Header Status ── */
|
|
1057
|
-
if (self._headerStatusDot) {
|
|
1058
|
-
self._headerStatusDot.className = 'wakz-hdr-status-dot ' + (cfg.online ? 'online' : 'offline');
|
|
1059
|
-
self._headerStatusDot.style.display = cfg.showStatus ? '' : 'none';
|
|
1336
|
+
/* ── Header Title & Subtitle (DYNAMIC from config) ── */
|
|
1337
|
+
if (self._headerTitleEl) self._headerTitleEl.textContent = cfg.botName;
|
|
1338
|
+
if (self._headerSubtitleEl) {
|
|
1339
|
+
var sub = cfg.botSubtitle || str.defaultSubtitle || '';
|
|
1340
|
+
self._headerSubtitleEl.textContent = sub;
|
|
1060
1341
|
}
|
|
1061
|
-
|
|
1062
|
-
|
|
1342
|
+
|
|
1343
|
+
/* ── Header Status Pill ── */
|
|
1344
|
+
if (self._headerStatusPill) {
|
|
1345
|
+
self._headerStatusPill.className = 'wakz-status-pill ' + (cfg.online ? 'wakz-status-pill--online' : 'wakz-status-pill--offline');
|
|
1346
|
+
self._headerStatusPill.style.display = cfg.showStatus ? '' : 'none';
|
|
1347
|
+
/* Rebuild pill content if needed */
|
|
1348
|
+
if (self._headerStatusDot) {
|
|
1349
|
+
self._headerStatusDot.className = 'wakz-status-dot';
|
|
1350
|
+
}
|
|
1351
|
+
if (self._headerStatusText) {
|
|
1352
|
+
self._headerStatusText.textContent = cfg.online ? str.online : str.offline;
|
|
1353
|
+
}
|
|
1063
1354
|
}
|
|
1064
1355
|
|
|
1065
1356
|
/* ── Input ── */
|
|
@@ -1067,8 +1358,7 @@
|
|
|
1067
1358
|
self._inputEl.dir = isRtl ? 'rtl' : 'ltr';
|
|
1068
1359
|
|
|
1069
1360
|
/* ── Close button label ── */
|
|
1070
|
-
|
|
1071
|
-
if (closeBtn) closeBtn.setAttribute('aria-label', str.closeChat);
|
|
1361
|
+
if (self._closeBtn) self._closeBtn.setAttribute('aria-label', str.closeChat);
|
|
1072
1362
|
|
|
1073
1363
|
/* ── Send button label ── */
|
|
1074
1364
|
self._sendBtn.setAttribute('aria-label', str.sendMessage);
|
|
@@ -1098,7 +1388,6 @@
|
|
|
1098
1388
|
.then(function (res) { return res.json(); })
|
|
1099
1389
|
.then(function (data) {
|
|
1100
1390
|
if (data && data.success && data.messages && data.messages.length > 0) {
|
|
1101
|
-
/* Clear any existing messages (e.g., welcome) and render history */
|
|
1102
1391
|
self._clearMessages();
|
|
1103
1392
|
self._knownMessageIds = {};
|
|
1104
1393
|
var msgs = data.messages;
|
|
@@ -1109,7 +1398,6 @@
|
|
|
1109
1398
|
var role = m.role === 'user' ? 'user' : 'bot';
|
|
1110
1399
|
self._appendMessage(role, m.content, false, m.createdAt, m.role === 'human_agent');
|
|
1111
1400
|
}
|
|
1112
|
-
/* Set last poll time to the most recent message */
|
|
1113
1401
|
var lastMsg = msgs[msgs.length - 1];
|
|
1114
1402
|
if (lastMsg && lastMsg.createdAt) {
|
|
1115
1403
|
self._lastPollTime = lastMsg.createdAt;
|
|
@@ -1127,7 +1415,7 @@
|
|
|
1127
1415
|
|
|
1128
1416
|
WAKZWidget.prototype._startPolling = function () {
|
|
1129
1417
|
var self = this;
|
|
1130
|
-
self._stopPolling();
|
|
1418
|
+
self._stopPolling();
|
|
1131
1419
|
if (!self._lastPollTime) {
|
|
1132
1420
|
self._lastPollTime = new Date().toISOString();
|
|
1133
1421
|
}
|
|
@@ -1147,7 +1435,7 @@
|
|
|
1147
1435
|
WAKZWidget.prototype._pollForNewMessages = function () {
|
|
1148
1436
|
var self = this;
|
|
1149
1437
|
if (!self.server || !self.apiKey || !self._lastPollTime) return;
|
|
1150
|
-
/* Skip polling while waiting for our own reply
|
|
1438
|
+
/* Skip polling while waiting for our own reply */
|
|
1151
1439
|
if (self._pendingReply) return;
|
|
1152
1440
|
|
|
1153
1441
|
var url = self.server + '/api/v1/embed/chat?api_key=' +
|
|
@@ -1171,7 +1459,6 @@
|
|
|
1171
1459
|
var isHumanAgent = m.role === 'human_agent';
|
|
1172
1460
|
self._appendMessage(role, m.content, false, m.createdAt, isHumanAgent);
|
|
1173
1461
|
}
|
|
1174
|
-
/* Update last poll time */
|
|
1175
1462
|
var lastMsg = msgs[msgs.length - 1];
|
|
1176
1463
|
if (lastMsg && lastMsg.createdAt) {
|
|
1177
1464
|
self._lastPollTime = lastMsg.createdAt;
|
|
@@ -1189,51 +1476,51 @@
|
|
|
1189
1476
|
|
|
1190
1477
|
WAKZWidget.prototype._clearMessages = function () {
|
|
1191
1478
|
var self = this;
|
|
1192
|
-
|
|
1479
|
+
/* Remove all children from messages-inner */
|
|
1480
|
+
if (self._messagesInner) {
|
|
1481
|
+
while (self._messagesInner.firstChild) {
|
|
1482
|
+
self._messagesInner.removeChild(self._messagesInner.firstChild);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1193
1485
|
self.messages = [];
|
|
1194
1486
|
self._knownMessageIds = {};
|
|
1195
1487
|
};
|
|
1196
1488
|
|
|
1197
1489
|
/* ════════════════════════════════════════════════════════════════
|
|
1198
|
-
APPEND WELCOME MESSAGE
|
|
1490
|
+
APPEND WELCOME MESSAGE — no bubble, matching bot messages
|
|
1199
1491
|
════════════════════════════════════════════════════════════════ */
|
|
1200
1492
|
|
|
1201
1493
|
WAKZWidget.prototype._appendWelcomeMessage = function (text) {
|
|
1202
1494
|
var self = this;
|
|
1203
1495
|
if (!text) return;
|
|
1204
1496
|
|
|
1205
|
-
var
|
|
1497
|
+
var row = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
|
|
1498
|
+
|
|
1499
|
+
var content = _el('div', { className: 'wakz-bot-content' });
|
|
1206
1500
|
|
|
1207
|
-
/* Bot
|
|
1208
|
-
var
|
|
1209
|
-
|
|
1210
|
-
wrap.appendChild(avatar);
|
|
1501
|
+
/* Bot label */
|
|
1502
|
+
var label = _el('span', { className: 'wakz-bot-label' }, [self.config.botName]);
|
|
1503
|
+
content.appendChild(label);
|
|
1211
1504
|
|
|
1212
|
-
/*
|
|
1213
|
-
var
|
|
1214
|
-
|
|
1505
|
+
/* Bot text */
|
|
1506
|
+
var textEl = _el('p', { className: 'wakz-bot-text' });
|
|
1507
|
+
textEl.textContent = text;
|
|
1508
|
+
content.appendChild(textEl);
|
|
1215
1509
|
|
|
1216
|
-
|
|
1510
|
+
row.appendChild(content);
|
|
1511
|
+
self._messagesInner.appendChild(row);
|
|
1217
1512
|
self.messages.push({ sender: 'bot', text: text });
|
|
1218
1513
|
self._scrollToBottom();
|
|
1219
1514
|
};
|
|
1220
1515
|
|
|
1221
1516
|
/* ════════════════════════════════════════════════════════════════
|
|
1222
|
-
APPEND MESSAGE TO CHAT
|
|
1517
|
+
APPEND MESSAGE TO CHAT — v4 rendering
|
|
1223
1518
|
════════════════════════════════════════════════════════════════ */
|
|
1224
1519
|
|
|
1225
1520
|
WAKZWidget.prototype._appendMessage = function (sender, text, isError, timestamp, isHumanAgent) {
|
|
1226
1521
|
var self = this;
|
|
1227
1522
|
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
var bubbleClass = 'wakz-bubble ' + sender;
|
|
1231
|
-
if (isError) bubbleClass += ' error-bubble';
|
|
1232
|
-
var bubble = _el('div', { className: bubbleClass });
|
|
1233
|
-
|
|
1234
|
-
bubble.appendChild(document.createTextNode(text));
|
|
1235
|
-
|
|
1236
|
-
/* Timestamp */
|
|
1523
|
+
/* ── Format timestamp ── */
|
|
1237
1524
|
var tsText = '';
|
|
1238
1525
|
if (timestamp) {
|
|
1239
1526
|
try {
|
|
@@ -1249,69 +1536,161 @@
|
|
|
1249
1536
|
tsText = now.getHours().toString().padStart(2, '0') + ':' +
|
|
1250
1537
|
now.getMinutes().toString().padStart(2, '0');
|
|
1251
1538
|
}
|
|
1252
|
-
bubble.appendChild(_el('span', { className: 'wakz-ts' }, [tsText]));
|
|
1253
1539
|
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
self.messages.splice(i, 1);
|
|
1275
|
-
break;
|
|
1540
|
+
if (sender === 'user') {
|
|
1541
|
+
/* ── USER MESSAGE: dark bubble (#111) ── */
|
|
1542
|
+
if (isError) {
|
|
1543
|
+
/* Error: red error bubble */
|
|
1544
|
+
var errRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--user' });
|
|
1545
|
+
var errBubble = _el('div', { className: 'wakz-error-bubble' });
|
|
1546
|
+
errBubble.appendChild(document.createTextNode(text));
|
|
1547
|
+
|
|
1548
|
+
var errStr = _strings(self.config.language);
|
|
1549
|
+
var errRetryBtn = _el('button', { className: 'wakz-retry' }, [
|
|
1550
|
+
_ICONS.error + ' ' + errStr.retry
|
|
1551
|
+
]);
|
|
1552
|
+
(function (rowCapture, errText) {
|
|
1553
|
+
errRetryBtn.addEventListener('click', function () {
|
|
1554
|
+
if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
|
|
1555
|
+
for (var i = self.messages.length - 1; i >= 0; i--) {
|
|
1556
|
+
if (self.messages[i].text === errText && self.messages[i].isError) {
|
|
1557
|
+
self.messages.splice(i, 1);
|
|
1558
|
+
break;
|
|
1559
|
+
}
|
|
1276
1560
|
}
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
break;
|
|
1561
|
+
var lastUserMsg = null;
|
|
1562
|
+
for (var j = self.messages.length - 1; j >= 0; j--) {
|
|
1563
|
+
if (self.messages[j].sender === 'user') {
|
|
1564
|
+
lastUserMsg = self.messages[j].text;
|
|
1565
|
+
break;
|
|
1566
|
+
}
|
|
1284
1567
|
}
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1568
|
+
if (lastUserMsg) self._sendToAPI(lastUserMsg);
|
|
1569
|
+
});
|
|
1570
|
+
})(errRow, text);
|
|
1571
|
+
errBubble.appendChild(errRetryBtn);
|
|
1572
|
+
errRow.appendChild(errBubble);
|
|
1573
|
+
self._messagesInner.appendChild(errRow);
|
|
1574
|
+
self.messages.push({ sender: sender, text: text, isError: !!isError });
|
|
1575
|
+
} else {
|
|
1576
|
+
/* Normal user message: dark bubble */
|
|
1577
|
+
var userRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--user' });
|
|
1578
|
+
var userCard = _el('div', { className: 'wakz-user-card' });
|
|
1579
|
+
|
|
1580
|
+
var userText = _el('p', { className: 'wakz-user-text' });
|
|
1581
|
+
userText.textContent = text; /* XSS safe: textContent */
|
|
1582
|
+
userCard.appendChild(userText);
|
|
1583
|
+
|
|
1584
|
+
userCard.appendChild(_el('span', { className: 'wakz-user-time' }, [tsText]));
|
|
1585
|
+
userRow.appendChild(userCard);
|
|
1586
|
+
self._messagesInner.appendChild(userRow);
|
|
1587
|
+
self.messages.push({ sender: sender, text: text, isError: false });
|
|
1588
|
+
}
|
|
1589
|
+
} else if (isHumanAgent) {
|
|
1590
|
+
/* ── SUPPORT MESSAGE: green accent ── */
|
|
1591
|
+
var supRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--support' });
|
|
1592
|
+
var supContent = _el('div', { className: 'wakz-support-content' });
|
|
1593
|
+
|
|
1594
|
+
/* Support label with dot */
|
|
1595
|
+
var supLabel = _el('span', { className: 'wakz-support-label' });
|
|
1596
|
+
supLabel.appendChild(_el('span', { className: 'wakz-support-label-dot' }));
|
|
1597
|
+
var supStr = _strings(self.config.language);
|
|
1598
|
+
supLabel.appendChild(document.createTextNode(supStr.humanBadge || 'Support Team'));
|
|
1599
|
+
supContent.appendChild(supLabel);
|
|
1600
|
+
|
|
1601
|
+
/* Support text */
|
|
1602
|
+
var supText = _el('p', { className: 'wakz-support-text' });
|
|
1603
|
+
supText.textContent = text; /* XSS safe: textContent */
|
|
1604
|
+
supContent.appendChild(supText);
|
|
1605
|
+
|
|
1606
|
+
supContent.appendChild(_el('span', { className: 'wakz-support-time' }, [tsText]));
|
|
1607
|
+
supRow.appendChild(supContent);
|
|
1608
|
+
self._messagesInner.appendChild(supRow);
|
|
1609
|
+
self.messages.push({ sender: 'support', text: text, isError: false });
|
|
1610
|
+
} else {
|
|
1611
|
+
/* ── BOT MESSAGE: no bubble, on background ── */
|
|
1612
|
+
if (isError) {
|
|
1613
|
+
/* Error: red error bubble */
|
|
1614
|
+
var botErrRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
|
|
1615
|
+
var botErrBubble = _el('div', { className: 'wakz-error-bubble' });
|
|
1616
|
+
botErrBubble.appendChild(document.createTextNode(text));
|
|
1617
|
+
|
|
1618
|
+
var botErrStr = _strings(self.config.language);
|
|
1619
|
+
var botErrRetry = _el('button', { className: 'wakz-retry' }, [
|
|
1620
|
+
_ICONS.error + ' ' + botErrStr.retry
|
|
1621
|
+
]);
|
|
1622
|
+
(function (rowCapture, errText) {
|
|
1623
|
+
botErrRetry.addEventListener('click', function () {
|
|
1624
|
+
if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
|
|
1625
|
+
for (var i = self.messages.length - 1; i >= 0; i--) {
|
|
1626
|
+
if (self.messages[i].text === errText && self.messages[i].isError) {
|
|
1627
|
+
self.messages.splice(i, 1);
|
|
1628
|
+
break;
|
|
1629
|
+
}
|
|
1630
|
+
}
|
|
1631
|
+
var lastUserMsg = null;
|
|
1632
|
+
for (var j = self.messages.length - 1; j >= 0; j--) {
|
|
1633
|
+
if (self.messages[j].sender === 'user') {
|
|
1634
|
+
lastUserMsg = self.messages[j].text;
|
|
1635
|
+
break;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
if (lastUserMsg) self._sendToAPI(lastUserMsg);
|
|
1639
|
+
});
|
|
1640
|
+
})(botErrRow, text);
|
|
1641
|
+
botErrBubble.appendChild(botErrRetry);
|
|
1642
|
+
botErrRow.appendChild(botErrBubble);
|
|
1643
|
+
self._messagesInner.appendChild(botErrRow);
|
|
1644
|
+
self.messages.push({ sender: sender, text: text, isError: true });
|
|
1645
|
+
} else {
|
|
1646
|
+
/* Normal bot message: no bubble */
|
|
1647
|
+
var botRow = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
|
|
1648
|
+
var botContent = _el('div', { className: 'wakz-bot-content' });
|
|
1649
|
+
|
|
1650
|
+
/* Bot label */
|
|
1651
|
+
botContent.appendChild(_el('span', { className: 'wakz-bot-label' }, [self.config.botName]));
|
|
1291
1652
|
|
|
1292
|
-
|
|
1293
|
-
|
|
1653
|
+
/* Bot text */
|
|
1654
|
+
var botTextEl = _el('p', { className: 'wakz-bot-text' });
|
|
1655
|
+
botTextEl.textContent = text; /* XSS safe: textContent */
|
|
1656
|
+
botContent.appendChild(botTextEl);
|
|
1657
|
+
|
|
1658
|
+
/* Timestamp */
|
|
1659
|
+
botContent.appendChild(_el('span', { className: 'wakz-bot-time' }, [tsText]));
|
|
1660
|
+
|
|
1661
|
+
botRow.appendChild(botContent);
|
|
1662
|
+
self._messagesInner.appendChild(botRow);
|
|
1663
|
+
self.messages.push({ sender: sender, text: text, isError: false });
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1294
1666
|
|
|
1295
|
-
self.messages.push({ sender: sender, text: text, isError: !!isError });
|
|
1296
1667
|
self._scrollToBottom();
|
|
1297
1668
|
};
|
|
1298
1669
|
|
|
1299
1670
|
/* ════════════════════════════════════════════════════════════════
|
|
1300
|
-
TYPING INDICATOR
|
|
1671
|
+
TYPING INDICATOR — dots with label, no bubble
|
|
1301
1672
|
════════════════════════════════════════════════════════════════ */
|
|
1302
1673
|
|
|
1303
1674
|
WAKZWidget.prototype._showTyping = function () {
|
|
1304
1675
|
var self = this;
|
|
1305
1676
|
if (self._typingEl) return;
|
|
1306
1677
|
|
|
1307
|
-
self._typingEl = _el('div', { className: 'wakz-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1678
|
+
self._typingEl = _el('div', { className: 'wakz-typing-row' });
|
|
1679
|
+
|
|
1680
|
+
var typingContent = _el('div', { className: 'wakz-typing-content' });
|
|
1681
|
+
|
|
1682
|
+
/* Typing label */
|
|
1683
|
+
typingContent.appendChild(_el('span', { className: 'wakz-typing-label' }, [self.config.botName]));
|
|
1684
|
+
|
|
1685
|
+
/* Bouncing dots */
|
|
1686
|
+
var typingDots = _el('div', { className: 'wakz-typing-dots' });
|
|
1687
|
+
typingDots.appendChild(_el('span'));
|
|
1688
|
+
typingDots.appendChild(_el('span'));
|
|
1689
|
+
typingDots.appendChild(_el('span'));
|
|
1690
|
+
typingContent.appendChild(typingDots);
|
|
1691
|
+
|
|
1692
|
+
self._typingEl.appendChild(typingContent);
|
|
1693
|
+
self._messagesInner.appendChild(self._typingEl);
|
|
1315
1694
|
self._scrollToBottom();
|
|
1316
1695
|
};
|
|
1317
1696
|
|
|
@@ -1351,6 +1730,7 @@
|
|
|
1351
1730
|
/* Clear input */
|
|
1352
1731
|
self._inputEl.value = '';
|
|
1353
1732
|
self._inputEl.style.height = 'auto';
|
|
1733
|
+
self._sendBtn.classList.remove('wakz-send--active');
|
|
1354
1734
|
|
|
1355
1735
|
/* Send to API */
|
|
1356
1736
|
self._sendToAPI(text);
|
|
@@ -1372,7 +1752,7 @@
|
|
|
1372
1752
|
self._sendBtn.disabled = true;
|
|
1373
1753
|
self._showTyping();
|
|
1374
1754
|
|
|
1375
|
-
/* Freeze poll time BEFORE sending
|
|
1755
|
+
/* Freeze poll time BEFORE sending */
|
|
1376
1756
|
self._lastPollTime = new Date().toISOString();
|
|
1377
1757
|
self._pendingReply = true;
|
|
1378
1758
|
|
|
@@ -1408,7 +1788,6 @@
|
|
|
1408
1788
|
} else {
|
|
1409
1789
|
self._appendMessage('bot', _strings(self.config.language).errorMsg, true);
|
|
1410
1790
|
}
|
|
1411
|
-
/* Advance poll time past any messages created during this request */
|
|
1412
1791
|
self._lastPollTime = (data && data.timestamp)
|
|
1413
1792
|
? new Date(new Date(data.timestamp).getTime() + 1000).toISOString()
|
|
1414
1793
|
: new Date(Date.now() + 1000).toISOString();
|
|
@@ -1417,7 +1796,6 @@
|
|
|
1417
1796
|
self._hideTyping();
|
|
1418
1797
|
self._pendingReply = false;
|
|
1419
1798
|
self._appendMessage('bot', _strings(self.config.language).errorMsg, true);
|
|
1420
|
-
/* Advance poll time even on error */
|
|
1421
1799
|
self._lastPollTime = new Date(Date.now() + 1000).toISOString();
|
|
1422
1800
|
})
|
|
1423
1801
|
.finally(function () {
|
|
@@ -1432,7 +1810,7 @@
|
|
|
1432
1810
|
════════════════════════════════════════════════════════════════ */
|
|
1433
1811
|
|
|
1434
1812
|
function boot() {
|
|
1435
|
-
try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget] Init error:', e); }
|
|
1813
|
+
try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget v4.0.0] Init error:', e); }
|
|
1436
1814
|
}
|
|
1437
1815
|
|
|
1438
1816
|
if (document.readyState === 'loading') {
|