wakz-chat-widget 1.1.0 → 2.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 +408 -245
- package/package.json +2 -2
package/index.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* WAKZ Chat Widget
|
|
2
|
+
* WAKZ Chat Widget v3.0.0
|
|
3
3
|
* ─────────────────────────────────────────────────────────────────
|
|
4
4
|
* A production-grade, self-contained chat widget using Shadow DOM.
|
|
5
|
-
*
|
|
5
|
+
* Premium glassmorphism design matching the WAKZ site design system.
|
|
6
6
|
*
|
|
7
7
|
* Embed: <script src="/wakz-widget.js" data-api-key="xxx" data-server="https://..." async></script>
|
|
8
|
+
* New attrs: data-icon-color="#171717" data-icon-shape="circle"
|
|
8
9
|
*
|
|
9
10
|
* ZERO external dependencies — pure vanilla JavaScript.
|
|
10
11
|
*/
|
|
@@ -50,7 +51,9 @@
|
|
|
50
51
|
if (!target && scripts.length > 0) target = scripts[scripts.length - 1];
|
|
51
52
|
return {
|
|
52
53
|
apiKey: (target && target.getAttribute('data-api-key')) || '',
|
|
53
|
-
server: (target && target.getAttribute('data-server')) || ''
|
|
54
|
+
server: (target && target.getAttribute('data-server')) || '',
|
|
55
|
+
iconColor: (target && target.getAttribute('data-icon-color')) || '',
|
|
56
|
+
iconShape: (target && target.getAttribute('data-icon-shape')) || ''
|
|
54
57
|
};
|
|
55
58
|
}
|
|
56
59
|
|
|
@@ -92,12 +95,21 @@
|
|
|
92
95
|
════════════════════════════════════════════════════════════════ */
|
|
93
96
|
|
|
94
97
|
var _ICONS = {
|
|
95
|
-
|
|
96
|
-
|
|
98
|
+
/* Modern chat icon: rounded square with 3 horizontal chat lines */
|
|
99
|
+
chatIcon:
|
|
100
|
+
'<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">' +
|
|
101
|
+
'<rect x="3" y="3" width="18" height="18" rx="5" ry="5" stroke="currentColor" stroke-width="1.8" fill="none"/>' +
|
|
102
|
+
'<line x1="8" y1="9" x2="16" y2="9" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>' +
|
|
103
|
+
'<line x1="8" y1="12.5" x2="14" y2="12.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>' +
|
|
104
|
+
'<line x1="8" y1="16" x2="12" y2="16" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>' +
|
|
105
|
+
'</svg>',
|
|
106
|
+
/* Send arrow */
|
|
97
107
|
send:
|
|
98
108
|
'<svg viewBox="0 0 24 24" fill="currentColor"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg>',
|
|
109
|
+
/* Close X */
|
|
99
110
|
close:
|
|
100
|
-
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2
|
|
111
|
+
'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>',
|
|
112
|
+
/* Error circle */
|
|
101
113
|
error:
|
|
102
114
|
'<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>'
|
|
103
115
|
};
|
|
@@ -157,11 +169,12 @@
|
|
|
157
169
|
botName: 'WAKZ',
|
|
158
170
|
welcomeMessage: '',
|
|
159
171
|
primaryColor: '#171717',
|
|
160
|
-
|
|
161
|
-
|
|
172
|
+
iconColor: '#171717',
|
|
173
|
+
iconShape: 'circle',
|
|
174
|
+
chatBg: '#FAFAFA',
|
|
162
175
|
widgetBg: '#ffffff',
|
|
163
176
|
position: 'bottom-right',
|
|
164
|
-
language: '
|
|
177
|
+
language: 'ar',
|
|
165
178
|
showStatus: true,
|
|
166
179
|
online: true
|
|
167
180
|
};
|
|
@@ -182,6 +195,8 @@
|
|
|
182
195
|
self.apiKey = attrs.apiKey;
|
|
183
196
|
self.server = attrs.server;
|
|
184
197
|
self.visitorId = _getVisitorId();
|
|
198
|
+
self._scriptIconColor = attrs.iconColor;
|
|
199
|
+
self._scriptIconShape = attrs.iconShape;
|
|
185
200
|
|
|
186
201
|
/* ── Runtime state ── */
|
|
187
202
|
self.config = Object.assign({}, _DEFAULTS);
|
|
@@ -201,6 +216,7 @@
|
|
|
201
216
|
self._host = null;
|
|
202
217
|
self._shadow = null;
|
|
203
218
|
self._root = null;
|
|
219
|
+
self._overlayEl = null;
|
|
204
220
|
self._chatWindow = null;
|
|
205
221
|
self._messagesContainer = null;
|
|
206
222
|
self._inputEl = null;
|
|
@@ -219,7 +235,7 @@
|
|
|
219
235
|
}
|
|
220
236
|
|
|
221
237
|
/* ════════════════════════════════════════════════════════════════
|
|
222
|
-
CSS — Complete styling injected into Shadow DOM
|
|
238
|
+
CSS — Complete premium styling injected into Shadow DOM
|
|
223
239
|
════════════════════════════════════════════════════════════════ */
|
|
224
240
|
|
|
225
241
|
WAKZWidget.prototype._injectCSS = function () {
|
|
@@ -230,18 +246,14 @@
|
|
|
230
246
|
/* ── CSS Custom Properties (theming) ── */
|
|
231
247
|
':host {',
|
|
232
248
|
' --wakz-primary: #171717;',
|
|
233
|
-
' --wakz-
|
|
234
|
-
' --wakz-chat-bg: #
|
|
249
|
+
' --wakz-icon-color: #171717;',
|
|
250
|
+
' --wakz-chat-bg: #FAFAFA;',
|
|
235
251
|
' --wakz-widget-bg: #ffffff;',
|
|
236
|
-
' --wakz-radius
|
|
237
|
-
' --wakz-radius-bubble:
|
|
238
|
-
' --wakz-radius-fab: 28px;',
|
|
239
|
-
' --wakz-shadow-sm: 0 1px 3px rgba(0,0,0,.08), 0 1px 2px rgba(0,0,0,.06);',
|
|
240
|
-
' --wakz-shadow-md: 0 4px 12px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.06);',
|
|
241
|
-
' --wakz-shadow-lg: 0 12px 40px rgba(0,0,0,.15), 0 4px 12px rgba(0,0,0,.1);',
|
|
242
|
-
' --wakz-shadow-xl: 0 20px 60px rgba(0,0,0,.2), 0 8px 20px rgba(0,0,0,.12);',
|
|
243
|
-
' --wakz-transition: 200ms ease;',
|
|
252
|
+
' --wakz-radius: 20px;',
|
|
253
|
+
' --wakz-radius-bubble: 18px;',
|
|
244
254
|
' --wakz-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;',
|
|
255
|
+
' --wakz-shadow: 0 25px 60px rgba(0,0,0,0.15), 0 8px 20px rgba(0,0,0,0.1);',
|
|
256
|
+
' --wakz-shadow-sm: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);',
|
|
245
257
|
' all: initial;',
|
|
246
258
|
' font-family: var(--wakz-font);',
|
|
247
259
|
'}',
|
|
@@ -259,34 +271,46 @@
|
|
|
259
271
|
'.wakz-fab {',
|
|
260
272
|
' position: fixed;',
|
|
261
273
|
' z-index: 2147483647;',
|
|
262
|
-
' width:
|
|
263
|
-
' height:
|
|
264
|
-
' border-radius:
|
|
274
|
+
' width: 52px;',
|
|
275
|
+
' height: 52px;',
|
|
276
|
+
' border-radius: 50%;',
|
|
265
277
|
' border: none;',
|
|
266
278
|
' cursor: pointer;',
|
|
267
279
|
' display: flex;',
|
|
268
280
|
' align-items: center;',
|
|
269
281
|
' justify-content: center;',
|
|
270
|
-
' box-shadow:
|
|
271
|
-
' transition: transform
|
|
282
|
+
' box-shadow: 0 12px 40px rgba(0,0,0,0.15), 0 4px 12px rgba(0,0,0,0.1);',
|
|
283
|
+
' transition: opacity 0.3s cubic-bezier(0.16,1,0.3,1), transform 0.3s cubic-bezier(0.16,1,0.3,1), box-shadow 0.2s ease;',
|
|
272
284
|
' outline: none;',
|
|
273
285
|
' -webkit-tap-highlight-color: transparent;',
|
|
274
|
-
' background: var(--wakz-
|
|
286
|
+
' background: var(--wakz-icon-color, #171717);',
|
|
275
287
|
'}',
|
|
276
288
|
'.wakz-fab:hover {',
|
|
277
289
|
' transform: scale(1.08);',
|
|
278
|
-
' box-shadow:
|
|
290
|
+
' box-shadow: 0 20px 60px rgba(0,0,0,0.2), 0 8px 20px rgba(0,0,0,0.12);',
|
|
279
291
|
'}',
|
|
280
292
|
'.wakz-fab:active {',
|
|
281
293
|
' transform: scale(0.96);',
|
|
282
294
|
'}',
|
|
283
295
|
'.wakz-fab svg {',
|
|
284
|
-
' width:
|
|
285
|
-
' height:
|
|
296
|
+
' width: 24px;',
|
|
297
|
+
' height: 24px;',
|
|
286
298
|
' color: #ffffff;',
|
|
287
299
|
' pointer-events: none;',
|
|
288
300
|
'}',
|
|
289
301
|
|
|
302
|
+
/* ── FAB Shape: rounded square ── */
|
|
303
|
+
'.wakz-fab-shape-rounded {',
|
|
304
|
+
' border-radius: 16px;',
|
|
305
|
+
'}',
|
|
306
|
+
|
|
307
|
+
/* ── FAB hidden when chat is open ── */
|
|
308
|
+
'.wakz-fab-hidden {',
|
|
309
|
+
' opacity: 0;',
|
|
310
|
+
' pointer-events: none;',
|
|
311
|
+
' transform: scale(0.8);',
|
|
312
|
+
'}',
|
|
313
|
+
|
|
290
314
|
/* ── FAB Positioning ── */
|
|
291
315
|
'.wakz-fab-pos-br { bottom: 24px; right: 24px; }',
|
|
292
316
|
'.wakz-fab-pos-bl { bottom: 24px; left: 24px; }',
|
|
@@ -307,18 +331,18 @@
|
|
|
307
331
|
══════════════════════════════════════════════════ */
|
|
308
332
|
'.wakz-fab-dot {',
|
|
309
333
|
' position: absolute;',
|
|
310
|
-
' top:
|
|
311
|
-
' right:
|
|
312
|
-
' width:
|
|
313
|
-
' height:
|
|
334
|
+
' top: -1px;',
|
|
335
|
+
' right: -1px;',
|
|
336
|
+
' width: 12px;',
|
|
337
|
+
' height: 12px;',
|
|
314
338
|
' border-radius: 50%;',
|
|
315
|
-
' border:
|
|
339
|
+
' border: 2px solid #ffffff;',
|
|
316
340
|
' z-index: 2;',
|
|
317
341
|
' transition: background 0.3s ease;',
|
|
318
342
|
'}',
|
|
319
343
|
'.wakz-fab-pos-bl .wakz-fab-dot {',
|
|
320
344
|
' right: auto;',
|
|
321
|
-
' left:
|
|
345
|
+
' left: -1px;',
|
|
322
346
|
'}',
|
|
323
347
|
|
|
324
348
|
/* ── Online (green pulse) ── */
|
|
@@ -339,45 +363,60 @@
|
|
|
339
363
|
' animation: none;',
|
|
340
364
|
'}',
|
|
341
365
|
|
|
342
|
-
/*
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
'
|
|
366
|
+
/* ══════════════════════════════════════════════════
|
|
367
|
+
OVERLAY BACKDROP
|
|
368
|
+
══════════════════════════════════════════════════ */
|
|
369
|
+
'.wakz-overlay {',
|
|
370
|
+
' position: fixed;',
|
|
371
|
+
' top: 0;',
|
|
372
|
+
' left: 0;',
|
|
373
|
+
' right: 0;',
|
|
374
|
+
' bottom: 0;',
|
|
375
|
+
' z-index: 2147483645;',
|
|
376
|
+
' background: rgba(0,0,0,0.4);',
|
|
377
|
+
' -webkit-backdrop-filter: blur(4px);',
|
|
378
|
+
' backdrop-filter: blur(4px);',
|
|
379
|
+
' opacity: 0;',
|
|
380
|
+
' pointer-events: none;',
|
|
381
|
+
' transition: opacity 0.3s cubic-bezier(0.16,1,0.3,1);',
|
|
382
|
+
'}',
|
|
383
|
+
'.wakz-overlay.wakz-visible {',
|
|
384
|
+
' opacity: 1;',
|
|
385
|
+
' pointer-events: auto;',
|
|
346
386
|
'}',
|
|
347
387
|
|
|
348
388
|
/* ══════════════════════════════════════════════════
|
|
349
|
-
CHAT WINDOW
|
|
389
|
+
CHAT WINDOW — Centered Modal
|
|
350
390
|
══════════════════════════════════════════════════ */
|
|
351
391
|
'.wakz-window {',
|
|
352
392
|
' position: fixed;',
|
|
353
393
|
' z-index: 2147483646;',
|
|
354
|
-
'
|
|
355
|
-
'
|
|
356
|
-
'
|
|
357
|
-
'
|
|
394
|
+
' top: 50%;',
|
|
395
|
+
' left: 50%;',
|
|
396
|
+
' transform: translate(-50%, -50%) scale(0.95);',
|
|
397
|
+
' width: 420px;',
|
|
398
|
+
' max-height: 75vh;',
|
|
399
|
+
' border-radius: 20px;',
|
|
358
400
|
' overflow: hidden;',
|
|
359
401
|
' display: flex;',
|
|
360
402
|
' flex-direction: column;',
|
|
361
403
|
' background: var(--wakz-widget-bg);',
|
|
362
|
-
'
|
|
404
|
+
' border: 1px solid #E5E5E5;',
|
|
405
|
+
' box-shadow: 0 25px 60px rgba(0,0,0,0.15), 0 8px 20px rgba(0,0,0,0.1);',
|
|
406
|
+
' -webkit-backdrop-filter: blur(20px);',
|
|
407
|
+
' backdrop-filter: blur(20px);',
|
|
363
408
|
' opacity: 0;',
|
|
364
|
-
' transform: translateY(20px) scale(0.95);',
|
|
365
409
|
' pointer-events: none;',
|
|
366
|
-
' transition: opacity 0.3s cubic-bezier(0.
|
|
367
|
-
' transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);',
|
|
410
|
+
' transition: opacity 0.3s cubic-bezier(0.16,1,0.3,1), transform 0.3s cubic-bezier(0.16,1,0.3,1);',
|
|
368
411
|
'}',
|
|
369
412
|
'.wakz-window.wakz-visible {',
|
|
370
413
|
' opacity: 1;',
|
|
371
|
-
' transform:
|
|
414
|
+
' transform: translate(-50%, -50%) scale(1);',
|
|
372
415
|
' pointer-events: auto;',
|
|
373
416
|
'}',
|
|
374
417
|
|
|
375
|
-
/* ── Window Positioning ── */
|
|
376
|
-
'.wakz-win-pos-br { bottom: 92px; right: 24px; }',
|
|
377
|
-
'.wakz-win-pos-bl { bottom: 92px; left: 24px; }',
|
|
378
|
-
|
|
379
418
|
/* ══════════════════════════════════════════════════
|
|
380
|
-
HEADER
|
|
419
|
+
HEADER — Glassmorphism (matching floatingGlassShell)
|
|
381
420
|
══════════════════════════════════════════════════ */
|
|
382
421
|
'.wakz-hdr {',
|
|
383
422
|
' flex-shrink: 0;',
|
|
@@ -385,30 +424,35 @@
|
|
|
385
424
|
' display: flex;',
|
|
386
425
|
' align-items: center;',
|
|
387
426
|
' justify-content: space-between;',
|
|
388
|
-
' color: #
|
|
427
|
+
' color: #171717;',
|
|
389
428
|
' cursor: default;',
|
|
390
429
|
' user-select: none;',
|
|
391
|
-
' background:
|
|
430
|
+
' background: rgba(255,255,255,0.85);',
|
|
431
|
+
' -webkit-backdrop-filter: blur(20px);',
|
|
432
|
+
' backdrop-filter: blur(20px);',
|
|
433
|
+
' border-bottom: 1px solid rgba(0,0,0,0.06);',
|
|
434
|
+
' height: 60px;',
|
|
392
435
|
'}',
|
|
393
|
-
'.wakz-hdr-
|
|
436
|
+
'.wakz-hdr-right {',
|
|
394
437
|
' display: flex;',
|
|
395
438
|
' align-items: center;',
|
|
396
439
|
' gap: 11px;',
|
|
397
440
|
' min-width: 0;',
|
|
398
441
|
'}',
|
|
399
442
|
|
|
400
|
-
/* ── Bot Avatar ── */
|
|
443
|
+
/* ── Bot Avatar (header) ── */
|
|
401
444
|
'.wakz-avatar {',
|
|
402
|
-
' width:
|
|
403
|
-
' height:
|
|
445
|
+
' width: 36px;',
|
|
446
|
+
' height: 36px;',
|
|
404
447
|
' border-radius: 50%;',
|
|
405
|
-
' background:
|
|
448
|
+
' background: var(--wakz-primary);',
|
|
406
449
|
' display: flex;',
|
|
407
450
|
' align-items: center;',
|
|
408
451
|
' justify-content: center;',
|
|
409
452
|
' font-weight: 700;',
|
|
410
|
-
' font-size:
|
|
453
|
+
' font-size: 15px;',
|
|
411
454
|
' flex-shrink: 0;',
|
|
455
|
+
' color: #ffffff;',
|
|
412
456
|
' letter-spacing: 0.5px;',
|
|
413
457
|
'}',
|
|
414
458
|
|
|
@@ -419,20 +463,27 @@
|
|
|
419
463
|
' min-width: 0;',
|
|
420
464
|
'}',
|
|
421
465
|
'.wakz-hdr-name {',
|
|
422
|
-
' font-size:
|
|
466
|
+
' font-size: 16px;',
|
|
423
467
|
' font-weight: 600;',
|
|
424
468
|
' line-height: 1.3;',
|
|
469
|
+
' color: #171717;',
|
|
425
470
|
' white-space: nowrap;',
|
|
426
471
|
' overflow: hidden;',
|
|
427
472
|
' text-overflow: ellipsis;',
|
|
428
473
|
'}',
|
|
474
|
+
|
|
475
|
+
/* ── Header Left: status + close ── */
|
|
476
|
+
'.wakz-hdr-left {',
|
|
477
|
+
' display: flex;',
|
|
478
|
+
' align-items: center;',
|
|
479
|
+
' gap: 10px;',
|
|
480
|
+
'}',
|
|
429
481
|
'.wakz-hdr-status {',
|
|
430
482
|
' font-size: 12px;',
|
|
431
|
-
'
|
|
483
|
+
' color: #171717;',
|
|
432
484
|
' display: flex;',
|
|
433
485
|
' align-items: center;',
|
|
434
486
|
' gap: 5px;',
|
|
435
|
-
' margin-top: 2px;',
|
|
436
487
|
'}',
|
|
437
488
|
'.wakz-hdr-status-dot {',
|
|
438
489
|
' width: 7px;',
|
|
@@ -442,8 +493,8 @@
|
|
|
442
493
|
' flex-shrink: 0;',
|
|
443
494
|
' transition: background 0.3s ease;',
|
|
444
495
|
'}',
|
|
445
|
-
'.wakz-hdr-status-dot.online { background: #
|
|
446
|
-
'.wakz-hdr-status-dot.offline { background: #
|
|
496
|
+
'.wakz-hdr-status-dot.online { background: #22c55e; }',
|
|
497
|
+
'.wakz-hdr-status-dot.offline { background: #ef4444; }',
|
|
447
498
|
|
|
448
499
|
/* ── Close Button ── */
|
|
449
500
|
'.wakz-close {',
|
|
@@ -451,18 +502,18 @@
|
|
|
451
502
|
' height: 32px;',
|
|
452
503
|
' border-radius: 50%;',
|
|
453
504
|
' border: none;',
|
|
454
|
-
' background:
|
|
455
|
-
' color: #
|
|
505
|
+
' background: transparent;',
|
|
506
|
+
' color: #171717;',
|
|
456
507
|
' cursor: pointer;',
|
|
457
508
|
' display: flex;',
|
|
458
509
|
' align-items: center;',
|
|
459
510
|
' justify-content: center;',
|
|
460
|
-
' transition: background
|
|
511
|
+
' transition: background 0.2s ease;',
|
|
461
512
|
' outline: none;',
|
|
462
513
|
' flex-shrink: 0;',
|
|
463
514
|
'}',
|
|
464
515
|
'.wakz-close:hover {',
|
|
465
|
-
' background: rgba(
|
|
516
|
+
' background: rgba(0,0,0,0.06);',
|
|
466
517
|
'}',
|
|
467
518
|
'.wakz-close svg {',
|
|
468
519
|
' width: 18px;',
|
|
@@ -476,90 +527,130 @@
|
|
|
476
527
|
' flex: 1;',
|
|
477
528
|
' overflow-y: auto;',
|
|
478
529
|
' overflow-x: hidden;',
|
|
479
|
-
' padding:
|
|
530
|
+
' padding: 16px;',
|
|
480
531
|
' display: flex;',
|
|
481
532
|
' flex-direction: column;',
|
|
482
|
-
' gap:
|
|
533
|
+
' gap: 8px;',
|
|
483
534
|
' scroll-behavior: smooth;',
|
|
484
535
|
' background: var(--wakz-chat-bg);',
|
|
485
536
|
'}',
|
|
486
537
|
'.wakz-msgs::-webkit-scrollbar { width: 5px; }',
|
|
487
538
|
'.wakz-msgs::-webkit-scrollbar-track { background: transparent; }',
|
|
488
539
|
'.wakz-msgs::-webkit-scrollbar-thumb {',
|
|
489
|
-
' background: rgba(0,0,0,0.
|
|
540
|
+
' background: rgba(0,0,0,0.08);',
|
|
490
541
|
' border-radius: 10px;',
|
|
491
542
|
'}',
|
|
492
543
|
|
|
493
544
|
/* ══════════════════════════════════════════════════
|
|
494
|
-
MESSAGE
|
|
545
|
+
MESSAGE STYLES
|
|
495
546
|
══════════════════════════════════════════════════ */
|
|
496
|
-
'.wakz-msg-row {',
|
|
497
|
-
' display: flex;',
|
|
498
|
-
' max-width: 82%;',
|
|
499
|
-
' animation: wakz-msg-in 0.3s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
|
|
500
|
-
'}',
|
|
501
|
-
'.wakz-msg-row.bot { align-self: flex-start; }',
|
|
502
|
-
'.wakz-msg-row.user { align-self: flex-end; }',
|
|
503
|
-
|
|
504
547
|
'@keyframes wakz-msg-in {',
|
|
505
548
|
' 0% { opacity: 0; transform: translateY(8px); }',
|
|
506
549
|
' 100% { opacity: 1; transform: translateY(0); }',
|
|
507
550
|
'}',
|
|
508
551
|
|
|
509
|
-
|
|
510
|
-
'
|
|
552
|
+
/* ── User Message (bubble, right-aligned LTR / left-aligned RTL) ── */
|
|
553
|
+
'.wakz-msg-row {',
|
|
554
|
+
' animation: wakz-msg-in 0.3s cubic-bezier(0.16,1,0.3,1) forwards;',
|
|
555
|
+
'}',
|
|
556
|
+
'.wakz-msg-row.user {',
|
|
557
|
+
' align-self: flex-end;',
|
|
558
|
+
' max-width: 75%;',
|
|
559
|
+
'}',
|
|
560
|
+
'.wakz-msg-row.bot {',
|
|
561
|
+
' align-self: flex-start;',
|
|
562
|
+
' max-width: 85%;',
|
|
563
|
+
'}',
|
|
564
|
+
|
|
565
|
+
'.wakz-bubble-user {',
|
|
566
|
+
' padding: 10px 16px;',
|
|
511
567
|
' font-size: 14px;',
|
|
512
568
|
' line-height: 1.55;',
|
|
513
569
|
' word-wrap: break-word;',
|
|
514
570
|
' overflow-wrap: break-word;',
|
|
515
571
|
' white-space: pre-wrap;',
|
|
516
|
-
' border-radius:
|
|
517
|
-
' position: relative;',
|
|
518
|
-
'}',
|
|
519
|
-
'.wakz-bubble.bot {',
|
|
520
|
-
' background: #ffffff;',
|
|
521
|
-
' color: #1a1a1a;',
|
|
522
|
-
' border-bottom-left-radius: 4px;',
|
|
523
|
-
' box-shadow: var(--wakz-shadow-sm);',
|
|
524
|
-
'}',
|
|
525
|
-
'.wakz-bubble.user {',
|
|
526
|
-
' color: #ffffff;',
|
|
527
|
-
' border-bottom-right-radius: 4px;',
|
|
572
|
+
' border-radius: 18px 18px 6px 18px;',
|
|
528
573
|
' background: var(--wakz-primary);',
|
|
529
|
-
'
|
|
530
|
-
'.wakz-bubble.error-bubble {',
|
|
531
|
-
' background: #fef2f2;',
|
|
532
|
-
' color: #dc2626;',
|
|
533
|
-
' border: 1px solid #fecaca;',
|
|
534
|
-
' border-bottom-left-radius: 4px;',
|
|
535
|
-
' box-shadow: none;',
|
|
574
|
+
' color: #ffffff;',
|
|
536
575
|
'}',
|
|
537
576
|
|
|
538
|
-
/* ──
|
|
577
|
+
/* ── Timestamp ── */
|
|
539
578
|
'.wakz-ts {',
|
|
540
579
|
' display: block;',
|
|
541
|
-
' font-size:
|
|
542
|
-
' opacity: 0.
|
|
580
|
+
' font-size: 10px;',
|
|
581
|
+
' opacity: 0.6;',
|
|
543
582
|
' margin-top: 4px;',
|
|
544
583
|
'}',
|
|
545
|
-
'.wakz-bubble
|
|
584
|
+
'.wakz-bubble-user .wakz-ts {',
|
|
546
585
|
' text-align: right;',
|
|
586
|
+
' color: rgba(255,255,255,0.7);',
|
|
587
|
+
'}',
|
|
588
|
+
|
|
589
|
+
/* ── Bot Message (no bubble, flat on bg with left accent border) ── */
|
|
590
|
+
'.wakz-msg-bot-wrap {',
|
|
591
|
+
' display: flex;',
|
|
592
|
+
' flex-direction: column;',
|
|
593
|
+
' gap: 2px;',
|
|
594
|
+
'}',
|
|
595
|
+
'.wakz-msg-bot-avatar {',
|
|
596
|
+
' width: 20px;',
|
|
597
|
+
' height: 20px;',
|
|
598
|
+
' border-radius: 50%;',
|
|
599
|
+
' background: var(--wakz-primary);',
|
|
600
|
+
' display: flex;',
|
|
601
|
+
' align-items: center;',
|
|
602
|
+
' justify-content: center;',
|
|
603
|
+
' color: #ffffff;',
|
|
604
|
+
' font-weight: 700;',
|
|
605
|
+
' font-size: 9px;',
|
|
606
|
+
' flex-shrink: 0;',
|
|
607
|
+
' margin-bottom: 2px;',
|
|
608
|
+
'}',
|
|
609
|
+
'.wakz-msg-bot-content {',
|
|
610
|
+
' border-left: 3px solid rgba(23,23,23,0.2);',
|
|
611
|
+
' padding: 10px 0 10px 14px;',
|
|
612
|
+
' font-size: 14px;',
|
|
613
|
+
' line-height: 1.6;',
|
|
614
|
+
' color: #374151;',
|
|
615
|
+
' word-wrap: break-word;',
|
|
616
|
+
' overflow-wrap: break-word;',
|
|
617
|
+
' white-space: pre-wrap;',
|
|
618
|
+
'}',
|
|
619
|
+
'.wakz-msg-bot-content .wakz-ts {',
|
|
620
|
+
' color: #9CA3AF;',
|
|
547
621
|
'}',
|
|
548
622
|
|
|
549
|
-
/* ── Human Agent
|
|
623
|
+
/* ── Support / Human Agent Message ── */
|
|
624
|
+
'.wakz-msg-bot-content.wakz-human {',
|
|
625
|
+
' border-left-color: #16A34A;',
|
|
626
|
+
'}',
|
|
550
627
|
'.wakz-human-badge {',
|
|
551
|
-
' display: inline-
|
|
552
|
-
'
|
|
553
|
-
'
|
|
628
|
+
' display: inline-flex;',
|
|
629
|
+
' align-items: center;',
|
|
630
|
+
' font-size: 11px;',
|
|
631
|
+
' background: rgba(22,163,74,0.08);',
|
|
554
632
|
' color: #16A34A;',
|
|
555
|
-
' border-radius:
|
|
556
|
-
' padding:
|
|
557
|
-
' margin-top:
|
|
633
|
+
' border-radius: 20px;',
|
|
634
|
+
' padding: 2px 8px;',
|
|
635
|
+
' margin-top: 6px;',
|
|
558
636
|
' font-weight: 600;',
|
|
559
|
-
' letter-spacing: 0.2px;',
|
|
560
637
|
'}',
|
|
561
638
|
|
|
562
|
-
/* ──
|
|
639
|
+
/* ── Error bubble ── */
|
|
640
|
+
'.wakz-bubble-error {',
|
|
641
|
+
' padding: 10px 14px;',
|
|
642
|
+
' font-size: 14px;',
|
|
643
|
+
' line-height: 1.55;',
|
|
644
|
+
' word-wrap: break-word;',
|
|
645
|
+
' overflow-wrap: break-word;',
|
|
646
|
+
' white-space: pre-wrap;',
|
|
647
|
+
' background: #FEF2F2;',
|
|
648
|
+
' color: #DC2626;',
|
|
649
|
+
' border: 1px solid #FECACA;',
|
|
650
|
+
' border-radius: 18px 18px 6px 18px;',
|
|
651
|
+
'}',
|
|
652
|
+
|
|
653
|
+
/* ── Retry Button (inside error) ── */
|
|
563
654
|
'.wakz-retry {',
|
|
564
655
|
' display: inline-flex;',
|
|
565
656
|
' align-items: center;',
|
|
@@ -574,7 +665,7 @@
|
|
|
574
665
|
' color: #dc2626;',
|
|
575
666
|
' cursor: pointer;',
|
|
576
667
|
' font-family: var(--wakz-font);',
|
|
577
|
-
' transition: background
|
|
668
|
+
' transition: background 0.2s ease, border-color 0.2s ease;',
|
|
578
669
|
' outline: none;',
|
|
579
670
|
'}',
|
|
580
671
|
'.wakz-retry:hover {',
|
|
@@ -583,23 +674,32 @@
|
|
|
583
674
|
'}',
|
|
584
675
|
|
|
585
676
|
/* ══════════════════════════════════════════════════
|
|
586
|
-
|
|
677
|
+
WELCOME MESSAGE
|
|
678
|
+
══════════════════════════════════════════════════ */
|
|
679
|
+
'.wakz-welcome-wrap {',
|
|
680
|
+
' display: flex;',
|
|
681
|
+
' flex-direction: column;',
|
|
682
|
+
' gap: 2px;',
|
|
683
|
+
' max-width: 85%;',
|
|
684
|
+
' align-self: flex-start;',
|
|
685
|
+
' animation: wakz-msg-in 0.35s cubic-bezier(0.16,1,0.3,1) forwards;',
|
|
686
|
+
'}',
|
|
687
|
+
|
|
688
|
+
/* ══════════════════════════════════════════════════
|
|
689
|
+
TYPING INDICATOR (no bubble — on background)
|
|
587
690
|
══════════════════════════════════════════════════ */
|
|
588
691
|
'.wakz-typing {',
|
|
589
692
|
' display: flex;',
|
|
590
693
|
' align-items: center;',
|
|
591
694
|
' gap: 4px;',
|
|
592
|
-
' padding: 14px
|
|
593
|
-
'
|
|
594
|
-
' border-radius: var(--wakz-radius-bubble);',
|
|
595
|
-
' border-bottom-left-radius: 4px;',
|
|
596
|
-
' box-shadow: var(--wakz-shadow-sm);',
|
|
695
|
+
' padding: 10px 0 10px 14px;',
|
|
696
|
+
' border-left: 3px solid rgba(23,23,23,0.2);',
|
|
597
697
|
'}',
|
|
598
698
|
'.wakz-typing-dot {',
|
|
599
699
|
' width: 7px;',
|
|
600
700
|
' height: 7px;',
|
|
601
701
|
' border-radius: 50%;',
|
|
602
|
-
' background: #
|
|
702
|
+
' background: #9CA3AF;',
|
|
603
703
|
' animation: wakz-bounce-dot 1.4s ease-in-out infinite;',
|
|
604
704
|
'}',
|
|
605
705
|
'.wakz-typing-dot:nth-child(2) { animation-delay: 0.16s; }',
|
|
@@ -610,31 +710,33 @@
|
|
|
610
710
|
'}',
|
|
611
711
|
|
|
612
712
|
/* ══════════════════════════════════════════════════
|
|
613
|
-
INPUT AREA
|
|
713
|
+
INPUT AREA — Glass Effect
|
|
614
714
|
══════════════════════════════════════════════════ */
|
|
615
715
|
'.wakz-input-wrap {',
|
|
616
716
|
' flex-shrink: 0;',
|
|
617
|
-
' padding: 12px
|
|
618
|
-
' border-top: 1px solid
|
|
619
|
-
' background:
|
|
717
|
+
' padding: 12px 16px;',
|
|
718
|
+
' border-top: 1px solid rgba(0,0,0,0.06);',
|
|
719
|
+
' background: rgba(255,255,255,0.7);',
|
|
720
|
+
' -webkit-backdrop-filter: blur(12px);',
|
|
721
|
+
' backdrop-filter: blur(12px);',
|
|
620
722
|
' display: flex;',
|
|
621
723
|
' align-items: flex-end;',
|
|
622
724
|
' gap: 8px;',
|
|
623
725
|
'}',
|
|
624
726
|
'.wakz-input {',
|
|
625
727
|
' flex: 1;',
|
|
626
|
-
' border: 1.5px solid #
|
|
627
|
-
' border-radius:
|
|
728
|
+
' border: 1.5px solid #E5E5E5;',
|
|
729
|
+
' border-radius: 14px;',
|
|
628
730
|
' padding: 10px 16px;',
|
|
629
731
|
' font-size: 14px;',
|
|
630
732
|
' line-height: 1.4;',
|
|
631
733
|
' outline: none;',
|
|
632
734
|
' font-family: var(--wakz-font);',
|
|
633
|
-
' transition: border-color
|
|
735
|
+
' transition: border-color 0.2s ease, background 0.2s ease;',
|
|
634
736
|
' resize: none;',
|
|
635
737
|
' max-height: 100px;',
|
|
636
738
|
' overflow-y: auto;',
|
|
637
|
-
' background: #
|
|
739
|
+
' background: #F9FAFB;',
|
|
638
740
|
' color: #111827;',
|
|
639
741
|
'}',
|
|
640
742
|
'.wakz-input:focus {',
|
|
@@ -645,10 +747,10 @@
|
|
|
645
747
|
' color: #9ca3af;',
|
|
646
748
|
'}',
|
|
647
749
|
|
|
648
|
-
/* ── Send Button ── */
|
|
750
|
+
/* ── Send Button (floating circle, separate from textarea) ── */
|
|
649
751
|
'.wakz-send {',
|
|
650
|
-
' width:
|
|
651
|
-
' height:
|
|
752
|
+
' width: 44px;',
|
|
753
|
+
' height: 44px;',
|
|
652
754
|
' border-radius: 50%;',
|
|
653
755
|
' border: none;',
|
|
654
756
|
' color: #ffffff;',
|
|
@@ -657,20 +759,21 @@
|
|
|
657
759
|
' align-items: center;',
|
|
658
760
|
' justify-content: center;',
|
|
659
761
|
' flex-shrink: 0;',
|
|
660
|
-
' transition: opacity
|
|
762
|
+
' transition: opacity 0.2s ease, transform 0.15s ease, box-shadow 0.2s ease;',
|
|
661
763
|
' outline: none;',
|
|
662
764
|
' background: var(--wakz-primary);',
|
|
663
|
-
' box-shadow:
|
|
765
|
+
' box-shadow: 0 2px 8px rgba(0,0,0,0.12);',
|
|
664
766
|
'}',
|
|
665
767
|
'.wakz-send:hover:not(:disabled) {',
|
|
666
|
-
'
|
|
768
|
+
' transform: scale(1.05);',
|
|
769
|
+
' box-shadow: 0 4px 16px rgba(0,0,0,0.18);',
|
|
667
770
|
'}',
|
|
668
771
|
'.wakz-send:disabled {',
|
|
669
772
|
' opacity: 0.35;',
|
|
670
773
|
' cursor: not-allowed;',
|
|
671
774
|
'}',
|
|
672
775
|
'.wakz-send:not(:disabled):active {',
|
|
673
|
-
' transform: scale(0.
|
|
776
|
+
' transform: scale(0.92);',
|
|
674
777
|
'}',
|
|
675
778
|
'.wakz-send svg {',
|
|
676
779
|
' width: 18px;',
|
|
@@ -678,69 +781,56 @@
|
|
|
678
781
|
' pointer-events: none;',
|
|
679
782
|
'}',
|
|
680
783
|
|
|
681
|
-
/* ══════════════════════════════════════════════════
|
|
682
|
-
WELCOME MESSAGE
|
|
683
|
-
══════════════════════════════════════════════════ */
|
|
684
|
-
'.wakz-welcome-wrap {',
|
|
685
|
-
' display: flex;',
|
|
686
|
-
' gap: 8px;',
|
|
687
|
-
' max-width: 88%;',
|
|
688
|
-
' align-self: flex-start;',
|
|
689
|
-
' animation: wakz-msg-in 0.35s cubic-bezier(0.4, 0, 0.2, 1) forwards;',
|
|
690
|
-
'}',
|
|
691
|
-
'.wakz-welcome-avatar {',
|
|
692
|
-
' width: 28px;',
|
|
693
|
-
' height: 28px;',
|
|
694
|
-
' border-radius: 50%;',
|
|
695
|
-
' background: var(--wakz-primary);',
|
|
696
|
-
' display: flex;',
|
|
697
|
-
' align-items: center;',
|
|
698
|
-
' justify-content: center;',
|
|
699
|
-
' color: #ffffff;',
|
|
700
|
-
' font-weight: 700;',
|
|
701
|
-
' font-size: 12px;',
|
|
702
|
-
' flex-shrink: 0;',
|
|
703
|
-
' align-self: flex-end;',
|
|
704
|
-
' margin-bottom: 2px;',
|
|
705
|
-
'}',
|
|
706
|
-
|
|
707
784
|
/* ══════════════════════════════════════════════════
|
|
708
785
|
RTL SUPPORT
|
|
709
786
|
══════════════════════════════════════════════════ */
|
|
710
787
|
'.wakz-rtl { direction: rtl; }',
|
|
711
|
-
'.wakz-rtl .wakz-bubble
|
|
712
|
-
' border-
|
|
713
|
-
'
|
|
788
|
+
'.wakz-rtl .wakz-bubble-user {',
|
|
789
|
+
' border-radius: 18px 18px 18px 6px;',
|
|
790
|
+
'}',
|
|
791
|
+
'.wakz-rtl .wakz-bubble-user .wakz-ts {',
|
|
792
|
+
' text-align: left;',
|
|
793
|
+
'}',
|
|
794
|
+
'.wakz-rtl .wakz-msg-bot-content {',
|
|
795
|
+
' border-left: none;',
|
|
796
|
+
' border-right: 3px solid rgba(23,23,23,0.2);',
|
|
797
|
+
' padding: 10px 14px 10px 0;',
|
|
714
798
|
'}',
|
|
715
|
-
'.wakz-rtl .wakz-
|
|
716
|
-
' border-
|
|
717
|
-
' border-
|
|
799
|
+
'.wakz-rtl .wakz-msg-bot-content.wakz-human {',
|
|
800
|
+
' border-left: none;',
|
|
801
|
+
' border-right-color: #16A34A;',
|
|
718
802
|
'}',
|
|
719
803
|
'.wakz-rtl .wakz-typing {',
|
|
720
|
-
' border-
|
|
721
|
-
' border-
|
|
804
|
+
' border-left: none;',
|
|
805
|
+
' border-right: 3px solid rgba(23,23,23,0.2);',
|
|
806
|
+
' padding: 10px 14px 10px 0;',
|
|
722
807
|
'}',
|
|
723
|
-
'.wakz-rtl .wakz-bubble
|
|
724
|
-
'
|
|
808
|
+
'.wakz-rtl .wakz-bubble-error {',
|
|
809
|
+
' border-radius: 18px 18px 18px 6px;',
|
|
725
810
|
'}',
|
|
726
811
|
|
|
727
812
|
/* ══════════════════════════════════════════════════
|
|
728
|
-
MOBILE RESPONSIVE
|
|
813
|
+
MOBILE RESPONSIVE (< 480px)
|
|
729
814
|
══════════════════════════════════════════════════ */
|
|
730
815
|
'@media (max-width: 480px) {',
|
|
816
|
+
' .wakz-overlay {',
|
|
817
|
+
' display: none;',
|
|
818
|
+
' }',
|
|
731
819
|
' .wakz-window {',
|
|
820
|
+
' top: auto !important;',
|
|
821
|
+
' left: 0 !important;',
|
|
822
|
+
' right: 0 !important;',
|
|
823
|
+
' bottom: 0 !important;',
|
|
732
824
|
' width: 100vw !important;',
|
|
733
825
|
' height: 100vh !important;',
|
|
734
|
-
' min-height: 100vh !important;',
|
|
735
826
|
' max-height: 100vh !important;',
|
|
736
|
-
'
|
|
737
|
-
'
|
|
738
|
-
'
|
|
739
|
-
'
|
|
740
|
-
' border-radius: 0 !important;',
|
|
827
|
+
' border-radius: 20px 20px 0 0 !important;',
|
|
828
|
+
' transform: translateY(100%) !important;',
|
|
829
|
+
' border: none !important;',
|
|
830
|
+
' border-top: 1px solid #E5E5E5 !important;',
|
|
741
831
|
' }',
|
|
742
832
|
' .wakz-window.wakz-visible {',
|
|
743
|
-
' transform: translateY(0)
|
|
833
|
+
' transform: translateY(0) !important;',
|
|
744
834
|
' }',
|
|
745
835
|
' .wakz-fab-pos-br { bottom: 16px; right: 16px; }',
|
|
746
836
|
' .wakz-fab-pos-bl { bottom: 16px; left: 16px; }',
|
|
@@ -757,6 +847,8 @@
|
|
|
757
847
|
var isRtl = self.config.language === 'ar';
|
|
758
848
|
var posClass = self.config.position === 'bottom-left' ? 'bl' : 'br';
|
|
759
849
|
var str = _strings(self.config.language);
|
|
850
|
+
var iconColor = self._scriptIconColor || self.config.iconColor;
|
|
851
|
+
var iconShape = self._scriptIconShape || self.config.iconShape;
|
|
760
852
|
|
|
761
853
|
/* ── Host + Shadow DOM ── */
|
|
762
854
|
self._host = _el('div');
|
|
@@ -769,11 +861,16 @@
|
|
|
769
861
|
self._shadow.appendChild(self._root);
|
|
770
862
|
|
|
771
863
|
/* ══════════════ FLOATING ACTION BUTTON ══════════════ */
|
|
864
|
+
var fabClasses = 'wakz-fab wakz-fab-pos-' + posClass;
|
|
865
|
+
if (iconShape === 'rounded') fabClasses += ' wakz-fab-shape-rounded';
|
|
866
|
+
|
|
772
867
|
self._toggleBtn = _el('button', {
|
|
773
|
-
className:
|
|
774
|
-
'aria-label': str.openChat
|
|
868
|
+
className: fabClasses,
|
|
869
|
+
'aria-label': str.openChat,
|
|
870
|
+
style: { '--wakz-icon-color': iconColor }
|
|
775
871
|
});
|
|
776
|
-
self._toggleBtn.
|
|
872
|
+
self._toggleBtn.style.background = iconColor;
|
|
873
|
+
self._toggleBtn.innerHTML = _ICONS.chatIcon;
|
|
777
874
|
|
|
778
875
|
/* Status dot on FAB */
|
|
779
876
|
self._statusDot = _el('span', { className: 'wakz-fab-dot ' + (self.config.online ? 'online' : 'offline') });
|
|
@@ -781,32 +878,41 @@
|
|
|
781
878
|
self._toggleBtn.appendChild(self._statusDot);
|
|
782
879
|
self._root.appendChild(self._toggleBtn);
|
|
783
880
|
|
|
784
|
-
/* ══════════════
|
|
785
|
-
self.
|
|
881
|
+
/* ══════════════ OVERLAY BACKDROP ══════════════ */
|
|
882
|
+
self._overlayEl = _el('div', { className: 'wakz-overlay' });
|
|
883
|
+
self._root.appendChild(self._overlayEl);
|
|
884
|
+
|
|
885
|
+
/* ══════════════ CHAT WINDOW (Centered Modal) ══════════════ */
|
|
886
|
+
self._chatWindow = _el('div', { className: 'wakz-window' });
|
|
786
887
|
|
|
787
888
|
/* ── Header ── */
|
|
788
889
|
var headerEl = _el('div', { className: 'wakz-hdr' });
|
|
789
890
|
|
|
790
|
-
|
|
891
|
+
/* Right side: avatar + name (in RTL, right side = start) */
|
|
892
|
+
var headerRight = _el('div', { className: 'wakz-hdr-right' });
|
|
791
893
|
var avatarLetter = (self.config.botName || 'W')[0].toUpperCase();
|
|
792
|
-
|
|
894
|
+
headerRight.appendChild(_el('div', { className: 'wakz-avatar' }, [avatarLetter]));
|
|
793
895
|
|
|
794
896
|
var headerInfo = _el('div', { className: 'wakz-hdr-info' });
|
|
795
897
|
headerInfo.appendChild(_el('span', { className: 'wakz-hdr-name' }, [self.config.botName]));
|
|
898
|
+
headerRight.appendChild(headerInfo);
|
|
899
|
+
headerEl.appendChild(headerRight);
|
|
900
|
+
|
|
901
|
+
/* Left side: status + close (in RTL, left side = end) */
|
|
902
|
+
var headerLeft = _el('div', { className: 'wakz-hdr-left' });
|
|
796
903
|
|
|
797
904
|
var statusLine = _el('span', { className: 'wakz-hdr-status' });
|
|
798
905
|
self._headerStatusDot = _el('span', { className: 'wakz-hdr-status-dot ' + (self.config.online ? 'online' : 'offline') });
|
|
799
906
|
if (self.config.showStatus) statusLine.appendChild(self._headerStatusDot);
|
|
800
907
|
self._headerStatusText = document.createTextNode(self.config.online ? str.online : str.offline);
|
|
801
908
|
statusLine.appendChild(self._headerStatusText);
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
headerLeft.appendChild(headerInfo);
|
|
805
|
-
headerEl.appendChild(headerLeft);
|
|
909
|
+
headerLeft.appendChild(statusLine);
|
|
806
910
|
|
|
807
911
|
var closeBtn = _el('button', { className: 'wakz-close', 'aria-label': str.closeChat });
|
|
808
912
|
closeBtn.innerHTML = _ICONS.close;
|
|
809
|
-
|
|
913
|
+
headerLeft.appendChild(closeBtn);
|
|
914
|
+
headerEl.appendChild(headerLeft);
|
|
915
|
+
|
|
810
916
|
self._chatWindow.appendChild(headerEl);
|
|
811
917
|
|
|
812
918
|
/* ── Messages Container ── */
|
|
@@ -852,6 +958,11 @@
|
|
|
852
958
|
self.toggleChat(false);
|
|
853
959
|
});
|
|
854
960
|
|
|
961
|
+
/* Overlay backdrop click to close */
|
|
962
|
+
self._overlayEl.addEventListener('click', function () {
|
|
963
|
+
self.toggleChat(false);
|
|
964
|
+
});
|
|
965
|
+
|
|
855
966
|
/* Send button click */
|
|
856
967
|
self._sendBtn.addEventListener('click', function () {
|
|
857
968
|
self._handleSend();
|
|
@@ -900,6 +1011,9 @@
|
|
|
900
1011
|
self.isOpen = open;
|
|
901
1012
|
if (open) {
|
|
902
1013
|
self._chatWindow.classList.add('wakz-visible');
|
|
1014
|
+
self._overlayEl.classList.add('wakz-visible');
|
|
1015
|
+
/* Hide FAB when chat is open */
|
|
1016
|
+
self._toggleBtn.classList.add('wakz-fab-hidden');
|
|
903
1017
|
/* Fetch history on first open (after config is loaded) */
|
|
904
1018
|
if (self._configLoaded && !self._hasFetchedHistory) {
|
|
905
1019
|
self._fetchHistory();
|
|
@@ -913,6 +1027,9 @@
|
|
|
913
1027
|
setTimeout(function () { self._inputEl.focus(); }, 320);
|
|
914
1028
|
} else {
|
|
915
1029
|
self._chatWindow.classList.remove('wakz-visible');
|
|
1030
|
+
self._overlayEl.classList.remove('wakz-visible');
|
|
1031
|
+
/* Show FAB when chat is closed */
|
|
1032
|
+
self._toggleBtn.classList.remove('wakz-fab-hidden');
|
|
916
1033
|
/* Stop polling when chat is closed */
|
|
917
1034
|
self._stopPolling();
|
|
918
1035
|
}
|
|
@@ -939,6 +1056,9 @@
|
|
|
939
1056
|
.then(function (data) {
|
|
940
1057
|
if (data && data.success && data.config) {
|
|
941
1058
|
self.config = Object.assign({}, _DEFAULTS, data.config);
|
|
1059
|
+
/* Apply script-level overrides */
|
|
1060
|
+
if (self._scriptIconColor) self.config.iconColor = self._scriptIconColor;
|
|
1061
|
+
if (self._scriptIconShape) self.config.iconShape = self._scriptIconShape;
|
|
942
1062
|
self._configLoaded = true;
|
|
943
1063
|
self._applyConfig();
|
|
944
1064
|
} else {
|
|
@@ -978,11 +1098,13 @@
|
|
|
978
1098
|
var str = _strings(cfg.language);
|
|
979
1099
|
var isRtl = cfg.language === 'ar';
|
|
980
1100
|
var posClass = cfg.position === 'bottom-left' ? 'bl' : 'br';
|
|
1101
|
+
var iconColor = cfg.iconColor || '#171717';
|
|
1102
|
+
var iconShape = cfg.iconShape || 'circle';
|
|
981
1103
|
|
|
982
1104
|
/* ── Update CSS custom properties ── */
|
|
983
1105
|
var hostStyle = self._shadow.host.style;
|
|
984
1106
|
hostStyle.setProperty('--wakz-primary', cfg.primaryColor);
|
|
985
|
-
hostStyle.setProperty('--wakz-
|
|
1107
|
+
hostStyle.setProperty('--wakz-icon-color', iconColor);
|
|
986
1108
|
hostStyle.setProperty('--wakz-chat-bg', cfg.chatBg);
|
|
987
1109
|
hostStyle.setProperty('--wakz-widget-bg', cfg.widgetBg);
|
|
988
1110
|
|
|
@@ -991,19 +1113,19 @@
|
|
|
991
1113
|
else self._root.classList.remove('wakz-rtl');
|
|
992
1114
|
|
|
993
1115
|
/* ── FAB ── */
|
|
994
|
-
|
|
1116
|
+
var fabClasses = 'wakz-fab wakz-fab-pos-' + posClass + ' wakz-fab-enter';
|
|
1117
|
+
if (iconShape === 'rounded') fabClasses += ' wakz-fab-shape-rounded';
|
|
1118
|
+
if (self.isOpen) fabClasses += ' wakz-fab-hidden';
|
|
1119
|
+
self._toggleBtn.className = fabClasses;
|
|
1120
|
+
self._toggleBtn.style.background = iconColor;
|
|
995
1121
|
self._toggleBtn.setAttribute('aria-label', str.openChat);
|
|
996
1122
|
|
|
997
1123
|
/* ── FAB Status Dot ── */
|
|
998
1124
|
self._statusDot.className = 'wakz-fab-dot ' + (cfg.online ? 'online' : 'offline');
|
|
999
1125
|
self._statusDot.style.display = cfg.showStatus ? '' : 'none';
|
|
1000
1126
|
|
|
1001
|
-
/* ── Window
|
|
1002
|
-
self._chatWindow.className = 'wakz-window
|
|
1003
|
-
|
|
1004
|
-
/* ── Header ── */
|
|
1005
|
-
var headerEl = self._chatWindow.querySelector('.wakz-hdr');
|
|
1006
|
-
if (headerEl) headerEl.style.background = cfg.primaryColor;
|
|
1127
|
+
/* ── Window ── */
|
|
1128
|
+
self._chatWindow.className = 'wakz-window' + (self.isOpen ? ' wakz-visible' : '');
|
|
1007
1129
|
|
|
1008
1130
|
/* ── Bot Name & Avatar ── */
|
|
1009
1131
|
var nameEl = self._chatWindow.querySelector('.wakz-hdr-name');
|
|
@@ -1151,7 +1273,7 @@
|
|
|
1151
1273
|
};
|
|
1152
1274
|
|
|
1153
1275
|
/* ════════════════════════════════════════════════════════════════
|
|
1154
|
-
APPEND WELCOME MESSAGE (
|
|
1276
|
+
APPEND WELCOME MESSAGE (bot style — no bubble, flat on bg)
|
|
1155
1277
|
════════════════════════════════════════════════════════════════ */
|
|
1156
1278
|
|
|
1157
1279
|
WAKZWidget.prototype._appendWelcomeMessage = function (text) {
|
|
@@ -1161,13 +1283,13 @@
|
|
|
1161
1283
|
var wrap = _el('div', { className: 'wakz-welcome-wrap' });
|
|
1162
1284
|
|
|
1163
1285
|
/* Bot avatar */
|
|
1164
|
-
var avatar = _el('div', { className: 'wakz-
|
|
1286
|
+
var avatar = _el('div', { className: 'wakz-msg-bot-avatar' },
|
|
1165
1287
|
[(self.config.botName || 'W')[0].toUpperCase()]);
|
|
1166
1288
|
wrap.appendChild(avatar);
|
|
1167
1289
|
|
|
1168
|
-
/*
|
|
1169
|
-
var
|
|
1170
|
-
wrap.appendChild(
|
|
1290
|
+
/* Flat content with accent border */
|
|
1291
|
+
var content = _el('div', { className: 'wakz-msg-bot-content' }, [text]);
|
|
1292
|
+
wrap.appendChild(content);
|
|
1171
1293
|
|
|
1172
1294
|
self._messagesContainer.appendChild(wrap);
|
|
1173
1295
|
self.messages.push({ sender: 'bot', text: text });
|
|
@@ -1181,41 +1303,30 @@
|
|
|
1181
1303
|
WAKZWidget.prototype._appendMessage = function (sender, text, isError, timestamp, isHumanAgent) {
|
|
1182
1304
|
var self = this;
|
|
1183
1305
|
|
|
1184
|
-
|
|
1306
|
+
if (sender === 'user') {
|
|
1307
|
+
/* ── User message: rounded bubble ── */
|
|
1308
|
+
var row = _el('div', { className: 'wakz-msg-row user' });
|
|
1309
|
+
var bubble = _el('div', { className: 'wakz-bubble-user' });
|
|
1310
|
+
bubble.appendChild(document.createTextNode(text));
|
|
1185
1311
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
bubble.appendChild(document.createTextNode(text));
|
|
1191
|
-
|
|
1192
|
-
/* Timestamp */
|
|
1193
|
-
var tsText = '';
|
|
1194
|
-
if (timestamp) {
|
|
1195
|
-
try {
|
|
1196
|
-
var d = new Date(timestamp);
|
|
1197
|
-
if (!isNaN(d.getTime())) {
|
|
1198
|
-
tsText = d.getHours().toString().padStart(2, '0') + ':' +
|
|
1199
|
-
d.getMinutes().toString().padStart(2, '0');
|
|
1200
|
-
}
|
|
1201
|
-
} catch (e) { /* ignore */ }
|
|
1202
|
-
}
|
|
1203
|
-
if (!tsText) {
|
|
1204
|
-
var now = new Date();
|
|
1205
|
-
tsText = now.getHours().toString().padStart(2, '0') + ':' +
|
|
1206
|
-
now.getMinutes().toString().padStart(2, '0');
|
|
1207
|
-
}
|
|
1208
|
-
bubble.appendChild(_el('span', { className: 'wakz-ts' }, [tsText]));
|
|
1312
|
+
/* Timestamp */
|
|
1313
|
+
var tsText = self._formatTime(timestamp);
|
|
1314
|
+
bubble.appendChild(_el('span', { className: 'wakz-ts' }, [tsText]));
|
|
1209
1315
|
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1316
|
+
row.appendChild(bubble);
|
|
1317
|
+
self._messagesContainer.appendChild(row);
|
|
1318
|
+
self.messages.push({ sender: sender, text: text, isError: !!isError });
|
|
1319
|
+
self._scrollToBottom();
|
|
1320
|
+
return;
|
|
1215
1321
|
}
|
|
1216
1322
|
|
|
1217
|
-
/* Retry button for errors */
|
|
1218
1323
|
if (isError) {
|
|
1324
|
+
/* ── Error message: red-tinted bubble ── */
|
|
1325
|
+
var errRow = _el('div', { className: 'wakz-msg-row bot' });
|
|
1326
|
+
var errBubble = _el('div', { className: 'wakz-bubble-error' });
|
|
1327
|
+
errBubble.appendChild(document.createTextNode(text));
|
|
1328
|
+
|
|
1329
|
+
/* Retry button for errors */
|
|
1219
1330
|
var str = _strings(self.config.language);
|
|
1220
1331
|
var retryBtn = _el('button', { className: 'wakz-retry' }, [
|
|
1221
1332
|
_ICONS.error + ' ' + str.retry
|
|
@@ -1241,19 +1352,71 @@
|
|
|
1241
1352
|
}
|
|
1242
1353
|
if (lastUserMsg) self._sendToAPI(lastUserMsg);
|
|
1243
1354
|
});
|
|
1244
|
-
})(
|
|
1245
|
-
|
|
1355
|
+
})(errRow);
|
|
1356
|
+
errBubble.appendChild(retryBtn);
|
|
1357
|
+
|
|
1358
|
+
errRow.appendChild(errBubble);
|
|
1359
|
+
self._messagesContainer.appendChild(errRow);
|
|
1360
|
+
self.messages.push({ sender: sender, text: text, isError: true });
|
|
1361
|
+
self._scrollToBottom();
|
|
1362
|
+
return;
|
|
1246
1363
|
}
|
|
1247
1364
|
|
|
1248
|
-
|
|
1249
|
-
|
|
1365
|
+
/* ── Bot / Support message: flat on bg with accent border ── */
|
|
1366
|
+
var botRow = _el('div', { className: 'wakz-msg-row bot' });
|
|
1367
|
+
var wrap = _el('div', { className: 'wakz-msg-bot-wrap' });
|
|
1250
1368
|
|
|
1251
|
-
|
|
1369
|
+
/* Small bot avatar */
|
|
1370
|
+
var avatar = _el('div', { className: 'wakz-msg-bot-avatar' },
|
|
1371
|
+
[(self.config.botName || 'W')[0].toUpperCase()]);
|
|
1372
|
+
wrap.appendChild(avatar);
|
|
1373
|
+
|
|
1374
|
+
/* Flat content */
|
|
1375
|
+
var contentClass = 'wakz-msg-bot-content';
|
|
1376
|
+
if (isHumanAgent) contentClass += ' wakz-human';
|
|
1377
|
+
var content = _el('div', { className: contentClass });
|
|
1378
|
+
content.appendChild(document.createTextNode(text));
|
|
1379
|
+
|
|
1380
|
+
/* Timestamp */
|
|
1381
|
+
var botTs = self._formatTime(timestamp);
|
|
1382
|
+
content.appendChild(_el('span', { className: 'wakz-ts' }, [botTs]));
|
|
1383
|
+
|
|
1384
|
+
/* Human agent badge */
|
|
1385
|
+
if (isHumanAgent) {
|
|
1386
|
+
var iStr = _strings(self.config.language);
|
|
1387
|
+
var badge = _el('span', { className: 'wakz-human-badge' }, [iStr.humanBadge || '👤 فريق الدعم']);
|
|
1388
|
+
content.appendChild(badge);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
wrap.appendChild(content);
|
|
1392
|
+
botRow.appendChild(wrap);
|
|
1393
|
+
self._messagesContainer.appendChild(botRow);
|
|
1394
|
+
|
|
1395
|
+
self.messages.push({ sender: sender, text: text, isError: false, isHumanAgent: !!isHumanAgent });
|
|
1252
1396
|
self._scrollToBottom();
|
|
1253
1397
|
};
|
|
1254
1398
|
|
|
1255
1399
|
/* ════════════════════════════════════════════════════════════════
|
|
1256
|
-
|
|
1400
|
+
FORMAT TIME
|
|
1401
|
+
════════════════════════════════════════════════════════════════ */
|
|
1402
|
+
|
|
1403
|
+
WAKZWidget.prototype._formatTime = function (timestamp) {
|
|
1404
|
+
if (timestamp) {
|
|
1405
|
+
try {
|
|
1406
|
+
var d = new Date(timestamp);
|
|
1407
|
+
if (!isNaN(d.getTime())) {
|
|
1408
|
+
return d.getHours().toString().padStart(2, '0') + ':' +
|
|
1409
|
+
d.getMinutes().toString().padStart(2, '0');
|
|
1410
|
+
}
|
|
1411
|
+
} catch (e) { /* ignore */ }
|
|
1412
|
+
}
|
|
1413
|
+
var now = new Date();
|
|
1414
|
+
return now.getHours().toString().padStart(2, '0') + ':' +
|
|
1415
|
+
now.getMinutes().toString().padStart(2, '0');
|
|
1416
|
+
};
|
|
1417
|
+
|
|
1418
|
+
/* ════════════════════════════════════════════════════════════════
|
|
1419
|
+
TYPING INDICATOR (no bubble — on background)
|
|
1257
1420
|
════════════════════════════════════════════════════════════════ */
|
|
1258
1421
|
|
|
1259
1422
|
WAKZWidget.prototype._showTyping = function () {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wakz-chat-widget",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Premium AI chat widget by WAKZ — Glassmorphism UI, Shadow DOM, zero deps, centered modal design.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prepublishOnly": "echo 'Ready to publish wakz-chat-widget'"
|