@salesforcedevs/docs-components 0.0.32-chat → 0.0.33-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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/docs-components",
3
- "version": "0.0.32-chat",
3
+ "version": "0.0.33-chat",
4
4
  "description": "Docs Lightning web components for DSC",
5
5
  "license": "MIT",
6
6
  "main": "index.js",
@@ -5,6 +5,7 @@
5
5
  right: 0;
6
6
  height: 100vh;
7
7
  z-index: 100000;
8
+ font-family: "Salesforce Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
8
9
  }
9
10
 
10
11
  /* Apply content shift to main page content when chat is open */
@@ -36,26 +37,26 @@ body.chat-closed .global-header {
36
37
  position: fixed;
37
38
  bottom: 20px;
38
39
  right: 20px;
39
- width: 60px;
40
- height: 60px;
40
+ width: 64px;
41
+ height: 64px;
41
42
  border-radius: 50%;
42
- background-color: #0066cc;
43
+ background: linear-gradient(135deg, #0176d3 0%, #005fb2 100%);
43
44
  color: white;
44
45
  border: none;
45
46
  cursor: pointer;
46
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
47
+ box-shadow: 0 8px 24px rgb(1 118 211 / 25%), 0 2px 8px rgb(1 118 211 / 15%);
47
48
  z-index: 1001;
48
49
  display: flex;
49
50
  align-items: center;
50
51
  justify-content: center;
51
- transition: all 0.3s ease;
52
- animation: pulse 2s infinite;
52
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
53
+ animation: pulse 3s infinite;
53
54
  }
54
55
 
55
56
  .chat-trigger-button:hover {
56
- background-color: #0052a3;
57
- transform: scale(1.1);
58
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4);
57
+ background: linear-gradient(135deg, #005fb2 0%, #003e73 100%);
58
+ transform: scale(1.05);
59
+ box-shadow: 0 12px 32px rgb(1 118 211 / 35%), 0 4px 12px rgb(1 118 211 / 25%);
59
60
  }
60
61
 
61
62
  .chat-trigger-button:active {
@@ -79,13 +80,15 @@ body.chat-closed .global-header {
79
80
 
80
81
  @keyframes pulse {
81
82
  0% {
82
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 0 rgba(0, 102, 204, 0.7);
83
+ box-shadow: 0 8px 24px rgb(1 118 211 / 25%), 0 2px 8px rgb(1 118 211 / 15%), 0 0 0 0 rgb(1 118 211 / 40%);
83
84
  }
85
+
84
86
  70% {
85
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 10px rgba(0, 102, 204, 0);
87
+ box-shadow: 0 8px 24px rgb(1 118 211 / 25%), 0 2px 8px rgb(1 118 211 / 15%), 0 0 0 16px rgb(1 118 211 / 0%);
86
88
  }
89
+
87
90
  100% {
88
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3), 0 0 0 0 rgba(0, 102, 204, 0);
91
+ box-shadow: 0 8px 24px rgb(1 118 211 / 25%), 0 2px 8px rgb(1 118 211 / 15%), 0 0 0 0 rgb(1 118 211 / 0%);
89
92
  }
90
93
  }
91
94
 
@@ -93,32 +96,46 @@ body.chat-closed .global-header {
93
96
  .chat-container {
94
97
  height: 100vh;
95
98
  width: 400px;
96
- background-color: #ffffff;
97
- box-shadow: -2px 0 10px rgba(0, 0, 0, 0.1);
99
+ background-color: #fff;
100
+ box-shadow: -8px 0 32px rgb(0 0 0 / 12%), -2px 0 8px rgb(0 0 0 / 8%);
98
101
  transform: translateX(100%);
99
- transition: transform 0.3s ease-in-out;
102
+ transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1);
100
103
  display: flex;
101
104
  flex-direction: column;
102
- border-left: 1px solid #e0e0e0;
105
+ border-left: 1px solid #d8dde6;
106
+ backdrop-filter: blur(20px);
103
107
  }
104
108
 
105
- .chat-container--open {
109
+ .chat-container_open {
106
110
  transform: translateX(0);
107
111
  }
108
112
 
109
- .chat-container--disabled {
113
+ .chat-container_disabled {
110
114
  opacity: 0.6;
111
115
  pointer-events: none;
112
116
  }
113
117
 
114
118
  .chat-header {
115
- background-color: #f8f9fa;
116
- padding: 16px;
117
- border-bottom: 1px solid #e0e0e0;
119
+ background: linear-gradient(135deg, #0176d3 0%, #005fb2 100%);
120
+ padding: 20px 24px;
121
+ border-bottom: 1px solid rgb(1 118 211 / 20%);
118
122
  display: flex;
119
123
  align-items: center;
120
124
  justify-content: space-between;
121
125
  flex-shrink: 0;
126
+ backdrop-filter: blur(10px);
127
+ position: relative;
128
+ }
129
+
130
+ .chat-header::before {
131
+ content: "";
132
+ position: absolute;
133
+ top: 0;
134
+ left: 0;
135
+ right: 0;
136
+ bottom: 0;
137
+ background: linear-gradient(135deg, rgb(255 255 255 / 5%) 0%, rgb(255 255 255 / 1%) 100%);
138
+ pointer-events: none;
122
139
  }
123
140
 
124
141
  .chat-header-actions {
@@ -129,28 +146,31 @@ body.chat-closed .global-header {
129
146
 
130
147
  .chat-close-button,
131
148
  .chat-clear-button {
132
- width: 32px;
133
- height: 32px;
149
+ width: 36px;
150
+ height: 36px;
134
151
  border: none;
135
- background: none;
152
+ background: rgb(255 255 255 / 15%);
136
153
  cursor: pointer;
137
154
  display: flex;
138
155
  align-items: center;
139
156
  justify-content: center;
140
- border-radius: 4px;
141
- transition: background-color 0.2s ease;
142
- color: #666666;
157
+ border-radius: 8px;
158
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
159
+ color: white;
160
+ position: relative;
161
+ z-index: 1;
143
162
  }
144
163
 
145
164
  .chat-close-button:hover,
146
165
  .chat-clear-button:hover {
147
- background-color: #e9ecef;
148
- color: #333333;
166
+ background: rgb(255 255 255 / 25%);
167
+ transform: scale(1.05);
168
+ color: white;
149
169
  }
150
170
 
151
171
  .chat-clear-button:hover {
152
- background-color: #fee;
153
- color: #dc3545;
172
+ background: rgb(255 82 82 / 20%);
173
+ color: #ff6b6b;
154
174
  }
155
175
 
156
176
  .close-icon,
@@ -161,24 +181,29 @@ body.chat-closed .global-header {
161
181
 
162
182
  .chat-title {
163
183
  margin: 0;
164
- font-size: 18px;
165
- font-weight: 600;
166
- color: #333333;
184
+ font-size: 20px;
185
+ font-weight: 700;
186
+ color: white;
167
187
  flex: 1;
188
+ position: relative;
189
+ z-index: 1;
190
+ letter-spacing: -0.02em;
168
191
  }
169
192
 
170
193
  .chat-messages {
171
194
  flex: 1;
172
195
  overflow-y: auto;
173
- padding: 16px;
196
+ padding: 24px 20px;
174
197
  scroll-behavior: smooth;
175
198
  min-height: 0;
199
+ background: linear-gradient(180deg, #fafbfc 0%, #f7f9fb 100%);
176
200
  }
177
201
 
178
202
  .message-wrapper {
179
- margin-bottom: 16px;
203
+ margin-bottom: 20px;
180
204
  display: flex;
181
205
  align-items: flex-start;
206
+ animation: message-slide-in 0.4s cubic-bezier(0.4, 0, 0.2, 1);
182
207
  }
183
208
 
184
209
  .message-wrapper[data-sender="user"] {
@@ -201,35 +226,43 @@ body.chat-closed .global-header {
201
226
  }
202
227
 
203
228
  .message-bubble {
204
- padding: 12px 16px;
205
- border-radius: 18px;
229
+ padding: 14px 18px;
230
+ border-radius: 20px;
206
231
  word-wrap: break-word;
207
232
  max-width: 100%;
233
+ position: relative;
234
+ backdrop-filter: blur(10px);
235
+ box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
208
236
  }
209
237
 
210
238
  .message-wrapper[data-sender="user"] .message-bubble {
211
- background-color: #0066cc;
239
+ background: linear-gradient(135deg, #0176d3 0%, #005fb2 100%);
212
240
  color: white;
241
+ border-bottom-right-radius: 8px;
213
242
  }
214
243
 
215
244
  .message-wrapper[data-sender="assistant"] .message-bubble {
216
- background-color: #f0f0f0;
217
- color: #333333;
245
+ background: white;
246
+ color: #181818;
247
+ border: 1px solid #e5e7ea;
248
+ border-bottom-left-radius: 8px;
218
249
  }
219
250
 
220
251
  .message-text {
221
252
  margin: 0;
222
- line-height: 1.4;
223
- font-size: 14px;
253
+ line-height: 1.5;
254
+ font-size: 15px;
255
+ font-weight: 400;
224
256
  }
225
257
 
226
258
  .message-timestamp {
227
259
  font-size: 12px;
228
- color: #666666;
229
- margin-top: 4px;
260
+ color: #706e6b;
261
+ margin-top: 6px;
230
262
  display: flex;
231
263
  align-items: center;
232
264
  gap: 4px;
265
+ font-weight: 400;
233
266
  }
234
267
 
235
268
  .message-sender {
@@ -252,7 +285,7 @@ body.chat-closed .global-header {
252
285
  width: 8px;
253
286
  height: 8px;
254
287
  border-radius: 50%;
255
- background-color: #666666;
288
+ background-color: #0176d3;
256
289
  animation: typing 1.4s infinite ease-in-out both;
257
290
  }
258
291
 
@@ -265,21 +298,37 @@ body.chat-closed .global-header {
265
298
  }
266
299
 
267
300
  @keyframes typing {
268
- 0%, 80%, 100% {
301
+ 0%,
302
+ 80%,
303
+ 100% {
269
304
  transform: scale(0);
270
305
  opacity: 0.5;
271
306
  }
307
+
272
308
  40% {
273
309
  transform: scale(1);
274
310
  opacity: 1;
275
311
  }
276
312
  }
277
313
 
314
+ @keyframes message-slide-in {
315
+ from {
316
+ opacity: 0;
317
+ transform: translateY(12px);
318
+ }
319
+
320
+ to {
321
+ opacity: 1;
322
+ transform: translateY(0);
323
+ }
324
+ }
325
+
278
326
  .chat-input-area {
279
- border-top: 1px solid #e0e0e0;
280
- padding: 16px;
281
- background-color: #ffffff;
327
+ border-top: 1px solid #e5e7ea;
328
+ padding: 20px 24px;
329
+ background: white;
282
330
  flex-shrink: 0;
331
+ backdrop-filter: blur(20px);
283
332
  }
284
333
 
285
334
  .chat-input-container {
@@ -290,18 +339,22 @@ body.chat-closed .global-header {
290
339
 
291
340
  .chat-input {
292
341
  flex: 1;
293
- padding: 12px 16px;
294
- border: 1px solid #e0e0e0;
295
- border-radius: 20px;
296
- font-size: 14px;
342
+ padding: 14px 18px;
343
+ border: 2px solid #d8dde6;
344
+ border-radius: 24px;
345
+ font-size: 15px;
297
346
  outline: none;
298
- background-color: #f8f9fa;
299
- transition: border-color 0.2s ease;
347
+ background-color: #fafbfc;
348
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
349
+ font-family: inherit;
350
+ line-height: 1.4;
300
351
  }
301
352
 
302
353
  .chat-input:focus {
303
- border-color: #0066cc;
304
- background-color: #ffffff;
354
+ border-color: #0176d3;
355
+ background-color: #fff;
356
+ box-shadow: 0 0 0 3px rgb(1 118 211 / 10%);
357
+ transform: translateY(-1px);
305
358
  }
306
359
 
307
360
  .chat-input:disabled {
@@ -310,26 +363,32 @@ body.chat-closed .global-header {
310
363
  }
311
364
 
312
365
  .chat-send-button {
313
- width: 40px;
314
- height: 40px;
366
+ width: 44px;
367
+ height: 44px;
315
368
  border: none;
316
369
  border-radius: 50%;
317
- background-color: #0066cc;
370
+ background: linear-gradient(135deg, #0176d3 0%, #005fb2 100%);
318
371
  color: white;
319
372
  cursor: pointer;
320
373
  display: flex;
321
374
  align-items: center;
322
375
  justify-content: center;
323
- transition: background-color 0.2s ease;
376
+ transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
377
+ box-shadow: 0 4px 12px rgb(1 118 211 / 25%);
378
+ margin-left: 12px;
324
379
  }
325
380
 
326
381
  .chat-send-button:hover:not(:disabled) {
327
- background-color: #0052a3;
382
+ background: linear-gradient(135deg, #005fb2 0%, #003e73 100%);
383
+ transform: scale(1.05);
384
+ box-shadow: 0 6px 16px rgb(1 118 211 / 35%);
328
385
  }
329
386
 
330
387
  .chat-send-button:disabled {
331
- background-color: #cccccc;
388
+ background: #d8dde6;
332
389
  cursor: not-allowed;
390
+ transform: none;
391
+ box-shadow: none;
333
392
  }
334
393
 
335
394
  .send-icon {
@@ -340,10 +399,10 @@ body.chat-closed .global-header {
340
399
  /* Responsive design */
341
400
  @media (max-width: 768px) {
342
401
  .chat-trigger-button {
343
- width: 50px;
344
- height: 50px;
345
- bottom: 15px;
346
- right: 15px;
402
+ width: 56px;
403
+ height: 56px;
404
+ bottom: 16px;
405
+ right: 16px;
347
406
  }
348
407
 
349
408
  .chat-icon {
@@ -362,12 +421,28 @@ body.chat-closed .global-header {
362
421
  transform: translateX(100%);
363
422
  }
364
423
 
365
- .chat-container--open {
424
+ .chat-container_open {
366
425
  transform: translateX(0);
367
426
  }
368
427
 
428
+ .chat-header {
429
+ padding: 16px 20px;
430
+ }
431
+
432
+ .chat-title {
433
+ font-size: 18px;
434
+ }
435
+
436
+ .chat-messages {
437
+ padding: 20px 16px;
438
+ }
439
+
440
+ .chat-input-area {
441
+ padding: 16px 20px;
442
+ }
443
+
369
444
  .message-content {
370
- max-width: 90%;
445
+ max-width: 85%;
371
446
  }
372
447
  }
373
448
 
@@ -378,29 +453,29 @@ body.chat-closed .global-header {
378
453
  bottom: 10px;
379
454
  right: 10px;
380
455
  }
381
-
456
+
382
457
  .chat-icon {
383
458
  width: 20px;
384
459
  height: 20px;
385
460
  }
386
-
461
+
387
462
  .chat-trigger-text {
388
463
  font-size: 7px;
389
464
  margin-top: 16px;
390
465
  }
391
-
466
+
392
467
  .chat-container {
393
468
  width: 100%;
394
469
  }
395
-
470
+
396
471
  .chat-header {
397
472
  padding: 12px;
398
473
  }
399
-
474
+
400
475
  .chat-messages {
401
476
  padding: 12px;
402
477
  }
403
-
478
+
404
479
  .chat-input-area {
405
480
  padding: 12px;
406
481
  }
@@ -411,11 +486,11 @@ body.chat-closed .global-header {
411
486
  .chat-trigger-button {
412
487
  animation: none;
413
488
  }
414
-
489
+
415
490
  .typing-dot {
416
491
  animation: none;
417
492
  }
418
-
493
+
419
494
  .chat-messages {
420
495
  scroll-behavior: auto;
421
496
  }
@@ -424,17 +499,17 @@ body.chat-closed .global-header {
424
499
  /* High contrast mode support */
425
500
  @media (prefers-contrast: high) {
426
501
  .chat-container {
427
- border: 2px solid #000000;
502
+ border: 2px solid #000;
428
503
  }
429
-
504
+
430
505
  .message-wrapper[data-sender="user"] .message-bubble {
431
- background-color: #000000;
432
- color: #ffffff;
506
+ background-color: #000;
507
+ color: #fff;
433
508
  }
434
-
509
+
435
510
  .message-wrapper[data-sender="assistant"] .message-bubble {
436
- background-color: #ffffff;
437
- color: #000000;
438
- border: 1px solid #000000;
511
+ background-color: #fff;
512
+ color: #000;
513
+ border: 1px solid #000;
439
514
  }
440
- }
515
+ }
@@ -1,13 +1,23 @@
1
1
  <template>
2
2
  <!-- Floating trigger button - visible when chat is closed -->
3
3
  <template lwc:if={showTriggerButton}>
4
- <button
4
+ <button
5
5
  class="chat-trigger-button"
6
6
  onclick={handleOpenClick}
7
7
  aria-label="Open chat"
8
8
  >
9
- <svg class="chat-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
10
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"/>
9
+ <svg
10
+ class="chat-icon"
11
+ viewBox="0 0 24 24"
12
+ fill="none"
13
+ stroke="currentColor"
14
+ >
15
+ <path
16
+ stroke-linecap="round"
17
+ stroke-linejoin="round"
18
+ stroke-width="2"
19
+ d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"
20
+ />
11
21
  </svg>
12
22
  <!-- <span class="chat-trigger-text">Chat</span> -->
13
23
  </button>
@@ -18,31 +28,55 @@
18
28
  <div class="chat-header">
19
29
  <h3 class="chat-title">{title}</h3>
20
30
  <div class="chat-header-actions">
21
- <button
31
+ <button
22
32
  class="chat-clear-button"
23
33
  onclick={handleClearClick}
24
34
  aria-label="Clear chat messages"
25
35
  title="Clear chat messages"
26
36
  >
27
- <svg class="clear-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
28
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/>
37
+ <svg
38
+ class="clear-icon"
39
+ viewBox="0 0 24 24"
40
+ fill="none"
41
+ stroke="currentColor"
42
+ >
43
+ <path
44
+ stroke-linecap="round"
45
+ stroke-linejoin="round"
46
+ stroke-width="2"
47
+ d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"
48
+ />
29
49
  </svg>
30
50
  </button>
31
- <button
51
+ <button
32
52
  class="chat-close-button"
33
53
  onclick={handleCloseClick}
34
54
  aria-label="Close chat"
35
55
  >
36
- <svg class="close-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
37
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
56
+ <svg
57
+ class="close-icon"
58
+ viewBox="0 0 24 24"
59
+ fill="none"
60
+ stroke="currentColor"
61
+ >
62
+ <path
63
+ stroke-linecap="round"
64
+ stroke-linejoin="round"
65
+ stroke-width="2"
66
+ d="M6 18L18 6M6 6l12 12"
67
+ />
38
68
  </svg>
39
69
  </button>
40
70
  </div>
41
71
  </div>
42
-
72
+
43
73
  <div class="chat-messages">
44
74
  <template for:each={messagesWithTyping} for:item="message">
45
- <div key={message.id} class="message-wrapper" data-sender={message.sender}>
75
+ <div
76
+ key={message.id}
77
+ class="message-wrapper"
78
+ data-sender={message.sender}
79
+ >
46
80
  <div class="message-content">
47
81
  <div class="message-bubble">
48
82
  <template lwc:if={message.isTyping}>
@@ -72,29 +106,39 @@
72
106
  </div>
73
107
  </template>
74
108
  </div>
75
-
109
+
76
110
  <div class="chat-input-area">
77
111
  <div class="chat-input-container">
78
- <input
79
- type="text"
80
- class="chat-input"
112
+ <input
113
+ type="text"
114
+ class="chat-input"
81
115
  placeholder={placeholder}
82
116
  value={currentMessage}
83
117
  oninput={handleInputChange}
84
118
  onkeydown={handleKeyDown}
85
119
  disabled={disabled}
86
120
  />
87
- <button
121
+ <button
88
122
  class="chat-send-button"
89
123
  onclick={handleSendClick}
90
124
  disabled={sendButtonDisabled}
91
125
  aria-label="Send message"
92
126
  >
93
- <svg class="send-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
94
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"/>
127
+ <svg
128
+ class="send-icon"
129
+ viewBox="0 0 24 24"
130
+ fill="none"
131
+ stroke="currentColor"
132
+ >
133
+ <path
134
+ stroke-linecap="round"
135
+ stroke-linejoin="round"
136
+ stroke-width="2"
137
+ d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8"
138
+ />
95
139
  </svg>
96
140
  </button>
97
141
  </div>
98
142
  </div>
99
143
  </div>
100
- </template>
144
+ </template>
@@ -16,7 +16,7 @@ export default class Chat extends LightningElement {
16
16
  @api placeholder: string = "Type your message...";
17
17
  @api assistantName: string = "Assistant";
18
18
  @api maxHeight: string = "400px";
19
-
19
+
20
20
  @api
21
21
  get disabled() {
22
22
  return this._disabled;
@@ -47,42 +47,42 @@ export default class Chat extends LightningElement {
47
47
  @track messages: ChatMessage[] = [];
48
48
  @track currentMessage: string = "";
49
49
  @track isAssistantTyping: boolean = false;
50
-
50
+
51
51
  private _disabled: boolean = false;
52
52
  private _showTimestamp: boolean = false;
53
53
  private _isOpen: boolean = false;
54
54
  private messageIdCounter: number = 0;
55
-
55
+
56
56
  // localStorage keys for persisting messages and open state
57
- private static readonly STORAGE_KEY = 'doc-chat-messages';
58
- private static readonly OPEN_STATE_KEY = 'doc-chat-should-open';
57
+ private static readonly STORAGE_KEY = "doc-chat-messages";
58
+ private static readonly OPEN_STATE_KEY = "doc-chat-should-open";
59
59
 
60
60
  connectedCallback() {
61
61
  // Load existing messages from localStorage
62
62
  this.loadMessages();
63
-
63
+
64
64
  // Add welcome message only if no existing messages
65
65
  if (this.messages.length === 0) {
66
66
  this.addMessage("Hello! How can I help you today?", "assistant");
67
67
  }
68
-
68
+
69
69
  // Check if chat should be opened after reload
70
70
  this.checkAndOpenAfterReload();
71
-
71
+
72
72
  // Ensure body has proper class state
73
73
  this.updateBodyClass();
74
74
  }
75
75
 
76
76
  disconnectedCallback() {
77
77
  // Clean up body classes when component is destroyed
78
- document.body.classList.remove('chat-open', 'chat-closed');
78
+ document.body.classList.remove("chat-open", "chat-closed");
79
79
  }
80
80
 
81
81
  get chatContainerClass() {
82
82
  return cx(
83
83
  "chat-container",
84
- this.disabled && "chat-container--disabled",
85
- this.isOpen && "chat-container--open"
84
+ this.disabled && "chat-container_disabled",
85
+ this.isOpen && "chat-container_open"
86
86
  );
87
87
  }
88
88
 
@@ -123,7 +123,8 @@ export default class Chat extends LightningElement {
123
123
  private scrollToBottom() {
124
124
  // Use setTimeout to ensure DOM is updated
125
125
  setTimeout(() => {
126
- const messagesContainer = this.template.querySelector('.chat-messages');
126
+ const messagesContainer =
127
+ this.template.querySelector(".chat-messages");
127
128
  if (messagesContainer) {
128
129
  messagesContainer.scrollTop = messagesContainer.scrollHeight;
129
130
  }
@@ -133,26 +134,29 @@ export default class Chat extends LightningElement {
133
134
  private updateBodyClass() {
134
135
  // Update body classes to trigger content shift
135
136
  if (this.isOpen) {
136
- document.body.classList.remove('chat-closed');
137
- document.body.classList.add('chat-open');
137
+ document.body.classList.remove("chat-closed");
138
+ document.body.classList.add("chat-open");
138
139
  } else {
139
- document.body.classList.remove('chat-open');
140
- document.body.classList.add('chat-closed');
140
+ document.body.classList.remove("chat-open");
141
+ document.body.classList.add("chat-closed");
141
142
  }
142
143
  }
143
144
 
144
145
  private saveMessages() {
145
146
  try {
146
- const messagesToSave = this.messages.map(msg => ({
147
+ const messagesToSave = this.messages.map((msg) => ({
147
148
  id: msg.id,
148
149
  text: msg.text,
149
150
  timestamp: msg.timestamp.toISOString(),
150
151
  sender: msg.sender,
151
152
  formattedTime: msg.formattedTime
152
153
  }));
153
- localStorage.setItem(Chat.STORAGE_KEY, JSON.stringify(messagesToSave));
154
+ localStorage.setItem(
155
+ Chat.STORAGE_KEY,
156
+ JSON.stringify(messagesToSave)
157
+ );
154
158
  } catch (error) {
155
- console.warn('Failed to save messages to localStorage:', error);
159
+ console.warn("Failed to save messages to localStorage:", error);
156
160
  }
157
161
  }
158
162
 
@@ -168,14 +172,22 @@ export default class Chat extends LightningElement {
168
172
  sender: msg.sender,
169
173
  formattedTime: msg.formattedTime
170
174
  }));
171
-
175
+
172
176
  // Update message counter to avoid ID conflicts
173
- const lastId = this.messages.length > 0 ?
174
- Math.max(...this.messages.map(m => parseInt(m.id.replace('msg-', '')) || 0)) : 0;
177
+ const lastId =
178
+ this.messages.length > 0
179
+ ? Math.max(
180
+ ...this.messages.map(
181
+ (m) =>
182
+ parseInt(m.id.replace("msg-", ""), 10) ||
183
+ 0
184
+ )
185
+ )
186
+ : 0;
175
187
  this.messageIdCounter = lastId + 1;
176
188
  }
177
189
  } catch (error) {
178
- console.warn('Failed to load messages from localStorage:', error);
190
+ console.warn("Failed to load messages from localStorage:", error);
179
191
  this.messages = [];
180
192
  }
181
193
  }
@@ -188,27 +200,32 @@ export default class Chat extends LightningElement {
188
200
  // Add welcome message after clearing
189
201
  this.addMessage("Hello! How can I help you today?", "assistant");
190
202
  } catch (error) {
191
- console.warn('Failed to clear messages from localStorage:', error);
203
+ console.warn("Failed to clear messages from localStorage:", error);
192
204
  }
193
205
  }
194
206
 
195
207
  private checkAndOpenAfterReload() {
196
208
  try {
197
209
  const shouldOpen = localStorage.getItem(Chat.OPEN_STATE_KEY);
198
- if (shouldOpen === 'true') {
210
+ if (shouldOpen === "true") {
199
211
  // Clear the flag
200
212
  localStorage.removeItem(Chat.OPEN_STATE_KEY);
201
213
  // Open the chat
202
- this.isOpen = true;
214
+ this._isOpen = true;
203
215
  this.updateBodyClass();
204
-
216
+
205
217
  // Dispatch custom event to notify parent components
206
- this.dispatchEvent(new CustomEvent('chatopened', {
207
- detail: { opened: true }
208
- }));
218
+ this.dispatchEvent(
219
+ new CustomEvent("chatopened", {
220
+ detail: { opened: true }
221
+ })
222
+ );
209
223
  }
210
224
  } catch (error) {
211
- console.warn('Failed to check open state from localStorage:', error);
225
+ console.warn(
226
+ "Failed to check open state from localStorage:",
227
+ error
228
+ );
212
229
  }
213
230
  }
214
231
 
@@ -218,7 +235,7 @@ export default class Chat extends LightningElement {
218
235
  }
219
236
 
220
237
  handleKeyDown(event: KeyboardEvent) {
221
- if (event.key === 'Enter' && !event.shiftKey) {
238
+ if (event.key === "Enter" && !event.shiftKey) {
222
239
  event.preventDefault();
223
240
  this.sendMessage();
224
241
  }
@@ -239,14 +256,16 @@ export default class Chat extends LightningElement {
239
256
  this.currentMessage = "";
240
257
 
241
258
  // Clear input
242
- const input = this.template.querySelector('.chat-input') as HTMLInputElement;
259
+ const input = this.template.querySelector(
260
+ ".chat-input"
261
+ ) as HTMLInputElement;
243
262
  if (input) {
244
263
  input.value = "";
245
264
  }
246
265
 
247
266
  // Simulate assistant typing
248
267
  this.isAssistantTyping = true;
249
-
268
+
250
269
  // Simulate assistant response after a delay
251
270
  setTimeout(() => {
252
271
  this.isAssistantTyping = false;
@@ -257,22 +276,34 @@ export default class Chat extends LightningElement {
257
276
  private simulateAssistantResponse(userMessage: string) {
258
277
  // Simple response simulation - in a real implementation, this would call an API
259
278
  let response = `I received your message: "${userMessage}". `;
260
-
261
- if (userMessage.toLowerCase().includes("hello") || userMessage.toLowerCase().includes("hi")) {
279
+
280
+ if (
281
+ userMessage.toLowerCase().includes("hello") ||
282
+ userMessage.toLowerCase().includes("hi")
283
+ ) {
262
284
  response = "Hello! Nice to meet you. How can I assist you today?";
263
285
  } else if (userMessage.toLowerCase().includes("help")) {
264
- response = "I'm here to help! Feel free to ask me any questions about the documentation or topics you're interested in.";
265
- } else if (userMessage.toLowerCase().includes("documentation") || userMessage.toLowerCase().includes("docs")) {
266
- response = "I can help you navigate the documentation. What specific topic are you looking for?";
286
+ response =
287
+ "I'm here to help! Feel free to ask me any questions about the documentation or topics you're interested in.";
288
+ } else if (
289
+ userMessage.toLowerCase().includes("documentation") ||
290
+ userMessage.toLowerCase().includes("docs")
291
+ ) {
292
+ response =
293
+ "I can help you navigate the documentation. What specific topic are you looking for?";
267
294
  } else {
268
- response = "That's an interesting question. Let me help you with that. Could you provide more details about what you're looking for?";
295
+ response =
296
+ "That's an interesting question. Let me help you with that. Could you provide more details about what you're looking for?";
269
297
  }
270
298
 
271
299
  this.addMessage(response, "assistant");
272
300
  }
273
301
 
274
302
  formatTimestamp(timestamp: Date) {
275
- return timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
303
+ return timestamp.toLocaleTimeString([], {
304
+ hour: "2-digit",
305
+ minute: "2-digit"
306
+ });
276
307
  }
277
308
 
278
309
  get sendButtonDisabled() {
@@ -280,32 +311,35 @@ export default class Chat extends LightningElement {
280
311
  }
281
312
 
282
313
  handleCloseClick() {
283
- this.isOpen = false;
314
+ this._isOpen = false;
284
315
  this.updateBodyClass();
285
-
316
+
286
317
  // Dispatch custom event to notify parent components
287
- this.dispatchEvent(new CustomEvent('chatclosed', {
288
- detail: { closed: true }
289
- }));
318
+ this.dispatchEvent(
319
+ new CustomEvent("chatclosed", {
320
+ detail: { closed: true }
321
+ })
322
+ );
290
323
  }
291
324
 
292
325
  handleClearClick() {
293
326
  this.clearMessages();
294
-
327
+
295
328
  // Dispatch custom event to notify parent components
296
- this.dispatchEvent(new CustomEvent('chatcleared', {
297
- detail: { cleared: true }
298
- }));
329
+ this.dispatchEvent(
330
+ new CustomEvent("chatcleared", {
331
+ detail: { cleared: true }
332
+ })
333
+ );
299
334
  }
300
335
 
301
336
  handleOpenClick() {
302
337
  try {
303
338
  // Set flag to open chat after reload
304
- localStorage.setItem(Chat.OPEN_STATE_KEY, 'true');
339
+ localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
305
340
  } catch (error) {
306
- console.warn('Failed to set open state in localStorage:', error);
341
+ console.warn("Failed to set open state in localStorage:", error);
307
342
  }
308
-
309
343
  // Hard reload the page to clear cache when opening chat
310
344
  window.location.reload();
311
345
  }
@@ -313,22 +347,24 @@ export default class Chat extends LightningElement {
313
347
  openChat() {
314
348
  try {
315
349
  // Set flag to open chat after reload
316
- localStorage.setItem(Chat.OPEN_STATE_KEY, 'true');
350
+ localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
317
351
  } catch (error) {
318
- console.warn('Failed to set open state in localStorage:', error);
352
+ console.warn("Failed to set open state in localStorage:", error);
319
353
  }
320
-
354
+
321
355
  // Hard reload the page to clear cache when opening chat
322
356
  window.location.reload();
323
357
  }
324
358
 
325
359
  closeChat() {
326
- this.isOpen = false;
360
+ this._isOpen = false;
327
361
  this.updateBodyClass();
328
-
362
+
329
363
  // Dispatch custom event to notify parent components
330
- this.dispatchEvent(new CustomEvent('chatclosed', {
331
- detail: { closed: true }
332
- }));
364
+ this.dispatchEvent(
365
+ new CustomEvent("chatclosed", {
366
+ detail: { closed: true }
367
+ })
368
+ );
333
369
  }
334
- }
370
+ }