ttp-agent-sdk 2.34.0 → 2.34.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent-widget.dev.js +847 -229
- package/dist/agent-widget.dev.js.map +1 -1
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.esm.js.map +1 -1
- package/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/demos/widget-customization.html +1464 -198
- package/dist/examples/widget-customization.html +1464 -198
- package/examples/widget-customization.html +1464 -198
- package/package.json +1 -1
|
@@ -325,8 +325,7 @@
|
|
|
325
325
|
|
|
326
326
|
.mock-widget {
|
|
327
327
|
position: absolute;
|
|
328
|
-
|
|
329
|
-
right: 60px;
|
|
328
|
+
/* Position is set dynamically via updateMockWidgetPosition() */
|
|
330
329
|
z-index: 1000;
|
|
331
330
|
/* Ensure widget doesn't get clipped */
|
|
332
331
|
min-width: 360px;
|
|
@@ -402,10 +401,7 @@
|
|
|
402
401
|
min-width: 450px;
|
|
403
402
|
}
|
|
404
403
|
|
|
405
|
-
|
|
406
|
-
bottom: 20px;
|
|
407
|
-
right: 20px;
|
|
408
|
-
}
|
|
404
|
+
/* Position is set dynamically via updateMockWidgetPosition() */
|
|
409
405
|
}
|
|
410
406
|
|
|
411
407
|
@media (max-width: 1200px) {
|
|
@@ -423,7 +419,15 @@
|
|
|
423
419
|
}
|
|
424
420
|
|
|
425
421
|
/* Mock widget styles - will be dynamically generated */
|
|
422
|
+
.mock-button-container {
|
|
423
|
+
position: relative;
|
|
424
|
+
display: inline-flex;
|
|
425
|
+
align-items: center;
|
|
426
|
+
justify-content: center;
|
|
427
|
+
}
|
|
428
|
+
|
|
426
429
|
.mock-widget-button {
|
|
430
|
+
position: relative;
|
|
427
431
|
width: 60px;
|
|
428
432
|
height: 60px;
|
|
429
433
|
border-radius: 50%;
|
|
@@ -436,17 +440,150 @@
|
|
|
436
440
|
justify-content: center;
|
|
437
441
|
font-size: 24px;
|
|
438
442
|
transition: all 0.3s;
|
|
443
|
+
margin: 0;
|
|
444
|
+
flex-shrink: 0;
|
|
439
445
|
}
|
|
440
446
|
|
|
441
447
|
.mock-widget-button:hover {
|
|
442
448
|
transform: scale(1.1);
|
|
443
449
|
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
|
|
444
450
|
}
|
|
451
|
+
|
|
452
|
+
/* Prompt bubble styles */
|
|
453
|
+
.mock-prompt-bubble {
|
|
454
|
+
position: absolute;
|
|
455
|
+
z-index: 10002;
|
|
456
|
+
pointer-events: none;
|
|
457
|
+
white-space: nowrap;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
.mock-prompt-bubble.top {
|
|
461
|
+
bottom: calc(100% + 18px);
|
|
462
|
+
left: 50%;
|
|
463
|
+
transform: translateX(-50%);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
.mock-prompt-bubble.left {
|
|
467
|
+
right: calc(100% + 12px);
|
|
468
|
+
top: 50%;
|
|
469
|
+
transform: translateY(-50%);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
.mock-prompt-bubble.right {
|
|
473
|
+
left: calc(100% + 12px);
|
|
474
|
+
top: 50%;
|
|
475
|
+
transform: translateY(-50%);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.mock-prompt-bubble-content {
|
|
479
|
+
position: relative;
|
|
480
|
+
padding: 8px 16px;
|
|
481
|
+
border-radius: 20px;
|
|
482
|
+
font-weight: 500;
|
|
483
|
+
font-size: 14px;
|
|
484
|
+
box-shadow: 0 4px 15px rgba(124, 58, 237, 0.3);
|
|
485
|
+
overflow: hidden;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.mock-prompt-bubble-shimmer {
|
|
489
|
+
position: absolute;
|
|
490
|
+
inset: 0;
|
|
491
|
+
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.25), transparent);
|
|
492
|
+
animation: mock-shimmer 2s infinite;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
@keyframes mock-shimmer {
|
|
496
|
+
0% { transform: translateX(-100%); }
|
|
497
|
+
100% { transform: translateX(200%); }
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
@keyframes mock-bounce {
|
|
501
|
+
0%, 100% { transform: translateX(-50%) translateY(0); }
|
|
502
|
+
50% { transform: translateX(-50%) translateY(-10px); }
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
@keyframes mock-float {
|
|
506
|
+
0%, 100% { transform: translateX(-50%) translateY(0); }
|
|
507
|
+
50% { transform: translateX(-50%) translateY(-8px); }
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
@keyframes mock-pulse-ring {
|
|
511
|
+
0% { transform: scale(1); opacity: 0.4; }
|
|
512
|
+
100% { transform: scale(1.8); opacity: 0; }
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
.mock-prompt-bubble.animation-bounce {
|
|
516
|
+
animation: mock-bounce 1s ease-in-out infinite;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
.mock-prompt-bubble.animation-pulse {
|
|
520
|
+
animation: pulse 2s ease-in-out infinite;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.mock-prompt-bubble.animation-float {
|
|
524
|
+
animation: mock-float 2s ease-in-out infinite;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/* Ensure top-positioned bubbles maintain horizontal centering during animations */
|
|
528
|
+
.mock-prompt-bubble.top.animation-bounce,
|
|
529
|
+
.mock-prompt-bubble.top.animation-float,
|
|
530
|
+
.mock-prompt-bubble.top.animation-pulse {
|
|
531
|
+
/* Animation keyframes already include translateX(-50%) for centering */
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.mock-prompt-bubble-arrow {
|
|
535
|
+
position: absolute;
|
|
536
|
+
width: 0;
|
|
537
|
+
height: 0;
|
|
538
|
+
border: 8px solid transparent;
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
.mock-prompt-bubble.top .mock-prompt-bubble-arrow {
|
|
542
|
+
top: 100%;
|
|
543
|
+
left: 50%;
|
|
544
|
+
transform: translateX(-50%);
|
|
545
|
+
border-top-color: var(--mock-prompt-bg-color, #7c3aed);
|
|
546
|
+
border-bottom: none;
|
|
547
|
+
margin-left: 0;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
.mock-prompt-bubble.left .mock-prompt-bubble-arrow {
|
|
551
|
+
left: 100%;
|
|
552
|
+
top: 50%;
|
|
553
|
+
transform: translateY(-50%);
|
|
554
|
+
border-left-color: var(--mock-prompt-bg-color, #7c3aed);
|
|
555
|
+
border-right: none;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
.mock-prompt-bubble.right .mock-prompt-bubble-arrow {
|
|
559
|
+
right: 100%;
|
|
560
|
+
top: 50%;
|
|
561
|
+
transform: translateY(-50%);
|
|
562
|
+
border-right-color: var(--mock-prompt-bg-color, #7c3aed);
|
|
563
|
+
border-left: none;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.mock-pulse-rings {
|
|
567
|
+
position: absolute;
|
|
568
|
+
inset: 0;
|
|
569
|
+
border-radius: 50%;
|
|
570
|
+
pointer-events: none;
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.mock-pulse-ring {
|
|
574
|
+
position: absolute;
|
|
575
|
+
inset: 0;
|
|
576
|
+
border-radius: 50%;
|
|
577
|
+
animation: mock-pulse-ring 2s ease-out infinite;
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
.mock-pulse-ring:nth-child(2) {
|
|
581
|
+
animation-delay: 0.5s;
|
|
582
|
+
}
|
|
445
583
|
|
|
446
584
|
.mock-widget-panel {
|
|
447
|
-
position:
|
|
448
|
-
|
|
449
|
-
right: 0;
|
|
585
|
+
position: relative;
|
|
586
|
+
/* Position is controlled by parent .mock-widget */
|
|
450
587
|
width: 360px;
|
|
451
588
|
height: 550px;
|
|
452
589
|
background: white;
|
|
@@ -494,80 +631,116 @@
|
|
|
494
631
|
.mock-panel-content {
|
|
495
632
|
flex: 1;
|
|
496
633
|
overflow-y: auto;
|
|
497
|
-
padding:
|
|
634
|
+
padding: 0; /* Remove padding so landing screen fills entire area */
|
|
498
635
|
}
|
|
499
636
|
|
|
500
637
|
.mock-landing-screen {
|
|
501
638
|
display: flex;
|
|
502
639
|
flex-direction: column;
|
|
503
640
|
align-items: center;
|
|
504
|
-
justify-content:
|
|
505
|
-
|
|
506
|
-
padding:
|
|
641
|
+
justify-content: flex-start;
|
|
642
|
+
flex: 1;
|
|
643
|
+
padding: 32px 24px;
|
|
507
644
|
text-align: center;
|
|
645
|
+
overflow-y: auto;
|
|
646
|
+
min-height: 0;
|
|
647
|
+
width: 100%;
|
|
648
|
+
/* Background will be set inline via style attribute to match widget config */
|
|
508
649
|
}
|
|
509
650
|
|
|
510
651
|
.mock-landing-logo {
|
|
511
|
-
|
|
512
|
-
|
|
652
|
+
width: 88px;
|
|
653
|
+
height: 88px;
|
|
654
|
+
border-radius: 22px;
|
|
655
|
+
margin-bottom: 20px;
|
|
513
656
|
display: flex;
|
|
514
657
|
align-items: center;
|
|
515
658
|
justify-content: center;
|
|
659
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
660
|
+
box-shadow: 0 8px 28px rgba(102, 126, 234, 0.35);
|
|
661
|
+
border: none; /* No border by default - will be overridden by inline styles */
|
|
516
662
|
}
|
|
517
663
|
|
|
518
664
|
.mock-landing-logo img {
|
|
519
665
|
display: block;
|
|
666
|
+
border: none !important;
|
|
667
|
+
outline: none !important;
|
|
520
668
|
}
|
|
521
669
|
|
|
522
670
|
.mock-landing-title {
|
|
523
|
-
font-size:
|
|
524
|
-
font-weight:
|
|
525
|
-
color: #
|
|
526
|
-
margin-bottom:
|
|
671
|
+
font-size: 20px;
|
|
672
|
+
font-weight: 600;
|
|
673
|
+
color: #1e1b4b;
|
|
674
|
+
margin-bottom: 6px;
|
|
675
|
+
line-height: 1.3;
|
|
527
676
|
}
|
|
528
677
|
|
|
529
678
|
.mock-landing-subtitle {
|
|
530
679
|
font-size: 14px;
|
|
531
680
|
color: #64748b;
|
|
532
|
-
margin-bottom:
|
|
681
|
+
margin-bottom: 28px;
|
|
533
682
|
}
|
|
534
683
|
|
|
535
684
|
.mock-mode-cards {
|
|
536
685
|
display: flex;
|
|
537
|
-
gap:
|
|
686
|
+
gap: 12px;
|
|
538
687
|
width: 100%;
|
|
688
|
+
justify-content: center;
|
|
539
689
|
}
|
|
540
690
|
|
|
541
691
|
.mock-mode-card {
|
|
542
692
|
flex: 1;
|
|
693
|
+
max-width: 160px;
|
|
543
694
|
background: white;
|
|
544
|
-
border:
|
|
545
|
-
border-radius:
|
|
546
|
-
padding:
|
|
695
|
+
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
696
|
+
border-radius: 18px;
|
|
697
|
+
padding: 20px 16px;
|
|
547
698
|
cursor: pointer;
|
|
548
|
-
|
|
699
|
+
display: flex;
|
|
700
|
+
flex-direction: column;
|
|
701
|
+
align-items: center;
|
|
702
|
+
gap: 12px;
|
|
703
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
704
|
+
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.06);
|
|
549
705
|
}
|
|
550
706
|
|
|
551
707
|
.mock-mode-card:hover {
|
|
552
|
-
|
|
553
|
-
|
|
708
|
+
transform: translateY(-4px);
|
|
709
|
+
box-shadow: 0 8px 24px rgba(124, 58, 237, 0.2);
|
|
710
|
+
border-color: rgba(124, 58, 237, 0.3);
|
|
554
711
|
}
|
|
555
712
|
|
|
556
713
|
.mock-mode-icon {
|
|
557
|
-
|
|
558
|
-
|
|
714
|
+
width: 56px;
|
|
715
|
+
height: 56px;
|
|
716
|
+
display: flex;
|
|
717
|
+
align-items: center;
|
|
718
|
+
justify-content: center;
|
|
719
|
+
border-radius: 16px;
|
|
720
|
+
background: #7C3AED;
|
|
721
|
+
color: #fff;
|
|
722
|
+
box-shadow: 0 4px 14px rgba(124, 58, 237, 0.35);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
.mock-mode-icon svg {
|
|
726
|
+
stroke: white;
|
|
727
|
+
fill: none;
|
|
559
728
|
}
|
|
560
729
|
|
|
561
730
|
.mock-mode-title {
|
|
562
|
-
font-size:
|
|
731
|
+
font-size: 14px;
|
|
563
732
|
font-weight: 600;
|
|
564
|
-
color: #
|
|
565
|
-
|
|
733
|
+
color: #1e1b4b;
|
|
734
|
+
text-align: center;
|
|
566
735
|
}
|
|
567
736
|
|
|
568
737
|
.mock-mode-desc {
|
|
569
|
-
|
|
570
|
-
|
|
738
|
+
display: none; /* Hide description to match real widget */
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
@keyframes pulse {
|
|
742
|
+
0%, 100% { transform: scale(1); opacity: 1; }
|
|
743
|
+
50% { transform: scale(1.15); opacity: 0.8; }
|
|
571
744
|
}
|
|
572
745
|
|
|
573
746
|
.mock-text-interface {
|
|
@@ -586,21 +759,57 @@
|
|
|
586
759
|
}
|
|
587
760
|
|
|
588
761
|
.mock-message {
|
|
762
|
+
display: flex;
|
|
763
|
+
gap: 8px;
|
|
764
|
+
align-items: center;
|
|
589
765
|
max-width: 75%;
|
|
766
|
+
padding: 4px 0;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
.mock-message.user {
|
|
770
|
+
align-self: flex-end;
|
|
771
|
+
flex-direction: row-reverse; /* Avatar on right for LTR */
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
.mock-message.agent {
|
|
775
|
+
align-self: flex-start;
|
|
776
|
+
flex-direction: row; /* Avatar on left for LTR */
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
/* RTL support - reverse flex direction */
|
|
780
|
+
.mock-text-interface[style*="direction: rtl"] .mock-message.user {
|
|
781
|
+
flex-direction: row; /* Avatar on left for RTL */
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.mock-text-interface[style*="direction: rtl"] .mock-message.agent {
|
|
785
|
+
flex-direction: row-reverse; /* Avatar on right for RTL */
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
.mock-message-avatar {
|
|
789
|
+
width: 20px;
|
|
790
|
+
height: 20px;
|
|
791
|
+
display: flex;
|
|
792
|
+
align-items: center;
|
|
793
|
+
justify-content: center;
|
|
794
|
+
flex-shrink: 0;
|
|
795
|
+
font-size: 18px;
|
|
796
|
+
line-height: 1;
|
|
797
|
+
background: transparent;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
.mock-message-bubble {
|
|
590
801
|
padding: 12px 16px;
|
|
591
802
|
border-radius: 16px;
|
|
592
803
|
font-size: 14px;
|
|
593
804
|
line-height: 1.5;
|
|
594
805
|
}
|
|
595
806
|
|
|
596
|
-
.mock-message.user {
|
|
597
|
-
align-self: flex-end;
|
|
807
|
+
.mock-message.user .mock-message-bubble {
|
|
598
808
|
background: #E5E7EB;
|
|
599
809
|
color: #1F2937;
|
|
600
810
|
}
|
|
601
811
|
|
|
602
|
-
.mock-message.agent {
|
|
603
|
-
align-self: flex-start;
|
|
812
|
+
.mock-message.agent .mock-message-bubble {
|
|
604
813
|
background: #F3F4F6;
|
|
605
814
|
color: #1F2937;
|
|
606
815
|
}
|
|
@@ -1074,11 +1283,15 @@
|
|
|
1074
1283
|
<div class="preview-area" id="previewArea">
|
|
1075
1284
|
<!-- Container to ensure proper scrolling - must be taller than preview area -->
|
|
1076
1285
|
<div style="position: relative; min-height: 800px; width: 100%; padding-bottom: 200px;">
|
|
1077
|
-
<div class="mock-widget" id="mockWidget" data-element-type="position"
|
|
1286
|
+
<div class="mock-widget" id="mockWidget" data-element-type="position">
|
|
1078
1287
|
<div class="mock-widget-panel" id="mockPanel">
|
|
1079
1288
|
<!-- Panel content will be dynamically generated -->
|
|
1080
1289
|
</div>
|
|
1081
|
-
<
|
|
1290
|
+
<div class="mock-button-container" id="mockButtonContainer">
|
|
1291
|
+
<div class="mock-prompt-bubble" id="mockPromptBubble" style="display: none;"></div>
|
|
1292
|
+
<div class="mock-pulse-rings" id="mockPulseRings" style="display: none;"></div>
|
|
1293
|
+
<button class="mock-widget-button" id="mockButton">🎤</button>
|
|
1294
|
+
</div>
|
|
1082
1295
|
</div>
|
|
1083
1296
|
</div>
|
|
1084
1297
|
</div>
|
|
@@ -1156,14 +1369,21 @@
|
|
|
1156
1369
|
},
|
|
1157
1370
|
header: {
|
|
1158
1371
|
title: 'Chat Assistant',
|
|
1159
|
-
backgroundColor: '#7C3AED',
|
|
1372
|
+
backgroundColor: '#7C3AED', // Default purple
|
|
1160
1373
|
textColor: '#FFFFFF',
|
|
1161
|
-
showCloseButton: true
|
|
1374
|
+
showCloseButton: true,
|
|
1375
|
+
onlineIndicatorText: 'Online',
|
|
1376
|
+
onlineIndicatorColor: '#FFFFFF',
|
|
1377
|
+
onlineIndicatorDotColor: '#10b981'
|
|
1162
1378
|
},
|
|
1163
1379
|
messages: {
|
|
1164
1380
|
userBackgroundColor: '#E5E7EB',
|
|
1165
1381
|
agentBackgroundColor: '#F3F4F6',
|
|
1166
|
-
textColor: '#1F2937',
|
|
1382
|
+
textColor: '#1F2937', // Fallback for backward compatibility
|
|
1383
|
+
userTextColor: '#1F2937',
|
|
1384
|
+
agentTextColor: '#1F2937',
|
|
1385
|
+
userAvatarIcon: '👤',
|
|
1386
|
+
agentAvatarIcon: '🤖',
|
|
1167
1387
|
fontSize: '14px',
|
|
1168
1388
|
borderRadius: 16
|
|
1169
1389
|
},
|
|
@@ -1177,6 +1397,8 @@
|
|
|
1177
1397
|
voice: {
|
|
1178
1398
|
micButtonColor: '#7C3AED',
|
|
1179
1399
|
micButtonActiveColor: '#EF4444',
|
|
1400
|
+
speakerButtonColor: '#FFFFFF',
|
|
1401
|
+
endCallButtonColor: '#ef4444',
|
|
1180
1402
|
avatarBackgroundColor: '#667eea',
|
|
1181
1403
|
avatarType: 'icon', // 'icon' or 'image'
|
|
1182
1404
|
avatarIcon: '🤖',
|
|
@@ -1186,29 +1408,48 @@
|
|
|
1186
1408
|
startCallButtonTextColor: '#FFFFFF',
|
|
1187
1409
|
statusTitleColor: '#1e293b',
|
|
1188
1410
|
statusSubtitleColor: '#64748b',
|
|
1411
|
+
statusDotColor: '#10b981',
|
|
1412
|
+
statusText: 'Listening...',
|
|
1413
|
+
liveTranscriptTextColor: '#64748b',
|
|
1414
|
+
liveTranscriptFontSize: '14px',
|
|
1415
|
+
liveIndicatorDotColor: '#10b981',
|
|
1416
|
+
liveIndicatorTextColor: '#10b981',
|
|
1189
1417
|
waveformType: 'waveform', // 'waveform', 'icon', or 'image'
|
|
1190
1418
|
waveformIcon: '🎤',
|
|
1191
1419
|
waveformImageUrl: ''
|
|
1192
1420
|
},
|
|
1193
1421
|
landing: {
|
|
1422
|
+
backgroundColor: 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)', // Default gradient matching real widget
|
|
1194
1423
|
logo: '🤖',
|
|
1195
1424
|
logoType: 'icon', // 'icon' or 'image'
|
|
1196
1425
|
logoIcon: '🤖',
|
|
1197
1426
|
logoImageUrl: '',
|
|
1427
|
+
logoBackgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
1428
|
+
logoBackgroundEnabled: true,
|
|
1198
1429
|
title: 'Welcome to AI Assistant',
|
|
1199
1430
|
subtitle: 'Choose how you\'d like to interact',
|
|
1200
1431
|
voiceCardTitle: 'Voice Call',
|
|
1201
|
-
voiceCardDesc: 'Start a voice conversation',
|
|
1202
1432
|
textCardTitle: 'Text Chat',
|
|
1203
|
-
textCardDesc: 'Chat via text messages',
|
|
1204
1433
|
titleColor: '#1e293b',
|
|
1205
1434
|
subtitleColor: '#64748b',
|
|
1206
1435
|
modeCardBackgroundColor: '#FFFFFF'
|
|
1207
1436
|
},
|
|
1208
1437
|
position: {
|
|
1209
1438
|
vertical: 'bottom',
|
|
1210
|
-
horizontal: '
|
|
1439
|
+
horizontal: 'left',
|
|
1211
1440
|
offset: { x: 20, y: 20 }
|
|
1441
|
+
},
|
|
1442
|
+
promptAnimation: {
|
|
1443
|
+
enabled: false,
|
|
1444
|
+
text: 'Try me!',
|
|
1445
|
+
backgroundColor: 'linear-gradient(135deg, #7c3aed, #4f46e5)',
|
|
1446
|
+
textColor: '#ffffff',
|
|
1447
|
+
animationType: 'bounce',
|
|
1448
|
+
showShimmer: true,
|
|
1449
|
+
showPulseRings: true,
|
|
1450
|
+
hideAfterClick: true,
|
|
1451
|
+
hideAfterSeconds: null,
|
|
1452
|
+
position: 'top'
|
|
1212
1453
|
}
|
|
1213
1454
|
};
|
|
1214
1455
|
|
|
@@ -1217,13 +1458,17 @@
|
|
|
1217
1458
|
let panelOpen = true; // Start with panel open to show defaults
|
|
1218
1459
|
let clickTimeout = null; // Track single vs double click
|
|
1219
1460
|
let historyExpanded = false; // Track conversation history state
|
|
1461
|
+
let isInitializing = true; // Track if we're in the initial load phase
|
|
1462
|
+
let lastClickTime = 0; // Track clicks for double-click detection
|
|
1463
|
+
let lastClickElement = null;
|
|
1464
|
+
let lastClickType = null;
|
|
1220
1465
|
|
|
1221
1466
|
// Initialize mock widget
|
|
1222
1467
|
function initMockWidget() {
|
|
1223
1468
|
const mockButton = document.getElementById('mockButton');
|
|
1224
1469
|
const mockPanel = document.getElementById('mockPanel');
|
|
1225
1470
|
|
|
1226
|
-
// Apply button styles
|
|
1471
|
+
// Apply button styles (this will also update prompt bubble)
|
|
1227
1472
|
applyButtonStyles(mockButton);
|
|
1228
1473
|
|
|
1229
1474
|
// Open panel by default to show defaults
|
|
@@ -1236,13 +1481,28 @@
|
|
|
1236
1481
|
if (panelOpen) {
|
|
1237
1482
|
renderPanelContent();
|
|
1238
1483
|
}
|
|
1484
|
+
// Update prompt bubble visibility based on panel state
|
|
1485
|
+
updatePromptBubble(mockButton);
|
|
1486
|
+
// Sync actual widget state with mock panel
|
|
1487
|
+
syncWidgetWithMockPanel();
|
|
1239
1488
|
});
|
|
1240
1489
|
|
|
1241
1490
|
// Render initial panel content with defaults
|
|
1242
1491
|
renderPanelContent();
|
|
1243
1492
|
|
|
1493
|
+
// Update prompt bubble visibility (should be hidden since panel starts open)
|
|
1494
|
+
updatePromptBubble(mockButton);
|
|
1495
|
+
|
|
1244
1496
|
// Show default customization controls
|
|
1245
1497
|
showCustomizationControls('default');
|
|
1498
|
+
|
|
1499
|
+
// Initialize config code to show only appId and agentId
|
|
1500
|
+
updateConfigCode();
|
|
1501
|
+
|
|
1502
|
+
// Apply initial position after a brief delay to ensure DOM is ready
|
|
1503
|
+
setTimeout(() => {
|
|
1504
|
+
updateMockWidgetPosition();
|
|
1505
|
+
}, 0);
|
|
1246
1506
|
}
|
|
1247
1507
|
|
|
1248
1508
|
function applyButtonStyles(button) {
|
|
@@ -1297,6 +1557,9 @@
|
|
|
1297
1557
|
// Make button highlightable
|
|
1298
1558
|
button.dataset.elementType = 'button';
|
|
1299
1559
|
|
|
1560
|
+
// Update prompt bubble if enabled
|
|
1561
|
+
updatePromptBubble(button);
|
|
1562
|
+
|
|
1300
1563
|
// Remove old event listeners by replacing the button
|
|
1301
1564
|
const oldButton = button;
|
|
1302
1565
|
const newButton = oldButton.cloneNode(true);
|
|
@@ -1306,15 +1569,147 @@
|
|
|
1306
1569
|
newButton.addEventListener('click', (e) => {
|
|
1307
1570
|
e.preventDefault();
|
|
1308
1571
|
e.stopPropagation();
|
|
1309
|
-
|
|
1572
|
+
|
|
1573
|
+
// For button, single click should toggle panel immediately
|
|
1574
|
+
// Double click will still select for editing (without double-toggling)
|
|
1575
|
+
const currentTime = Date.now();
|
|
1576
|
+
const timeSinceLastClick = currentTime - lastClickTime;
|
|
1577
|
+
|
|
1578
|
+
// Check if this is a double click (within 400ms and same element)
|
|
1579
|
+
if (timeSinceLastClick < 400 && lastClickElement === newButton && lastClickType === 'button') {
|
|
1580
|
+
// Double click - just select for editing (don't toggle panel again)
|
|
1581
|
+
lastClickTime = 0;
|
|
1582
|
+
lastClickElement = null;
|
|
1583
|
+
lastClickType = null;
|
|
1584
|
+
selectElement('button', newButton, e);
|
|
1585
|
+
} else {
|
|
1586
|
+
// Single click - toggle panel immediately and select button
|
|
1587
|
+
lastClickTime = currentTime;
|
|
1588
|
+
lastClickElement = newButton;
|
|
1589
|
+
lastClickType = 'button';
|
|
1590
|
+
|
|
1591
|
+
// Toggle panel
|
|
1592
|
+
panelOpen = !panelOpen;
|
|
1593
|
+
const panel = document.getElementById('mockPanel');
|
|
1594
|
+
panel.classList.toggle('open');
|
|
1595
|
+
if (panelOpen) {
|
|
1596
|
+
renderPanelContent();
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
// Update prompt bubble visibility based on panel state
|
|
1600
|
+
updatePromptBubble(newButton);
|
|
1601
|
+
// Sync actual widget state with mock panel
|
|
1602
|
+
syncWidgetWithMockPanel();
|
|
1603
|
+
|
|
1604
|
+
// Select the button for editing (so user can customize it)
|
|
1605
|
+
selectElement('button', newButton, e);
|
|
1606
|
+
}
|
|
1310
1607
|
});
|
|
1311
1608
|
}
|
|
1312
1609
|
|
|
1610
|
+
function updatePromptBubble(button) {
|
|
1611
|
+
const promptConfig = widgetConfig.promptAnimation || {};
|
|
1612
|
+
const promptBubble = document.getElementById('mockPromptBubble');
|
|
1613
|
+
const pulseRings = document.getElementById('mockPulseRings');
|
|
1614
|
+
|
|
1615
|
+
if (!promptBubble || !pulseRings) return;
|
|
1616
|
+
|
|
1617
|
+
// Show/hide prompt bubble - hide when mock panel is open, show when closed
|
|
1618
|
+
if (promptConfig.enabled === true && !panelOpen) {
|
|
1619
|
+
promptBubble.style.display = 'block';
|
|
1620
|
+
|
|
1621
|
+
// Extract solid color from gradient for arrow
|
|
1622
|
+
let arrowColor = '#7c3aed';
|
|
1623
|
+
if (promptConfig.backgroundColor && promptConfig.backgroundColor.includes('gradient')) {
|
|
1624
|
+
const match = promptConfig.backgroundColor.match(/#[0-9a-fA-F]{6}/);
|
|
1625
|
+
if (match) arrowColor = match[0];
|
|
1626
|
+
} else if (promptConfig.backgroundColor) {
|
|
1627
|
+
arrowColor = promptConfig.backgroundColor;
|
|
1628
|
+
}
|
|
1629
|
+
|
|
1630
|
+
// Set CSS variable for arrow color
|
|
1631
|
+
promptBubble.style.setProperty('--mock-prompt-bg-color', arrowColor);
|
|
1632
|
+
|
|
1633
|
+
// Build prompt bubble HTML
|
|
1634
|
+
// Convert 'pulse' to 'bounce' if pulse is selected (pulse option removed)
|
|
1635
|
+
const animationType = promptConfig.animationType === 'pulse' ? 'bounce' : promptConfig.animationType;
|
|
1636
|
+
const animationClass = animationType === 'none' ? '' : `animation-${animationType}`;
|
|
1637
|
+
const shimmerHTML = promptConfig.showShimmer !== false ? '<div class="mock-prompt-bubble-shimmer"></div>' : '';
|
|
1638
|
+
const position = promptConfig.position || 'top';
|
|
1639
|
+
|
|
1640
|
+
promptBubble.className = `mock-prompt-bubble ${position} ${animationClass}`;
|
|
1641
|
+
promptBubble.innerHTML = `
|
|
1642
|
+
<div class="mock-prompt-bubble-content" style="background: ${promptConfig.backgroundColor || 'linear-gradient(135deg, #7c3aed, #4f46e5)'}; color: ${promptConfig.textColor || '#ffffff'};">
|
|
1643
|
+
${shimmerHTML}
|
|
1644
|
+
<span style="position: relative; z-index: 1;">${promptConfig.text || 'Try me!'}</span>
|
|
1645
|
+
</div>
|
|
1646
|
+
<div class="mock-prompt-bubble-arrow"></div>
|
|
1647
|
+
`;
|
|
1648
|
+
} else {
|
|
1649
|
+
promptBubble.style.display = 'none';
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
// Show/hide pulse rings - hide when mock panel is open, show when closed
|
|
1653
|
+
if (promptConfig.enabled === true && promptConfig.showPulseRings !== false && !panelOpen) {
|
|
1654
|
+
pulseRings.style.display = 'block';
|
|
1655
|
+
|
|
1656
|
+
// Extract solid color from gradient for rings
|
|
1657
|
+
let ringColor = '#7c3aed';
|
|
1658
|
+
if (promptConfig.backgroundColor && promptConfig.backgroundColor.includes('gradient')) {
|
|
1659
|
+
const match = promptConfig.backgroundColor.match(/#[0-9a-fA-F]{6}/);
|
|
1660
|
+
if (match) ringColor = match[0];
|
|
1661
|
+
} else if (promptConfig.backgroundColor) {
|
|
1662
|
+
ringColor = promptConfig.backgroundColor;
|
|
1663
|
+
}
|
|
1664
|
+
|
|
1665
|
+
pulseRings.innerHTML = `
|
|
1666
|
+
<div class="mock-pulse-ring" style="background-color: ${ringColor}33;"></div>
|
|
1667
|
+
<div class="mock-pulse-ring" style="background-color: ${ringColor}1a;"></div>
|
|
1668
|
+
`;
|
|
1669
|
+
} else {
|
|
1670
|
+
pulseRings.style.display = 'none';
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1313
1674
|
function getSizeValue(size) {
|
|
1314
1675
|
const sizes = { small: 48, medium: 60, large: 72, xl: 84 };
|
|
1315
1676
|
return sizes[size] || 60;
|
|
1316
1677
|
}
|
|
1317
1678
|
|
|
1679
|
+
function updateMockWidgetPosition() {
|
|
1680
|
+
const mockWidget = document.getElementById('mockWidget');
|
|
1681
|
+
if (!mockWidget) {
|
|
1682
|
+
console.warn('Mock widget not found, retrying...');
|
|
1683
|
+
setTimeout(updateMockWidgetPosition, 100);
|
|
1684
|
+
return;
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
const pos = widgetConfig.position;
|
|
1688
|
+
const offset = pos.offset || { x: 20, y: 20 };
|
|
1689
|
+
|
|
1690
|
+
// Clear any existing positioning
|
|
1691
|
+
mockWidget.style.top = '';
|
|
1692
|
+
mockWidget.style.bottom = '';
|
|
1693
|
+
mockWidget.style.left = '';
|
|
1694
|
+
mockWidget.style.right = '';
|
|
1695
|
+
|
|
1696
|
+
// Set position
|
|
1697
|
+
mockWidget.style.position = 'absolute';
|
|
1698
|
+
|
|
1699
|
+
// Vertical positioning - use config value
|
|
1700
|
+
if (pos.vertical === 'top') {
|
|
1701
|
+
mockWidget.style.setProperty('top', `${offset.y}px`, 'important');
|
|
1702
|
+
mockWidget.style.setProperty('bottom', 'auto', 'important');
|
|
1703
|
+
} else if (pos.vertical === 'bottom') {
|
|
1704
|
+
mockWidget.style.setProperty('bottom', `${offset.y}px`, 'important');
|
|
1705
|
+
mockWidget.style.setProperty('top', 'auto', 'important');
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// Horizontal positioning - ALWAYS keep mock widget on the right side
|
|
1709
|
+
mockWidget.style.setProperty('right', `${offset.x}px`, 'important');
|
|
1710
|
+
mockWidget.style.setProperty('left', 'auto', 'important');
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1318
1713
|
function renderPanelContent() {
|
|
1319
1714
|
const mockPanel = document.getElementById('mockPanel');
|
|
1320
1715
|
|
|
@@ -1322,8 +1717,12 @@
|
|
|
1322
1717
|
mockPanel.style.width = widgetConfig.panel.width + 'px';
|
|
1323
1718
|
mockPanel.style.height = widgetConfig.panel.height + 'px';
|
|
1324
1719
|
mockPanel.style.borderRadius = widgetConfig.panel.borderRadius + 'px';
|
|
1325
|
-
|
|
1720
|
+
// Panel background should match landing background to avoid double-frame effect
|
|
1721
|
+
const landingBg = widgetConfig.landing.backgroundColor || 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)';
|
|
1722
|
+
mockPanel.style.backgroundColor = landingBg;
|
|
1326
1723
|
mockPanel.style.border = widgetConfig.panel.border;
|
|
1724
|
+
// Apply direction (LTR/RTL)
|
|
1725
|
+
mockPanel.style.direction = widgetConfig.direction || 'ltr';
|
|
1327
1726
|
|
|
1328
1727
|
// Render based on current view
|
|
1329
1728
|
if (currentView === 'landing') {
|
|
@@ -1340,36 +1739,67 @@
|
|
|
1340
1739
|
|
|
1341
1740
|
function renderLandingScreen(panel) {
|
|
1342
1741
|
const config = widgetConfig.landing;
|
|
1742
|
+
const iconBgColor = config.modeCardIconBackgroundColor || '#7C3AED';
|
|
1743
|
+
// Determine logo background - use logoBackgroundColor if enabled, otherwise transparent
|
|
1744
|
+
let logoBg = 'transparent';
|
|
1745
|
+
if (config.logoType === 'image' && config.logoBackgroundEnabled !== false) {
|
|
1746
|
+
logoBg = config.logoBackgroundColor || 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
|
|
1747
|
+
} else if (config.logoType === 'icon') {
|
|
1748
|
+
// For icon type, use the default avatar background
|
|
1749
|
+
logoBg = config.avatarBackground || 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)';
|
|
1750
|
+
}
|
|
1751
|
+
|
|
1343
1752
|
panel.innerHTML = `
|
|
1344
|
-
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor};" data-element-type="header">
|
|
1345
|
-
<
|
|
1753
|
+
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor}; direction: ${widgetConfig.direction || 'ltr'};" data-element-type="header">
|
|
1754
|
+
<div style="display: flex; align-items: center; gap: 8px;">
|
|
1755
|
+
<span>${widgetConfig.header.title}</span>
|
|
1756
|
+
<div style="display: flex; align-items: center; gap: 6px; margin-left: 8px;" data-element-type="onlineIndicator">
|
|
1757
|
+
<div style="width: 6px; height: 6px; background: ${widgetConfig.header.onlineIndicatorDotColor || '#10b981'}; border-radius: 50%; animation: pulse 2s ease-in-out infinite;"></div>
|
|
1758
|
+
<span style="font-size: 12px; opacity: 0.9; color: ${widgetConfig.header.onlineIndicatorColor || widgetConfig.header.textColor};">${widgetConfig.header.onlineIndicatorText || 'Online'}</span>
|
|
1759
|
+
</div>
|
|
1760
|
+
</div>
|
|
1346
1761
|
${widgetConfig.header.showCloseButton ? '<button class="mock-panel-close" data-element-type="closeButton">×</button>' : ''}
|
|
1347
1762
|
</div>
|
|
1348
|
-
<div class="mock-panel-content">
|
|
1349
|
-
<div class="mock-landing-screen">
|
|
1350
|
-
<div class="mock-landing-logo" data-element-type="landingLogo">
|
|
1763
|
+
<div class="mock-panel-content" style="direction: ${widgetConfig.direction || 'ltr'};">
|
|
1764
|
+
<div class="mock-landing-screen" style="background: ${config.backgroundColor || 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)'}; height: 100%;" data-element-type="landingBackground">
|
|
1765
|
+
<div class="mock-landing-logo" style="background: ${logoBg}; ${logoBg !== 'transparent' ? 'box-shadow: 0 8px 28px rgba(102, 126, 234, 0.35); border: none !important;' : 'box-shadow: none !important; border: none !important; outline: none !important;'}" data-element-type="landingLogo">
|
|
1351
1766
|
${config.logoType === 'image' && config.logoImageUrl ? `
|
|
1352
|
-
<img src="${config.logoImageUrl}" alt="Logo" style="max-width:
|
|
1767
|
+
<img src="${config.logoImageUrl}" alt="Logo" style="max-width: 44px; max-height: 44px; object-fit: contain;">
|
|
1353
1768
|
` : `
|
|
1354
|
-
<span>${config.logoIcon || config.logo || '🤖'}</span>
|
|
1769
|
+
<span style="font-size: 44px; line-height: 1;">${config.logoIcon || config.logo || '🤖'}</span>
|
|
1355
1770
|
`}
|
|
1356
1771
|
</div>
|
|
1357
|
-
<div class="mock-landing-title" style="color: ${config.titleColor};" data-element-type="landingTitle">${config.title || 'Welcome to AI Assistant'}</div>
|
|
1358
|
-
<div class="mock-landing-subtitle" style="color: ${config.subtitleColor};" data-element-type="landingSubtitle">${config.subtitle || 'Choose how you\'d like to interact'}</div>
|
|
1772
|
+
<div class="mock-landing-title" style="color: ${config.titleColor || '#1e1b4b'};" data-element-type="landingTitle">${config.title || 'Welcome to AI Assistant'}</div>
|
|
1773
|
+
<div class="mock-landing-subtitle" style="color: ${config.subtitleColor || '#64748b'};" data-element-type="landingSubtitle">${config.subtitle || 'Choose how you\'d like to interact'}</div>
|
|
1359
1774
|
<div class="mock-mode-cards">
|
|
1360
|
-
<div class="mock-mode-card" style="background: ${config.modeCardBackgroundColor};" data-element-type="modeCard" data-mode="voice">
|
|
1361
|
-
<div class="mock-mode-icon"
|
|
1362
|
-
|
|
1363
|
-
|
|
1775
|
+
<div class="mock-mode-card" style="background: ${config.modeCardBackgroundColor || '#ffffff'}; border: 1px solid ${config.modeCardBorderColor || 'rgba(0, 0, 0, 0.06)'};" data-element-type="modeCard" data-mode="voice">
|
|
1776
|
+
<div class="mock-mode-icon" style="background: ${iconBgColor}; color: #fff; box-shadow: 0 4px 14px rgba(124, 58, 237, 0.35);">
|
|
1777
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width: 26px; height: 26px;">
|
|
1778
|
+
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
|
|
1779
|
+
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
|
|
1780
|
+
<line x1="12" y1="19" x2="12" y2="23"/>
|
|
1781
|
+
<line x1="8" y1="23" x2="16" y2="23"/>
|
|
1782
|
+
</svg>
|
|
1783
|
+
</div>
|
|
1784
|
+
<div class="mock-mode-title" style="color: ${config.modeCardTitleColor || '#1e1b4b'};">${config.voiceCardTitle || 'Voice Call'}</div>
|
|
1364
1785
|
</div>
|
|
1365
|
-
<div class="mock-mode-card" style="background: ${config.modeCardBackgroundColor};" data-element-type="modeCard" data-mode="text">
|
|
1366
|
-
<div class="mock-mode-icon"
|
|
1367
|
-
|
|
1368
|
-
|
|
1786
|
+
<div class="mock-mode-card" style="background: ${config.modeCardBackgroundColor || '#ffffff'}; border: 1px solid ${config.modeCardBorderColor || 'rgba(0, 0, 0, 0.06)'};" data-element-type="modeCard" data-mode="text">
|
|
1787
|
+
<div class="mock-mode-icon" style="background: ${iconBgColor}; color: #fff; box-shadow: 0 4px 14px rgba(124, 58, 237, 0.35);">
|
|
1788
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="width: 26px; height: 26px;">
|
|
1789
|
+
<path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"/>
|
|
1790
|
+
</svg>
|
|
1791
|
+
</div>
|
|
1792
|
+
<div class="mock-mode-title" style="color: ${config.modeCardTitleColor || '#1e1b4b'};">${config.textCardTitle || 'Text Chat'}</div>
|
|
1369
1793
|
</div>
|
|
1370
1794
|
</div>
|
|
1371
1795
|
</div>
|
|
1372
1796
|
</div>
|
|
1797
|
+
<div class="mock-footer" style="padding: 10px 16px; text-align: center; border-top: 1px solid rgba(0,0,0,0.06); font-size: 11px; color: #64748b; background: #fff; flex-shrink: 0;">
|
|
1798
|
+
<span style="display: inline-flex; align-items: center; gap: 4px;">
|
|
1799
|
+
<span>⚡</span>
|
|
1800
|
+
<span>Powered by TalkToPC</span>
|
|
1801
|
+
</span>
|
|
1802
|
+
</div>
|
|
1373
1803
|
`;
|
|
1374
1804
|
|
|
1375
1805
|
// Make elements selectable
|
|
@@ -1379,20 +1809,29 @@
|
|
|
1379
1809
|
function renderTextInterface(panel) {
|
|
1380
1810
|
const config = widgetConfig.text;
|
|
1381
1811
|
panel.innerHTML = `
|
|
1382
|
-
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor};" data-element-type="header">
|
|
1812
|
+
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor}; direction: ${widgetConfig.direction || 'ltr'};" data-element-type="header">
|
|
1383
1813
|
<span>${widgetConfig.header.title}</span>
|
|
1384
1814
|
${widgetConfig.header.showCloseButton ? '<button class="mock-panel-close" data-element-type="closeButton" onclick="switchView(\'landing\')">×</button>' : ''}
|
|
1385
1815
|
</div>
|
|
1386
|
-
<div class="mock-text-interface">
|
|
1816
|
+
<div class="mock-text-interface" style="direction: ${widgetConfig.direction || 'ltr'};">
|
|
1387
1817
|
<div class="mock-messages">
|
|
1388
|
-
<div class="mock-message user"
|
|
1389
|
-
|
|
1818
|
+
<div class="mock-message user" data-element-type="userMessage">
|
|
1819
|
+
<div class="mock-message-avatar">${widgetConfig.messages.userAvatarIcon || '👤'}</div>
|
|
1820
|
+
<div class="mock-message-bubble" style="background: ${widgetConfig.messages.userBackgroundColor}; color: ${widgetConfig.messages.userTextColor || widgetConfig.messages.textColor || '#1F2937'}; border-radius: ${widgetConfig.messages.borderRadius}px; font-size: ${widgetConfig.messages.fontSize};">
|
|
1821
|
+
Hello! How can I help you?
|
|
1822
|
+
</div>
|
|
1390
1823
|
</div>
|
|
1391
|
-
<div class="mock-message agent"
|
|
1392
|
-
|
|
1824
|
+
<div class="mock-message agent" data-element-type="agentMessage">
|
|
1825
|
+
<div class="mock-message-avatar">${widgetConfig.messages.agentAvatarIcon || '🤖'}</div>
|
|
1826
|
+
<div class="mock-message-bubble" style="background: ${widgetConfig.messages.agentBackgroundColor}; color: ${widgetConfig.messages.agentTextColor || widgetConfig.messages.textColor || '#1F2937'}; border-radius: ${widgetConfig.messages.borderRadius}px; font-size: ${widgetConfig.messages.fontSize};">
|
|
1827
|
+
Hi! I'm here to assist you. What would you like to know?
|
|
1828
|
+
</div>
|
|
1393
1829
|
</div>
|
|
1394
|
-
<div class="mock-message user"
|
|
1395
|
-
|
|
1830
|
+
<div class="mock-message user" data-element-type="userMessage">
|
|
1831
|
+
<div class="mock-message-avatar">${widgetConfig.messages.userAvatarIcon || '👤'}</div>
|
|
1832
|
+
<div class="mock-message-bubble" style="background: ${widgetConfig.messages.userBackgroundColor}; color: ${widgetConfig.messages.userTextColor || widgetConfig.messages.textColor || '#1F2937'}; border-radius: ${widgetConfig.messages.borderRadius}px; font-size: ${widgetConfig.messages.fontSize};">
|
|
1833
|
+
Can you tell me about your features?
|
|
1834
|
+
</div>
|
|
1396
1835
|
</div>
|
|
1397
1836
|
</div>
|
|
1398
1837
|
<div class="mock-input-area">
|
|
@@ -1410,12 +1849,12 @@
|
|
|
1410
1849
|
const config = widgetConfig.voice;
|
|
1411
1850
|
// Show active call state matching real widget structure
|
|
1412
1851
|
panel.innerHTML = `
|
|
1413
|
-
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor};" data-element-type="header">
|
|
1852
|
+
<div class="mock-panel-header" style="background: ${widgetConfig.header.backgroundColor}; color: ${widgetConfig.header.textColor}; direction: ${widgetConfig.direction || 'ltr'};" data-element-type="header">
|
|
1414
1853
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
1415
1854
|
<span>${widgetConfig.header.title}</span>
|
|
1416
|
-
<div style="display: flex; align-items: center; gap: 6px; margin-left: 8px;">
|
|
1417
|
-
<div style="width: 6px; height: 6px; background: #10b981; border-radius: 50%;"></div>
|
|
1418
|
-
<span style="font-size: 12px; opacity: 0.9;"
|
|
1855
|
+
<div style="display: flex; align-items: center; gap: 6px; margin-left: 8px;" data-element-type="onlineIndicator">
|
|
1856
|
+
<div style="width: 6px; height: 6px; background: ${widgetConfig.header.onlineIndicatorDotColor || '#10b981'}; border-radius: 50%;"></div>
|
|
1857
|
+
<span style="font-size: 12px; opacity: 0.9; color: ${widgetConfig.header.onlineIndicatorColor || widgetConfig.header.textColor};">${widgetConfig.header.onlineIndicatorText || 'Online'}</span>
|
|
1419
1858
|
</div>
|
|
1420
1859
|
</div>
|
|
1421
1860
|
<div style="display: flex; align-items: center; gap: 8px;">
|
|
@@ -1423,7 +1862,7 @@
|
|
|
1423
1862
|
${widgetConfig.header.showCloseButton ? '<button class="mock-panel-close" data-element-type="closeButton">×</button>' : ''}
|
|
1424
1863
|
</div>
|
|
1425
1864
|
</div>
|
|
1426
|
-
<div class="mock-voice-interface">
|
|
1865
|
+
<div class="mock-voice-interface" style="direction: ${widgetConfig.direction || 'ltr'};">
|
|
1427
1866
|
<!-- Voice Section -->
|
|
1428
1867
|
<!-- Multi-row layout when history is collapsed -->
|
|
1429
1868
|
<div class="mock-voice-section" id="mockVoiceSectionExpanded">
|
|
@@ -1475,19 +1914,19 @@
|
|
|
1475
1914
|
<span>Listening...</span>
|
|
1476
1915
|
</div>
|
|
1477
1916
|
<div class="mock-voice-controls">
|
|
1478
|
-
<button class="mock-control-btn secondary" data-element-type="micButton" title="Mute">
|
|
1917
|
+
<button class="mock-control-btn secondary" data-element-type="micButton" title="Mute" style="background: ${config.micButtonColor || '#FFFFFF'};">
|
|
1479
1918
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
1480
1919
|
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
|
|
1481
1920
|
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
|
|
1482
1921
|
<line x1="12" y1="19" x2="12" y2="23"/>
|
|
1483
1922
|
</svg>
|
|
1484
1923
|
</button>
|
|
1485
|
-
<button class="mock-control-btn danger" data-element-type="endCallButton" title="End Call">
|
|
1924
|
+
<button class="mock-control-btn danger" data-element-type="endCallButton" title="End Call" style="background: ${config.endCallButtonColor || '#ef4444'};">
|
|
1486
1925
|
<svg fill="none" stroke="currentColor" stroke-width="1.8" viewBox="0 0 24 24">
|
|
1487
1926
|
<path d="M22 16.92v3a2 2 0 01-2.18 2 19.79 19.79 0 01-8.63-3.07 19.5 19.5 0 01-6-6 19.79 19.79 0 01-3.07-8.67A2 2 0 014.11 2h3a2 2 0 012 1.72c.127.96.361 1.903.7 2.81a2 2 0 01-.45 2.11L8.09 9.91a16 16 0 006 6l1.27-1.27a2 2 0 012.11-.45c.907.339 1.85.573 2.81.7A2 2 0 0122 16.92z" transform="rotate(135 12 12)"/>
|
|
1488
1927
|
</svg>
|
|
1489
1928
|
</button>
|
|
1490
|
-
<button class="mock-control-btn secondary" data-element-type="speakerButton" title="Speaker">
|
|
1929
|
+
<button class="mock-control-btn secondary" data-element-type="speakerButton" title="Speaker" style="background: ${config.speakerButtonColor || '#FFFFFF'};">
|
|
1491
1930
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
1492
1931
|
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/>
|
|
1493
1932
|
<path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07"/>
|
|
@@ -1547,7 +1986,7 @@
|
|
|
1547
1986
|
<span>Listening...</span>
|
|
1548
1987
|
</div>
|
|
1549
1988
|
<div class="mock-compact-controls">
|
|
1550
|
-
<button class="mock-control-btn secondary" data-element-type="micButton" title="Mute">
|
|
1989
|
+
<button class="mock-control-btn secondary" data-element-type="micButton" title="Mute" style="background: ${config.micButtonColor || '#FFFFFF'};">
|
|
1551
1990
|
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
1552
1991
|
<path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z"/>
|
|
1553
1992
|
<path d="M19 10v2a7 7 0 0 1-14 0v-2"/>
|
|
@@ -1583,11 +2022,11 @@
|
|
|
1583
2022
|
|
|
1584
2023
|
<!-- Collapsed: Live transcript only (no bubbles) -->
|
|
1585
2024
|
<div class="mock-live-transcript-collapsed" id="collapsedTranscript" data-element-type="liveTranscript">
|
|
1586
|
-
<div class="mock-live-indicator" data-element-type="liveIndicator">
|
|
1587
|
-
<div class="mock-live-dot"></div>
|
|
2025
|
+
<div class="mock-live-indicator" data-element-type="liveIndicator" style="color: ${config.liveIndicatorTextColor || '#10b981'};">
|
|
2026
|
+
<div class="mock-live-dot" style="background: ${config.liveIndicatorDotColor || '#10b981'};"></div>
|
|
1588
2027
|
<span>LIVE</span>
|
|
1589
2028
|
</div>
|
|
1590
|
-
<div class="mock-live-text-collapsed" data-element-type="liveTranscriptText" style="color: #64748b; font-size: 14px; line-height: 1.6; margin-top: 8px;">
|
|
2029
|
+
<div class="mock-live-text-collapsed" data-element-type="liveTranscriptText" style="color: ${config.liveTranscriptTextColor || '#64748b'}; font-size: ${config.liveTranscriptFontSize || '14px'}; line-height: 1.6; margin-top: 8px;">
|
|
1591
2030
|
Hello, I'm Sasha from Bridgewise, How can I help you today?
|
|
1592
2031
|
</div>
|
|
1593
2032
|
</div>
|
|
@@ -1671,36 +2110,73 @@
|
|
|
1671
2110
|
});
|
|
1672
2111
|
|
|
1673
2112
|
elements.forEach(el => {
|
|
1674
|
-
//
|
|
2113
|
+
// Check if this element is inside another element with data-element-type (child elements)
|
|
1675
2114
|
const parentWithType = el.parentElement.closest('[data-element-type]');
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
2115
|
+
const isChild = parentWithType && parentWithType !== panel;
|
|
2116
|
+
|
|
2117
|
+
if (isChild) {
|
|
2118
|
+
// This is a child element (e.g., modeCard inside landingBackground)
|
|
2119
|
+
// Attach listener directly to the element
|
|
2120
|
+
el.addEventListener('click', (e) => {
|
|
2121
|
+
// Find the actual element with data-element-type (in case click is on child like icon/title)
|
|
2122
|
+
let targetElement = e.target;
|
|
2123
|
+
let foundElement = null;
|
|
2124
|
+
|
|
2125
|
+
// Walk up the DOM tree to find the element with data-element-type
|
|
2126
|
+
while (targetElement && targetElement !== panel && targetElement !== document.body) {
|
|
2127
|
+
if (targetElement.hasAttribute && targetElement.hasAttribute('data-element-type')) {
|
|
2128
|
+
foundElement = targetElement;
|
|
2129
|
+
break;
|
|
2130
|
+
}
|
|
2131
|
+
targetElement = targetElement.parentElement;
|
|
2132
|
+
}
|
|
2133
|
+
|
|
2134
|
+
// Use found element or fallback to the element we're attaching to
|
|
2135
|
+
const elementToUse = foundElement || el;
|
|
2136
|
+
const elementType = elementToUse.getAttribute('data-element-type');
|
|
2137
|
+
|
|
2138
|
+
console.log('✅ Child element clicked:', elementType, elementToUse.getAttribute('data-mode'), 'clicked on:', e.target.tagName, e.target.className);
|
|
2139
|
+
|
|
2140
|
+
// Don't stop propagation immediately - let handleElementClick process it
|
|
2141
|
+
handleElementClick(elementType, elementToUse, e);
|
|
2142
|
+
|
|
2143
|
+
// Only prevent default and stop propagation after handling
|
|
1683
2144
|
e.preventDefault();
|
|
1684
2145
|
e.stopPropagation();
|
|
1685
|
-
|
|
1686
|
-
});
|
|
2146
|
+
}, true); // Use capture phase - runs before bubbling phase, so it runs BEFORE parent handlers
|
|
1687
2147
|
} else {
|
|
1688
|
-
// This is a top-level element
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
2148
|
+
// This is a top-level element (e.g., landingBackground)
|
|
2149
|
+
el.addEventListener('click', (e) => {
|
|
2150
|
+
// IMPORTANT: Check if click is inside ANY child element with data-element-type
|
|
2151
|
+
// Walk up from the target to see if we hit a child element with data-element-type
|
|
2152
|
+
let current = e.target;
|
|
2153
|
+
while (current && current !== el && current !== panel && current !== document.body) {
|
|
2154
|
+
// Check if this element has data-element-type and is a child of el
|
|
2155
|
+
if (current.hasAttribute && current.hasAttribute('data-element-type')) {
|
|
2156
|
+
if (current !== el && el.contains(current)) {
|
|
2157
|
+
// Found a child element with data-element-type - let it handle the click
|
|
2158
|
+
console.log('⏭️ Parent ignoring click - child element found:', current.dataset.elementType);
|
|
2159
|
+
return; // Don't handle - let the child handle it
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
current = current.parentElement;
|
|
2163
|
+
}
|
|
2164
|
+
|
|
2165
|
+
// Also check: if the target itself is inside a child element with data-element-type
|
|
2166
|
+
const closestChild = Array.from(el.querySelectorAll('[data-element-type]')).find(child => {
|
|
2167
|
+
return child !== el && child.contains(e.target);
|
|
2168
|
+
});
|
|
2169
|
+
if (closestChild) {
|
|
2170
|
+
console.log('⏭️ Parent ignoring click - target is inside child:', closestChild.dataset.elementType);
|
|
1698
2171
|
return;
|
|
1699
2172
|
}
|
|
2173
|
+
|
|
2174
|
+
// Only handle clicks directly on this element (not on any child elements)
|
|
2175
|
+
console.log('✅ Parent element clicked directly:', el.dataset.elementType, 'target:', e.target);
|
|
1700
2176
|
e.preventDefault();
|
|
1701
2177
|
e.stopPropagation();
|
|
1702
|
-
handleElementClick(
|
|
1703
|
-
});
|
|
2178
|
+
handleElementClick(el.dataset.elementType, el, e);
|
|
2179
|
+
}, false); // Use bubbling phase so child handlers (capture phase) run first
|
|
1704
2180
|
}
|
|
1705
2181
|
});
|
|
1706
2182
|
}
|
|
@@ -1734,18 +2210,21 @@
|
|
|
1734
2210
|
showCustomizationControls(elementType);
|
|
1735
2211
|
}
|
|
1736
2212
|
|
|
1737
|
-
let lastClickTime = 0;
|
|
1738
|
-
let lastClickElement = null;
|
|
1739
|
-
let lastClickType = null;
|
|
1740
|
-
|
|
1741
2213
|
function handleElementClick(elementType, element, event) {
|
|
2214
|
+
// If event was prevented/stopped, don't process
|
|
2215
|
+
if (event && event.defaultPrevented) {
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
|
|
1742
2219
|
const currentTime = Date.now();
|
|
1743
2220
|
const timeSinceLastClick = currentTime - lastClickTime;
|
|
1744
2221
|
|
|
1745
2222
|
// Check if this is a double click (within 400ms and same element type)
|
|
2223
|
+
// Compare by element reference, not just type, to ensure it's the same element
|
|
1746
2224
|
if (timeSinceLastClick < 400 && lastClickElement && elementType === lastClickType &&
|
|
1747
|
-
lastClickElement
|
|
2225
|
+
lastClickElement === element) {
|
|
1748
2226
|
// Double click detected - perform normal interaction
|
|
2227
|
+
console.log('🖱️ Double click detected on:', elementType);
|
|
1749
2228
|
lastClickTime = 0;
|
|
1750
2229
|
lastClickElement = null;
|
|
1751
2230
|
lastClickType = null;
|
|
@@ -1754,6 +2233,7 @@
|
|
|
1754
2233
|
}
|
|
1755
2234
|
|
|
1756
2235
|
// Single click - wait to see if there's a second click
|
|
2236
|
+
console.log('🖱️ Single click detected on:', elementType, 'waiting for potential double click...');
|
|
1757
2237
|
lastClickTime = currentTime;
|
|
1758
2238
|
lastClickElement = element;
|
|
1759
2239
|
lastClickType = elementType;
|
|
@@ -1761,6 +2241,7 @@
|
|
|
1761
2241
|
setTimeout(() => {
|
|
1762
2242
|
// If no second click happened, treat as single click
|
|
1763
2243
|
if (lastClickTime === currentTime && lastClickElement === element) {
|
|
2244
|
+
console.log('🖱️ Single click confirmed on:', elementType);
|
|
1764
2245
|
lastClickTime = 0;
|
|
1765
2246
|
lastClickElement = null;
|
|
1766
2247
|
lastClickType = null;
|
|
@@ -1788,6 +2269,13 @@
|
|
|
1788
2269
|
if (panelOpen) {
|
|
1789
2270
|
renderPanelContent();
|
|
1790
2271
|
}
|
|
2272
|
+
// Update prompt bubble visibility based on panel state
|
|
2273
|
+
const mockButton = document.getElementById('mockButton');
|
|
2274
|
+
if (mockButton) {
|
|
2275
|
+
updatePromptBubble(mockButton);
|
|
2276
|
+
}
|
|
2277
|
+
// Sync actual widget state with mock panel
|
|
2278
|
+
syncWidgetWithMockPanel();
|
|
1791
2279
|
} else if (elementType === 'conversationToggle') {
|
|
1792
2280
|
// Toggle conversation history
|
|
1793
2281
|
toggleConversationHistory();
|
|
@@ -1893,6 +2381,49 @@
|
|
|
1893
2381
|
<input type="color" id="btnHoverColor" value="${widgetConfig.button.hoverColor}">
|
|
1894
2382
|
</div>
|
|
1895
2383
|
</div>
|
|
2384
|
+
<div class="customization-group">
|
|
2385
|
+
<h3>"Try Me" Prompt Animation</h3>
|
|
2386
|
+
<div class="control-item">
|
|
2387
|
+
<label>
|
|
2388
|
+
<input type="checkbox" id="promptEnabled" ${widgetConfig.promptAnimation?.enabled === true ? 'checked' : ''}>
|
|
2389
|
+
Enable Prompt Animation
|
|
2390
|
+
</label>
|
|
2391
|
+
</div>
|
|
2392
|
+
<div class="control-item" id="promptControls" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2393
|
+
<label>Prompt Text</label>
|
|
2394
|
+
<input type="text" id="promptText" value="${widgetConfig.promptAnimation?.text || 'Try me!'}" placeholder="Try me!">
|
|
2395
|
+
</div>
|
|
2396
|
+
<div class="control-item" id="promptBgColorControl" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2397
|
+
<label>Background Color/Gradient</label>
|
|
2398
|
+
<input type="text" id="promptBgColor" value="${widgetConfig.promptAnimation?.backgroundColor || 'linear-gradient(135deg, #7c3aed, #4f46e5)'}" placeholder="linear-gradient(135deg, #7c3aed, #4f46e5)">
|
|
2399
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">Supports solid colors (e.g., #7c3aed) or gradients</p>
|
|
2400
|
+
</div>
|
|
2401
|
+
<div class="control-item" id="promptTextColorControl" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2402
|
+
<label>Text Color</label>
|
|
2403
|
+
<input type="color" id="promptTextColor" value="${widgetConfig.promptAnimation?.textColor || '#ffffff'}">
|
|
2404
|
+
</div>
|
|
2405
|
+
<div class="control-item" id="promptAnimationTypeControl" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2406
|
+
<label>Animation Type</label>
|
|
2407
|
+
<select id="promptAnimationType">
|
|
2408
|
+
<option value="bounce" ${widgetConfig.promptAnimation?.animationType === 'bounce' ? 'selected' : ''}>Bounce</option>
|
|
2409
|
+
<option value="float" ${widgetConfig.promptAnimation?.animationType === 'float' ? 'selected' : ''}>Float</option>
|
|
2410
|
+
<option value="none" ${widgetConfig.promptAnimation?.animationType === 'none' ? 'selected' : ''}>None</option>
|
|
2411
|
+
</select>
|
|
2412
|
+
</div>
|
|
2413
|
+
<div class="control-item" id="promptHideAfterSecondsControl" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2414
|
+
<label>Auto-Hide After (seconds)</label>
|
|
2415
|
+
<input type="number" id="promptHideAfterSeconds" value="${widgetConfig.promptAnimation?.hideAfterSeconds || ''}" placeholder="Leave empty for never" min="0" step="1">
|
|
2416
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">Leave empty to never auto-hide</p>
|
|
2417
|
+
</div>
|
|
2418
|
+
<div class="control-item" id="promptPositionControl" style="display: ${widgetConfig.promptAnimation?.enabled === true ? 'block' : 'none'};">
|
|
2419
|
+
<label>Position</label>
|
|
2420
|
+
<select id="promptPosition">
|
|
2421
|
+
<option value="top" ${widgetConfig.promptAnimation?.position === 'top' ? 'selected' : ''}>Top</option>
|
|
2422
|
+
<option value="left" ${widgetConfig.promptAnimation?.position === 'left' ? 'selected' : ''}>Left</option>
|
|
2423
|
+
<option value="right" ${widgetConfig.promptAnimation?.position === 'right' ? 'selected' : ''}>Right</option>
|
|
2424
|
+
</select>
|
|
2425
|
+
</div>
|
|
2426
|
+
</div>
|
|
1896
2427
|
<div class="customization-group">
|
|
1897
2428
|
<h3>Icon</h3>
|
|
1898
2429
|
<div class="control-item">
|
|
@@ -1919,6 +2450,7 @@
|
|
|
1919
2450
|
</div>
|
|
1920
2451
|
`;
|
|
1921
2452
|
break;
|
|
2453
|
+
case 'onlineIndicator':
|
|
1922
2454
|
case 'header':
|
|
1923
2455
|
controlsHTML = `
|
|
1924
2456
|
<div class="customization-group">
|
|
@@ -1941,6 +2473,21 @@
|
|
|
1941
2473
|
Show Close Button
|
|
1942
2474
|
</label>
|
|
1943
2475
|
</div>
|
|
2476
|
+
<div class="control-item" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid #374151;">
|
|
2477
|
+
<label style="font-weight: 600; color: #f9fafb; margin-bottom: 8px; display: block;">Online Indicator</label>
|
|
2478
|
+
<div class="control-item">
|
|
2479
|
+
<label>Indicator Text</label>
|
|
2480
|
+
<input type="text" id="onlineIndicatorText" value="${widgetConfig.header.onlineIndicatorText || 'Online'}" placeholder="Online">
|
|
2481
|
+
</div>
|
|
2482
|
+
<div class="control-item">
|
|
2483
|
+
<label>Indicator Text Color</label>
|
|
2484
|
+
<input type="color" id="onlineIndicatorColor" value="${widgetConfig.header.onlineIndicatorColor || widgetConfig.header.textColor}">
|
|
2485
|
+
</div>
|
|
2486
|
+
<div class="control-item">
|
|
2487
|
+
<label>Indicator Dot Color</label>
|
|
2488
|
+
<input type="color" id="onlineIndicatorDotColor" value="${widgetConfig.header.onlineIndicatorDotColor || '#10b981'}">
|
|
2489
|
+
</div>
|
|
2490
|
+
</div>
|
|
1944
2491
|
</div>
|
|
1945
2492
|
`;
|
|
1946
2493
|
break;
|
|
@@ -1960,10 +2507,6 @@
|
|
|
1960
2507
|
<label>Border Radius (px)</label>
|
|
1961
2508
|
<input type="number" id="panelRadius" value="${widgetConfig.panel.borderRadius}">
|
|
1962
2509
|
</div>
|
|
1963
|
-
<div class="control-item">
|
|
1964
|
-
<label>Background Color</label>
|
|
1965
|
-
<input type="color" id="panelBgColor" value="${widgetConfig.panel.backgroundColor}">
|
|
1966
|
-
</div>
|
|
1967
2510
|
</div>
|
|
1968
2511
|
<div class="customization-group">
|
|
1969
2512
|
<h3>Widget Position</h3>
|
|
@@ -2071,8 +2614,25 @@
|
|
|
2071
2614
|
<input type="color" id="msgAgentBg" value="${widgetConfig.messages.agentBackgroundColor}">
|
|
2072
2615
|
</div>
|
|
2073
2616
|
<div class="control-item">
|
|
2074
|
-
<label>Text Color</label>
|
|
2075
|
-
<input type="color" id="
|
|
2617
|
+
<label>User Message Text Color</label>
|
|
2618
|
+
<input type="color" id="msgUserTextColor" value="${widgetConfig.messages.userTextColor || widgetConfig.messages.textColor || '#1F2937'}">
|
|
2619
|
+
</div>
|
|
2620
|
+
<div class="control-item">
|
|
2621
|
+
<label>Agent Message Text Color</label>
|
|
2622
|
+
<input type="color" id="msgAgentTextColor" value="${widgetConfig.messages.agentTextColor || widgetConfig.messages.textColor || '#1F2937'}">
|
|
2623
|
+
</div>
|
|
2624
|
+
<div class="control-item" style="margin-top: 16px; padding-top: 16px; border-top: 1px solid #374151;">
|
|
2625
|
+
<label style="font-weight: 600; color: #f9fafb; margin-bottom: 8px; display: block;">Message Avatars</label>
|
|
2626
|
+
<div class="control-item">
|
|
2627
|
+
<label>User Avatar Icon</label>
|
|
2628
|
+
<input type="text" id="msgUserAvatarIcon" value="${widgetConfig.messages.userAvatarIcon || '👤'}" placeholder="👤">
|
|
2629
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">Emoji or text to display next to user messages</p>
|
|
2630
|
+
</div>
|
|
2631
|
+
<div class="control-item">
|
|
2632
|
+
<label>Agent Avatar Icon</label>
|
|
2633
|
+
<input type="text" id="msgAgentAvatarIcon" value="${widgetConfig.messages.agentAvatarIcon || '🤖'}" placeholder="🤖">
|
|
2634
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">Emoji or text to display next to agent messages</p>
|
|
2635
|
+
</div>
|
|
2076
2636
|
</div>
|
|
2077
2637
|
<div class="control-item">
|
|
2078
2638
|
<label>Font Size</label>
|
|
@@ -2145,10 +2705,6 @@
|
|
|
2145
2705
|
<label>Background Color</label>
|
|
2146
2706
|
<input type="color" id="micBtnColor" value="${widgetConfig.voice.micButtonColor}">
|
|
2147
2707
|
</div>
|
|
2148
|
-
<div class="control-item">
|
|
2149
|
-
<label>Active/Muted Color</label>
|
|
2150
|
-
<input type="color" id="micBtnActive" value="${widgetConfig.voice.micButtonActiveColor}">
|
|
2151
|
-
</div>
|
|
2152
2708
|
</div>
|
|
2153
2709
|
`;
|
|
2154
2710
|
break;
|
|
@@ -2158,7 +2714,7 @@
|
|
|
2158
2714
|
<h3>End Call Button</h3>
|
|
2159
2715
|
<div class="control-item">
|
|
2160
2716
|
<label>Background Color</label>
|
|
2161
|
-
<input type="color" id="endCallBtnColor" value="#ef4444">
|
|
2717
|
+
<input type="color" id="endCallBtnColor" value="${widgetConfig.voice.endCallButtonColor || '#ef4444'}">
|
|
2162
2718
|
</div>
|
|
2163
2719
|
</div>
|
|
2164
2720
|
`;
|
|
@@ -2169,7 +2725,7 @@
|
|
|
2169
2725
|
<h3>Speaker Button</h3>
|
|
2170
2726
|
<div class="control-item">
|
|
2171
2727
|
<label>Background Color</label>
|
|
2172
|
-
<input type="color" id="speakerBtnColor" value="#FFFFFF">
|
|
2728
|
+
<input type="color" id="speakerBtnColor" value="${widgetConfig.voice.speakerButtonColor || '#FFFFFF'}">
|
|
2173
2729
|
</div>
|
|
2174
2730
|
</div>
|
|
2175
2731
|
`;
|
|
@@ -2222,15 +2778,15 @@
|
|
|
2222
2778
|
<h3>Status Text</h3>
|
|
2223
2779
|
<div class="control-item">
|
|
2224
2780
|
<label>Status Text</label>
|
|
2225
|
-
<input type="text" id="statusText" value="Listening..." placeholder="Listening...">
|
|
2781
|
+
<input type="text" id="statusText" value="${widgetConfig.voice.statusText || 'Listening...'}" placeholder="Listening...">
|
|
2226
2782
|
</div>
|
|
2227
2783
|
<div class="control-item">
|
|
2228
2784
|
<label>Text Color</label>
|
|
2229
|
-
<input type="color" id="statusTitleColor" value="${widgetConfig.voice.statusTitleColor}">
|
|
2785
|
+
<input type="color" id="statusTitleColor" value="${widgetConfig.voice.statusTitleColor || '#1e293b'}">
|
|
2230
2786
|
</div>
|
|
2231
2787
|
<div class="control-item">
|
|
2232
2788
|
<label>Status Dot Color</label>
|
|
2233
|
-
<input type="color" id="statusDotColor" value="#10b981">
|
|
2789
|
+
<input type="color" id="statusDotColor" value="${widgetConfig.voice.statusDotColor || '#10b981'}">
|
|
2234
2790
|
</div>
|
|
2235
2791
|
</div>
|
|
2236
2792
|
`;
|
|
@@ -2242,11 +2798,11 @@
|
|
|
2242
2798
|
<h3>Live Transcript (Collapsed View)</h3>
|
|
2243
2799
|
<div class="control-item">
|
|
2244
2800
|
<label>Transcript Text Color</label>
|
|
2245
|
-
<input type="color" id="liveTranscriptColor" value="#64748b">
|
|
2801
|
+
<input type="color" id="liveTranscriptColor" value="${widgetConfig.voice.liveTranscriptTextColor || '#64748b'}">
|
|
2246
2802
|
</div>
|
|
2247
2803
|
<div class="control-item">
|
|
2248
2804
|
<label>Font Size</label>
|
|
2249
|
-
<input type="text" id="liveTranscriptFontSize" value="14px" placeholder="14px">
|
|
2805
|
+
<input type="text" id="liveTranscriptFontSize" value="${widgetConfig.voice.liveTranscriptFontSize || '14px'}" placeholder="14px">
|
|
2250
2806
|
</div>
|
|
2251
2807
|
<p style="color: #6b7280; font-size: 12px; margin-top: 8px;">
|
|
2252
2808
|
This is the live transcript shown when history is collapsed. It displays only the current spoken text (max 2 lines).
|
|
@@ -2326,11 +2882,11 @@
|
|
|
2326
2882
|
<h3>Live Indicator</h3>
|
|
2327
2883
|
<div class="control-item">
|
|
2328
2884
|
<label>Live Dot Color</label>
|
|
2329
|
-
<input type="color" id="liveDotColor" value="#10b981">
|
|
2885
|
+
<input type="color" id="liveDotColor" value="${widgetConfig.voice.liveIndicatorDotColor || '#10b981'}">
|
|
2330
2886
|
</div>
|
|
2331
2887
|
<div class="control-item">
|
|
2332
2888
|
<label>Live Text Color</label>
|
|
2333
|
-
<input type="color" id="liveTextColor" value="#10b981">
|
|
2889
|
+
<input type="color" id="liveTextColor" value="${widgetConfig.voice.liveIndicatorTextColor || '#10b981'}">
|
|
2334
2890
|
</div>
|
|
2335
2891
|
</div>
|
|
2336
2892
|
`;
|
|
@@ -2354,7 +2910,23 @@
|
|
|
2354
2910
|
<label>Image URL</label>
|
|
2355
2911
|
<input type="text" id="landingLogoImageUrl" value="${widgetConfig.landing.logoImageUrl || ''}" placeholder="https://example.com/logo.png">
|
|
2356
2912
|
</div>
|
|
2357
|
-
|
|
2913
|
+
<div class="control-item" id="logoBackgroundControl" style="display: ${widgetConfig.landing.logoType === 'image' ? 'block' : 'none'}; margin-top: 16px; padding-top: 16px; border-top: 1px solid #374151;">
|
|
2914
|
+
<label style="font-weight: 600; color: #f9fafb; margin-bottom: 8px; display: block;">Background</label>
|
|
2915
|
+
<div class="control-item">
|
|
2916
|
+
<label>
|
|
2917
|
+
<input type="checkbox" id="logoBackgroundEnabled" ${widgetConfig.landing.logoBackgroundEnabled !== false ? 'checked' : ''}>
|
|
2918
|
+
Enable Background
|
|
2919
|
+
</label>
|
|
2920
|
+
</div>
|
|
2921
|
+
<div class="control-item" id="logoBackgroundColorControl" style="display: ${widgetConfig.landing.logoBackgroundEnabled !== false ? 'block' : 'none'};">
|
|
2922
|
+
<label>Background Color</label>
|
|
2923
|
+
<input type="color" id="logoBackgroundColor" value="${widgetConfig.landing.logoBackgroundColor && widgetConfig.landing.logoBackgroundColor.startsWith('#') ? widgetConfig.landing.logoBackgroundColor : '#667eea'}">
|
|
2924
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">
|
|
2925
|
+
Background color for the logo container. Uncheck "Enable Background" to make it transparent.
|
|
2926
|
+
</p>
|
|
2927
|
+
</div>
|
|
2928
|
+
</div>
|
|
2929
|
+
</div>
|
|
2358
2930
|
`;
|
|
2359
2931
|
break;
|
|
2360
2932
|
case 'landingTitle':
|
|
@@ -2387,6 +2959,30 @@
|
|
|
2387
2959
|
</div>
|
|
2388
2960
|
`;
|
|
2389
2961
|
break;
|
|
2962
|
+
case 'landingBackground':
|
|
2963
|
+
// Extract color from gradient or use default
|
|
2964
|
+
const currentBg = widgetConfig.landing.backgroundColor || 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)';
|
|
2965
|
+
let defaultColor = '#ffffff';
|
|
2966
|
+
if (currentBg.startsWith('#')) {
|
|
2967
|
+
defaultColor = currentBg;
|
|
2968
|
+
} else if (currentBg.includes('#')) {
|
|
2969
|
+
// Extract the first hex color from gradient (usually the main color)
|
|
2970
|
+
const hexMatch = currentBg.match(/#[0-9a-fA-F]{6}/);
|
|
2971
|
+
if (hexMatch) defaultColor = hexMatch[0];
|
|
2972
|
+
}
|
|
2973
|
+
controlsHTML = `
|
|
2974
|
+
<div class="customization-group">
|
|
2975
|
+
<h3>Landing Screen - Background</h3>
|
|
2976
|
+
<div class="control-item">
|
|
2977
|
+
<label>Background Color</label>
|
|
2978
|
+
<input type="color" id="landingBgColor" value="${defaultColor}">
|
|
2979
|
+
<p style="color: #6b7280; font-size: 11px; margin-top: 4px;">
|
|
2980
|
+
Pick a solid color for the background. Default uses a subtle gradient.
|
|
2981
|
+
</p>
|
|
2982
|
+
</div>
|
|
2983
|
+
</div>
|
|
2984
|
+
`;
|
|
2985
|
+
break;
|
|
2390
2986
|
case 'modeCard':
|
|
2391
2987
|
controlsHTML = `
|
|
2392
2988
|
<div class="customization-group">
|
|
@@ -2395,18 +2991,10 @@
|
|
|
2395
2991
|
<label>Voice Card Title</label>
|
|
2396
2992
|
<input type="text" id="voiceCardTitle" value="Voice Call" placeholder="Voice Call">
|
|
2397
2993
|
</div>
|
|
2398
|
-
<div class="control-item">
|
|
2399
|
-
<label>Voice Card Description</label>
|
|
2400
|
-
<input type="text" id="voiceCardDesc" value="Start a voice conversation" placeholder="Start a voice conversation">
|
|
2401
|
-
</div>
|
|
2402
2994
|
<div class="control-item">
|
|
2403
2995
|
<label>Text Card Title</label>
|
|
2404
2996
|
<input type="text" id="textCardTitle" value="Text Chat" placeholder="Text Chat">
|
|
2405
2997
|
</div>
|
|
2406
|
-
<div class="control-item">
|
|
2407
|
-
<label>Text Card Description</label>
|
|
2408
|
-
<input type="text" id="textCardDesc" value="Chat via text messages" placeholder="Chat via text messages">
|
|
2409
|
-
</div>
|
|
2410
2998
|
<div class="control-item">
|
|
2411
2999
|
<label>Background Color</label>
|
|
2412
3000
|
<input type="color" id="modeCardBg" value="${widgetConfig.landing.modeCardBackgroundColor}">
|
|
@@ -2485,6 +3073,65 @@
|
|
|
2485
3073
|
applyButtonStyles(document.getElementById('mockButton'));
|
|
2486
3074
|
updateConfigCode();
|
|
2487
3075
|
});
|
|
3076
|
+
|
|
3077
|
+
// Prompt Animation controls
|
|
3078
|
+
document.getElementById('promptEnabled')?.addEventListener('change', (e) => {
|
|
3079
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3080
|
+
widgetConfig.promptAnimation.enabled = e.target.checked;
|
|
3081
|
+
const promptControls = document.getElementById('promptControls');
|
|
3082
|
+
const allControls = ['promptControls', 'promptBgColorControl', 'promptTextColorControl', 'promptAnimationTypeControl', 'promptHideAfterSecondsControl', 'promptPositionControl'];
|
|
3083
|
+
allControls.forEach(id => {
|
|
3084
|
+
const el = document.getElementById(id);
|
|
3085
|
+
if (el) el.style.display = e.target.checked ? 'block' : 'none';
|
|
3086
|
+
});
|
|
3087
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3088
|
+
updateConfigCode();
|
|
3089
|
+
});
|
|
3090
|
+
|
|
3091
|
+
document.getElementById('promptText')?.addEventListener('input', (e) => {
|
|
3092
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3093
|
+
widgetConfig.promptAnimation.text = e.target.value;
|
|
3094
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3095
|
+
updateConfigCode();
|
|
3096
|
+
});
|
|
3097
|
+
|
|
3098
|
+
document.getElementById('promptBgColor')?.addEventListener('input', (e) => {
|
|
3099
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3100
|
+
widgetConfig.promptAnimation.backgroundColor = e.target.value;
|
|
3101
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3102
|
+
updateConfigCode();
|
|
3103
|
+
});
|
|
3104
|
+
|
|
3105
|
+
document.getElementById('promptTextColor')?.addEventListener('input', (e) => {
|
|
3106
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3107
|
+
widgetConfig.promptAnimation.textColor = e.target.value;
|
|
3108
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3109
|
+
updateConfigCode();
|
|
3110
|
+
});
|
|
3111
|
+
|
|
3112
|
+
document.getElementById('promptAnimationType')?.addEventListener('change', (e) => {
|
|
3113
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3114
|
+
// If pulse was previously selected, default to bounce
|
|
3115
|
+
const value = e.target.value === 'pulse' ? 'bounce' : e.target.value;
|
|
3116
|
+
widgetConfig.promptAnimation.animationType = value;
|
|
3117
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3118
|
+
updateConfigCode();
|
|
3119
|
+
});
|
|
3120
|
+
|
|
3121
|
+
|
|
3122
|
+
document.getElementById('promptHideAfterSeconds')?.addEventListener('input', (e) => {
|
|
3123
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3124
|
+
const value = e.target.value.trim();
|
|
3125
|
+
widgetConfig.promptAnimation.hideAfterSeconds = value === '' ? null : parseInt(value) || null;
|
|
3126
|
+
updateConfigCode();
|
|
3127
|
+
});
|
|
3128
|
+
|
|
3129
|
+
document.getElementById('promptPosition')?.addEventListener('change', (e) => {
|
|
3130
|
+
if (!widgetConfig.promptAnimation) widgetConfig.promptAnimation = {};
|
|
3131
|
+
widgetConfig.promptAnimation.position = e.target.value;
|
|
3132
|
+
applyButtonStyles(document.getElementById('mockButton'));
|
|
3133
|
+
updateConfigCode();
|
|
3134
|
+
});
|
|
2488
3135
|
document.getElementById('iconCustomImage')?.addEventListener('input', (e) => {
|
|
2489
3136
|
widgetConfig.icon.customImage = e.target.value;
|
|
2490
3137
|
applyButtonStyles(document.getElementById('mockButton'));
|
|
@@ -2502,15 +3149,17 @@
|
|
|
2502
3149
|
});
|
|
2503
3150
|
}
|
|
2504
3151
|
|
|
2505
|
-
// Header controls
|
|
2506
|
-
if (elementType === 'header') {
|
|
3152
|
+
// Header controls (also applies to onlineIndicator)
|
|
3153
|
+
if (elementType === 'header' || elementType === 'onlineIndicator') {
|
|
2507
3154
|
document.getElementById('headerTitle')?.addEventListener('input', (e) => {
|
|
2508
3155
|
widgetConfig.header.title = e.target.value;
|
|
2509
3156
|
renderPanelContent();
|
|
2510
3157
|
updateConfigCode();
|
|
2511
3158
|
});
|
|
2512
3159
|
document.getElementById('headerBgColor')?.addEventListener('input', (e) => {
|
|
2513
|
-
|
|
3160
|
+
const newColor = e.target.value;
|
|
3161
|
+
console.log('🎨 Header color changed to:', newColor);
|
|
3162
|
+
widgetConfig.header.backgroundColor = newColor;
|
|
2514
3163
|
renderPanelContent();
|
|
2515
3164
|
updateConfigCode();
|
|
2516
3165
|
});
|
|
@@ -2524,6 +3173,21 @@
|
|
|
2524
3173
|
renderPanelContent();
|
|
2525
3174
|
updateConfigCode();
|
|
2526
3175
|
});
|
|
3176
|
+
document.getElementById('onlineIndicatorText')?.addEventListener('input', (e) => {
|
|
3177
|
+
widgetConfig.header.onlineIndicatorText = e.target.value;
|
|
3178
|
+
renderPanelContent();
|
|
3179
|
+
updateConfigCode();
|
|
3180
|
+
});
|
|
3181
|
+
document.getElementById('onlineIndicatorColor')?.addEventListener('input', (e) => {
|
|
3182
|
+
widgetConfig.header.onlineIndicatorColor = e.target.value;
|
|
3183
|
+
renderPanelContent();
|
|
3184
|
+
updateConfigCode();
|
|
3185
|
+
});
|
|
3186
|
+
document.getElementById('onlineIndicatorDotColor')?.addEventListener('input', (e) => {
|
|
3187
|
+
widgetConfig.header.onlineIndicatorDotColor = e.target.value;
|
|
3188
|
+
renderPanelContent();
|
|
3189
|
+
updateConfigCode();
|
|
3190
|
+
});
|
|
2527
3191
|
}
|
|
2528
3192
|
|
|
2529
3193
|
// Panel controls
|
|
@@ -2537,31 +3201,31 @@
|
|
|
2537
3201
|
updateConfigCode();
|
|
2538
3202
|
});
|
|
2539
3203
|
});
|
|
2540
|
-
document.getElementById('panelBgColor')?.addEventListener('input', (e) => {
|
|
2541
|
-
widgetConfig.panel.backgroundColor = e.target.value;
|
|
2542
|
-
renderPanelContent();
|
|
2543
|
-
updateConfigCode();
|
|
2544
|
-
});
|
|
2545
3204
|
// Position controls (included in panel settings)
|
|
2546
3205
|
document.getElementById('positionVertical')?.addEventListener('change', (e) => {
|
|
2547
3206
|
widgetConfig.position.vertical = e.target.value;
|
|
3207
|
+
updateMockWidgetPosition();
|
|
2548
3208
|
updateConfigCode();
|
|
2549
3209
|
});
|
|
2550
3210
|
document.getElementById('positionHorizontal')?.addEventListener('change', (e) => {
|
|
2551
3211
|
widgetConfig.position.horizontal = e.target.value;
|
|
3212
|
+
// Don't update mock widget position - it always stays on the right
|
|
2552
3213
|
updateConfigCode();
|
|
2553
3214
|
});
|
|
2554
3215
|
document.getElementById('positionOffsetX')?.addEventListener('input', (e) => {
|
|
2555
3216
|
widgetConfig.position.offset.x = parseInt(e.target.value) || 0;
|
|
3217
|
+
updateMockWidgetPosition();
|
|
2556
3218
|
updateConfigCode();
|
|
2557
3219
|
});
|
|
2558
3220
|
document.getElementById('positionOffsetY')?.addEventListener('input', (e) => {
|
|
2559
3221
|
widgetConfig.position.offset.y = parseInt(e.target.value) || 0;
|
|
3222
|
+
updateMockWidgetPosition();
|
|
2560
3223
|
updateConfigCode();
|
|
2561
3224
|
});
|
|
2562
3225
|
// Direction controls (included in panel settings)
|
|
2563
3226
|
document.getElementById('direction')?.addEventListener('change', (e) => {
|
|
2564
3227
|
widgetConfig.direction = e.target.value;
|
|
3228
|
+
renderPanelContent(); // Re-render mock panel with new direction
|
|
2565
3229
|
updateConfigCode();
|
|
2566
3230
|
});
|
|
2567
3231
|
}
|
|
@@ -2570,18 +3234,22 @@
|
|
|
2570
3234
|
if (elementType === 'position') {
|
|
2571
3235
|
document.getElementById('positionVertical')?.addEventListener('change', (e) => {
|
|
2572
3236
|
widgetConfig.position.vertical = e.target.value;
|
|
3237
|
+
updateMockWidgetPosition();
|
|
2573
3238
|
updateConfigCode();
|
|
2574
3239
|
});
|
|
2575
3240
|
document.getElementById('positionHorizontal')?.addEventListener('change', (e) => {
|
|
2576
3241
|
widgetConfig.position.horizontal = e.target.value;
|
|
3242
|
+
// Don't update mock widget position - it always stays on the right
|
|
2577
3243
|
updateConfigCode();
|
|
2578
3244
|
});
|
|
2579
3245
|
document.getElementById('positionOffsetX')?.addEventListener('input', (e) => {
|
|
2580
3246
|
widgetConfig.position.offset.x = parseInt(e.target.value) || 0;
|
|
3247
|
+
updateMockWidgetPosition();
|
|
2581
3248
|
updateConfigCode();
|
|
2582
3249
|
});
|
|
2583
3250
|
document.getElementById('positionOffsetY')?.addEventListener('input', (e) => {
|
|
2584
3251
|
widgetConfig.position.offset.y = parseInt(e.target.value) || 0;
|
|
3252
|
+
updateMockWidgetPosition();
|
|
2585
3253
|
updateConfigCode();
|
|
2586
3254
|
});
|
|
2587
3255
|
}
|
|
@@ -2590,6 +3258,7 @@
|
|
|
2590
3258
|
if (elementType === 'direction') {
|
|
2591
3259
|
document.getElementById('direction')?.addEventListener('change', (e) => {
|
|
2592
3260
|
widgetConfig.direction = e.target.value;
|
|
3261
|
+
renderPanelContent(); // Re-render mock panel with new direction
|
|
2593
3262
|
updateConfigCode();
|
|
2594
3263
|
});
|
|
2595
3264
|
}
|
|
@@ -2606,8 +3275,23 @@
|
|
|
2606
3275
|
renderPanelContent();
|
|
2607
3276
|
updateConfigCode();
|
|
2608
3277
|
});
|
|
2609
|
-
document.getElementById('
|
|
2610
|
-
widgetConfig.messages.
|
|
3278
|
+
document.getElementById('msgUserTextColor')?.addEventListener('input', (e) => {
|
|
3279
|
+
widgetConfig.messages.userTextColor = e.target.value;
|
|
3280
|
+
renderPanelContent();
|
|
3281
|
+
updateConfigCode();
|
|
3282
|
+
});
|
|
3283
|
+
document.getElementById('msgAgentTextColor')?.addEventListener('input', (e) => {
|
|
3284
|
+
widgetConfig.messages.agentTextColor = e.target.value;
|
|
3285
|
+
renderPanelContent();
|
|
3286
|
+
updateConfigCode();
|
|
3287
|
+
});
|
|
3288
|
+
document.getElementById('msgUserAvatarIcon')?.addEventListener('input', (e) => {
|
|
3289
|
+
widgetConfig.messages.userAvatarIcon = e.target.value;
|
|
3290
|
+
renderPanelContent();
|
|
3291
|
+
updateConfigCode();
|
|
3292
|
+
});
|
|
3293
|
+
document.getElementById('msgAgentAvatarIcon')?.addEventListener('input', (e) => {
|
|
3294
|
+
widgetConfig.messages.agentAvatarIcon = e.target.value;
|
|
2611
3295
|
renderPanelContent();
|
|
2612
3296
|
updateConfigCode();
|
|
2613
3297
|
});
|
|
@@ -2677,10 +3361,6 @@
|
|
|
2677
3361
|
renderPanelContent();
|
|
2678
3362
|
updateConfigCode();
|
|
2679
3363
|
});
|
|
2680
|
-
document.getElementById('micBtnActive')?.addEventListener('input', (e) => {
|
|
2681
|
-
widgetConfig.voice.micButtonActiveColor = e.target.value;
|
|
2682
|
-
updateConfigCode();
|
|
2683
|
-
});
|
|
2684
3364
|
}
|
|
2685
3365
|
|
|
2686
3366
|
// Voice avatar controls (for voice interface)
|
|
@@ -2727,6 +3407,7 @@
|
|
|
2727
3407
|
// Status text controls
|
|
2728
3408
|
if (elementType === 'statusTitle' || elementType === 'statusSubtitle') {
|
|
2729
3409
|
document.getElementById('statusText')?.addEventListener('input', (e) => {
|
|
3410
|
+
widgetConfig.voice.statusText = e.target.value;
|
|
2730
3411
|
// Update status text in both regular and compact views
|
|
2731
3412
|
const statusEls = document.querySelectorAll('.mock-voice-status span, .mock-compact-status span');
|
|
2732
3413
|
statusEls.forEach(el => el.textContent = e.target.value);
|
|
@@ -2739,6 +3420,7 @@
|
|
|
2739
3420
|
updateConfigCode();
|
|
2740
3421
|
});
|
|
2741
3422
|
document.getElementById('statusDotColor')?.addEventListener('input', (e) => {
|
|
3423
|
+
widgetConfig.voice.statusDotColor = e.target.value;
|
|
2742
3424
|
const dots = document.querySelectorAll('.mock-status-dot');
|
|
2743
3425
|
dots.forEach(dot => dot.style.background = e.target.value);
|
|
2744
3426
|
updateConfigCode();
|
|
@@ -2753,14 +3435,18 @@
|
|
|
2753
3435
|
// Live indicator controls
|
|
2754
3436
|
if (elementType === 'liveIndicator') {
|
|
2755
3437
|
document.getElementById('liveDotColor')?.addEventListener('input', (e) => {
|
|
3438
|
+
widgetConfig.voice.liveIndicatorDotColor = e.target.value;
|
|
2756
3439
|
const dots = document.querySelectorAll('.mock-live-dot');
|
|
2757
3440
|
dots.forEach(dot => dot.style.background = e.target.value);
|
|
2758
|
-
|
|
3441
|
+
renderPanelContent();
|
|
3442
|
+
updateConfigCode(); // This will call updateActualWidget() with debounce
|
|
2759
3443
|
});
|
|
2760
3444
|
document.getElementById('liveTextColor')?.addEventListener('input', (e) => {
|
|
3445
|
+
widgetConfig.voice.liveIndicatorTextColor = e.target.value;
|
|
2761
3446
|
const indicators = document.querySelectorAll('.mock-live-indicator');
|
|
2762
3447
|
indicators.forEach(ind => ind.style.color = e.target.value);
|
|
2763
|
-
|
|
3448
|
+
renderPanelContent();
|
|
3449
|
+
updateConfigCode(); // This will call updateActualWidget() with debounce
|
|
2764
3450
|
});
|
|
2765
3451
|
}
|
|
2766
3452
|
|
|
@@ -2781,8 +3467,10 @@
|
|
|
2781
3467
|
// End call button controls
|
|
2782
3468
|
if (elementType === 'endCallButton') {
|
|
2783
3469
|
document.getElementById('endCallBtnColor')?.addEventListener('input', (e) => {
|
|
3470
|
+
widgetConfig.voice.endCallButtonColor = e.target.value;
|
|
2784
3471
|
const buttons = document.querySelectorAll('[data-element-type="endCallButton"]');
|
|
2785
3472
|
buttons.forEach(btn => btn.style.background = e.target.value);
|
|
3473
|
+
renderPanelContent();
|
|
2786
3474
|
updateConfigCode();
|
|
2787
3475
|
});
|
|
2788
3476
|
}
|
|
@@ -2790,8 +3478,10 @@
|
|
|
2790
3478
|
// Speaker button controls
|
|
2791
3479
|
if (elementType === 'speakerButton') {
|
|
2792
3480
|
document.getElementById('speakerBtnColor')?.addEventListener('input', (e) => {
|
|
3481
|
+
widgetConfig.voice.speakerButtonColor = e.target.value;
|
|
2793
3482
|
const buttons = document.querySelectorAll('[data-element-type="speakerButton"]');
|
|
2794
3483
|
buttons.forEach(btn => btn.style.background = e.target.value);
|
|
3484
|
+
renderPanelContent();
|
|
2795
3485
|
updateConfigCode();
|
|
2796
3486
|
});
|
|
2797
3487
|
}
|
|
@@ -2831,14 +3521,18 @@
|
|
|
2831
3521
|
// Live transcript controls
|
|
2832
3522
|
if (elementType === 'liveTranscript' || elementType === 'liveTranscriptText') {
|
|
2833
3523
|
document.getElementById('liveTranscriptColor')?.addEventListener('input', (e) => {
|
|
3524
|
+
widgetConfig.voice.liveTranscriptTextColor = e.target.value;
|
|
2834
3525
|
const text = document.querySelector('.mock-live-text-collapsed');
|
|
2835
3526
|
if (text) text.style.color = e.target.value;
|
|
2836
|
-
|
|
3527
|
+
renderPanelContent();
|
|
3528
|
+
updateConfigCode(); // This will call updateActualWidget() with debounce
|
|
2837
3529
|
});
|
|
2838
3530
|
document.getElementById('liveTranscriptFontSize')?.addEventListener('input', (e) => {
|
|
3531
|
+
widgetConfig.voice.liveTranscriptFontSize = e.target.value;
|
|
2839
3532
|
const text = document.querySelector('.mock-live-text-collapsed');
|
|
2840
3533
|
if (text) text.style.fontSize = e.target.value;
|
|
2841
|
-
|
|
3534
|
+
renderPanelContent();
|
|
3535
|
+
updateConfigCode(); // This will call updateActualWidget() with debounce
|
|
2842
3536
|
});
|
|
2843
3537
|
}
|
|
2844
3538
|
|
|
@@ -2863,8 +3557,10 @@
|
|
|
2863
3557
|
// Show/hide relevant controls
|
|
2864
3558
|
const iconControl = document.getElementById('logoIconControl');
|
|
2865
3559
|
const imageControl = document.getElementById('logoImageControl');
|
|
3560
|
+
const backgroundControl = document.getElementById('logoBackgroundControl');
|
|
2866
3561
|
if (iconControl) iconControl.style.display = e.target.value === 'icon' ? 'block' : 'none';
|
|
2867
3562
|
if (imageControl) imageControl.style.display = e.target.value === 'image' ? 'block' : 'none';
|
|
3563
|
+
if (backgroundControl) backgroundControl.style.display = e.target.value === 'image' ? 'block' : 'none';
|
|
2868
3564
|
renderPanelContent();
|
|
2869
3565
|
updateConfigCode();
|
|
2870
3566
|
});
|
|
@@ -2879,6 +3575,18 @@
|
|
|
2879
3575
|
renderPanelContent();
|
|
2880
3576
|
updateConfigCode();
|
|
2881
3577
|
});
|
|
3578
|
+
document.getElementById('logoBackgroundEnabled')?.addEventListener('change', (e) => {
|
|
3579
|
+
widgetConfig.landing.logoBackgroundEnabled = e.target.checked;
|
|
3580
|
+
const colorControl = document.getElementById('logoBackgroundColorControl');
|
|
3581
|
+
if (colorControl) colorControl.style.display = e.target.checked ? 'block' : 'none';
|
|
3582
|
+
renderPanelContent();
|
|
3583
|
+
updateConfigCode();
|
|
3584
|
+
});
|
|
3585
|
+
document.getElementById('logoBackgroundColor')?.addEventListener('input', (e) => {
|
|
3586
|
+
widgetConfig.landing.logoBackgroundColor = e.target.value;
|
|
3587
|
+
renderPanelContent();
|
|
3588
|
+
updateConfigCode();
|
|
3589
|
+
});
|
|
2882
3590
|
}
|
|
2883
3591
|
|
|
2884
3592
|
if (elementType === 'landingTitle') {
|
|
@@ -2907,14 +3615,17 @@
|
|
|
2907
3615
|
});
|
|
2908
3616
|
}
|
|
2909
3617
|
|
|
2910
|
-
if (elementType === '
|
|
2911
|
-
document.getElementById('
|
|
2912
|
-
widgetConfig.landing.
|
|
3618
|
+
if (elementType === 'landingBackground') {
|
|
3619
|
+
document.getElementById('landingBgColor')?.addEventListener('input', (e) => {
|
|
3620
|
+
widgetConfig.landing.backgroundColor = e.target.value;
|
|
2913
3621
|
renderPanelContent();
|
|
2914
3622
|
updateConfigCode();
|
|
2915
3623
|
});
|
|
2916
|
-
|
|
2917
|
-
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
if (elementType === 'modeCard') {
|
|
3627
|
+
document.getElementById('voiceCardTitle')?.addEventListener('input', (e) => {
|
|
3628
|
+
widgetConfig.landing.voiceCardTitle = e.target.value;
|
|
2918
3629
|
renderPanelContent();
|
|
2919
3630
|
updateConfigCode();
|
|
2920
3631
|
});
|
|
@@ -2923,11 +3634,6 @@
|
|
|
2923
3634
|
renderPanelContent();
|
|
2924
3635
|
updateConfigCode();
|
|
2925
3636
|
});
|
|
2926
|
-
document.getElementById('textCardDesc')?.addEventListener('input', (e) => {
|
|
2927
|
-
widgetConfig.landing.textCardDesc = e.target.value;
|
|
2928
|
-
renderPanelContent();
|
|
2929
|
-
updateConfigCode();
|
|
2930
|
-
});
|
|
2931
3637
|
document.getElementById('modeCardBg')?.addEventListener('input', (e) => {
|
|
2932
3638
|
widgetConfig.landing.modeCardBackgroundColor = e.target.value;
|
|
2933
3639
|
renderPanelContent();
|
|
@@ -2936,34 +3642,526 @@
|
|
|
2936
3642
|
}
|
|
2937
3643
|
}
|
|
2938
3644
|
|
|
3645
|
+
// Actual widget instance
|
|
3646
|
+
let actualWidgetInstance = null;
|
|
3647
|
+
let updateWidgetTimeout = null;
|
|
3648
|
+
let widgetManuallyClosed = false; // Track if widget was manually closed by user
|
|
3649
|
+
const AGENT_ID = 'agent_20e0b3047';
|
|
3650
|
+
const APP_ID = 'app_8LGyEp2cS6vn4GLad8WLNRlyrOq0MrvDRPXk';
|
|
3651
|
+
|
|
3652
|
+
function getTTPChatWidget() {
|
|
3653
|
+
// SDK exposes TTPChatWidget as window.TTPAgentSDK.TTPChatWidget
|
|
3654
|
+
if (window.TTPAgentSDK && window.TTPAgentSDK.TTPChatWidget) {
|
|
3655
|
+
return window.TTPAgentSDK.TTPChatWidget;
|
|
3656
|
+
}
|
|
3657
|
+
// Fallback for direct access (if SDK exposes it directly)
|
|
3658
|
+
if (window.TTPChatWidget) {
|
|
3659
|
+
return window.TTPChatWidget;
|
|
3660
|
+
}
|
|
3661
|
+
return null;
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
// Default configuration values (used to compare and only show changed values)
|
|
3665
|
+
const defaultConfig = {
|
|
3666
|
+
direction: 'ltr',
|
|
3667
|
+
button: {
|
|
3668
|
+
size: 'medium',
|
|
3669
|
+
shape: 'circle',
|
|
3670
|
+
backgroundColor: '#FFFFFF',
|
|
3671
|
+
hoverColor: '#D3D3D3',
|
|
3672
|
+
shadow: true,
|
|
3673
|
+
shadowColor: 'rgba(0,0,0,0.15)'
|
|
3674
|
+
},
|
|
3675
|
+
icon: {
|
|
3676
|
+
type: 'custom',
|
|
3677
|
+
customImage: 'https://talktopc.com/logo192.png',
|
|
3678
|
+
size: 'medium',
|
|
3679
|
+
backgroundColor: '#FFFFFF'
|
|
3680
|
+
},
|
|
3681
|
+
panel: {
|
|
3682
|
+
width: 360,
|
|
3683
|
+
height: 550,
|
|
3684
|
+
borderRadius: 24,
|
|
3685
|
+
backgroundColor: '#FFFFFF',
|
|
3686
|
+
border: '1px solid #E5E7EB'
|
|
3687
|
+
},
|
|
3688
|
+
position: {
|
|
3689
|
+
vertical: 'bottom',
|
|
3690
|
+
horizontal: 'left',
|
|
3691
|
+
offset: { x: 20, y: 20 }
|
|
3692
|
+
},
|
|
3693
|
+
header: {
|
|
3694
|
+
title: 'Chat Assistant',
|
|
3695
|
+
backgroundColor: '#7C3AED',
|
|
3696
|
+
textColor: '#FFFFFF',
|
|
3697
|
+
showCloseButton: true,
|
|
3698
|
+
onlineIndicatorText: 'Online',
|
|
3699
|
+
onlineIndicatorColor: '#FFFFFF',
|
|
3700
|
+
onlineIndicatorDotColor: '#10b981'
|
|
3701
|
+
},
|
|
3702
|
+
messages: {
|
|
3703
|
+
userBackgroundColor: '#E5E7EB',
|
|
3704
|
+
agentBackgroundColor: '#F3F4F6',
|
|
3705
|
+
textColor: '#1F2937',
|
|
3706
|
+
userTextColor: '#1F2937',
|
|
3707
|
+
agentTextColor: '#1F2937',
|
|
3708
|
+
userAvatarIcon: '👤',
|
|
3709
|
+
agentAvatarIcon: '🤖',
|
|
3710
|
+
fontSize: '14px',
|
|
3711
|
+
borderRadius: 16
|
|
3712
|
+
},
|
|
3713
|
+
text: {
|
|
3714
|
+
sendButtonText: '→',
|
|
3715
|
+
sendButtonColor: '#7C3AED',
|
|
3716
|
+
sendButtonHoverColor: '#6D28D9',
|
|
3717
|
+
inputPlaceholder: 'Type your message...',
|
|
3718
|
+
inputFocusColor: '#7C3AED'
|
|
3719
|
+
},
|
|
3720
|
+
voice: {
|
|
3721
|
+
micButtonColor: '#7C3AED',
|
|
3722
|
+
micButtonActiveColor: '#EF4444',
|
|
3723
|
+
speakerButtonColor: '#FFFFFF',
|
|
3724
|
+
endCallButtonColor: '#ef4444',
|
|
3725
|
+
avatarBackgroundColor: '#667eea',
|
|
3726
|
+
avatarType: 'icon',
|
|
3727
|
+
avatarIcon: '🤖',
|
|
3728
|
+
avatarImageUrl: '',
|
|
3729
|
+
startCallButtonText: 'Start Call',
|
|
3730
|
+
startCallButtonColor: '#667eea',
|
|
3731
|
+
startCallButtonTextColor: '#FFFFFF',
|
|
3732
|
+
statusTitleColor: '#1e293b',
|
|
3733
|
+
statusSubtitleColor: '#64748b',
|
|
3734
|
+
statusDotColor: '#10b981',
|
|
3735
|
+
statusText: 'Listening...',
|
|
3736
|
+
liveTranscriptTextColor: '#64748b',
|
|
3737
|
+
liveTranscriptFontSize: '14px',
|
|
3738
|
+
liveIndicatorDotColor: '#10b981',
|
|
3739
|
+
liveIndicatorTextColor: '#10b981',
|
|
3740
|
+
waveformType: 'waveform',
|
|
3741
|
+
waveformIcon: '🎤',
|
|
3742
|
+
waveformImageUrl: ''
|
|
3743
|
+
},
|
|
3744
|
+
landing: {
|
|
3745
|
+
backgroundColor: 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)',
|
|
3746
|
+
logo: '🤖',
|
|
3747
|
+
logoType: 'icon',
|
|
3748
|
+
logoIcon: '🤖',
|
|
3749
|
+
logoImageUrl: '',
|
|
3750
|
+
logoBackgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
3751
|
+
logoBackgroundEnabled: true,
|
|
3752
|
+
title: 'Welcome to AI Assistant',
|
|
3753
|
+
subtitle: 'Choose how you\'d like to interact',
|
|
3754
|
+
voiceCardTitle: 'Voice Call',
|
|
3755
|
+
textCardTitle: 'Text Chat',
|
|
3756
|
+
titleColor: '#1e293b',
|
|
3757
|
+
subtitleColor: '#64748b',
|
|
3758
|
+
modeCardBackgroundColor: '#FFFFFF'
|
|
3759
|
+
},
|
|
3760
|
+
promptAnimation: {
|
|
3761
|
+
enabled: false,
|
|
3762
|
+
text: 'Try me!',
|
|
3763
|
+
backgroundColor: 'linear-gradient(135deg, #7c3aed, #4f46e5)',
|
|
3764
|
+
textColor: '#ffffff',
|
|
3765
|
+
animationType: 'bounce',
|
|
3766
|
+
showShimmer: true,
|
|
3767
|
+
showPulseRings: true,
|
|
3768
|
+
hideAfterClick: true,
|
|
3769
|
+
hideAfterSeconds: null,
|
|
3770
|
+
position: 'top'
|
|
3771
|
+
}
|
|
3772
|
+
};
|
|
3773
|
+
|
|
3774
|
+
// Helper function to deep compare objects and return only changed properties
|
|
3775
|
+
function getChangedProperties(current, defaults) {
|
|
3776
|
+
if (current === null || current === undefined) {
|
|
3777
|
+
return undefined;
|
|
3778
|
+
}
|
|
3779
|
+
|
|
3780
|
+
if (typeof current !== 'object' || Array.isArray(current)) {
|
|
3781
|
+
// Primitive values or arrays - compare directly
|
|
3782
|
+
return JSON.stringify(current) === JSON.stringify(defaults) ? undefined : current;
|
|
3783
|
+
}
|
|
3784
|
+
|
|
3785
|
+
// Object comparison
|
|
3786
|
+
const result = {};
|
|
3787
|
+
let hasChanges = false;
|
|
3788
|
+
|
|
3789
|
+
// Check all keys in current object
|
|
3790
|
+
for (const key in current) {
|
|
3791
|
+
if (current.hasOwnProperty(key)) {
|
|
3792
|
+
const currentValue = current[key];
|
|
3793
|
+
const defaultValue = defaults[key];
|
|
3794
|
+
|
|
3795
|
+
if (defaultValue === undefined) {
|
|
3796
|
+
// Property doesn't exist in defaults - include it
|
|
3797
|
+
result[key] = currentValue;
|
|
3798
|
+
hasChanges = true;
|
|
3799
|
+
} else if (typeof currentValue === 'object' && currentValue !== null && !Array.isArray(currentValue) &&
|
|
3800
|
+
typeof defaultValue === 'object' && defaultValue !== null && !Array.isArray(defaultValue)) {
|
|
3801
|
+
// Nested object - recurse
|
|
3802
|
+
const nestedChanges = getChangedProperties(currentValue, defaultValue);
|
|
3803
|
+
if (nestedChanges !== undefined) {
|
|
3804
|
+
result[key] = nestedChanges;
|
|
3805
|
+
hasChanges = true;
|
|
3806
|
+
}
|
|
3807
|
+
} else {
|
|
3808
|
+
// Primitive or array comparison
|
|
3809
|
+
if (JSON.stringify(currentValue) !== JSON.stringify(defaultValue)) {
|
|
3810
|
+
result[key] = currentValue;
|
|
3811
|
+
hasChanges = true;
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
return hasChanges ? result : undefined;
|
|
3818
|
+
}
|
|
3819
|
+
|
|
2939
3820
|
function updateConfigCode() {
|
|
2940
3821
|
const codeOutput = document.getElementById('configCode');
|
|
2941
3822
|
|
|
2942
|
-
//
|
|
3823
|
+
// Start with required fields
|
|
2943
3824
|
const displayConfig = {
|
|
2944
|
-
agentId:
|
|
2945
|
-
appId:
|
|
2946
|
-
direction: widgetConfig.direction,
|
|
2947
|
-
button: widgetConfig.button,
|
|
2948
|
-
icon: widgetConfig.icon,
|
|
2949
|
-
panel: widgetConfig.panel,
|
|
2950
|
-
header: widgetConfig.header,
|
|
2951
|
-
messages: widgetConfig.messages,
|
|
2952
|
-
text: widgetConfig.text,
|
|
2953
|
-
voice: widgetConfig.voice,
|
|
2954
|
-
landing: widgetConfig.landing,
|
|
2955
|
-
position: widgetConfig.position
|
|
3825
|
+
agentId: AGENT_ID,
|
|
3826
|
+
appId: APP_ID
|
|
2956
3827
|
};
|
|
2957
3828
|
|
|
2958
|
-
//
|
|
3829
|
+
// Only add properties that differ from defaults
|
|
3830
|
+
const changedDirection = widgetConfig.direction !== defaultConfig.direction ? widgetConfig.direction : undefined;
|
|
3831
|
+
if (changedDirection !== undefined) {
|
|
3832
|
+
displayConfig.direction = changedDirection;
|
|
3833
|
+
}
|
|
3834
|
+
|
|
3835
|
+
const changedButton = getChangedProperties(widgetConfig.button, defaultConfig.button);
|
|
3836
|
+
if (changedButton !== undefined) {
|
|
3837
|
+
displayConfig.button = changedButton;
|
|
3838
|
+
}
|
|
3839
|
+
|
|
3840
|
+
const changedIcon = getChangedProperties(widgetConfig.icon, defaultConfig.icon);
|
|
3841
|
+
if (changedIcon !== undefined) {
|
|
3842
|
+
displayConfig.icon = changedIcon;
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
const changedPanel = getChangedProperties(widgetConfig.panel, defaultConfig.panel);
|
|
3846
|
+
if (changedPanel !== undefined) {
|
|
3847
|
+
displayConfig.panel = changedPanel;
|
|
3848
|
+
}
|
|
3849
|
+
|
|
3850
|
+
const changedPosition = getChangedProperties(widgetConfig.position, defaultConfig.position);
|
|
3851
|
+
if (changedPosition !== undefined) {
|
|
3852
|
+
displayConfig.position = changedPosition;
|
|
3853
|
+
}
|
|
3854
|
+
|
|
3855
|
+
const changedHeader = getChangedProperties(widgetConfig.header, defaultConfig.header);
|
|
3856
|
+
if (changedHeader !== undefined) {
|
|
3857
|
+
displayConfig.header = changedHeader;
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3860
|
+
const changedMessages = getChangedProperties(widgetConfig.messages, defaultConfig.messages);
|
|
3861
|
+
if (changedMessages !== undefined) {
|
|
3862
|
+
displayConfig.messages = changedMessages;
|
|
3863
|
+
}
|
|
3864
|
+
|
|
3865
|
+
const changedText = getChangedProperties(widgetConfig.text, defaultConfig.text);
|
|
3866
|
+
if (changedText !== undefined) {
|
|
3867
|
+
displayConfig.text = changedText;
|
|
3868
|
+
}
|
|
3869
|
+
|
|
3870
|
+
const changedVoice = getChangedProperties(widgetConfig.voice, defaultConfig.voice);
|
|
3871
|
+
if (changedVoice !== undefined) {
|
|
3872
|
+
displayConfig.voice = changedVoice;
|
|
3873
|
+
}
|
|
3874
|
+
|
|
3875
|
+
const changedLanding = getChangedProperties(widgetConfig.landing, defaultConfig.landing);
|
|
3876
|
+
if (changedLanding !== undefined) {
|
|
3877
|
+
displayConfig.landing = changedLanding;
|
|
3878
|
+
}
|
|
3879
|
+
|
|
3880
|
+
const changedPromptAnimation = getChangedProperties(widgetConfig.promptAnimation, defaultConfig.promptAnimation);
|
|
3881
|
+
if (changedPromptAnimation !== undefined) {
|
|
3882
|
+
displayConfig.promptAnimation = changedPromptAnimation;
|
|
3883
|
+
}
|
|
3884
|
+
|
|
3885
|
+
// Format as proper JavaScript object
|
|
2959
3886
|
let configStr = JSON.stringify(displayConfig, null, 2);
|
|
2960
3887
|
|
|
2961
|
-
|
|
2962
|
-
configStr = configStr
|
|
2963
|
-
.replace(/"agentId": "your_agent_id"/g, '"agentId": "your_agent_id" // Required: Your agent ID')
|
|
2964
|
-
.replace(/"appId": "your_app_id"/g, '"appId": "your_app_id" // Required: Your app ID');
|
|
3888
|
+
codeOutput.textContent = `const widget = new TTPAgentSDK.TTPChatWidget(${configStr});`;
|
|
2965
3889
|
|
|
2966
|
-
|
|
3890
|
+
// Always update actual widget when config changes (with debounce)
|
|
3891
|
+
if (getTTPChatWidget()) {
|
|
3892
|
+
// Debounce widget updates to avoid rapid recreations
|
|
3893
|
+
if (updateWidgetTimeout) {
|
|
3894
|
+
clearTimeout(updateWidgetTimeout);
|
|
3895
|
+
}
|
|
3896
|
+
updateWidgetTimeout = setTimeout(() => {
|
|
3897
|
+
updateActualWidget();
|
|
3898
|
+
}, 300); // Wait 300ms after last change
|
|
3899
|
+
} else {
|
|
3900
|
+
// Only warn if not during initial load (when SDK might not be loaded yet)
|
|
3901
|
+
if (!isInitializing) {
|
|
3902
|
+
console.warn('TTPChatWidget not available, cannot update actual widget');
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
}
|
|
3906
|
+
|
|
3907
|
+
// Function to sync actual widget state with mock panel state
|
|
3908
|
+
// Only called when mock panel state changes, not on customization changes
|
|
3909
|
+
function syncWidgetWithMockPanel() {
|
|
3910
|
+
if (!actualWidgetInstance) return;
|
|
3911
|
+
|
|
3912
|
+
setTimeout(() => {
|
|
3913
|
+
// Check if widget uses Shadow DOM (default behavior)
|
|
3914
|
+
const shadowHost = document.getElementById('ttp-widget-shadow-host');
|
|
3915
|
+
let widgetPanel;
|
|
3916
|
+
|
|
3917
|
+
if (shadowHost && shadowHost.shadowRoot) {
|
|
3918
|
+
// Widget uses Shadow DOM - access elements through shadow root
|
|
3919
|
+
widgetPanel = shadowHost.shadowRoot.querySelector('[id^="ttp-chat-widget-panel"], #text-chat-panel');
|
|
3920
|
+
} else {
|
|
3921
|
+
// Widget uses regular DOM - access elements directly
|
|
3922
|
+
widgetPanel = document.querySelector('[id^="ttp-chat-widget-panel"], #text-chat-panel');
|
|
3923
|
+
}
|
|
3924
|
+
|
|
3925
|
+
if (widgetPanel && actualWidgetInstance) {
|
|
3926
|
+
const isCurrentlyOpen = widgetPanel.classList.contains('open');
|
|
3927
|
+
|
|
3928
|
+
if (panelOpen) {
|
|
3929
|
+
// Mock panel is open - ensure widget is open (unless user manually closed it)
|
|
3930
|
+
if (!isCurrentlyOpen && !widgetManuallyClosed) {
|
|
3931
|
+
if (typeof actualWidgetInstance.open === 'function') {
|
|
3932
|
+
try {
|
|
3933
|
+
actualWidgetInstance.open();
|
|
3934
|
+
widgetManuallyClosed = false; // Reset since we're opening it
|
|
3935
|
+
} catch (e) {
|
|
3936
|
+
console.warn('⚠️ Error opening widget:', e);
|
|
3937
|
+
}
|
|
3938
|
+
} else if (typeof actualWidgetInstance.togglePanel === 'function') {
|
|
3939
|
+
try {
|
|
3940
|
+
actualWidgetInstance.togglePanel();
|
|
3941
|
+
widgetManuallyClosed = false; // Reset since we're opening it
|
|
3942
|
+
} catch (e) {
|
|
3943
|
+
console.warn('⚠️ Error opening widget:', e);
|
|
3944
|
+
}
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
} else {
|
|
3948
|
+
// Mock panel is closed - ensure widget is closed
|
|
3949
|
+
if (isCurrentlyOpen) {
|
|
3950
|
+
// Widget is open, so close it
|
|
3951
|
+
widgetManuallyClosed = false; // Reset since we're closing via mock panel
|
|
3952
|
+
if (typeof actualWidgetInstance.togglePanel === 'function') {
|
|
3953
|
+
try {
|
|
3954
|
+
// togglePanel will close it if it's open
|
|
3955
|
+
actualWidgetInstance.togglePanel();
|
|
3956
|
+
} catch (e) {
|
|
3957
|
+
console.warn('⚠️ Error closing widget:', e);
|
|
3958
|
+
// Fallback: directly manipulate the DOM
|
|
3959
|
+
widgetPanel.classList.remove('open');
|
|
3960
|
+
if (actualWidgetInstance) {
|
|
3961
|
+
actualWidgetInstance.isOpen = false;
|
|
3962
|
+
}
|
|
3963
|
+
}
|
|
3964
|
+
} else if (typeof actualWidgetInstance.close === 'function') {
|
|
3965
|
+
try {
|
|
3966
|
+
actualWidgetInstance.close();
|
|
3967
|
+
} catch (e) {
|
|
3968
|
+
console.warn('⚠️ Error closing widget:', e);
|
|
3969
|
+
// Fallback: directly manipulate the DOM
|
|
3970
|
+
widgetPanel.classList.remove('open');
|
|
3971
|
+
if (actualWidgetInstance) {
|
|
3972
|
+
actualWidgetInstance.isOpen = false;
|
|
3973
|
+
}
|
|
3974
|
+
}
|
|
3975
|
+
} else {
|
|
3976
|
+
// Fallback: directly manipulate the DOM
|
|
3977
|
+
widgetPanel.classList.remove('open');
|
|
3978
|
+
if (actualWidgetInstance) {
|
|
3979
|
+
actualWidgetInstance.isOpen = false;
|
|
3980
|
+
}
|
|
3981
|
+
}
|
|
3982
|
+
}
|
|
3983
|
+
}
|
|
3984
|
+
}
|
|
3985
|
+
}, 100); // Small delay to ensure widget is ready
|
|
3986
|
+
}
|
|
3987
|
+
|
|
3988
|
+
// Listen for widget close events to track manual closes
|
|
3989
|
+
function setupWidgetCloseTracking() {
|
|
3990
|
+
if (!actualWidgetInstance) return;
|
|
3991
|
+
|
|
3992
|
+
setTimeout(() => {
|
|
3993
|
+
const shadowHost = document.getElementById('ttp-widget-shadow-host');
|
|
3994
|
+
let closeBtn;
|
|
3995
|
+
|
|
3996
|
+
if (shadowHost && shadowHost.shadowRoot) {
|
|
3997
|
+
closeBtn = shadowHost.shadowRoot.querySelector('[id*="close"], .close-btn, [class*="close"]');
|
|
3998
|
+
} else {
|
|
3999
|
+
closeBtn = document.querySelector('[id*="close"], .close-btn, [class*="close"]');
|
|
4000
|
+
}
|
|
4001
|
+
|
|
4002
|
+
if (closeBtn) {
|
|
4003
|
+
// Remove any existing listeners by cloning
|
|
4004
|
+
const newCloseBtn = closeBtn.cloneNode(true);
|
|
4005
|
+
closeBtn.parentNode.replaceChild(newCloseBtn, closeBtn);
|
|
4006
|
+
|
|
4007
|
+
newCloseBtn.addEventListener('click', () => {
|
|
4008
|
+
widgetManuallyClosed = true;
|
|
4009
|
+
// Don't sync immediately - let the widget close naturally
|
|
4010
|
+
setTimeout(() => {
|
|
4011
|
+
// Only sync if mock panel is closed (user wants it closed)
|
|
4012
|
+
if (!panelOpen) {
|
|
4013
|
+
syncWidgetWithMockPanel();
|
|
4014
|
+
}
|
|
4015
|
+
}, 100);
|
|
4016
|
+
});
|
|
4017
|
+
}
|
|
4018
|
+
}, 300);
|
|
4019
|
+
}
|
|
4020
|
+
|
|
4021
|
+
function updateActualWidget() {
|
|
4022
|
+
const TTPChatWidget = getTTPChatWidget();
|
|
4023
|
+
if (!TTPChatWidget) {
|
|
4024
|
+
console.warn('TTPChatWidget not available yet');
|
|
4025
|
+
return;
|
|
4026
|
+
}
|
|
4027
|
+
|
|
4028
|
+
// Destroy existing widget if it exists
|
|
4029
|
+
if (actualWidgetInstance) {
|
|
4030
|
+
try {
|
|
4031
|
+
// Try to call destroy method if it exists
|
|
4032
|
+
if (typeof actualWidgetInstance.destroy === 'function') {
|
|
4033
|
+
actualWidgetInstance.destroy();
|
|
4034
|
+
}
|
|
4035
|
+
|
|
4036
|
+
// Remove widget elements from DOM (multiple possible selectors)
|
|
4037
|
+
const selectors = [
|
|
4038
|
+
'[id^="ttp-chat-widget-button"]',
|
|
4039
|
+
'[id^="ttp-chat-widget-panel"]',
|
|
4040
|
+
'[id*="ttp-chat"]',
|
|
4041
|
+
'.ttp-chat-widget-button',
|
|
4042
|
+
'.ttp-chat-widget-panel',
|
|
4043
|
+
'[class*="ttp-chat"]'
|
|
4044
|
+
];
|
|
4045
|
+
|
|
4046
|
+
let removedCount = 0;
|
|
4047
|
+
selectors.forEach(selector => {
|
|
4048
|
+
const elements = document.querySelectorAll(selector);
|
|
4049
|
+
elements.forEach(el => {
|
|
4050
|
+
if (el && el.parentNode) {
|
|
4051
|
+
el.parentNode.removeChild(el);
|
|
4052
|
+
removedCount++;
|
|
4053
|
+
}
|
|
4054
|
+
});
|
|
4055
|
+
});
|
|
4056
|
+
|
|
4057
|
+
actualWidgetInstance = null;
|
|
4058
|
+
|
|
4059
|
+
// Wait a bit to ensure DOM is cleaned up before creating new widget
|
|
4060
|
+
setTimeout(() => {
|
|
4061
|
+
createNewWidget(TTPChatWidget);
|
|
4062
|
+
}, 150);
|
|
4063
|
+
} catch (e) {
|
|
4064
|
+
console.warn('Error removing old widget:', e);
|
|
4065
|
+
actualWidgetInstance = null;
|
|
4066
|
+
setTimeout(() => {
|
|
4067
|
+
createNewWidget(TTPChatWidget);
|
|
4068
|
+
}, 150);
|
|
4069
|
+
}
|
|
4070
|
+
} else {
|
|
4071
|
+
createNewWidget(TTPChatWidget);
|
|
4072
|
+
}
|
|
4073
|
+
}
|
|
4074
|
+
|
|
4075
|
+
function createNewWidget(TTPChatWidget) {
|
|
4076
|
+
|
|
4077
|
+
// Create config for actual widget - use the same config as mock but positioned differently
|
|
4078
|
+
// Deep copy to avoid mutations and ensure fresh config
|
|
4079
|
+
const actualConfig = {
|
|
4080
|
+
agentId: AGENT_ID,
|
|
4081
|
+
appId: APP_ID,
|
|
4082
|
+
direction: widgetConfig.direction,
|
|
4083
|
+
button: JSON.parse(JSON.stringify(widgetConfig.button)),
|
|
4084
|
+
icon: JSON.parse(JSON.stringify(widgetConfig.icon)),
|
|
4085
|
+
panel: JSON.parse(JSON.stringify(widgetConfig.panel)),
|
|
4086
|
+
header: JSON.parse(JSON.stringify(widgetConfig.header)), // Deep copy header to ensure color is included
|
|
4087
|
+
messages: JSON.parse(JSON.stringify(widgetConfig.messages)),
|
|
4088
|
+
text: JSON.parse(JSON.stringify(widgetConfig.text)),
|
|
4089
|
+
voice: JSON.parse(JSON.stringify(widgetConfig.voice)),
|
|
4090
|
+
landing: JSON.parse(JSON.stringify(widgetConfig.landing)),
|
|
4091
|
+
promptAnimation: JSON.parse(JSON.stringify(widgetConfig.promptAnimation || {
|
|
4092
|
+
enabled: false,
|
|
4093
|
+
text: 'Try me!',
|
|
4094
|
+
backgroundColor: 'linear-gradient(135deg, #7c3aed, #4f46e5)',
|
|
4095
|
+
textColor: '#ffffff',
|
|
4096
|
+
animationType: 'bounce',
|
|
4097
|
+
showShimmer: true,
|
|
4098
|
+
showPulseRings: true,
|
|
4099
|
+
hideAfterClick: true,
|
|
4100
|
+
hideAfterSeconds: null,
|
|
4101
|
+
position: 'top'
|
|
4102
|
+
})), // Include promptAnimation config
|
|
4103
|
+
behavior: {
|
|
4104
|
+
startOpen: panelOpen, // Sync with mock panel state
|
|
4105
|
+
autoOpen: panelOpen, // Sync with mock panel state
|
|
4106
|
+
mode: 'unified'
|
|
4107
|
+
},
|
|
4108
|
+
position: {
|
|
4109
|
+
...widgetConfig.position,
|
|
4110
|
+
// Use the same position as configured (no inversion)
|
|
4111
|
+
offset: {
|
|
4112
|
+
x: widgetConfig.position.offset.x,
|
|
4113
|
+
y: widgetConfig.position.offset.y
|
|
4114
|
+
}
|
|
4115
|
+
}
|
|
4116
|
+
};
|
|
4117
|
+
|
|
4118
|
+
try {
|
|
4119
|
+
// Reset manual close tracking when widget is recreated (unless user manually closed it)
|
|
4120
|
+
// Don't reset if widget was manually closed and mock panel is also closed
|
|
4121
|
+
if (panelOpen) {
|
|
4122
|
+
widgetManuallyClosed = false;
|
|
4123
|
+
}
|
|
4124
|
+
|
|
4125
|
+
// Debug: Log the config being passed to widget
|
|
4126
|
+
console.log('🔧 Creating widget with config:', {
|
|
4127
|
+
...actualConfig,
|
|
4128
|
+
promptAnimation: actualConfig.promptAnimation
|
|
4129
|
+
});
|
|
4130
|
+
|
|
4131
|
+
actualWidgetInstance = new TTPChatWidget(actualConfig);
|
|
4132
|
+
|
|
4133
|
+
// Debug: Verify promptAnimation was received
|
|
4134
|
+
if (actualWidgetInstance && actualWidgetInstance.config) {
|
|
4135
|
+
console.log('✅ Widget created. promptAnimation config:', actualWidgetInstance.config.promptAnimation);
|
|
4136
|
+
}
|
|
4137
|
+
|
|
4138
|
+
// Setup tracking for manual closes
|
|
4139
|
+
setupWidgetCloseTracking();
|
|
4140
|
+
|
|
4141
|
+
// Only sync if mock panel is open (don't force open if user closed it)
|
|
4142
|
+
if (panelOpen && !widgetManuallyClosed) {
|
|
4143
|
+
setTimeout(() => {
|
|
4144
|
+
syncWidgetWithMockPanel();
|
|
4145
|
+
}, 200);
|
|
4146
|
+
}
|
|
4147
|
+
} catch (error) {
|
|
4148
|
+
console.error('❌ Error creating actual widget:', error);
|
|
4149
|
+
console.error('Error details:', error.stack);
|
|
4150
|
+
console.error('Config used:', actualConfig);
|
|
4151
|
+
alert('Failed to create widget. Check console for details. Error: ' + error.message);
|
|
4152
|
+
}
|
|
4153
|
+
}
|
|
4154
|
+
|
|
4155
|
+
function initActualWidget() {
|
|
4156
|
+
const TTPChatWidget = getTTPChatWidget();
|
|
4157
|
+
if (!TTPChatWidget) {
|
|
4158
|
+
setTimeout(initActualWidget, 100);
|
|
4159
|
+
return;
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
updateActualWidget();
|
|
4163
|
+
// Mark initialization as complete
|
|
4164
|
+
isInitializing = false;
|
|
2967
4165
|
}
|
|
2968
4166
|
|
|
2969
4167
|
function resetToDefaults() {
|
|
@@ -2992,19 +4190,26 @@
|
|
|
2992
4190
|
direction: 'ltr',
|
|
2993
4191
|
position: {
|
|
2994
4192
|
vertical: 'bottom',
|
|
2995
|
-
horizontal: '
|
|
4193
|
+
horizontal: 'left',
|
|
2996
4194
|
offset: { x: 20, y: 20 }
|
|
2997
4195
|
},
|
|
2998
4196
|
header: {
|
|
2999
4197
|
title: 'Chat Assistant',
|
|
3000
4198
|
backgroundColor: '#7C3AED',
|
|
3001
4199
|
textColor: '#FFFFFF',
|
|
3002
|
-
showCloseButton: true
|
|
4200
|
+
showCloseButton: true,
|
|
4201
|
+
onlineIndicatorText: 'Online',
|
|
4202
|
+
onlineIndicatorColor: '#FFFFFF',
|
|
4203
|
+
onlineIndicatorDotColor: '#10b981'
|
|
3003
4204
|
},
|
|
3004
4205
|
messages: {
|
|
3005
4206
|
userBackgroundColor: '#E5E7EB',
|
|
3006
4207
|
agentBackgroundColor: '#F3F4F6',
|
|
3007
|
-
textColor: '#1F2937',
|
|
4208
|
+
textColor: '#1F2937', // Fallback for backward compatibility
|
|
4209
|
+
userTextColor: '#1F2937',
|
|
4210
|
+
agentTextColor: '#1F2937',
|
|
4211
|
+
userAvatarIcon: '👤',
|
|
4212
|
+
agentAvatarIcon: '🤖',
|
|
3008
4213
|
fontSize: '14px',
|
|
3009
4214
|
borderRadius: 16
|
|
3010
4215
|
},
|
|
@@ -3018,6 +4223,8 @@
|
|
|
3018
4223
|
voice: {
|
|
3019
4224
|
micButtonColor: '#7C3AED',
|
|
3020
4225
|
micButtonActiveColor: '#EF4444',
|
|
4226
|
+
speakerButtonColor: '#FFFFFF',
|
|
4227
|
+
endCallButtonColor: '#ef4444',
|
|
3021
4228
|
avatarBackgroundColor: '#667eea',
|
|
3022
4229
|
avatarType: 'icon',
|
|
3023
4230
|
avatarIcon: '🤖',
|
|
@@ -3027,6 +4234,12 @@
|
|
|
3027
4234
|
startCallButtonTextColor: '#FFFFFF',
|
|
3028
4235
|
statusTitleColor: '#1e293b',
|
|
3029
4236
|
statusSubtitleColor: '#64748b',
|
|
4237
|
+
statusDotColor: '#10b981',
|
|
4238
|
+
statusText: 'Listening...',
|
|
4239
|
+
liveTranscriptTextColor: '#64748b',
|
|
4240
|
+
liveTranscriptFontSize: '14px',
|
|
4241
|
+
liveIndicatorDotColor: '#10b981',
|
|
4242
|
+
liveIndicatorTextColor: '#10b981',
|
|
3030
4243
|
waveformType: 'waveform',
|
|
3031
4244
|
waveformIcon: '🎤',
|
|
3032
4245
|
waveformImageUrl: ''
|
|
@@ -3036,24 +4249,21 @@
|
|
|
3036
4249
|
logoType: 'icon',
|
|
3037
4250
|
logoIcon: '🤖',
|
|
3038
4251
|
logoImageUrl: '',
|
|
4252
|
+
logoBackgroundColor: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
|
|
4253
|
+
logoBackgroundEnabled: true,
|
|
4254
|
+
backgroundColor: 'linear-gradient(180deg, #ffffff 0%, rgba(168, 85, 247, 0.03) 100%)',
|
|
3039
4255
|
title: 'Welcome to AI Assistant',
|
|
3040
4256
|
subtitle: 'Choose how you\'d like to interact',
|
|
3041
4257
|
voiceCardTitle: 'Voice Call',
|
|
3042
|
-
voiceCardDesc: 'Start a voice conversation',
|
|
3043
4258
|
textCardTitle: 'Text Chat',
|
|
3044
|
-
textCardDesc: 'Chat via text messages',
|
|
3045
4259
|
titleColor: '#1e293b',
|
|
3046
4260
|
subtitleColor: '#64748b',
|
|
3047
4261
|
modeCardBackgroundColor: '#FFFFFF'
|
|
3048
|
-
},
|
|
3049
|
-
position: {
|
|
3050
|
-
vertical: 'bottom',
|
|
3051
|
-
horizontal: 'right',
|
|
3052
|
-
offset: { x: 20, y: 20 }
|
|
3053
4262
|
}
|
|
3054
4263
|
};
|
|
3055
4264
|
|
|
3056
4265
|
initMockWidget();
|
|
4266
|
+
updateMockWidgetPosition();
|
|
3057
4267
|
updateConfigCode();
|
|
3058
4268
|
selectedElement = null;
|
|
3059
4269
|
document.querySelectorAll('.element-highlight').forEach(el => {
|
|
@@ -3072,6 +4282,13 @@
|
|
|
3072
4282
|
if (panelOpen) {
|
|
3073
4283
|
renderPanelContent();
|
|
3074
4284
|
}
|
|
4285
|
+
// Update prompt bubble visibility based on panel state
|
|
4286
|
+
const mockButton = document.getElementById('mockButton');
|
|
4287
|
+
if (mockButton) {
|
|
4288
|
+
updatePromptBubble(mockButton);
|
|
4289
|
+
}
|
|
4290
|
+
// Sync actual widget state with mock panel
|
|
4291
|
+
syncWidgetWithMockPanel();
|
|
3075
4292
|
});
|
|
3076
4293
|
|
|
3077
4294
|
// Make panel selectable (click on panel border/background)
|
|
@@ -3100,8 +4317,57 @@
|
|
|
3100
4317
|
}
|
|
3101
4318
|
}
|
|
3102
4319
|
|
|
4320
|
+
// Initialize mock widget and position
|
|
3103
4321
|
initMockWidget();
|
|
4322
|
+
// Ensure position is set after initialization
|
|
4323
|
+
setTimeout(() => {
|
|
4324
|
+
updateMockWidgetPosition();
|
|
4325
|
+
}, 50);
|
|
3104
4326
|
updateConfigCode();
|
|
4327
|
+
|
|
4328
|
+
// Initialize actual widget when SDK loads
|
|
4329
|
+
window.checkAndInitWidget = function() {
|
|
4330
|
+
const TTPChatWidget = getTTPChatWidget();
|
|
4331
|
+
if (TTPChatWidget) {
|
|
4332
|
+
initActualWidget();
|
|
4333
|
+
// Mark initialization as complete once SDK is ready
|
|
4334
|
+
isInitializing = false;
|
|
4335
|
+
} else {
|
|
4336
|
+
setTimeout(window.checkAndInitWidget, 100);
|
|
4337
|
+
}
|
|
4338
|
+
};
|
|
4339
|
+
|
|
4340
|
+
// Start checking for SDK (will also be called when script loads)
|
|
4341
|
+
window.checkAndInitWidget();
|
|
4342
|
+
|
|
4343
|
+
// Debug helper - expose widget instance globally for inspection
|
|
4344
|
+
window.debugWidget = function() {
|
|
4345
|
+
console.log('=== Widget Debug Info ===');
|
|
4346
|
+
console.log('actualWidgetInstance:', actualWidgetInstance);
|
|
4347
|
+
console.log('window.TTPAgentSDK:', window.TTPAgentSDK);
|
|
4348
|
+
console.log('TTPChatWidget available:', !!getTTPChatWidget());
|
|
4349
|
+
const widgetElements = document.querySelectorAll('[id*="ttp"], [class*="ttp"]');
|
|
4350
|
+
console.log('Widget elements in DOM:', widgetElements.length);
|
|
4351
|
+
widgetElements.forEach((el, idx) => {
|
|
4352
|
+
const style = window.getComputedStyle(el);
|
|
4353
|
+
console.log(`Element ${idx + 1}:`, {
|
|
4354
|
+
id: el.id,
|
|
4355
|
+
className: el.className,
|
|
4356
|
+
display: style.display,
|
|
4357
|
+
visibility: style.visibility,
|
|
4358
|
+
opacity: style.opacity,
|
|
4359
|
+
zIndex: style.zIndex
|
|
4360
|
+
});
|
|
4361
|
+
});
|
|
4362
|
+
return {
|
|
4363
|
+
instance: actualWidgetInstance,
|
|
4364
|
+
elements: Array.from(widgetElements),
|
|
4365
|
+
sdk: window.TTPAgentSDK
|
|
4366
|
+
};
|
|
4367
|
+
};
|
|
3105
4368
|
</script>
|
|
4369
|
+
|
|
4370
|
+
<!-- Load the widget SDK -->
|
|
4371
|
+
<script src="/dist/agent-widget.js?v=2.34.2" onload="if (typeof window.checkAndInitWidget === 'function') setTimeout(window.checkAndInitWidget, 100);" onerror="console.error('❌ Failed to load SDK script from /dist/agent-widget.js'); alert('Failed to load SDK. Check console for details.');"></script>
|
|
3106
4372
|
</body>
|
|
3107
4373
|
</html>
|