mini-chat-bot-widget 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chat-widget.esm.js +207 -10
- package/dist/chat-widget.esm.min.js +1 -1
- package/dist/chat-widget.umd.js +207 -10
- package/dist/chat-widget.umd.min.js +1 -1
- package/package.json +1 -1
- package/src/audio-chat-screen.js +193 -3
- package/src/chat-widget.js +8 -2
- package/src/text-chat-screen.js +184 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mini-chat-bot-widget",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "A tiny chat bot widget fixed at bottom right, distributable via npm and usable with a <script> tag.",
|
|
5
5
|
"main": "dist/chat-widget.umd.js",
|
|
6
6
|
"module": "dist/chat-widget.esm.js",
|
package/src/audio-chat-screen.js
CHANGED
|
@@ -464,7 +464,9 @@ class AudioChatScreen {
|
|
|
464
464
|
// Update existing message
|
|
465
465
|
const bubble = existingMessage.querySelector(".message-bubble");
|
|
466
466
|
if (bubble) {
|
|
467
|
-
|
|
467
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
468
|
+
const content = messageData.content || text;
|
|
469
|
+
bubble.innerHTML = !isUser ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
468
470
|
}
|
|
469
471
|
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
470
472
|
return;
|
|
@@ -526,10 +528,13 @@ class AudioChatScreen {
|
|
|
526
528
|
const timestamp = messageData?.timestamp ? new Date(messageData.timestamp) : new Date();
|
|
527
529
|
const formattedTime = this._formatTime(timestamp);
|
|
528
530
|
|
|
531
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
532
|
+
const renderedContent = !isUser ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
533
|
+
|
|
529
534
|
messageEl.innerHTML = `
|
|
530
535
|
<div class="message-content">
|
|
531
536
|
${attachmentsHTML}
|
|
532
|
-
<div class="message-bubble">${
|
|
537
|
+
<div class="message-bubble">${renderedContent}</div>
|
|
533
538
|
<div class="message-time">${formattedTime}</div>
|
|
534
539
|
</div>
|
|
535
540
|
`;
|
|
@@ -586,7 +591,10 @@ class AudioChatScreen {
|
|
|
586
591
|
if (existingEl) {
|
|
587
592
|
const bubble = existingEl.querySelector(".message-bubble");
|
|
588
593
|
if (bubble) {
|
|
589
|
-
|
|
594
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
595
|
+
const content = msg.content || "";
|
|
596
|
+
const isUserMessage = msg.sender === "user";
|
|
597
|
+
bubble.innerHTML = !isUserMessage ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
590
598
|
}
|
|
591
599
|
|
|
592
600
|
// Update attachments if they exist
|
|
@@ -687,6 +695,106 @@ class AudioChatScreen {
|
|
|
687
695
|
return div.innerHTML;
|
|
688
696
|
}
|
|
689
697
|
|
|
698
|
+
// Parse markdown to HTML
|
|
699
|
+
_parseMarkdown(text) {
|
|
700
|
+
if (!text || typeof text !== 'string') return '';
|
|
701
|
+
|
|
702
|
+
let html = text;
|
|
703
|
+
|
|
704
|
+
// Escape HTML first to prevent XSS
|
|
705
|
+
html = html
|
|
706
|
+
.replace(/&/g, '&')
|
|
707
|
+
.replace(/</g, '<')
|
|
708
|
+
.replace(/>/g, '>');
|
|
709
|
+
|
|
710
|
+
// Split into lines for processing
|
|
711
|
+
const lines = html.split('\n');
|
|
712
|
+
const processedLines = [];
|
|
713
|
+
let inList = false;
|
|
714
|
+
|
|
715
|
+
for (let i = 0; i < lines.length; i++) {
|
|
716
|
+
let line = lines[i];
|
|
717
|
+
|
|
718
|
+
// Check for headers first (#, ##, ###, etc.)
|
|
719
|
+
const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
720
|
+
if (headerMatch) {
|
|
721
|
+
if (inList) {
|
|
722
|
+
processedLines.push('</ul>');
|
|
723
|
+
inList = false;
|
|
724
|
+
}
|
|
725
|
+
const level = headerMatch[1].length;
|
|
726
|
+
const headerText = headerMatch[2];
|
|
727
|
+
// Process markdown inside header
|
|
728
|
+
let processedHeader = headerText;
|
|
729
|
+
processedHeader = processedHeader.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
730
|
+
processedHeader = processedHeader.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
731
|
+
processedHeader = processedHeader.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
732
|
+
processedHeader = processedHeader.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
733
|
+
processedLines.push(`<h${level}>${processedHeader}</h${level}>`);
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Check if this is a list item (before processing bold/italic)
|
|
738
|
+
const listMatch = line.match(/^[\s]*[-*]\s+(.+)$/);
|
|
739
|
+
|
|
740
|
+
if (listMatch) {
|
|
741
|
+
// Process markdown inside list item
|
|
742
|
+
let listContent = listMatch[1];
|
|
743
|
+
|
|
744
|
+
// Bold: **text** (must be processed before italic)
|
|
745
|
+
listContent = listContent.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
746
|
+
listContent = listContent.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
747
|
+
|
|
748
|
+
// Italic: *text* (single asterisk, avoid matching **text**)
|
|
749
|
+
listContent = listContent.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
750
|
+
listContent = listContent.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
751
|
+
|
|
752
|
+
if (!inList) {
|
|
753
|
+
processedLines.push('<ul>');
|
|
754
|
+
inList = true;
|
|
755
|
+
}
|
|
756
|
+
processedLines.push(`<li>${listContent}</li>`);
|
|
757
|
+
} else {
|
|
758
|
+
if (inList) {
|
|
759
|
+
processedLines.push('</ul>');
|
|
760
|
+
inList = false;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
// Skip empty lines (they'll become <br> later)
|
|
764
|
+
if (line.trim() === '') {
|
|
765
|
+
processedLines.push('');
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Process markdown in non-list lines
|
|
770
|
+
// Bold: **text** (must be processed before italic)
|
|
771
|
+
line = line.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
772
|
+
line = line.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
773
|
+
|
|
774
|
+
// Italic: *text* (single asterisk, avoid matching **text**)
|
|
775
|
+
line = line.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
776
|
+
line = line.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
777
|
+
|
|
778
|
+
// Inline code: `code`
|
|
779
|
+
line = line.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
780
|
+
|
|
781
|
+
// Links: [text](url)
|
|
782
|
+
line = line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
|
|
783
|
+
|
|
784
|
+
processedLines.push(line);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
if (inList) {
|
|
789
|
+
processedLines.push('</ul>');
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// Join lines with <br> and return
|
|
793
|
+
html = processedLines.join('<br>');
|
|
794
|
+
|
|
795
|
+
return html;
|
|
796
|
+
}
|
|
797
|
+
|
|
690
798
|
// Show expanded image modal (mirrors TextChatScreen)
|
|
691
799
|
showExpandedImage(src, alt) {
|
|
692
800
|
const existingModal = document.querySelector(".expanded-image-modal");
|
|
@@ -1102,6 +1210,88 @@ class AudioChatScreen {
|
|
|
1102
1210
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
1103
1211
|
}
|
|
1104
1212
|
|
|
1213
|
+
/* Markdown styles */
|
|
1214
|
+
.audio-chat-screen .message-bubble strong {
|
|
1215
|
+
font-weight: 600;
|
|
1216
|
+
color: inherit;
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
.audio-chat-screen .message-bubble em {
|
|
1220
|
+
font-style: italic;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.audio-chat-screen .message-bubble ul {
|
|
1224
|
+
margin: 0px 0;
|
|
1225
|
+
padding-left: 20px;
|
|
1226
|
+
list-style-type: disc;
|
|
1227
|
+
margin-bottom:0px;
|
|
1228
|
+
margin-top:5px;
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
.audio-chat-screen .message-bubble li {
|
|
1232
|
+
margin: 0;
|
|
1233
|
+
line-height: 1.1;
|
|
1234
|
+
padding-left: 3px;
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
.audio-chat-screen .message-bubble h1,
|
|
1238
|
+
.audio-chat-screen .message-bubble h2,
|
|
1239
|
+
.audio-chat-screen .message-bubble h3,
|
|
1240
|
+
.audio-chat-screen .message-bubble h4,
|
|
1241
|
+
.audio-chat-screen .message-bubble h5,
|
|
1242
|
+
.audio-chat-screen .message-bubble h6 {
|
|
1243
|
+
margin: 0px 0 0px 0;
|
|
1244
|
+
font-weight: 600;
|
|
1245
|
+
color: inherit;
|
|
1246
|
+
line-height: 1.3;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
.audio-chat-screen .message-bubble h1 {
|
|
1250
|
+
font-size: 1.5em;
|
|
1251
|
+
}
|
|
1252
|
+
|
|
1253
|
+
.audio-chat-screen .message-bubble h2 {
|
|
1254
|
+
font-size: 1.3em;
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
.audio-chat-screen .message-bubble h3 {
|
|
1258
|
+
font-size: 1.15em;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
.audio-chat-screen .message-bubble h4 {
|
|
1262
|
+
font-size: 1.05em;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
.audio-chat-screen .message-bubble h5 {
|
|
1266
|
+
font-size: 1em;
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
.audio-chat-screen .message-bubble h6 {
|
|
1270
|
+
font-size: 0.95em;
|
|
1271
|
+
}
|
|
1272
|
+
|
|
1273
|
+
.audio-chat-screen .message-bubble code {
|
|
1274
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1275
|
+
padding: 2px 6px;
|
|
1276
|
+
border-radius: 4px;
|
|
1277
|
+
font-family: 'Courier New', Courier, monospace;
|
|
1278
|
+
font-size: 0.9em;
|
|
1279
|
+
}
|
|
1280
|
+
|
|
1281
|
+
.audio-chat-screen .message-bubble a {
|
|
1282
|
+
color: ${this.primaryColor};
|
|
1283
|
+
text-decoration: underline;
|
|
1284
|
+
}
|
|
1285
|
+
|
|
1286
|
+
.audio-chat-screen .message-bubble a:hover {
|
|
1287
|
+
opacity: 0.8;
|
|
1288
|
+
}
|
|
1289
|
+
|
|
1290
|
+
.audio-chat-screen .message-bubble br {
|
|
1291
|
+
line-height: 0.1; /* Adjust between 0 and 1 */
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
|
|
1105
1295
|
.audio-chat-screen .message-time {
|
|
1106
1296
|
font-size: 10px;
|
|
1107
1297
|
color: #94a3b8;
|
package/src/chat-widget.js
CHANGED
|
@@ -22,9 +22,10 @@ class ChatWidget {
|
|
|
22
22
|
this.threadId = options.threadId || null;
|
|
23
23
|
this.assistantId = options.assistantId || null;
|
|
24
24
|
this.selectedLanguage = options.selectedLanguage || "en";
|
|
25
|
-
this.accessToken = options.accessToken || "
|
|
26
|
-
this.supabaseToken = options.supabaseToken || "
|
|
25
|
+
this.accessToken = options.accessToken || "";
|
|
26
|
+
this.supabaseToken = options.supabaseToken || "";
|
|
27
27
|
this.userInfo = options.userInfo || {};
|
|
28
|
+
this.mcpServerUrl = options.mcpServerUrl || "http://localhost:8010/mcp";
|
|
28
29
|
// Store the custom getHeaders function or use default
|
|
29
30
|
this._customGetHeaders = options.getHeaders;
|
|
30
31
|
|
|
@@ -106,6 +107,9 @@ class ChatWidget {
|
|
|
106
107
|
}
|
|
107
108
|
}
|
|
108
109
|
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
|
|
109
113
|
_init() {
|
|
110
114
|
// Create container
|
|
111
115
|
this.container = document.createElement("div");
|
|
@@ -157,6 +161,7 @@ class ChatWidget {
|
|
|
157
161
|
this._renderScreen();
|
|
158
162
|
this._populateLanguageOptions();
|
|
159
163
|
this._bindEvents();
|
|
164
|
+
|
|
160
165
|
}
|
|
161
166
|
|
|
162
167
|
_applyStyles() {
|
|
@@ -1262,6 +1267,7 @@ class ChatWidget {
|
|
|
1262
1267
|
return;
|
|
1263
1268
|
}
|
|
1264
1269
|
|
|
1270
|
+
|
|
1265
1271
|
console.log(
|
|
1266
1272
|
"📤 Sending text message - Language:",
|
|
1267
1273
|
this.selectedLanguage,
|
package/src/text-chat-screen.js
CHANGED
|
@@ -421,7 +421,9 @@ class TextChatScreen {
|
|
|
421
421
|
// Update existing message
|
|
422
422
|
const bubble = existingMessage.querySelector(".message-bubble");
|
|
423
423
|
if (bubble) {
|
|
424
|
-
|
|
424
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
425
|
+
const content = messageData.content || text;
|
|
426
|
+
bubble.innerHTML = !isUser ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
425
427
|
}
|
|
426
428
|
messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
427
429
|
return;
|
|
@@ -483,11 +485,14 @@ class TextChatScreen {
|
|
|
483
485
|
const timestamp = messageData?.timestamp ? new Date(messageData.timestamp) : new Date();
|
|
484
486
|
const formattedTime = this._formatTime(timestamp);
|
|
485
487
|
|
|
488
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
489
|
+
const renderedContent = !isUser ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
490
|
+
|
|
486
491
|
messageEl.innerHTML = `
|
|
487
492
|
<div class="message-content">
|
|
488
493
|
${attachmentsHTML}
|
|
489
494
|
<div class="message-bubble">
|
|
490
|
-
${
|
|
495
|
+
${renderedContent}
|
|
491
496
|
</div>
|
|
492
497
|
<div class="message-time">${formattedTime}</div>
|
|
493
498
|
</div>
|
|
@@ -537,7 +542,10 @@ class TextChatScreen {
|
|
|
537
542
|
if (existingEl) {
|
|
538
543
|
const bubble = existingEl.querySelector(".message-bubble");
|
|
539
544
|
if (bubble) {
|
|
540
|
-
|
|
545
|
+
// Parse markdown for assistant messages, escape for user messages
|
|
546
|
+
const content = msg.content || "";
|
|
547
|
+
const isUserMessage = msg.sender === "user";
|
|
548
|
+
bubble.innerHTML = !isUserMessage ? this._parseMarkdown(content) : this._escapeHtml(content);
|
|
541
549
|
}
|
|
542
550
|
|
|
543
551
|
// Update attachments if they exist
|
|
@@ -676,6 +684,106 @@ class TextChatScreen {
|
|
|
676
684
|
return div.innerHTML;
|
|
677
685
|
}
|
|
678
686
|
|
|
687
|
+
// Parse markdown to HTML
|
|
688
|
+
_parseMarkdown(text) {
|
|
689
|
+
if (!text || typeof text !== 'string') return '';
|
|
690
|
+
|
|
691
|
+
let html = text;
|
|
692
|
+
|
|
693
|
+
// Escape HTML first to prevent XSS
|
|
694
|
+
html = html
|
|
695
|
+
.replace(/&/g, '&')
|
|
696
|
+
.replace(/</g, '<')
|
|
697
|
+
.replace(/>/g, '>');
|
|
698
|
+
|
|
699
|
+
// Split into lines for processing
|
|
700
|
+
const lines = html.split('\n');
|
|
701
|
+
const processedLines = [];
|
|
702
|
+
let inList = false;
|
|
703
|
+
|
|
704
|
+
for (let i = 0; i < lines.length; i++) {
|
|
705
|
+
let line = lines[i];
|
|
706
|
+
|
|
707
|
+
// Check for headers first (#, ##, ###, etc.)
|
|
708
|
+
const headerMatch = line.match(/^(#{1,6})\s+(.+)$/);
|
|
709
|
+
if (headerMatch) {
|
|
710
|
+
if (inList) {
|
|
711
|
+
processedLines.push('</ul>');
|
|
712
|
+
inList = false;
|
|
713
|
+
}
|
|
714
|
+
const level = headerMatch[1].length;
|
|
715
|
+
const headerText = headerMatch[2];
|
|
716
|
+
// Process markdown inside header
|
|
717
|
+
let processedHeader = headerText;
|
|
718
|
+
processedHeader = processedHeader.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
719
|
+
processedHeader = processedHeader.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
720
|
+
processedHeader = processedHeader.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
721
|
+
processedHeader = processedHeader.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
722
|
+
processedLines.push(`<h${level}>${processedHeader}</h${level}>`);
|
|
723
|
+
continue;
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
// Check if this is a list item (before processing bold/italic)
|
|
727
|
+
const listMatch = line.match(/^[\s]*[-*]\s+(.+)$/);
|
|
728
|
+
|
|
729
|
+
if (listMatch) {
|
|
730
|
+
// Process markdown inside list item
|
|
731
|
+
let listContent = listMatch[1];
|
|
732
|
+
|
|
733
|
+
// Bold: **text** (must be processed before italic)
|
|
734
|
+
listContent = listContent.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
735
|
+
listContent = listContent.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
736
|
+
|
|
737
|
+
// Italic: *text* (single asterisk, avoid matching **text**)
|
|
738
|
+
listContent = listContent.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
739
|
+
listContent = listContent.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
740
|
+
|
|
741
|
+
if (!inList) {
|
|
742
|
+
processedLines.push('<ul>');
|
|
743
|
+
inList = true;
|
|
744
|
+
}
|
|
745
|
+
processedLines.push(`<li>${listContent}</li>`);
|
|
746
|
+
} else {
|
|
747
|
+
if (inList) {
|
|
748
|
+
processedLines.push('</ul>');
|
|
749
|
+
inList = false;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Skip empty lines (they'll become <br> later)
|
|
753
|
+
if (line.trim() === '') {
|
|
754
|
+
processedLines.push('');
|
|
755
|
+
continue;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
// Process markdown in non-list lines
|
|
759
|
+
// Bold: **text** (must be processed before italic)
|
|
760
|
+
line = line.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
|
|
761
|
+
line = line.replace(/__([^_]+)__/g, '<strong>$1</strong>');
|
|
762
|
+
|
|
763
|
+
// Italic: *text* (single asterisk, avoid matching **text**)
|
|
764
|
+
line = line.replace(/(^|[^*])\*([^*]+)\*([^*]|$)/g, '$1<em>$2</em>$3');
|
|
765
|
+
line = line.replace(/(^|[^_])_([^_]+)_([^_]|$)/g, '$1<em>$2</em>$3');
|
|
766
|
+
|
|
767
|
+
// Inline code: `code`
|
|
768
|
+
line = line.replace(/`([^`]+)`/g, '<code>$1</code>');
|
|
769
|
+
|
|
770
|
+
// Links: [text](url)
|
|
771
|
+
line = line.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>');
|
|
772
|
+
|
|
773
|
+
processedLines.push(line);
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
if (inList) {
|
|
778
|
+
processedLines.push('</ul>');
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// Join lines with <br> and return
|
|
782
|
+
html = processedLines.join('<br>');
|
|
783
|
+
|
|
784
|
+
return html;
|
|
785
|
+
}
|
|
786
|
+
|
|
679
787
|
// Show expanded image modal
|
|
680
788
|
showExpandedImage(src, alt) {
|
|
681
789
|
// Remove existing modal if any
|
|
@@ -898,6 +1006,79 @@ class TextChatScreen {
|
|
|
898
1006
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
|
899
1007
|
}
|
|
900
1008
|
|
|
1009
|
+
/* ============================================
|
|
1010
|
+
Text Chat Message Bubble Styles
|
|
1011
|
+
============================================ */
|
|
1012
|
+
|
|
1013
|
+
/* Typography - Bold */
|
|
1014
|
+
.text-chat-screen .message-bubble strong {
|
|
1015
|
+
font-weight: 600;
|
|
1016
|
+
color: inherit;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
/* Typography - Italic */
|
|
1020
|
+
.text-chat-screen .message-bubble em {
|
|
1021
|
+
font-style: italic;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
/* Lists */
|
|
1025
|
+
.text-chat-screen .message-bubble ul {
|
|
1026
|
+
margin: 0px 0;
|
|
1027
|
+
padding-left: 20px;
|
|
1028
|
+
list-style-type: disc;
|
|
1029
|
+
margin-bottom:0px;
|
|
1030
|
+
margin-top:5px;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
.text-chat-screen .message-bubble li {
|
|
1034
|
+
margin: 0;
|
|
1035
|
+
line-height: 1.1;
|
|
1036
|
+
padding-left: 3px;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
/* Headings - Shared Styles */
|
|
1040
|
+
.text-chat-screen .message-bubble h1,
|
|
1041
|
+
.text-chat-screen .message-bubble h2,
|
|
1042
|
+
.text-chat-screen .message-bubble h3,
|
|
1043
|
+
.text-chat-screen .message-bubble h4,
|
|
1044
|
+
.text-chat-screen .message-bubble h5,
|
|
1045
|
+
.text-chat-screen .message-bubble h6 {
|
|
1046
|
+
margin: 0px 0 0px 0;
|
|
1047
|
+
font-weight: 600;
|
|
1048
|
+
color: inherit;
|
|
1049
|
+
line-height: 1.3;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
/* Heading Sizes */
|
|
1053
|
+
.text-chat-screen .message-bubble h1 { font-size: 1.5em; }
|
|
1054
|
+
.text-chat-screen .message-bubble h2 { font-size: 1.3em; }
|
|
1055
|
+
.text-chat-screen .message-bubble h3 { font-size: 1.15em; }
|
|
1056
|
+
.text-chat-screen .message-bubble h4 { font-size: 1.05em; }
|
|
1057
|
+
.text-chat-screen .message-bubble h5 { font-size: 1em; }
|
|
1058
|
+
.text-chat-screen .message-bubble h6 { font-size: 0.95em; }
|
|
1059
|
+
|
|
1060
|
+
/* Inline Code */
|
|
1061
|
+
.text-chat-screen .message-bubble code {
|
|
1062
|
+
background: rgba(0, 0, 0, 0.05);
|
|
1063
|
+
padding: 2px 6px;
|
|
1064
|
+
border-radius: 4px;
|
|
1065
|
+
font-family: 'Courier New', Courier, monospace;
|
|
1066
|
+
font-size: 0.9em;
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
/* Links */
|
|
1070
|
+
.text-chat-screen .message-bubble a {
|
|
1071
|
+
color: ${this.primaryColor};
|
|
1072
|
+
text-decoration: underline;
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
.text-chat-screen .message-bubble a:hover {
|
|
1076
|
+
opacity: 0.8;
|
|
1077
|
+
}
|
|
1078
|
+
.text-chat-screen .message-bubble br {
|
|
1079
|
+
line-height: 0.1; /* Adjust between 0 and 1 */
|
|
1080
|
+
}
|
|
1081
|
+
|
|
901
1082
|
.text-chat-screen .message-time {
|
|
902
1083
|
font-size: 10px;
|
|
903
1084
|
color: #94a3b8;
|