@salesforcedevs/docs-components 0.0.31-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.31-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,38 +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
-
56
- // localStorage key for persisting messages
57
- private static readonly STORAGE_KEY = 'doc-chat-messages';
55
+
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";
58
59
 
59
60
  connectedCallback() {
60
61
  // Load existing messages from localStorage
61
62
  this.loadMessages();
62
-
63
+
63
64
  // Add welcome message only if no existing messages
64
65
  if (this.messages.length === 0) {
65
66
  this.addMessage("Hello! How can I help you today?", "assistant");
66
67
  }
67
-
68
+
69
+ // Check if chat should be opened after reload
70
+ this.checkAndOpenAfterReload();
71
+
68
72
  // Ensure body has proper class state
69
73
  this.updateBodyClass();
70
74
  }
71
75
 
72
76
  disconnectedCallback() {
73
77
  // Clean up body classes when component is destroyed
74
- document.body.classList.remove('chat-open', 'chat-closed');
78
+ document.body.classList.remove("chat-open", "chat-closed");
75
79
  }
76
80
 
77
81
  get chatContainerClass() {
78
82
  return cx(
79
83
  "chat-container",
80
- this.disabled && "chat-container--disabled",
81
- this.isOpen && "chat-container--open"
84
+ this.disabled && "chat-container_disabled",
85
+ this.isOpen && "chat-container_open"
82
86
  );
83
87
  }
84
88
 
@@ -119,7 +123,8 @@ export default class Chat extends LightningElement {
119
123
  private scrollToBottom() {
120
124
  // Use setTimeout to ensure DOM is updated
121
125
  setTimeout(() => {
122
- const messagesContainer = this.template.querySelector('.chat-messages');
126
+ const messagesContainer =
127
+ this.template.querySelector(".chat-messages");
123
128
  if (messagesContainer) {
124
129
  messagesContainer.scrollTop = messagesContainer.scrollHeight;
125
130
  }
@@ -129,26 +134,29 @@ export default class Chat extends LightningElement {
129
134
  private updateBodyClass() {
130
135
  // Update body classes to trigger content shift
131
136
  if (this.isOpen) {
132
- document.body.classList.remove('chat-closed');
133
- document.body.classList.add('chat-open');
137
+ document.body.classList.remove("chat-closed");
138
+ document.body.classList.add("chat-open");
134
139
  } else {
135
- document.body.classList.remove('chat-open');
136
- document.body.classList.add('chat-closed');
140
+ document.body.classList.remove("chat-open");
141
+ document.body.classList.add("chat-closed");
137
142
  }
138
143
  }
139
144
 
140
145
  private saveMessages() {
141
146
  try {
142
- const messagesToSave = this.messages.map(msg => ({
147
+ const messagesToSave = this.messages.map((msg) => ({
143
148
  id: msg.id,
144
149
  text: msg.text,
145
150
  timestamp: msg.timestamp.toISOString(),
146
151
  sender: msg.sender,
147
152
  formattedTime: msg.formattedTime
148
153
  }));
149
- localStorage.setItem(Chat.STORAGE_KEY, JSON.stringify(messagesToSave));
154
+ localStorage.setItem(
155
+ Chat.STORAGE_KEY,
156
+ JSON.stringify(messagesToSave)
157
+ );
150
158
  } catch (error) {
151
- console.warn('Failed to save messages to localStorage:', error);
159
+ console.warn("Failed to save messages to localStorage:", error);
152
160
  }
153
161
  }
154
162
 
@@ -164,14 +172,22 @@ export default class Chat extends LightningElement {
164
172
  sender: msg.sender,
165
173
  formattedTime: msg.formattedTime
166
174
  }));
167
-
175
+
168
176
  // Update message counter to avoid ID conflicts
169
- const lastId = this.messages.length > 0 ?
170
- 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;
171
187
  this.messageIdCounter = lastId + 1;
172
188
  }
173
189
  } catch (error) {
174
- console.warn('Failed to load messages from localStorage:', error);
190
+ console.warn("Failed to load messages from localStorage:", error);
175
191
  this.messages = [];
176
192
  }
177
193
  }
@@ -184,7 +200,32 @@ export default class Chat extends LightningElement {
184
200
  // Add welcome message after clearing
185
201
  this.addMessage("Hello! How can I help you today?", "assistant");
186
202
  } catch (error) {
187
- console.warn('Failed to clear messages from localStorage:', error);
203
+ console.warn("Failed to clear messages from localStorage:", error);
204
+ }
205
+ }
206
+
207
+ private checkAndOpenAfterReload() {
208
+ try {
209
+ const shouldOpen = localStorage.getItem(Chat.OPEN_STATE_KEY);
210
+ if (shouldOpen === "true") {
211
+ // Clear the flag
212
+ localStorage.removeItem(Chat.OPEN_STATE_KEY);
213
+ // Open the chat
214
+ this._isOpen = true;
215
+ this.updateBodyClass();
216
+
217
+ // Dispatch custom event to notify parent components
218
+ this.dispatchEvent(
219
+ new CustomEvent("chatopened", {
220
+ detail: { opened: true }
221
+ })
222
+ );
223
+ }
224
+ } catch (error) {
225
+ console.warn(
226
+ "Failed to check open state from localStorage:",
227
+ error
228
+ );
188
229
  }
189
230
  }
190
231
 
@@ -194,7 +235,7 @@ export default class Chat extends LightningElement {
194
235
  }
195
236
 
196
237
  handleKeyDown(event: KeyboardEvent) {
197
- if (event.key === 'Enter' && !event.shiftKey) {
238
+ if (event.key === "Enter" && !event.shiftKey) {
198
239
  event.preventDefault();
199
240
  this.sendMessage();
200
241
  }
@@ -215,14 +256,16 @@ export default class Chat extends LightningElement {
215
256
  this.currentMessage = "";
216
257
 
217
258
  // Clear input
218
- const input = this.template.querySelector('.chat-input') as HTMLInputElement;
259
+ const input = this.template.querySelector(
260
+ ".chat-input"
261
+ ) as HTMLInputElement;
219
262
  if (input) {
220
263
  input.value = "";
221
264
  }
222
265
 
223
266
  // Simulate assistant typing
224
267
  this.isAssistantTyping = true;
225
-
268
+
226
269
  // Simulate assistant response after a delay
227
270
  setTimeout(() => {
228
271
  this.isAssistantTyping = false;
@@ -233,22 +276,34 @@ export default class Chat extends LightningElement {
233
276
  private simulateAssistantResponse(userMessage: string) {
234
277
  // Simple response simulation - in a real implementation, this would call an API
235
278
  let response = `I received your message: "${userMessage}". `;
236
-
237
- if (userMessage.toLowerCase().includes("hello") || userMessage.toLowerCase().includes("hi")) {
279
+
280
+ if (
281
+ userMessage.toLowerCase().includes("hello") ||
282
+ userMessage.toLowerCase().includes("hi")
283
+ ) {
238
284
  response = "Hello! Nice to meet you. How can I assist you today?";
239
285
  } else if (userMessage.toLowerCase().includes("help")) {
240
- response = "I'm here to help! Feel free to ask me any questions about the documentation or topics you're interested in.";
241
- } else if (userMessage.toLowerCase().includes("documentation") || userMessage.toLowerCase().includes("docs")) {
242
- 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?";
243
294
  } else {
244
- 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?";
245
297
  }
246
298
 
247
299
  this.addMessage(response, "assistant");
248
300
  }
249
301
 
250
302
  formatTimestamp(timestamp: Date) {
251
- return timestamp.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
303
+ return timestamp.toLocaleTimeString([], {
304
+ hour: "2-digit",
305
+ minute: "2-digit"
306
+ });
252
307
  }
253
308
 
254
309
  get sendButtonDisabled() {
@@ -256,51 +311,60 @@ export default class Chat extends LightningElement {
256
311
  }
257
312
 
258
313
  handleCloseClick() {
259
- this.isOpen = false;
314
+ this._isOpen = false;
260
315
  this.updateBodyClass();
261
-
316
+
262
317
  // Dispatch custom event to notify parent components
263
- this.dispatchEvent(new CustomEvent('chatclosed', {
264
- detail: { closed: true }
265
- }));
318
+ this.dispatchEvent(
319
+ new CustomEvent("chatclosed", {
320
+ detail: { closed: true }
321
+ })
322
+ );
266
323
  }
267
324
 
268
325
  handleClearClick() {
269
326
  this.clearMessages();
270
-
327
+
271
328
  // Dispatch custom event to notify parent components
272
- this.dispatchEvent(new CustomEvent('chatcleared', {
273
- detail: { cleared: true }
274
- }));
329
+ this.dispatchEvent(
330
+ new CustomEvent("chatcleared", {
331
+ detail: { cleared: true }
332
+ })
333
+ );
275
334
  }
276
335
 
277
336
  handleOpenClick() {
278
- this.isOpen = true;
279
- this.updateBodyClass();
280
-
281
- // Dispatch custom event to notify parent components
282
- this.dispatchEvent(new CustomEvent('chatopened', {
283
- detail: { opened: true }
284
- }));
337
+ try {
338
+ // Set flag to open chat after reload
339
+ localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
340
+ } catch (error) {
341
+ console.warn("Failed to set open state in localStorage:", error);
342
+ }
343
+ // Hard reload the page to clear cache when opening chat
344
+ window.location.reload();
285
345
  }
286
346
 
287
347
  openChat() {
288
- this.isOpen = true;
289
- this.updateBodyClass();
290
-
291
- // Dispatch custom event to notify parent components
292
- this.dispatchEvent(new CustomEvent('chatopened', {
293
- detail: { opened: true }
294
- }));
348
+ try {
349
+ // Set flag to open chat after reload
350
+ localStorage.setItem(Chat.OPEN_STATE_KEY, "true");
351
+ } catch (error) {
352
+ console.warn("Failed to set open state in localStorage:", error);
353
+ }
354
+
355
+ // Hard reload the page to clear cache when opening chat
356
+ window.location.reload();
295
357
  }
296
358
 
297
359
  closeChat() {
298
- this.isOpen = false;
360
+ this._isOpen = false;
299
361
  this.updateBodyClass();
300
-
362
+
301
363
  // Dispatch custom event to notify parent components
302
- this.dispatchEvent(new CustomEvent('chatclosed', {
303
- detail: { closed: true }
304
- }));
364
+ this.dispatchEvent(
365
+ new CustomEvent("chatclosed", {
366
+ detail: { closed: true }
367
+ })
368
+ );
305
369
  }
306
- }
370
+ }