@salesforcedevs/docs-components 0.0.35-chat → 0.0.37-chat
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/package.json +1 -1
- package/src/modules/doc/chat/chat.css +133 -36
- package/src/modules/doc/chat/chat.html +67 -10
- package/src/modules/doc/chat/chat.ts +86 -28
- package/src/assets/hi_bot.gif +0 -0
package/package.json
CHANGED
|
@@ -5,7 +5,9 @@
|
|
|
5
5
|
right: 0;
|
|
6
6
|
height: 100vh;
|
|
7
7
|
z-index: 100000;
|
|
8
|
-
font-family: "Salesforce Sans", -apple-system, BlinkMacSystemFont,
|
|
8
|
+
font-family: "Salesforce Sans", -apple-system, BlinkMacSystemFont,
|
|
9
|
+
"Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue",
|
|
10
|
+
sans-serif;
|
|
9
11
|
}
|
|
10
12
|
|
|
11
13
|
/* Apply content shift to main page content when chat is open */
|
|
@@ -50,6 +52,59 @@ body.chat-closed .global-header {
|
|
|
50
52
|
padding: 0;
|
|
51
53
|
}
|
|
52
54
|
|
|
55
|
+
/* Tooltip styling */
|
|
56
|
+
.chat-trigger-button::before {
|
|
57
|
+
content: attr(data-tooltip);
|
|
58
|
+
position: absolute;
|
|
59
|
+
right: 100%;
|
|
60
|
+
top: 50%;
|
|
61
|
+
transform: translateY(-50%);
|
|
62
|
+
background: linear-gradient(135deg, #0176d3 0%, #005fb2 100%);
|
|
63
|
+
color: white;
|
|
64
|
+
padding: 12px 16px;
|
|
65
|
+
border-radius: 12px;
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
font-weight: 500;
|
|
68
|
+
white-space: nowrap;
|
|
69
|
+
opacity: 0;
|
|
70
|
+
visibility: hidden;
|
|
71
|
+
margin-right: 16px;
|
|
72
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
73
|
+
box-shadow: 0 8px 24px rgb(1 118 211 / 25%), 0 2px 8px rgb(1 118 211 / 15%);
|
|
74
|
+
backdrop-filter: blur(10px);
|
|
75
|
+
z-index: 1002;
|
|
76
|
+
pointer-events: none;
|
|
77
|
+
letter-spacing: 0.02em;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* Tooltip arrow */
|
|
81
|
+
.chat-trigger-button::after {
|
|
82
|
+
content: "";
|
|
83
|
+
position: absolute;
|
|
84
|
+
right: 100%;
|
|
85
|
+
top: 50%;
|
|
86
|
+
transform: translateY(-50%);
|
|
87
|
+
margin-right: 8px;
|
|
88
|
+
width: 0;
|
|
89
|
+
height: 0;
|
|
90
|
+
border-left: 8px solid #0176d3;
|
|
91
|
+
border-top: 8px solid transparent;
|
|
92
|
+
border-bottom: 8px solid transparent;
|
|
93
|
+
opacity: 0;
|
|
94
|
+
visibility: hidden;
|
|
95
|
+
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
96
|
+
z-index: 1002;
|
|
97
|
+
pointer-events: none;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/* Show tooltip on hover */
|
|
101
|
+
.chat-trigger-button:hover::before,
|
|
102
|
+
.chat-trigger-button:hover::after {
|
|
103
|
+
opacity: 1;
|
|
104
|
+
visibility: visible;
|
|
105
|
+
transform: translateY(-50%) translateX(-4px);
|
|
106
|
+
}
|
|
107
|
+
|
|
53
108
|
.chat-trigger-button:hover .chat-gif {
|
|
54
109
|
transform: scale(1.1);
|
|
55
110
|
}
|
|
@@ -65,8 +120,6 @@ body.chat-closed .global-header {
|
|
|
65
120
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
|
66
121
|
}
|
|
67
122
|
|
|
68
|
-
|
|
69
|
-
|
|
70
123
|
@keyframes pulse {
|
|
71
124
|
0% {
|
|
72
125
|
transform: scale(1);
|
|
@@ -123,7 +176,11 @@ body.chat-closed .global-header {
|
|
|
123
176
|
left: 0;
|
|
124
177
|
right: 0;
|
|
125
178
|
bottom: 0;
|
|
126
|
-
background: linear-gradient(
|
|
179
|
+
background: linear-gradient(
|
|
180
|
+
135deg,
|
|
181
|
+
rgb(255 255 255 / 5%) 0%,
|
|
182
|
+
rgb(255 255 255 / 1%) 100%
|
|
183
|
+
);
|
|
127
184
|
pointer-events: none;
|
|
128
185
|
}
|
|
129
186
|
|
|
@@ -240,7 +297,11 @@ body.chat-closed .global-header {
|
|
|
240
297
|
content: "";
|
|
241
298
|
position: absolute;
|
|
242
299
|
inset: 0;
|
|
243
|
-
background: linear-gradient(
|
|
300
|
+
background: linear-gradient(
|
|
301
|
+
135deg,
|
|
302
|
+
rgb(255 255 255 / 20%) 0%,
|
|
303
|
+
rgb(255 255 255 / 10%) 100%
|
|
304
|
+
);
|
|
244
305
|
border-radius: 50%;
|
|
245
306
|
}
|
|
246
307
|
|
|
@@ -269,56 +330,61 @@ body.chat-closed .global-header {
|
|
|
269
330
|
}
|
|
270
331
|
|
|
271
332
|
@keyframes thinking-avatar-pulse {
|
|
272
|
-
0%,
|
|
273
|
-
|
|
333
|
+
0%,
|
|
334
|
+
100% {
|
|
335
|
+
transform: scale(1);
|
|
274
336
|
box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
|
|
275
337
|
}
|
|
276
338
|
|
|
277
|
-
50% {
|
|
278
|
-
transform: scale(1.08);
|
|
339
|
+
50% {
|
|
340
|
+
transform: scale(1.08);
|
|
279
341
|
box-shadow: 0 4px 16px rgb(0 0 0 / 20%);
|
|
280
342
|
}
|
|
281
343
|
}
|
|
282
344
|
|
|
283
345
|
@keyframes thinking-breathe {
|
|
284
|
-
0%,
|
|
285
|
-
|
|
346
|
+
0%,
|
|
347
|
+
100% {
|
|
348
|
+
transform: scale(1);
|
|
286
349
|
}
|
|
287
350
|
|
|
288
|
-
50% {
|
|
289
|
-
transform: scale(1.05);
|
|
351
|
+
50% {
|
|
352
|
+
transform: scale(1.05);
|
|
290
353
|
}
|
|
291
354
|
}
|
|
292
355
|
|
|
293
356
|
@keyframes thinking-smile-animation {
|
|
294
|
-
0%,
|
|
295
|
-
|
|
357
|
+
0%,
|
|
358
|
+
100% {
|
|
359
|
+
transform: translateY(0);
|
|
296
360
|
}
|
|
297
361
|
|
|
298
|
-
50% {
|
|
299
|
-
transform: translateY(-2px);
|
|
362
|
+
50% {
|
|
363
|
+
transform: translateY(-2px);
|
|
300
364
|
}
|
|
301
365
|
}
|
|
302
366
|
|
|
303
367
|
@keyframes think-blink {
|
|
304
|
-
0%,
|
|
305
|
-
|
|
368
|
+
0%,
|
|
369
|
+
85%,
|
|
370
|
+
100% {
|
|
371
|
+
transform: scaleY(1);
|
|
306
372
|
}
|
|
307
373
|
|
|
308
|
-
90% {
|
|
309
|
-
transform: scaleY(0.6);
|
|
374
|
+
90% {
|
|
375
|
+
transform: scaleY(0.6);
|
|
310
376
|
}
|
|
311
377
|
|
|
312
|
-
92% {
|
|
313
|
-
transform: scaleY(0.2);
|
|
378
|
+
92% {
|
|
379
|
+
transform: scaleY(0.2);
|
|
314
380
|
}
|
|
315
381
|
|
|
316
|
-
94% {
|
|
317
|
-
transform: scaleY(0.6);
|
|
382
|
+
94% {
|
|
383
|
+
transform: scaleY(0.6);
|
|
318
384
|
}
|
|
319
385
|
|
|
320
|
-
96% {
|
|
321
|
-
transform: scaleY(1);
|
|
386
|
+
96% {
|
|
387
|
+
transform: scaleY(1);
|
|
322
388
|
}
|
|
323
389
|
}
|
|
324
390
|
|
|
@@ -510,40 +576,52 @@ body.chat-closed .global-header {
|
|
|
510
576
|
bottom: 16px;
|
|
511
577
|
right: 16px;
|
|
512
578
|
}
|
|
513
|
-
|
|
579
|
+
|
|
514
580
|
.chat-gif {
|
|
515
581
|
width: 56px;
|
|
516
582
|
height: 56px;
|
|
517
583
|
}
|
|
518
|
-
|
|
519
584
|
|
|
520
|
-
|
|
585
|
+
/* Adjust tooltip for mobile */
|
|
586
|
+
.chat-trigger-button::before {
|
|
587
|
+
font-size: 13px;
|
|
588
|
+
padding: 10px 14px;
|
|
589
|
+
margin-right: 12px;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
.chat-trigger-button::after {
|
|
593
|
+
margin-right: 6px;
|
|
594
|
+
border-left-width: 6px;
|
|
595
|
+
border-top-width: 6px;
|
|
596
|
+
border-bottom-width: 6px;
|
|
597
|
+
}
|
|
598
|
+
|
|
521
599
|
.chat-container {
|
|
522
600
|
width: 100%;
|
|
523
601
|
right: 0;
|
|
524
602
|
transform: translateX(100%);
|
|
525
603
|
}
|
|
526
|
-
|
|
604
|
+
|
|
527
605
|
.chat-container_open {
|
|
528
606
|
transform: translateX(0);
|
|
529
607
|
}
|
|
530
|
-
|
|
608
|
+
|
|
531
609
|
.chat-header {
|
|
532
610
|
padding: 16px 20px;
|
|
533
611
|
}
|
|
534
|
-
|
|
612
|
+
|
|
535
613
|
.chat-title {
|
|
536
614
|
font-size: 18px;
|
|
537
615
|
}
|
|
538
|
-
|
|
616
|
+
|
|
539
617
|
.chat-messages {
|
|
540
618
|
padding: 20px 16px;
|
|
541
619
|
}
|
|
542
|
-
|
|
620
|
+
|
|
543
621
|
.chat-input-area {
|
|
544
622
|
padding: 16px 20px;
|
|
545
623
|
}
|
|
546
|
-
|
|
624
|
+
|
|
547
625
|
.message-content {
|
|
548
626
|
max-width: 85%;
|
|
549
627
|
}
|
|
@@ -574,7 +652,20 @@ body.chat-closed .global-header {
|
|
|
574
652
|
height: 48px;
|
|
575
653
|
}
|
|
576
654
|
|
|
655
|
+
/* Smaller tooltip for small screens */
|
|
656
|
+
.chat-trigger-button::before {
|
|
657
|
+
font-size: 12px;
|
|
658
|
+
padding: 8px 12px;
|
|
659
|
+
margin-right: 10px;
|
|
660
|
+
border-radius: 8px;
|
|
661
|
+
}
|
|
577
662
|
|
|
663
|
+
.chat-trigger-button::after {
|
|
664
|
+
margin-right: 4px;
|
|
665
|
+
border-left-width: 5px;
|
|
666
|
+
border-top-width: 5px;
|
|
667
|
+
border-bottom-width: 5px;
|
|
668
|
+
}
|
|
578
669
|
|
|
579
670
|
.chat-container {
|
|
580
671
|
width: 100%;
|
|
@@ -638,6 +729,12 @@ body.chat-closed .global-header {
|
|
|
638
729
|
.thinking-eye {
|
|
639
730
|
animation: none !important;
|
|
640
731
|
}
|
|
732
|
+
|
|
733
|
+
/* Disable tooltip animations for reduced motion users */
|
|
734
|
+
.chat-trigger-button::before,
|
|
735
|
+
.chat-trigger-button::after {
|
|
736
|
+
transition: none;
|
|
737
|
+
}
|
|
641
738
|
}
|
|
642
739
|
|
|
643
740
|
/* High contrast mode support */
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
class="chat-trigger-button"
|
|
6
6
|
onclick={handleOpenClick}
|
|
7
7
|
aria-label="Open chat"
|
|
8
|
+
data-tooltip="Chat with us!"
|
|
8
9
|
>
|
|
9
10
|
<img
|
|
10
11
|
class="chat-gif"
|
|
11
|
-
src="/
|
|
12
|
+
src="https://a.sfdcstatic.com/developer-website/sfdocs/hack-smart-agent/hi_bot_bg.gif"
|
|
12
13
|
alt="Hi Bot"
|
|
13
14
|
/>
|
|
14
15
|
<!-- <span class="chat-trigger-text">Chat</span> -->
|
|
@@ -70,7 +71,10 @@
|
|
|
70
71
|
data-sender={message.sender}
|
|
71
72
|
>
|
|
72
73
|
<!-- AI Avatar for assistant messages only -->
|
|
73
|
-
<div
|
|
74
|
+
<div
|
|
75
|
+
class="message-avatar-wrapper"
|
|
76
|
+
data-sender={message.sender}
|
|
77
|
+
>
|
|
74
78
|
<div class="avatar-container">
|
|
75
79
|
<svg
|
|
76
80
|
class="avatar-icon"
|
|
@@ -84,25 +88,78 @@
|
|
|
84
88
|
<line x1="230" y1="20" x2="230" y2="60" />
|
|
85
89
|
</g>
|
|
86
90
|
<circle cx="70" cy="20" r="10" fill="#3A98D8" />
|
|
87
|
-
<circle
|
|
91
|
+
<circle
|
|
92
|
+
cx="230"
|
|
93
|
+
cy="20"
|
|
94
|
+
r="10"
|
|
95
|
+
fill="#3A98D8"
|
|
96
|
+
/>
|
|
88
97
|
|
|
89
98
|
<!-- Robot Body -->
|
|
90
99
|
<g class="thinking-body">
|
|
91
|
-
<rect
|
|
100
|
+
<rect
|
|
101
|
+
x="40"
|
|
102
|
+
y="60"
|
|
103
|
+
width="220"
|
|
104
|
+
height="240"
|
|
105
|
+
rx="110"
|
|
106
|
+
ry="110"
|
|
107
|
+
fill="#3A98D8"
|
|
108
|
+
/>
|
|
92
109
|
|
|
93
110
|
<!-- Forehead Dots -->
|
|
94
|
-
<circle
|
|
95
|
-
|
|
111
|
+
<circle
|
|
112
|
+
cx="150"
|
|
113
|
+
cy="90"
|
|
114
|
+
r="6"
|
|
115
|
+
fill="#9ED4E6"
|
|
116
|
+
/>
|
|
117
|
+
<rect
|
|
118
|
+
x="135"
|
|
119
|
+
y="100"
|
|
120
|
+
width="30"
|
|
121
|
+
height="10"
|
|
122
|
+
rx="5"
|
|
123
|
+
ry="5"
|
|
124
|
+
fill="#9ED4E6"
|
|
125
|
+
/>
|
|
96
126
|
|
|
97
127
|
<!-- Face Panel -->
|
|
98
|
-
<rect
|
|
128
|
+
<rect
|
|
129
|
+
x="70"
|
|
130
|
+
y="130"
|
|
131
|
+
width="160"
|
|
132
|
+
height="80"
|
|
133
|
+
rx="40"
|
|
134
|
+
ry="40"
|
|
135
|
+
fill="#577C86"
|
|
136
|
+
/>
|
|
99
137
|
|
|
100
138
|
<!-- Eyes (Thinking animation) -->
|
|
101
|
-
<circle
|
|
102
|
-
|
|
139
|
+
<circle
|
|
140
|
+
class="thinking-eye"
|
|
141
|
+
cx="115"
|
|
142
|
+
cy="170"
|
|
143
|
+
r="10"
|
|
144
|
+
fill="#86D3BD"
|
|
145
|
+
/>
|
|
146
|
+
<circle
|
|
147
|
+
class="thinking-eye"
|
|
148
|
+
cx="185"
|
|
149
|
+
cy="170"
|
|
150
|
+
r="10"
|
|
151
|
+
fill="#86D3BD"
|
|
152
|
+
/>
|
|
103
153
|
|
|
104
154
|
<!-- Thinking Smile -->
|
|
105
|
-
<path
|
|
155
|
+
<path
|
|
156
|
+
class="thinking-smile"
|
|
157
|
+
d="M110 240 Q150 260 190 240"
|
|
158
|
+
stroke="#2F435A"
|
|
159
|
+
stroke-width="6"
|
|
160
|
+
fill="none"
|
|
161
|
+
stroke-linecap="round"
|
|
162
|
+
/>
|
|
106
163
|
</g>
|
|
107
164
|
</svg>
|
|
108
165
|
</div>
|
|
@@ -53,12 +53,19 @@ export default class Chat extends LightningElement {
|
|
|
53
53
|
private _isOpen: boolean = false;
|
|
54
54
|
private messageIdCounter: number = 0;
|
|
55
55
|
|
|
56
|
+
// API Configuration
|
|
57
|
+
private static readonly API_URL = "https://276ca7264b79.ngrok-free.app/api/llm/search";
|
|
58
|
+
private static readonly MAX_RESULTS = 5;
|
|
59
|
+
|
|
60
|
+
// Development mode flag - set to true if running in development
|
|
61
|
+
private static readonly IS_DEVELOPMENT = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
|
62
|
+
|
|
56
63
|
// localStorage keys for persisting messages and open state
|
|
57
64
|
private static readonly STORAGE_KEY = "doc-chat-messages";
|
|
58
65
|
private static readonly OPEN_STATE_KEY = "doc-chat-should-open";
|
|
59
66
|
|
|
60
67
|
connectedCallback() {
|
|
61
|
-
console.log(
|
|
68
|
+
console.log("---- Connected callback ------");
|
|
62
69
|
// Load existing messages from localStorage
|
|
63
70
|
this.loadMessages();
|
|
64
71
|
|
|
@@ -264,40 +271,91 @@ export default class Chat extends LightningElement {
|
|
|
264
271
|
input.value = "";
|
|
265
272
|
}
|
|
266
273
|
|
|
267
|
-
//
|
|
274
|
+
// Show typing indicator
|
|
268
275
|
this.isAssistantTyping = true;
|
|
269
276
|
|
|
270
|
-
//
|
|
277
|
+
// Get real assistant response from API
|
|
278
|
+
// Add a small delay to show the typing indicator
|
|
271
279
|
setTimeout(() => {
|
|
272
|
-
this.
|
|
273
|
-
|
|
274
|
-
}, 1000 + Math.random() * 2000);
|
|
280
|
+
this.getAssistantResponse(userMessage);
|
|
281
|
+
}, 500);
|
|
275
282
|
}
|
|
276
283
|
|
|
277
|
-
private
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
response =
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
284
|
+
private async callChatAPI(userMessage: string): Promise<string> {
|
|
285
|
+
try {
|
|
286
|
+
// Format chat history for API (exclude the current user message)
|
|
287
|
+
const chatHistory = this.messages.map(msg => ({
|
|
288
|
+
text: msg.text,
|
|
289
|
+
sender: msg.sender
|
|
290
|
+
}));
|
|
291
|
+
|
|
292
|
+
const requestBody = {
|
|
293
|
+
query: userMessage,
|
|
294
|
+
maxResults: Chat.MAX_RESULTS,
|
|
295
|
+
chatHistory: chatHistory
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
console.log('Sending API request:', requestBody);
|
|
299
|
+
|
|
300
|
+
const response = await fetch(Chat.API_URL, {
|
|
301
|
+
method: 'POST',
|
|
302
|
+
mode: 'cors', // Explicitly set CORS mode
|
|
303
|
+
headers: {
|
|
304
|
+
'Content-Type': 'application/json',
|
|
305
|
+
'ngrok-skip-browser-warning': 'true', // Skip ngrok browser warning
|
|
306
|
+
...(Chat.IS_DEVELOPMENT && { 'Access-Control-Allow-Origin': '*' })
|
|
307
|
+
},
|
|
308
|
+
body: JSON.stringify(requestBody)
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
if (!response.ok) {
|
|
312
|
+
const errorText = await response.text();
|
|
313
|
+
console.error('API Error Response:', errorText);
|
|
314
|
+
throw new Error(`API request failed with status: ${response.status}`);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const data = await response.json();
|
|
318
|
+
console.log('API Response:', data);
|
|
319
|
+
|
|
320
|
+
// Handle different possible response formats
|
|
321
|
+
const responseText = data.answer || data.text || data.response || data.result || data.message;
|
|
322
|
+
|
|
323
|
+
if (!responseText) {
|
|
324
|
+
console.warn('No response text found in API response:', data);
|
|
325
|
+
return 'I received your message but couldn\'t generate a proper response.';
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return responseText;
|
|
329
|
+
|
|
330
|
+
} catch (error) {
|
|
331
|
+
console.error('Chat API error:', error);
|
|
332
|
+
|
|
333
|
+
// Provide more specific error messages for CORS issues
|
|
334
|
+
if (error instanceof TypeError && error.message.includes('fetch')) {
|
|
335
|
+
return 'I\'m having trouble connecting to the service. This might be a CORS configuration issue. Please check your internet connection and try again.';
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
if (error instanceof Error && (error.message.includes('CORS') || error.message.includes('cross-origin'))) {
|
|
339
|
+
return 'I\'m having trouble connecting due to browser security restrictions. Please ask your administrator to configure CORS headers on the backend API.';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
return 'I apologize, but I\'m having trouble connecting to the service right now. Please try again later.';
|
|
298
343
|
}
|
|
344
|
+
}
|
|
299
345
|
|
|
300
|
-
|
|
346
|
+
private async getAssistantResponse(userMessage: string) {
|
|
347
|
+
try {
|
|
348
|
+
const response = await this.callChatAPI(userMessage);
|
|
349
|
+
this.addMessage(response, "assistant");
|
|
350
|
+
} catch (error) {
|
|
351
|
+
console.error('Error getting assistant response:', error);
|
|
352
|
+
this.addMessage(
|
|
353
|
+
'I apologize, but I encountered an error while processing your request. Please try again.',
|
|
354
|
+
"assistant"
|
|
355
|
+
);
|
|
356
|
+
} finally {
|
|
357
|
+
this.isAssistantTyping = false;
|
|
358
|
+
}
|
|
301
359
|
}
|
|
302
360
|
|
|
303
361
|
formatTimestamp(timestamp: Date) {
|
package/src/assets/hi_bot.gif
DELETED
|
Binary file
|