wakz-chat-widget 3.0.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 +702 -479
- package/package.json +1 -13
- package/README.md +0 -1
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',
|
|
@@ -245,16 +256,18 @@
|
|
|
245
256
|
self._root = null;
|
|
246
257
|
self._overlay = null;
|
|
247
258
|
self._chatWindow = null;
|
|
248
|
-
self.
|
|
249
|
-
self.
|
|
259
|
+
self._messagesInner = null;
|
|
260
|
+
self._inputWrap = null;
|
|
250
261
|
self._inputEl = null;
|
|
251
262
|
self._sendBtn = null;
|
|
252
263
|
self._toggleBtn = null;
|
|
253
264
|
self._statusDot = null;
|
|
265
|
+
self._headerTitleEl = null;
|
|
266
|
+
self._headerSubtitleEl = null;
|
|
267
|
+
self._headerStatusPill = null;
|
|
254
268
|
self._headerStatusDot = null;
|
|
255
269
|
self._headerStatusText = null;
|
|
256
|
-
self.
|
|
257
|
-
self._headerNameEl = null;
|
|
270
|
+
self._closeBtn = null;
|
|
258
271
|
|
|
259
272
|
/* ── Bootstrap ── */
|
|
260
273
|
self._injectCSS();
|
|
@@ -265,7 +278,7 @@
|
|
|
265
278
|
}
|
|
266
279
|
|
|
267
280
|
/* ════════════════════════════════════════════════════════════════
|
|
268
|
-
CSS — Complete
|
|
281
|
+
CSS — Complete Liquid Glass design (v4.0.0)
|
|
269
282
|
════════════════════════════════════════════════════════════════ */
|
|
270
283
|
|
|
271
284
|
WAKZWidget.prototype._injectCSS = function () {
|
|
@@ -275,18 +288,12 @@
|
|
|
275
288
|
self._styleEl.textContent = [
|
|
276
289
|
/* ── CSS Custom Properties (theming) ── */
|
|
277
290
|
':host {',
|
|
278
|
-
' --wakz-primary: #
|
|
279
|
-
' --wakz-btn: #
|
|
280
|
-
' --wakz-chat-bg: #
|
|
291
|
+
' --wakz-primary: #111111;',
|
|
292
|
+
' --wakz-btn: #111111;',
|
|
293
|
+
' --wakz-chat-bg: #ffffff;',
|
|
281
294
|
' --wakz-widget-bg: #ffffff;',
|
|
282
|
-
' --wakz-icon-radius: 50%;',
|
|
283
|
-
' --wakz-shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);',
|
|
284
|
-
' --wakz-shadow-md: 0 4px 12px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06);',
|
|
285
|
-
' --wakz-shadow-lg: 0 25px 60px rgba(0,0,0,.15), 0 10px 20px rgba(0,0,0,.1);',
|
|
286
|
-
' --wakz-transition: 200ms ease;',
|
|
287
|
-
' --wakz-font: \'Inter\', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;',
|
|
288
295
|
' all: initial;',
|
|
289
|
-
' font-family:
|
|
296
|
+
' font-family: "Cairo", "Tajawal", "IBM Plex Sans Arabic", system-ui, sans-serif;',
|
|
290
297
|
'}',
|
|
291
298
|
|
|
292
299
|
/* ── Reset ── */
|
|
@@ -297,38 +304,57 @@
|
|
|
297
304
|
'}',
|
|
298
305
|
|
|
299
306
|
/* ══════════════════════════════════════════════════
|
|
300
|
-
|
|
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
|
|
301
333
|
══════════════════════════════════════════════════ */
|
|
302
334
|
'.wakz-fab {',
|
|
303
335
|
' position: fixed;',
|
|
304
336
|
' z-index: 2147483647;',
|
|
305
|
-
' width:
|
|
306
|
-
' height:
|
|
307
|
-
' border-radius:
|
|
337
|
+
' width: 56px;',
|
|
338
|
+
' height: 56px;',
|
|
339
|
+
' border-radius: 50%;',
|
|
308
340
|
' border: none;',
|
|
309
341
|
' cursor: pointer;',
|
|
310
342
|
' display: flex;',
|
|
311
343
|
' align-items: center;',
|
|
312
344
|
' justify-content: center;',
|
|
313
|
-
'
|
|
314
|
-
'
|
|
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);',
|
|
315
349
|
' outline: none;',
|
|
316
350
|
' -webkit-tap-highlight-color: transparent;',
|
|
317
|
-
' background: var(--wakz-btn);',
|
|
318
351
|
'}',
|
|
319
352
|
'.wakz-fab:hover {',
|
|
320
|
-
' transform: scale(1.
|
|
321
|
-
' box-shadow: 0
|
|
322
|
-
'}',
|
|
323
|
-
'.wakz-fab:active {',
|
|
324
|
-
' transform: scale(0.94);',
|
|
325
|
-
'}',
|
|
326
|
-
'.wakz-fab svg {',
|
|
327
|
-
' width: 22px;',
|
|
328
|
-
' height: 22px;',
|
|
329
|
-
' color: #ffffff;',
|
|
330
|
-
' 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);',
|
|
331
355
|
'}',
|
|
356
|
+
'.wakz-fab:active { transform: scale(0.93); }',
|
|
357
|
+
'.wakz-fab svg { width: 26px; height: 26px; color: #fff; pointer-events: none; }',
|
|
332
358
|
|
|
333
359
|
/* ── FAB Positioning ── */
|
|
334
360
|
'.wakz-fab-pos-br { bottom: 24px; right: 24px; }',
|
|
@@ -341,14 +367,8 @@
|
|
|
341
367
|
'}',
|
|
342
368
|
|
|
343
369
|
/* ── FAB Entrance Bounce ── */
|
|
344
|
-
'@keyframes wakz-fab-enter {',
|
|
345
|
-
' 0% { opacity: 0; transform: scale(0.3); }',
|
|
346
|
-
' 50% { opacity: 1; transform: scale(1.12); }',
|
|
347
|
-
' 70% { transform: scale(0.92); }',
|
|
348
|
-
' 100% { transform: scale(1); }',
|
|
349
|
-
'}',
|
|
350
370
|
'.wakz-fab-enter {',
|
|
351
|
-
' 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;',
|
|
352
372
|
'}',
|
|
353
373
|
|
|
354
374
|
/* ══════════════════════════════════════════════════
|
|
@@ -365,31 +385,18 @@
|
|
|
365
385
|
' z-index: 2;',
|
|
366
386
|
' transition: background 0.3s ease;',
|
|
367
387
|
'}',
|
|
368
|
-
'.wakz-fab-pos-bl .wakz-fab-dot {',
|
|
369
|
-
' right: auto;',
|
|
370
|
-
' left: -1px;',
|
|
371
|
-
'}',
|
|
372
|
-
|
|
373
|
-
/* ── Online (green pulse) ── */
|
|
388
|
+
'.wakz-fab-pos-bl .wakz-fab-dot { right: auto; left: -1px; }',
|
|
374
389
|
'.wakz-fab-dot.online {',
|
|
375
390
|
' background: #22c55e;',
|
|
391
|
+
' animation: wakz-pulse-green 2.5s ease-in-out infinite;',
|
|
376
392
|
'}',
|
|
377
|
-
'@keyframes wakz-dot-pulse {',
|
|
378
|
-
' 0%, 100% { box-shadow: 0 0 0 0 rgba(34,197,94,0.5); }',
|
|
379
|
-
' 50% { box-shadow: 0 0 0 5px rgba(34,197,94,0); }',
|
|
380
|
-
'}',
|
|
381
|
-
'.wakz-fab-dot.online {',
|
|
382
|
-
' animation: wakz-dot-pulse 2s ease-in-out infinite;',
|
|
383
|
-
'}',
|
|
384
|
-
|
|
385
|
-
/* ── Offline (red, no pulse) ── */
|
|
386
393
|
'.wakz-fab-dot.offline {',
|
|
387
394
|
' background: #ef4444;',
|
|
388
395
|
' animation: none;',
|
|
389
396
|
'}',
|
|
390
397
|
|
|
391
398
|
/* ══════════════════════════════════════════════════
|
|
392
|
-
OVERLAY / BACKDROP —
|
|
399
|
+
OVERLAY / BACKDROP — blur behind modal
|
|
393
400
|
══════════════════════════════════════════════════ */
|
|
394
401
|
'.wakz-overlay {',
|
|
395
402
|
' position: fixed;',
|
|
@@ -400,7 +407,7 @@
|
|
|
400
407
|
' -webkit-backdrop-filter: blur(4px);',
|
|
401
408
|
' opacity: 0;',
|
|
402
409
|
' pointer-events: none;',
|
|
403
|
-
' transition: opacity 0.3s cubic-bezier(0.4,
|
|
410
|
+
' transition: opacity 0.3s cubic-bezier(0.4,0,0.2,1);',
|
|
404
411
|
'}',
|
|
405
412
|
'.wakz-overlay.wakz-visible {',
|
|
406
413
|
' opacity: 1;',
|
|
@@ -408,7 +415,7 @@
|
|
|
408
415
|
'}',
|
|
409
416
|
|
|
410
417
|
/* ══════════════════════════════════════════════════
|
|
411
|
-
CHAT WINDOW — Centered
|
|
418
|
+
CHAT WINDOW — Centered, 420x560, 24px radius
|
|
412
419
|
══════════════════════════════════════════════════ */
|
|
413
420
|
'.wakz-window {',
|
|
414
421
|
' position: fixed;',
|
|
@@ -416,18 +423,23 @@
|
|
|
416
423
|
' top: 50%;',
|
|
417
424
|
' left: 50%;',
|
|
418
425
|
' transform: translate(-50%, -50%) scale(0.95);',
|
|
419
|
-
' width:
|
|
420
|
-
' height:
|
|
421
|
-
'
|
|
426
|
+
' width: 420px;',
|
|
427
|
+
' height: 560px;',
|
|
428
|
+
' max-width: calc(100vw - 24px);',
|
|
429
|
+
' max-height: calc(100vh - 24px);',
|
|
430
|
+
' border-radius: 24px;',
|
|
422
431
|
' overflow: hidden;',
|
|
423
432
|
' display: flex;',
|
|
424
433
|
' flex-direction: column;',
|
|
425
434
|
' background: var(--wakz-widget-bg);',
|
|
426
|
-
' 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);',
|
|
427
439
|
' opacity: 0;',
|
|
428
440
|
' pointer-events: none;',
|
|
429
|
-
' transition: opacity 0.3s cubic-bezier(0.4,
|
|
430
|
-
' 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);',
|
|
431
443
|
'}',
|
|
432
444
|
'.wakz-window.wakz-visible {',
|
|
433
445
|
' opacity: 1;',
|
|
@@ -436,249 +448,342 @@
|
|
|
436
448
|
'}',
|
|
437
449
|
|
|
438
450
|
/* ══════════════════════════════════════════════════
|
|
439
|
-
HEADER —
|
|
451
|
+
FLOATING HEADER WRAP — absolute over messages
|
|
440
452
|
══════════════════════════════════════════════════ */
|
|
441
|
-
'.wakz-
|
|
442
|
-
'
|
|
443
|
-
'
|
|
444
|
-
'
|
|
445
|
-
'
|
|
446
|
-
'
|
|
447
|
-
'
|
|
448
|
-
' color: #171717;',
|
|
449
|
-
' cursor: default;',
|
|
450
|
-
' user-select: none;',
|
|
451
|
-
' background: rgba(255,255,255,0.85);',
|
|
452
|
-
' backdrop-filter: blur(24px);',
|
|
453
|
-
' -webkit-backdrop-filter: blur(24px);',
|
|
454
|
-
' border-bottom: 1px solid rgba(229,229,229,0.6);',
|
|
455
|
-
' box-shadow: 0 4px 12px rgba(0,0,0,0.05);',
|
|
456
|
-
' border-radius: 16px 16px 0 0;',
|
|
453
|
+
'.wakz-header-wrap {',
|
|
454
|
+
' position: absolute;',
|
|
455
|
+
' top: 12px;',
|
|
456
|
+
' right: 12px;',
|
|
457
|
+
' left: 12px;',
|
|
458
|
+
' z-index: 100;',
|
|
459
|
+
' pointer-events: none;',
|
|
457
460
|
'}',
|
|
458
|
-
|
|
461
|
+
|
|
462
|
+
/* ── HEADER — Liquid Glass Pill ── */
|
|
463
|
+
'.wakz-header {',
|
|
464
|
+
' pointer-events: all;',
|
|
459
465
|
' display: flex;',
|
|
460
466
|
' align-items: center;',
|
|
461
|
-
'
|
|
462
|
-
'
|
|
463
|
-
'
|
|
467
|
+
' justify-content: space-between;',
|
|
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;',
|
|
464
483
|
'}',
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
'
|
|
468
|
-
'
|
|
469
|
-
'
|
|
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;',
|
|
470
503
|
'}',
|
|
471
504
|
|
|
472
|
-
/* ──
|
|
473
|
-
'.wakz-
|
|
474
|
-
' width: 32px;',
|
|
475
|
-
' height: 32px;',
|
|
476
|
-
' border-radius: 50%;',
|
|
477
|
-
' background: rgba(23,23,23,0.1);',
|
|
505
|
+
/* ── Brand (right side in RTL) ── */
|
|
506
|
+
'.wakz-hdr-brand {',
|
|
478
507
|
' display: flex;',
|
|
479
508
|
' align-items: center;',
|
|
480
|
-
' justify-content: center;',
|
|
481
|
-
' font-weight: 700;',
|
|
482
|
-
' font-size: 14px;',
|
|
483
509
|
' flex-shrink: 0;',
|
|
484
|
-
'
|
|
510
|
+
' padding: 0 6px;',
|
|
485
511
|
'}',
|
|
486
|
-
|
|
487
|
-
/* ── Header Info ── */
|
|
488
512
|
'.wakz-hdr-info {',
|
|
489
513
|
' display: flex;',
|
|
490
514
|
' flex-direction: column;',
|
|
491
|
-
'
|
|
515
|
+
' gap: 1px;',
|
|
492
516
|
'}',
|
|
493
|
-
'.wakz-hdr-
|
|
517
|
+
'.wakz-hdr-title {',
|
|
494
518
|
' font-size: 15px;',
|
|
495
|
-
' font-weight:
|
|
496
|
-
'
|
|
497
|
-
'
|
|
498
|
-
'
|
|
499
|
-
'
|
|
500
|
-
' text-overflow: ellipsis;',
|
|
519
|
+
' font-weight: 900;',
|
|
520
|
+
' color: #0a0a0a;',
|
|
521
|
+
' letter-spacing: -0.2px;',
|
|
522
|
+
' line-height: 1.2;',
|
|
523
|
+
' font-family: "Cairo", sans-serif;',
|
|
501
524
|
'}',
|
|
502
|
-
'.wakz-hdr-
|
|
525
|
+
'.wakz-hdr-subtitle {',
|
|
503
526
|
' font-size: 11px;',
|
|
504
|
-
'
|
|
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 {',
|
|
505
535
|
' display: flex;',
|
|
506
536
|
' align-items: center;',
|
|
507
|
-
' gap:
|
|
508
|
-
'
|
|
537
|
+
' gap: 8px;',
|
|
538
|
+
' flex-shrink: 0;',
|
|
509
539
|
'}',
|
|
510
540
|
|
|
511
|
-
/* ──
|
|
512
|
-
'.wakz-
|
|
541
|
+
/* ── Status Pill ── */
|
|
542
|
+
'.wakz-status-pill {',
|
|
543
|
+
' display: inline-flex;',
|
|
544
|
+
' align-items: center;',
|
|
545
|
+
' gap: 5px;',
|
|
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);',
|
|
558
|
+
'}',
|
|
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 {',
|
|
513
567
|
' width: 6px;',
|
|
514
568
|
' height: 6px;',
|
|
515
569
|
' border-radius: 50%;',
|
|
516
|
-
' display: inline-block;',
|
|
517
570
|
' flex-shrink: 0;',
|
|
518
|
-
' transition: background 0.3s ease;',
|
|
519
571
|
'}',
|
|
520
|
-
'.wakz-
|
|
521
|
-
'
|
|
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
|
+
'}',
|
|
522
579
|
|
|
523
|
-
/* ── Close Button (
|
|
580
|
+
/* ── Close Button (glass circle) ── */
|
|
524
581
|
'.wakz-close {',
|
|
525
|
-
' width:
|
|
526
|
-
' height:
|
|
582
|
+
' width: 30px;',
|
|
583
|
+
' height: 30px;',
|
|
584
|
+
' min-width: 30px;',
|
|
585
|
+
' min-height: 30px;',
|
|
527
586
|
' border-radius: 50%;',
|
|
528
587
|
' border: none;',
|
|
529
|
-
' background: rgba(23,23,23,0.05);',
|
|
530
|
-
' color: #525252;',
|
|
531
588
|
' cursor: pointer;',
|
|
532
589
|
' display: flex;',
|
|
533
590
|
' align-items: center;',
|
|
534
591
|
' justify-content: center;',
|
|
535
|
-
'
|
|
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);',
|
|
536
603
|
' outline: none;',
|
|
537
|
-
' flex-shrink: 0;',
|
|
538
604
|
'}',
|
|
539
605
|
'.wakz-close:hover {',
|
|
540
|
-
' background: rgba(
|
|
541
|
-
' color: #
|
|
542
|
-
'
|
|
543
|
-
'
|
|
544
|
-
'
|
|
545
|
-
'
|
|
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);',
|
|
546
612
|
'}',
|
|
613
|
+
'.wakz-close:active { transform: scale(0.92); }',
|
|
614
|
+
'.wakz-close svg { width: 14px; height: 14px; }',
|
|
547
615
|
|
|
548
616
|
/* ══════════════════════════════════════════════════
|
|
549
|
-
MESSAGES AREA — scrollable
|
|
617
|
+
MESSAGES AREA — scrollable
|
|
550
618
|
══════════════════════════════════════════════════ */
|
|
551
619
|
'.wakz-msgs {',
|
|
552
620
|
' flex: 1;',
|
|
553
621
|
' overflow-y: auto;',
|
|
554
622
|
' overflow-x: hidden;',
|
|
555
|
-
' padding:
|
|
556
|
-
'
|
|
557
|
-
'
|
|
558
|
-
'
|
|
623
|
+
' padding: 0;',
|
|
624
|
+
' padding-top: 76px;',
|
|
625
|
+
' padding-bottom: 100px;',
|
|
626
|
+
' padding-right: 14px;',
|
|
627
|
+
' padding-left: 14px;',
|
|
559
628
|
' scroll-behavior: smooth;',
|
|
560
|
-
' background: var(--wakz-chat-bg);',
|
|
561
629
|
' position: relative;',
|
|
562
630
|
'}',
|
|
563
|
-
'.wakz-msgs::-webkit-scrollbar { width:
|
|
631
|
+
'.wakz-msgs::-webkit-scrollbar { width: 3px; }',
|
|
564
632
|
'.wakz-msgs::-webkit-scrollbar-track { background: transparent; }',
|
|
565
633
|
'.wakz-msgs::-webkit-scrollbar-thumb {',
|
|
566
|
-
' background: rgba(0,0,0,0.
|
|
567
|
-
' 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;',
|
|
568
642
|
'}',
|
|
569
643
|
|
|
570
644
|
/* ══════════════════════════════════════════════════
|
|
571
|
-
MESSAGE ROWS
|
|
645
|
+
MESSAGE ROWS
|
|
572
646
|
══════════════════════════════════════════════════ */
|
|
573
647
|
'.wakz-msg-row {',
|
|
574
648
|
' display: flex;',
|
|
575
|
-
'
|
|
576
|
-
'
|
|
577
|
-
'
|
|
578
|
-
' align-self: flex-start;',
|
|
579
|
-
' align-items: flex-start;',
|
|
580
|
-
' gap: 8px;',
|
|
581
|
-
' max-width: 80%;',
|
|
582
|
-
'}',
|
|
583
|
-
'.wakz-msg-row.user {',
|
|
584
|
-
' align-self: flex-end;',
|
|
585
|
-
' max-width: 75%;',
|
|
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;',
|
|
586
652
|
'}',
|
|
587
653
|
|
|
588
|
-
|
|
589
|
-
'
|
|
590
|
-
'
|
|
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);',
|
|
591
663
|
'}',
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
'
|
|
595
|
-
'
|
|
596
|
-
' font-size: 14px;',
|
|
597
|
-
' line-height: 1.55;',
|
|
598
|
-
' word-wrap: break-word;',
|
|
599
|
-
' overflow-wrap: break-word;',
|
|
664
|
+
'.wakz-user-text {',
|
|
665
|
+
' font-size: 13.5px;',
|
|
666
|
+
' font-weight: 400;',
|
|
667
|
+
' line-height: 1.7;',
|
|
600
668
|
' white-space: pre-wrap;',
|
|
601
|
-
'
|
|
602
|
-
'
|
|
603
|
-
'
|
|
604
|
-
'
|
|
605
|
-
'
|
|
669
|
+
' word-break: break-word;',
|
|
670
|
+
' text-align: right;',
|
|
671
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
672
|
+
'}',
|
|
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;',
|
|
606
680
|
'}',
|
|
607
681
|
|
|
608
|
-
/* ──
|
|
682
|
+
/* ── BOT MESSAGE — no bubble, on background ── */
|
|
683
|
+
'.wakz-msg-row--bot { justify-content: flex-start; }',
|
|
609
684
|
'.wakz-bot-content {',
|
|
685
|
+
' max-width: 78%;',
|
|
610
686
|
' display: flex;',
|
|
611
687
|
' flex-direction: column;',
|
|
612
|
-
'
|
|
613
|
-
'
|
|
688
|
+
' align-items: flex-end;',
|
|
689
|
+
' gap: 1px;',
|
|
690
|
+
'}',
|
|
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;',
|
|
614
698
|
'}',
|
|
615
699
|
'.wakz-bot-text {',
|
|
616
|
-
' font-size:
|
|
617
|
-
'
|
|
618
|
-
'
|
|
619
|
-
'
|
|
620
|
-
' overflow-wrap: break-word;',
|
|
700
|
+
' font-size: 13.5px;',
|
|
701
|
+
' font-weight: 400;',
|
|
702
|
+
' line-height: 1.75;',
|
|
703
|
+
' color: #333333;',
|
|
621
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;',
|
|
622
709
|
'}',
|
|
623
|
-
'.wakz-bot-
|
|
624
|
-
' font-size:
|
|
625
|
-
' color: #
|
|
710
|
+
'.wakz-bot-time {',
|
|
711
|
+
' font-size: 9.5px;',
|
|
712
|
+
' color: #cccccc;',
|
|
713
|
+
' display: block;',
|
|
714
|
+
' margin-top: 1px;',
|
|
715
|
+
' text-align: left;',
|
|
716
|
+
' padding-left: 4px;',
|
|
717
|
+
' font-family: "Tajawal", sans-serif;',
|
|
626
718
|
'}',
|
|
627
719
|
|
|
628
|
-
/* ──
|
|
629
|
-
'.wakz-
|
|
630
|
-
'
|
|
631
|
-
'
|
|
632
|
-
' border-radius: 50%;',
|
|
633
|
-
' background: rgba(23,23,23,0.08);',
|
|
720
|
+
/* ── SUPPORT MESSAGE — green accent ── */
|
|
721
|
+
'.wakz-msg-row--support { justify-content: flex-start; }',
|
|
722
|
+
'.wakz-support-content {',
|
|
723
|
+
' max-width: 78%;',
|
|
634
724
|
' display: flex;',
|
|
635
|
-
'
|
|
636
|
-
'
|
|
637
|
-
'
|
|
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 {',
|
|
638
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;',
|
|
639
747
|
' flex-shrink: 0;',
|
|
640
|
-
' color: var(--wakz-primary);',
|
|
641
|
-
' margin-top: 2px;',
|
|
642
748
|
'}',
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
'
|
|
646
|
-
'
|
|
647
|
-
'
|
|
648
|
-
'
|
|
649
|
-
'
|
|
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;',
|
|
650
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;',
|
|
651
768
|
'}',
|
|
652
769
|
|
|
653
770
|
/* ── Error Messages ── */
|
|
654
|
-
'.wakz-
|
|
771
|
+
'.wakz-error-bubble {',
|
|
772
|
+
' max-width: 78%;',
|
|
655
773
|
' padding: 10px 14px;',
|
|
656
|
-
' font-size:
|
|
657
|
-
' line-height: 1.
|
|
658
|
-
' word-wrap: break-word;',
|
|
659
|
-
' overflow-wrap: break-word;',
|
|
774
|
+
' font-size: 13.5px;',
|
|
775
|
+
' line-height: 1.6;',
|
|
660
776
|
' white-space: pre-wrap;',
|
|
777
|
+
' word-break: break-word;',
|
|
661
778
|
' border-radius: 14px;',
|
|
662
779
|
' border-bottom-left-radius: 4px;',
|
|
663
780
|
' background: #FEF2F2;',
|
|
664
781
|
' color: #DC2626;',
|
|
665
782
|
' border: 1px solid #FECACA;',
|
|
783
|
+
' font-family: "Tajawal", "Cairo", sans-serif;',
|
|
666
784
|
'}',
|
|
667
785
|
|
|
668
|
-
/* ──
|
|
669
|
-
'.wakz-human-badge {',
|
|
670
|
-
' display: inline-block;',
|
|
671
|
-
' font-size: 10px;',
|
|
672
|
-
' background: rgba(22, 163, 74, 0.08);',
|
|
673
|
-
' color: #16A34A;',
|
|
674
|
-
' border-radius: 6px;',
|
|
675
|
-
' padding: 2px 8px;',
|
|
676
|
-
' margin-top: 4px;',
|
|
677
|
-
' font-weight: 600;',
|
|
678
|
-
' letter-spacing: 0.2px;',
|
|
679
|
-
'}',
|
|
680
|
-
|
|
681
|
-
/* ── Retry Button (inside error bubble) ── */
|
|
786
|
+
/* ── Retry Button ── */
|
|
682
787
|
'.wakz-retry {',
|
|
683
788
|
' display: inline-flex;',
|
|
684
789
|
' align-items: center;',
|
|
@@ -692,183 +797,226 @@
|
|
|
692
797
|
' background: #ffffff;',
|
|
693
798
|
' color: #dc2626;',
|
|
694
799
|
' cursor: pointer;',
|
|
695
|
-
' font-family:
|
|
696
|
-
' transition: background
|
|
800
|
+
' font-family: "Cairo", "Tajawal", sans-serif;',
|
|
801
|
+
' transition: background 0.2s ease, border-color 0.2s ease;',
|
|
697
802
|
' outline: none;',
|
|
698
803
|
'}',
|
|
699
|
-
'.wakz-retry:hover {',
|
|
700
|
-
' background: #fef2f2;',
|
|
701
|
-
' border-color: #f87171;',
|
|
702
|
-
'}',
|
|
804
|
+
'.wakz-retry:hover { background: #fef2f2; border-color: #f87171; }',
|
|
703
805
|
|
|
704
806
|
/* ══════════════════════════════════════════════════
|
|
705
|
-
TYPING INDICATOR
|
|
807
|
+
TYPING INDICATOR
|
|
706
808
|
══════════════════════════════════════════════════ */
|
|
707
809
|
'.wakz-typing-row {',
|
|
708
810
|
' display: flex;',
|
|
709
|
-
' align-items: flex-
|
|
710
|
-
'
|
|
711
|
-
'
|
|
712
|
-
' animation: wakz-
|
|
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;',
|
|
713
828
|
'}',
|
|
714
|
-
'.wakz-typing {',
|
|
829
|
+
'.wakz-typing-dots {',
|
|
715
830
|
' display: flex;',
|
|
716
831
|
' align-items: center;',
|
|
717
832
|
' gap: 4px;',
|
|
718
|
-
' padding:
|
|
833
|
+
' padding: 8px 12px;',
|
|
719
834
|
'}',
|
|
720
|
-
'.wakz-typing-
|
|
835
|
+
'.wakz-typing-dots span {',
|
|
721
836
|
' width: 6px;',
|
|
722
837
|
' height: 6px;',
|
|
723
838
|
' border-radius: 50%;',
|
|
724
|
-
' background: #
|
|
725
|
-
' animation: wakz-bounce
|
|
726
|
-
'}',
|
|
727
|
-
'.wakz-typing-dot:nth-child(2) { animation-delay: 0.16s; }',
|
|
728
|
-
'.wakz-typing-dot:nth-child(3) { animation-delay: 0.32s; }',
|
|
729
|
-
'@keyframes wakz-bounce-dot {',
|
|
730
|
-
' 0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }',
|
|
731
|
-
' 30% { transform: translateY(-7px); opacity: 1; }',
|
|
839
|
+
' background: #bbb;',
|
|
840
|
+
' animation: wakz-typing-bounce 1.4s ease-in-out infinite;',
|
|
732
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; }',
|
|
733
845
|
|
|
734
846
|
/* ══════════════════════════════════════════════════
|
|
735
|
-
INPUT
|
|
847
|
+
FLOATING INPUT WRAP — absolute bottom
|
|
736
848
|
══════════════════════════════════════════════════ */
|
|
737
|
-
'.wakz-input-
|
|
849
|
+
'.wakz-input-wrap {',
|
|
738
850
|
' position: absolute;',
|
|
739
851
|
' bottom: 12px;',
|
|
740
|
-
' left: 12px;',
|
|
741
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%;',
|
|
742
860
|
' display: flex;',
|
|
743
|
-
' align-items:
|
|
861
|
+
' align-items: center;',
|
|
744
862
|
' gap: 8px;',
|
|
745
|
-
'
|
|
746
|
-
|
|
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%);',
|
|
747
874
|
' background: rgba(255,255,255,0.85);',
|
|
748
|
-
'
|
|
749
|
-
' -
|
|
750
|
-
'
|
|
751
|
-
'
|
|
752
|
-
'
|
|
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;',
|
|
753
904
|
'}',
|
|
905
|
+
|
|
906
|
+
/* ── Textarea ── */
|
|
754
907
|
'.wakz-input {',
|
|
755
908
|
' flex: 1;',
|
|
909
|
+
' resize: none;',
|
|
756
910
|
' border: none;',
|
|
757
|
-
' border-radius: 0;',
|
|
758
|
-
' padding: 6px 4px;',
|
|
759
|
-
' font-size: 14px;',
|
|
760
|
-
' line-height: 1.4;',
|
|
761
911
|
' outline: none;',
|
|
762
|
-
' font-family: var(--wakz-font);',
|
|
763
|
-
' resize: none;',
|
|
764
|
-
' max-height: 80px;',
|
|
765
|
-
' min-height: 22px;',
|
|
766
|
-
' overflow-y: auto;',
|
|
767
912
|
' background: transparent;',
|
|
768
|
-
'
|
|
769
|
-
'
|
|
770
|
-
'
|
|
771
|
-
'
|
|
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;',
|
|
920
|
+
' overflow-y: auto;',
|
|
921
|
+
' align-self: center;',
|
|
772
922
|
'}',
|
|
773
923
|
'.wakz-input::placeholder {',
|
|
774
|
-
' color: #
|
|
924
|
+
' color: #bbb;',
|
|
925
|
+
' font-weight: 400;',
|
|
926
|
+
' font-family: "Cairo", "Tajawal", sans-serif;',
|
|
775
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; }',
|
|
776
931
|
|
|
777
|
-
/* ── Send Button
|
|
932
|
+
/* ── Send Button — 40px circle, separate ── */
|
|
778
933
|
'.wakz-send {',
|
|
779
|
-
'
|
|
780
|
-
'
|
|
781
|
-
'
|
|
934
|
+
' flex-shrink: 0;',
|
|
935
|
+
' width: 40px;',
|
|
936
|
+
' height: 40px;',
|
|
937
|
+
' min-width: 40px;',
|
|
938
|
+
' min-height: 40px;',
|
|
782
939
|
' border-radius: 50%;',
|
|
783
940
|
' border: none;',
|
|
784
|
-
' color: #ffffff;',
|
|
785
941
|
' cursor: pointer;',
|
|
786
942
|
' display: flex;',
|
|
787
943
|
' align-items: center;',
|
|
788
944
|
' justify-content: center;',
|
|
789
|
-
'
|
|
790
|
-
'
|
|
945
|
+
' position: relative;',
|
|
946
|
+
' overflow: hidden;',
|
|
947
|
+
' transition: all 0.25s cubic-bezier(0.22,1,0.36,1);',
|
|
791
948
|
' outline: none;',
|
|
792
|
-
'
|
|
793
|
-
'
|
|
794
|
-
'
|
|
795
|
-
'.
|
|
796
|
-
'
|
|
797
|
-
'
|
|
798
|
-
'
|
|
799
|
-
'.
|
|
800
|
-
'
|
|
801
|
-
'
|
|
802
|
-
'}',
|
|
803
|
-
'.wakz-send:not(:disabled):active {',
|
|
804
|
-
' transform: scale(0.92);',
|
|
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;',
|
|
805
959
|
'}',
|
|
960
|
+
'.wakz-send:disabled { cursor: default; }',
|
|
806
961
|
'.wakz-send svg {',
|
|
807
|
-
' width:
|
|
808
|
-
' height:
|
|
962
|
+
' width: 18px;',
|
|
963
|
+
' height: 18px;',
|
|
809
964
|
' pointer-events: none;',
|
|
810
965
|
'}',
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
'
|
|
816
|
-
'
|
|
817
|
-
'
|
|
818
|
-
'
|
|
819
|
-
'
|
|
820
|
-
' align-self: flex-start;',
|
|
821
|
-
' animation: wakz-msg-in 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
|
|
966
|
+
/* ── Send Active State ── */
|
|
967
|
+
'.wakz-send--active {',
|
|
968
|
+
' background: #111111;',
|
|
969
|
+
' border-color: #111111;',
|
|
970
|
+
' color: #ffffff;',
|
|
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);',
|
|
822
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);',
|
|
980
|
+
'}',
|
|
981
|
+
'.wakz-send--active:active:not(:disabled) { transform: scale(0.93); }',
|
|
823
982
|
|
|
824
983
|
/* ══════════════════════════════════════════════════
|
|
825
984
|
RTL SUPPORT
|
|
826
985
|
══════════════════════════════════════════════════ */
|
|
827
986
|
'.wakz-rtl { direction: rtl; }',
|
|
828
|
-
'.wakz-rtl .wakz-
|
|
829
|
-
' border-
|
|
830
|
-
' border-bottom-left-radius: 4px;',
|
|
987
|
+
'.wakz-rtl .wakz-user-card {',
|
|
988
|
+
' border-radius: 18px 18px 18px 5px;',
|
|
831
989
|
'}',
|
|
832
|
-
'.wakz-rtl .wakz-
|
|
990
|
+
'.wakz-rtl .wakz-error-bubble {',
|
|
833
991
|
' border-bottom-left-radius: 14px;',
|
|
834
992
|
' border-bottom-right-radius: 4px;',
|
|
835
993
|
'}',
|
|
836
|
-
'.wakz-rtl .wakz-ts {',
|
|
837
|
-
' text-align: left;',
|
|
838
|
-
'}',
|
|
839
994
|
|
|
840
995
|
/* ══════════════════════════════════════════════════
|
|
841
|
-
|
|
996
|
+
RESPONSIVE
|
|
842
997
|
══════════════════════════════════════════════════ */
|
|
843
|
-
'@media (max-width:
|
|
998
|
+
'@media (max-width: 440px) {',
|
|
844
999
|
' .wakz-window {',
|
|
845
|
-
' width:
|
|
846
|
-
' height:
|
|
847
|
-
'
|
|
848
|
-
'
|
|
849
|
-
'
|
|
850
|
-
'
|
|
851
|
-
' .wakz-fab {',
|
|
852
|
-
' width: 44px;',
|
|
853
|
-
' height: 44px;',
|
|
854
|
-
' }',
|
|
855
|
-
' .wakz-fab-pos-br { bottom: 16px; right: 16px; }',
|
|
856
|
-
' .wakz-fab-pos-bl { bottom: 16px; left: 16px; }',
|
|
857
|
-
' .wakz-input-area {',
|
|
858
|
-
' left: 10px;',
|
|
859
|
-
' right: 10px;',
|
|
860
|
-
' bottom: 10px;',
|
|
861
|
-
' padding: 6px 8px 6px 12px;',
|
|
862
|
-
' }',
|
|
863
|
-
' .wakz-msgs {',
|
|
864
|
-
' padding: 14px 12px 84px;',
|
|
1000
|
+
' width: 100% !important;',
|
|
1001
|
+
' height: 100% !important;',
|
|
1002
|
+
' max-width: 100% !important;',
|
|
1003
|
+
' max-height: 100% !important;',
|
|
1004
|
+
' border-radius: 0 !important;',
|
|
1005
|
+
' box-shadow: none !important;',
|
|
865
1006
|
' }',
|
|
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; }',
|
|
866
1014
|
'}'
|
|
867
1015
|
].join('\n');
|
|
868
1016
|
};
|
|
869
1017
|
|
|
870
1018
|
/* ════════════════════════════════════════════════════════════════
|
|
871
|
-
DOM CREATION —
|
|
1019
|
+
DOM CREATION — v4.0.0 Liquid Glass structure
|
|
872
1020
|
════════════════════════════════════════════════════════════════ */
|
|
873
1021
|
|
|
874
1022
|
WAKZWidget.prototype._createDOM = function () {
|
|
@@ -882,6 +1030,13 @@
|
|
|
882
1030
|
document.body.appendChild(self._host);
|
|
883
1031
|
self._shadow = self._host.attachShadow({ mode: 'closed' });
|
|
884
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
|
+
|
|
885
1040
|
/* ── Root wrapper ── */
|
|
886
1041
|
self._root = _el('div', { className: 'wakz' + (isRtl ? ' wakz-rtl' : '') });
|
|
887
1042
|
self._shadow.appendChild(self._styleEl);
|
|
@@ -904,46 +1059,69 @@
|
|
|
904
1059
|
self._overlay = _el('div', { className: 'wakz-overlay' });
|
|
905
1060
|
self._root.appendChild(self._overlay);
|
|
906
1061
|
|
|
907
|
-
/* ══════════════ CHAT WINDOW
|
|
1062
|
+
/* ══════════════ CHAT WINDOW ══════════════ */
|
|
908
1063
|
self._chatWindow = _el('div', { className: 'wakz-window' });
|
|
909
1064
|
|
|
910
|
-
/* ──
|
|
911
|
-
|
|
1065
|
+
/* ── Messages Container (with floating header + input inside) ── */
|
|
1066
|
+
self._messagesContainer = _el('div', { className: 'wakz-msgs' });
|
|
912
1067
|
|
|
913
|
-
/*
|
|
914
|
-
var
|
|
915
|
-
var
|
|
916
|
-
self._headerAvatarEl = _el('div', { className: 'wakz-avatar' }, [avatarLetter]);
|
|
917
|
-
headerLeft.appendChild(self._headerAvatarEl);
|
|
1068
|
+
/* ══════════════ FLOATING HEADER (pill, absolute over messages) ══════════════ */
|
|
1069
|
+
var headerWrap = _el('div', { className: 'wakz-header-wrap' });
|
|
1070
|
+
var header = _el('div', { className: 'wakz-header' });
|
|
918
1071
|
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
headerInfo.appendChild(self._headerNameEl);
|
|
1072
|
+
/* Specular highlight (real DOM element, not ::before) */
|
|
1073
|
+
header.appendChild(_el('div', { className: 'wakz-specular' }));
|
|
922
1074
|
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
self.
|
|
927
|
-
|
|
928
|
-
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);
|
|
929
1080
|
|
|
930
|
-
|
|
931
|
-
|
|
1081
|
+
var subtitleText = self.config.botSubtitle || str.defaultSubtitle || '';
|
|
1082
|
+
self._headerSubtitleEl = _el('span', { className: 'wakz-hdr-subtitle' }, [subtitleText]);
|
|
1083
|
+
info.appendChild(self._headerSubtitleEl);
|
|
932
1084
|
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
var closeBtn = _el('button', { className: 'wakz-close', 'aria-label': str.closeChat });
|
|
936
|
-
closeBtn.innerHTML = _ICONS.close;
|
|
937
|
-
headerRight.appendChild(closeBtn);
|
|
938
|
-
headerEl.appendChild(headerRight);
|
|
1085
|
+
brand.appendChild(info);
|
|
1086
|
+
header.appendChild(brand);
|
|
939
1087
|
|
|
940
|
-
|
|
1088
|
+
/* Actions side (left in RTL) */
|
|
1089
|
+
var actions = _el('div', { className: 'wakz-hdr-actions' });
|
|
941
1090
|
|
|
942
|
-
/*
|
|
943
|
-
self.
|
|
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);
|
|
944
1115
|
|
|
945
|
-
/*
|
|
946
|
-
self.
|
|
1116
|
+
/* ══════════════ FLOATING INPUT (pill, absolute bottom) ══════════════ */
|
|
1117
|
+
self._inputWrap = _el('div', { className: 'wakz-input-wrap' });
|
|
1118
|
+
var inputRow = _el('div', { className: 'wakz-input-row' });
|
|
1119
|
+
|
|
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' }));
|
|
947
1125
|
|
|
948
1126
|
self._inputEl = _el('textarea', {
|
|
949
1127
|
className: 'wakz-input',
|
|
@@ -951,18 +1129,21 @@
|
|
|
951
1129
|
rows: 1,
|
|
952
1130
|
dir: isRtl ? 'rtl' : 'ltr'
|
|
953
1131
|
});
|
|
954
|
-
|
|
1132
|
+
inputGlass.appendChild(self._inputEl);
|
|
1133
|
+
inputRow.appendChild(inputGlass);
|
|
955
1134
|
|
|
1135
|
+
/* Send button (40px circle, separate from input) */
|
|
956
1136
|
self._sendBtn = _el('button', {
|
|
957
1137
|
className: 'wakz-send',
|
|
958
1138
|
'aria-label': str.sendMessage
|
|
959
1139
|
});
|
|
960
1140
|
self._sendBtn.innerHTML = _ICONS.send;
|
|
961
|
-
|
|
1141
|
+
inputRow.appendChild(self._sendBtn);
|
|
962
1142
|
|
|
963
|
-
self.
|
|
964
|
-
self.
|
|
1143
|
+
self._inputWrap.appendChild(inputRow);
|
|
1144
|
+
self._messagesContainer.appendChild(self._inputWrap);
|
|
965
1145
|
|
|
1146
|
+
self._chatWindow.appendChild(self._messagesContainer);
|
|
966
1147
|
self._root.appendChild(self._chatWindow);
|
|
967
1148
|
};
|
|
968
1149
|
|
|
@@ -984,7 +1165,7 @@
|
|
|
984
1165
|
});
|
|
985
1166
|
|
|
986
1167
|
/* Close button click */
|
|
987
|
-
self.
|
|
1168
|
+
self._closeBtn.addEventListener('click', function () {
|
|
988
1169
|
self.toggleChat(false);
|
|
989
1170
|
});
|
|
990
1171
|
|
|
@@ -1001,10 +1182,16 @@
|
|
|
1001
1182
|
}
|
|
1002
1183
|
});
|
|
1003
1184
|
|
|
1004
|
-
/* Auto-resize textarea (max
|
|
1185
|
+
/* Auto-resize textarea (max 48px) + toggle send active state */
|
|
1005
1186
|
self._inputEl.addEventListener('input', function () {
|
|
1006
1187
|
self._inputEl.style.height = 'auto';
|
|
1007
|
-
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
|
+
}
|
|
1008
1195
|
});
|
|
1009
1196
|
|
|
1010
1197
|
/* Escape to close */
|
|
@@ -1100,9 +1287,13 @@
|
|
|
1100
1287
|
self._statusDot.className = 'wakz-fab-dot offline';
|
|
1101
1288
|
self._statusDot.style.display = '';
|
|
1102
1289
|
}
|
|
1103
|
-
/* 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
|
+
}
|
|
1104
1295
|
if (self._headerStatusDot) {
|
|
1105
|
-
self._headerStatusDot.className = 'wakz-
|
|
1296
|
+
self._headerStatusDot.className = 'wakz-status-dot';
|
|
1106
1297
|
}
|
|
1107
1298
|
if (self._headerStatusText) {
|
|
1108
1299
|
self._headerStatusText.textContent = _strings(self.config.language).offline;
|
|
@@ -1123,7 +1314,6 @@
|
|
|
1123
1314
|
hostStyle.setProperty('--wakz-btn', cfg.btnColor);
|
|
1124
1315
|
hostStyle.setProperty('--wakz-chat-bg', cfg.chatBg);
|
|
1125
1316
|
hostStyle.setProperty('--wakz-widget-bg', cfg.widgetBg);
|
|
1126
|
-
hostStyle.setProperty('--wakz-icon-radius', cfg.iconRadius || '50%');
|
|
1127
1317
|
|
|
1128
1318
|
/* ── RTL ── */
|
|
1129
1319
|
if (isRtl) self._root.classList.add('wakz-rtl');
|
|
@@ -1143,17 +1333,24 @@
|
|
|
1143
1333
|
/* ── Overlay ── */
|
|
1144
1334
|
self._overlay.className = 'wakz-overlay' + (self.isOpen ? ' wakz-visible' : '');
|
|
1145
1335
|
|
|
1146
|
-
/* ──
|
|
1147
|
-
if (self.
|
|
1148
|
-
if (self.
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
if (self._headerStatusDot) {
|
|
1152
|
-
self._headerStatusDot.className = 'wakz-hdr-status-dot ' + (cfg.online ? 'online' : 'offline');
|
|
1153
|
-
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;
|
|
1154
1341
|
}
|
|
1155
|
-
|
|
1156
|
-
|
|
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
|
+
}
|
|
1157
1354
|
}
|
|
1158
1355
|
|
|
1159
1356
|
/* ── Input ── */
|
|
@@ -1161,8 +1358,7 @@
|
|
|
1161
1358
|
self._inputEl.dir = isRtl ? 'rtl' : 'ltr';
|
|
1162
1359
|
|
|
1163
1360
|
/* ── Close button label ── */
|
|
1164
|
-
|
|
1165
|
-
if (closeBtn) closeBtn.setAttribute('aria-label', str.closeChat);
|
|
1361
|
+
if (self._closeBtn) self._closeBtn.setAttribute('aria-label', str.closeChat);
|
|
1166
1362
|
|
|
1167
1363
|
/* ── Send button label ── */
|
|
1168
1364
|
self._sendBtn.setAttribute('aria-label', str.sendMessage);
|
|
@@ -1280,11 +1476,10 @@
|
|
|
1280
1476
|
|
|
1281
1477
|
WAKZWidget.prototype._clearMessages = function () {
|
|
1282
1478
|
var self = this;
|
|
1283
|
-
/* Remove all children
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
self._messagesContainer.removeChild(children[i]);
|
|
1479
|
+
/* Remove all children from messages-inner */
|
|
1480
|
+
if (self._messagesInner) {
|
|
1481
|
+
while (self._messagesInner.firstChild) {
|
|
1482
|
+
self._messagesInner.removeChild(self._messagesInner.firstChild);
|
|
1288
1483
|
}
|
|
1289
1484
|
}
|
|
1290
1485
|
self.messages = [];
|
|
@@ -1292,33 +1487,34 @@
|
|
|
1292
1487
|
};
|
|
1293
1488
|
|
|
1294
1489
|
/* ════════════════════════════════════════════════════════════════
|
|
1295
|
-
APPEND WELCOME MESSAGE — no bubble
|
|
1490
|
+
APPEND WELCOME MESSAGE — no bubble, matching bot messages
|
|
1296
1491
|
════════════════════════════════════════════════════════════════ */
|
|
1297
1492
|
|
|
1298
1493
|
WAKZWidget.prototype._appendWelcomeMessage = function (text) {
|
|
1299
1494
|
var self = this;
|
|
1300
1495
|
if (!text) return;
|
|
1301
1496
|
|
|
1302
|
-
var
|
|
1303
|
-
|
|
1304
|
-
/* Bot avatar (22px) */
|
|
1305
|
-
var avatar = _el('div', { className: 'wakz-bot-avatar' },
|
|
1306
|
-
[(self.config.botName || 'W')[0].toUpperCase()]);
|
|
1307
|
-
wrap.appendChild(avatar);
|
|
1497
|
+
var row = _el('div', { className: 'wakz-msg-row wakz-msg-row--bot' });
|
|
1308
1498
|
|
|
1309
|
-
/* Bot text content — no bubble */
|
|
1310
1499
|
var content = _el('div', { className: 'wakz-bot-content' });
|
|
1311
|
-
content.appendChild(_el('div', { className: 'wakz-bot-text' }, [text]));
|
|
1312
|
-
wrap.appendChild(content);
|
|
1313
1500
|
|
|
1314
|
-
/*
|
|
1315
|
-
|
|
1501
|
+
/* Bot label */
|
|
1502
|
+
var label = _el('span', { className: 'wakz-bot-label' }, [self.config.botName]);
|
|
1503
|
+
content.appendChild(label);
|
|
1504
|
+
|
|
1505
|
+
/* Bot text */
|
|
1506
|
+
var textEl = _el('p', { className: 'wakz-bot-text' });
|
|
1507
|
+
textEl.textContent = text;
|
|
1508
|
+
content.appendChild(textEl);
|
|
1509
|
+
|
|
1510
|
+
row.appendChild(content);
|
|
1511
|
+
self._messagesInner.appendChild(row);
|
|
1316
1512
|
self.messages.push({ sender: 'bot', text: text });
|
|
1317
1513
|
self._scrollToBottom();
|
|
1318
1514
|
};
|
|
1319
1515
|
|
|
1320
1516
|
/* ════════════════════════════════════════════════════════════════
|
|
1321
|
-
APPEND MESSAGE TO CHAT —
|
|
1517
|
+
APPEND MESSAGE TO CHAT — v4 rendering
|
|
1322
1518
|
════════════════════════════════════════════════════════════════ */
|
|
1323
1519
|
|
|
1324
1520
|
WAKZWidget.prototype._appendMessage = function (sender, text, isError, timestamp, isHumanAgent) {
|
|
@@ -1342,26 +1538,22 @@
|
|
|
1342
1538
|
}
|
|
1343
1539
|
|
|
1344
1540
|
if (sender === 'user') {
|
|
1345
|
-
/* ── USER MESSAGE:
|
|
1346
|
-
var row = _el('div', { className: 'wakz-msg-row user' });
|
|
1347
|
-
|
|
1348
|
-
var bubbleClass = 'wakz-bubble user';
|
|
1349
|
-
if (isError) bubbleClass += ' error-bubble';
|
|
1350
|
-
var bubble = _el('div', { className: bubbleClass });
|
|
1351
|
-
bubble.appendChild(document.createTextNode(text));
|
|
1352
|
-
bubble.appendChild(_el('span', { className: 'wakz-ts' }, [tsText]));
|
|
1353
|
-
|
|
1354
|
-
/* Retry button for error user messages */
|
|
1541
|
+
/* ── USER MESSAGE: dark bubble (#111) ── */
|
|
1355
1542
|
if (isError) {
|
|
1356
|
-
|
|
1357
|
-
var
|
|
1358
|
-
|
|
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
|
|
1359
1551
|
]);
|
|
1360
|
-
(function (rowCapture) {
|
|
1361
|
-
|
|
1552
|
+
(function (rowCapture, errText) {
|
|
1553
|
+
errRetryBtn.addEventListener('click', function () {
|
|
1362
1554
|
if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
|
|
1363
1555
|
for (var i = self.messages.length - 1; i >= 0; i--) {
|
|
1364
|
-
if (self.messages[i].text ===
|
|
1556
|
+
if (self.messages[i].text === errText && self.messages[i].isError) {
|
|
1365
1557
|
self.messages.splice(i, 1);
|
|
1366
1558
|
break;
|
|
1367
1559
|
}
|
|
@@ -1375,36 +1567,60 @@
|
|
|
1375
1567
|
}
|
|
1376
1568
|
if (lastUserMsg) self._sendToAPI(lastUserMsg);
|
|
1377
1569
|
});
|
|
1378
|
-
})(
|
|
1379
|
-
|
|
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 });
|
|
1380
1588
|
}
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
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 });
|
|
1385
1610
|
} else {
|
|
1386
|
-
/* ── BOT
|
|
1387
|
-
var botRow = _el('div', { className: 'wakz-msg-row bot' });
|
|
1388
|
-
|
|
1389
|
-
/* Small bot avatar (22px) */
|
|
1390
|
-
var botAvatar = _el('div', { className: 'wakz-bot-avatar' },
|
|
1391
|
-
[(self.config.botName || 'W')[0].toUpperCase()]);
|
|
1392
|
-
botRow.appendChild(botAvatar);
|
|
1393
|
-
|
|
1394
|
-
/* Content wrapper */
|
|
1395
|
-
var botContent = _el('div', { className: 'wakz-bot-content' });
|
|
1396
|
-
|
|
1611
|
+
/* ── BOT MESSAGE: no bubble, on background ── */
|
|
1397
1612
|
if (isError) {
|
|
1398
|
-
/* Error:
|
|
1399
|
-
var
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
var
|
|
1404
|
-
|
|
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
|
|
1405
1621
|
]);
|
|
1406
1622
|
(function (rowCapture, errText) {
|
|
1407
|
-
|
|
1623
|
+
botErrRetry.addEventListener('click', function () {
|
|
1408
1624
|
if (rowCapture.parentNode) rowCapture.parentNode.removeChild(rowCapture);
|
|
1409
1625
|
for (var i = self.messages.length - 1; i >= 0; i--) {
|
|
1410
1626
|
if (self.messages[i].text === errText && self.messages[i].isError) {
|
|
@@ -1421,34 +1637,38 @@
|
|
|
1421
1637
|
}
|
|
1422
1638
|
if (lastUserMsg) self._sendToAPI(lastUserMsg);
|
|
1423
1639
|
});
|
|
1424
|
-
})(
|
|
1425
|
-
|
|
1426
|
-
|
|
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 });
|
|
1427
1645
|
} else {
|
|
1428
|
-
/* Normal bot
|
|
1429
|
-
|
|
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]));
|
|
1652
|
+
|
|
1653
|
+
/* Bot text */
|
|
1654
|
+
var botTextEl = _el('p', { className: 'wakz-bot-text' });
|
|
1655
|
+
botTextEl.textContent = text; /* XSS safe: textContent */
|
|
1656
|
+
botContent.appendChild(botTextEl);
|
|
1430
1657
|
|
|
1431
1658
|
/* Timestamp */
|
|
1432
|
-
botContent.appendChild(_el('span', { className: 'wakz-bot-
|
|
1659
|
+
botContent.appendChild(_el('span', { className: 'wakz-bot-time' }, [tsText]));
|
|
1433
1660
|
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
var badge = _el('span', { className: 'wakz-human-badge' }, [iStr.humanBadge || '👤 فريق الدعم']);
|
|
1438
|
-
botContent.appendChild(badge);
|
|
1439
|
-
}
|
|
1661
|
+
botRow.appendChild(botContent);
|
|
1662
|
+
self._messagesInner.appendChild(botRow);
|
|
1663
|
+
self.messages.push({ sender: sender, text: text, isError: false });
|
|
1440
1664
|
}
|
|
1441
|
-
|
|
1442
|
-
botRow.appendChild(botContent);
|
|
1443
|
-
self._messagesContainer.insertBefore(botRow, self._inputArea);
|
|
1444
|
-
self.messages.push({ sender: sender, text: text, isError: !!isError });
|
|
1445
1665
|
}
|
|
1446
1666
|
|
|
1447
1667
|
self._scrollToBottom();
|
|
1448
1668
|
};
|
|
1449
1669
|
|
|
1450
1670
|
/* ════════════════════════════════════════════════════════════════
|
|
1451
|
-
TYPING INDICATOR —
|
|
1671
|
+
TYPING INDICATOR — dots with label, no bubble
|
|
1452
1672
|
════════════════════════════════════════════════════════════════ */
|
|
1453
1673
|
|
|
1454
1674
|
WAKZWidget.prototype._showTyping = function () {
|
|
@@ -1457,18 +1677,20 @@
|
|
|
1457
1677
|
|
|
1458
1678
|
self._typingEl = _el('div', { className: 'wakz-typing-row' });
|
|
1459
1679
|
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
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]));
|
|
1463
1684
|
|
|
1464
|
-
/* Bouncing dots
|
|
1465
|
-
var typingDots = _el('div', { className: 'wakz-typing' });
|
|
1466
|
-
typingDots.appendChild(_el('span'
|
|
1467
|
-
typingDots.appendChild(_el('span'
|
|
1468
|
-
typingDots.appendChild(_el('span'
|
|
1469
|
-
|
|
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);
|
|
1470
1691
|
|
|
1471
|
-
self.
|
|
1692
|
+
self._typingEl.appendChild(typingContent);
|
|
1693
|
+
self._messagesInner.appendChild(self._typingEl);
|
|
1472
1694
|
self._scrollToBottom();
|
|
1473
1695
|
};
|
|
1474
1696
|
|
|
@@ -1508,6 +1730,7 @@
|
|
|
1508
1730
|
/* Clear input */
|
|
1509
1731
|
self._inputEl.value = '';
|
|
1510
1732
|
self._inputEl.style.height = 'auto';
|
|
1733
|
+
self._sendBtn.classList.remove('wakz-send--active');
|
|
1511
1734
|
|
|
1512
1735
|
/* Send to API */
|
|
1513
1736
|
self._sendToAPI(text);
|
|
@@ -1587,7 +1810,7 @@
|
|
|
1587
1810
|
════════════════════════════════════════════════════════════════ */
|
|
1588
1811
|
|
|
1589
1812
|
function boot() {
|
|
1590
|
-
try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget
|
|
1813
|
+
try { new WAKZWidget(); } catch (e) { console.error('[WAKZ Widget v4.0.0] Init error:', e); }
|
|
1591
1814
|
}
|
|
1592
1815
|
|
|
1593
1816
|
if (document.readyState === 'loading') {
|