open-chat-studio-widget 0.4.8 → 0.5.1
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/README.md +23 -20
- package/dist/cjs/{index-AhSI5tER.js → index-Du0PBL6n.js} +4 -2
- package/dist/cjs/index-Du0PBL6n.js.map +1 -0
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js +1116 -301
- package/dist/cjs/open-chat-studio-widget.cjs.entry.js.map +1 -1
- package/dist/cjs/open-chat-studio-widget.cjs.js +2 -2
- package/dist/cjs/open-chat-studio-widget.entry.cjs.js.map +1 -1
- package/dist/collection/components/ocs-chat/{heroicons.js → icons.js} +23 -1
- package/dist/collection/components/ocs-chat/icons.js.map +1 -0
- package/dist/collection/components/ocs-chat/ocs-chat.css +596 -1983
- package/dist/collection/components/ocs-chat/ocs-chat.js +480 -273
- package/dist/collection/components/ocs-chat/ocs-chat.js.map +1 -1
- package/dist/collection/services/chat-session-service.js +145 -0
- package/dist/collection/services/chat-session-service.js.map +1 -0
- package/dist/collection/services/file-attachment-manager.js +125 -0
- package/dist/collection/services/file-attachment-manager.js.map +1 -0
- package/dist/collection/utils/cookies.js +5 -12
- package/dist/collection/utils/cookies.js.map +1 -1
- package/dist/collection/utils/markdown.js +1 -1
- package/dist/collection/utils/markdown.js.map +1 -1
- package/dist/collection/utils/translations.js +99 -0
- package/dist/collection/utils/translations.js.map +1 -0
- package/dist/components/open-chat-studio-widget.js +1122 -302
- package/dist/components/open-chat-studio-widget.js.map +1 -1
- package/dist/esm/{index-DkJ7OJTS.js → index-CX3v6rTy.js} +4 -3
- package/dist/esm/index-CX3v6rTy.js.map +1 -0
- package/dist/esm/loader.js +3 -3
- package/dist/esm/open-chat-studio-widget.entry.js +1116 -301
- package/dist/esm/open-chat-studio-widget.entry.js.map +1 -1
- package/dist/esm/open-chat-studio-widget.js +3 -3
- package/dist/open-chat-studio-widget/open-chat-studio-widget.entry.esm.js.map +1 -1
- package/dist/open-chat-studio-widget/open-chat-studio-widget.esm.js +1 -1
- package/dist/open-chat-studio-widget/p-90719a8b.entry.js +4 -0
- package/dist/open-chat-studio-widget/p-90719a8b.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/p-CX3v6rTy.js +3 -0
- package/dist/open-chat-studio-widget/p-CX3v6rTy.js.map +1 -0
- package/dist/types/components/ocs-chat/{heroicons.d.ts → icons.d.ts} +19 -0
- package/dist/types/components/ocs-chat/ocs-chat.d.ts +52 -36
- package/dist/types/components.d.ts +22 -8
- package/dist/types/services/chat-session-service.d.ts +78 -0
- package/dist/types/services/file-attachment-manager.d.ts +40 -0
- package/dist/types/utils/translations.d.ts +23 -0
- package/package.json +8 -3
- package/dist/cjs/index-AhSI5tER.js.map +0 -1
- package/dist/collection/components/ocs-chat/heroicons.js.map +0 -1
- package/dist/esm/index-DkJ7OJTS.js.map +0 -1
- package/dist/open-chat-studio-widget/p-DkJ7OJTS.js +0 -3
- package/dist/open-chat-studio-widget/p-DkJ7OJTS.js.map +0 -1
- package/dist/open-chat-studio-widget/p-bde68fbd.entry.js +0 -4
- package/dist/open-chat-studio-widget/p-bde68fbd.entry.js.map +0 -1
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var index = require('./index-
|
|
4
|
-
|
|
3
|
+
var index = require('./index-Du0PBL6n.js');
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
6
|
+
const OcsWidgetAvatar = () => {
|
|
7
|
+
return index.h("svg", { width: "24", height: "24", viewBox: "0 0 500 500", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg" },
|
|
8
|
+
index.h("path", { d: "M80.1777 149.487C73.7354 160.531 68.6208 172.445 65.0576 185.012C43.6097 196.458 29.0128 219.057 29.0127 245.065C29.0127 270.995 43.5207 293.535 64.8613 305.014C68.3612 317.586 73.409 329.512 79.7881 340.575C34.4248 332.436 2.20245e-05 292.771 0 245.065C0.000198788 197.223 34.6221 157.469 80.1777 149.487ZM419.821 149.487C465.377 157.469 500 197.223 500 245.065C500 292.771 465.575 332.436 420.211 340.575C426.59 329.512 431.638 317.586 435.138 305.014C456.479 293.535 470.987 270.995 470.987 245.065C470.987 219.056 456.39 196.458 434.941 185.012C431.378 172.445 426.264 160.532 419.821 149.487ZM259.868 16.4473C304.099 16.4473 341.297 46.5498 352.097 87.3848C340.566 81.9422 328.254 77.8819 315.375 75.4209C303.51 57.3742 283.08 45.46 259.868 45.46H253.289C230.975 45.4601 211.232 56.4698 199.197 73.3535C186.6 74.535 174.442 77.2268 162.906 81.248C175.656 43.5694 211.305 16.4474 253.289 16.4473H259.868Z" }),
|
|
9
|
+
index.h("path", { d: "M286.185 72.6685C371.571 72.6686 440.789 141.888 440.789 227.274V263.458C440.789 348.844 371.57 418.064 286.185 418.064H213.815C128.43 418.064 59.2111 348.844 59.2109 263.458V227.274C59.211 141.888 128.43 72.6686 213.815 72.6685H286.185ZM213.815 105.263C142.963 105.263 85.5265 162.7 85.5264 233.552V256.579C85.5264 327.431 142.963 384.868 213.815 384.869H286.185C357.037 384.868 414.474 327.431 414.474 256.579V233.552C414.473 162.7 357.037 105.263 286.185 105.263H213.815Z" }),
|
|
10
|
+
index.h("rect", { x: "289.475", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
|
|
11
|
+
index.h("rect", { x: "161.184", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
|
|
12
|
+
index.h("path", { d: "M325.658 483.553V414.58V401.316H148.027L325.658 483.553Z" }));
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Heroicon: x-mark
|
|
16
|
+
*/
|
|
5
17
|
const XMarkIcon = () => {
|
|
6
18
|
return index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
7
19
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M6 18 18 6M6 6l12 12" }));
|
|
@@ -15,22 +27,37 @@ const GripDotsVerticalIcon = () => {
|
|
|
15
27
|
index.h("circle", { cx: "16", cy: "12", r: "1.5" }),
|
|
16
28
|
index.h("circle", { cx: "16", cy: "18", r: "1.5" })));
|
|
17
29
|
};
|
|
30
|
+
/**
|
|
31
|
+
* Heroicon: plus-circle
|
|
32
|
+
*/
|
|
18
33
|
const PlusWithCircleIcon = () => {
|
|
19
34
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
20
35
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M12 9v6m3-3H9m12 0a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" })));
|
|
21
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Heroicon: arrows-pointing-out
|
|
39
|
+
*/
|
|
22
40
|
const ArrowsPointingOutIcon = () => {
|
|
23
41
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
24
42
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15" })));
|
|
25
43
|
};
|
|
44
|
+
/**
|
|
45
|
+
* Heroicon: arrows-pointing-in
|
|
46
|
+
*/
|
|
26
47
|
const ArrowsPointingInIcon = () => {
|
|
27
48
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
28
49
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M9 9V4.5M9 9H4.5M9 9 3.75 3.75M15 9h4.5M15 9V4.5M15 9l5.25-5.25M9 15v4.5M9 15H4.5M9 15l-5.25 5.25M15 15h4.5M15 15v4.5m0-4.5 5.25 5.25" })));
|
|
29
50
|
};
|
|
51
|
+
/**
|
|
52
|
+
* Heroicon: paper-clip
|
|
53
|
+
*/
|
|
30
54
|
const PaperClipIcon = () => {
|
|
31
55
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
32
56
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "m18.375 12.739-7.693 7.693a4.5 4.5 0 0 1-6.364-6.364l10.94-10.94A3 3 0 1 1 19.5 7.372L8.552 18.32m.009-.01-.01.01m5.699-9.941-7.81 7.81a1.5 1.5 0 0 0 2.112 2.13" })));
|
|
33
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Heroicon: document-check
|
|
60
|
+
*/
|
|
34
61
|
const CheckDocumentIcon = () => {
|
|
35
62
|
return (index.h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
36
63
|
index.h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M10.125 2.25h-4.5c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125v-9M10.125 2.25h.375a9 9 0 0 1 9 9v.375M10.125 2.25A3.375 3.375 0 0 1 13.5 5.625v1.5c0 .621.504 1.125 1.125 1.125h1.5a3.375 3.375 0 0 1 3.375 3.375M9 15l2.25 2.25L15 12" })));
|
|
@@ -4301,7 +4328,7 @@ function renderMarkdownSync(content) {
|
|
|
4301
4328
|
'href', 'target', 'rel', 'class', 'src', 'alt', 'title',
|
|
4302
4329
|
'width', 'height', 'align', 'colspan', 'rowspan'
|
|
4303
4330
|
],
|
|
4304
|
-
ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z
|
|
4331
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i,
|
|
4305
4332
|
ADD_ATTR: ['target'],
|
|
4306
4333
|
FORBID_TAGS: ['script', 'style', 'form', 'input', 'button'],
|
|
4307
4334
|
FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
|
|
@@ -4314,6 +4341,414 @@ function renderMarkdownSync(content) {
|
|
|
4314
4341
|
}
|
|
4315
4342
|
}
|
|
4316
4343
|
|
|
4344
|
+
/**
|
|
4345
|
+
* Convert a CSS percentage (60%) or pixel (10px) value to pixels.
|
|
4346
|
+
* @param value The CSS string value
|
|
4347
|
+
* @param maxValue The max value to use when converting from a percentage
|
|
4348
|
+
* @param defaultValue The default value if the CSS value is neither a percentage nor a pixel value.
|
|
4349
|
+
*/
|
|
4350
|
+
const varToPixels = (value, maxValue, defaultValue) => {
|
|
4351
|
+
value = value.trim();
|
|
4352
|
+
if (value.includes("%")) {
|
|
4353
|
+
const percent = percentToFloat(value);
|
|
4354
|
+
if (!isNaN(percent)) {
|
|
4355
|
+
return maxValue * percent;
|
|
4356
|
+
}
|
|
4357
|
+
}
|
|
4358
|
+
else if (value.includes("px")) {
|
|
4359
|
+
const pixels = parseFloat(value);
|
|
4360
|
+
if (!isNaN(pixels)) {
|
|
4361
|
+
return pixels;
|
|
4362
|
+
}
|
|
4363
|
+
}
|
|
4364
|
+
return defaultValue;
|
|
4365
|
+
};
|
|
4366
|
+
const percentToFloat = (percentageString) => {
|
|
4367
|
+
const numericValue = parseFloat(percentageString);
|
|
4368
|
+
if (isNaN(numericValue)) {
|
|
4369
|
+
return NaN;
|
|
4370
|
+
}
|
|
4371
|
+
return numericValue / 100;
|
|
4372
|
+
};
|
|
4373
|
+
|
|
4374
|
+
var ar = {
|
|
4375
|
+
"launcher.open": "فتح المحادثة",
|
|
4376
|
+
"window.close": "إغلاق",
|
|
4377
|
+
"window.newChat": "بدء محادثة جديدة",
|
|
4378
|
+
"window.fullscreen": "دخول وضع ملء الشاشة",
|
|
4379
|
+
"window.exitFullscreen": "الخروج من وضع ملء الشاشة",
|
|
4380
|
+
"attach.add": "إرفاق ملفات",
|
|
4381
|
+
"attach.remove": "إزالة الملف",
|
|
4382
|
+
"attach.success": "تم إرفاق الملف",
|
|
4383
|
+
"status.starting": "جارٍ بدء المحادثة...",
|
|
4384
|
+
"status.typing": "جارٍ تحضير الرد",
|
|
4385
|
+
"status.uploading": "جارٍ التحميل",
|
|
4386
|
+
"modal.newChatTitle": "بدء محادثة جديدة",
|
|
4387
|
+
"modal.newChatBody": "بدء محادثة جديدة سيؤدي إلى مسح المحادثة الحالية. هل ترغب بالمتابعة؟",
|
|
4388
|
+
"modal.cancel": "إلغاء",
|
|
4389
|
+
"modal.confirm": "تأكيد",
|
|
4390
|
+
"composer.placeholder": "اكتب رسالة...",
|
|
4391
|
+
"composer.send": "إرسال الرسالة",
|
|
4392
|
+
"error.fileTooLarge": "الملف كبير جدًا",
|
|
4393
|
+
"error.totalTooLarge": "إجمالي حجم الملفات كبير جدًا",
|
|
4394
|
+
"error.unsupportedType": "نوع الملف غير مدعوم",
|
|
4395
|
+
"error.connection": "خطأ في الاتصال. يرجى المحاولة مرة أخرى.",
|
|
4396
|
+
"error.sessionExpired": "انتهت صلاحية الجلسة. يرجى بدء محادثة جديدة.",
|
|
4397
|
+
"branding.poweredBy": "مدعوم من",
|
|
4398
|
+
"branding.buttonText": "",
|
|
4399
|
+
"branding.headerText": "",
|
|
4400
|
+
"content.welcomeMessages": [
|
|
4401
|
+
],
|
|
4402
|
+
"content.starterQuestions": [
|
|
4403
|
+
]
|
|
4404
|
+
};
|
|
4405
|
+
|
|
4406
|
+
var en = {
|
|
4407
|
+
"launcher.open": "Open chat",
|
|
4408
|
+
"window.close": "Close",
|
|
4409
|
+
"window.newChat": "Start new chat",
|
|
4410
|
+
"window.fullscreen": "Enter fullscreen",
|
|
4411
|
+
"window.exitFullscreen": "Exit fullscreen",
|
|
4412
|
+
"attach.add": "Attach files",
|
|
4413
|
+
"attach.remove": "Remove file",
|
|
4414
|
+
"attach.success": "File attached",
|
|
4415
|
+
"status.starting": "Starting chat...",
|
|
4416
|
+
"status.typing": "Preparing response",
|
|
4417
|
+
"status.uploading": "Uploading",
|
|
4418
|
+
"modal.newChatTitle": "Start New Chat",
|
|
4419
|
+
"modal.newChatBody": "Starting a new chat will clear your current conversation. Continue?",
|
|
4420
|
+
"modal.cancel": "Cancel",
|
|
4421
|
+
"modal.confirm": "Confirm",
|
|
4422
|
+
"composer.placeholder": "Type a message...",
|
|
4423
|
+
"composer.send": "Send message",
|
|
4424
|
+
"error.fileTooLarge": "File too large",
|
|
4425
|
+
"error.totalTooLarge": "Total file size too large",
|
|
4426
|
+
"error.unsupportedType": "Unsupported file type",
|
|
4427
|
+
"error.connection": "Connection error. Please try again.",
|
|
4428
|
+
"error.sessionExpired": "Session expired. Please start a new chat.",
|
|
4429
|
+
"branding.poweredBy": "Powered by",
|
|
4430
|
+
"branding.buttonText": "",
|
|
4431
|
+
"branding.headerText": "",
|
|
4432
|
+
"content.welcomeMessages": [
|
|
4433
|
+
],
|
|
4434
|
+
"content.starterQuestions": [
|
|
4435
|
+
]
|
|
4436
|
+
};
|
|
4437
|
+
|
|
4438
|
+
var es = {
|
|
4439
|
+
"launcher.open": "Abrir chat",
|
|
4440
|
+
"window.close": "Cerrar",
|
|
4441
|
+
"window.newChat": "Iniciar nuevo chat",
|
|
4442
|
+
"window.fullscreen": "Pantalla completa",
|
|
4443
|
+
"window.exitFullscreen": "Salir de pantalla completa",
|
|
4444
|
+
"attach.add": "Adjuntar archivos",
|
|
4445
|
+
"attach.remove": "Eliminar archivo",
|
|
4446
|
+
"attach.success": "Archivo adjunto",
|
|
4447
|
+
"status.starting": "Iniciando chat...",
|
|
4448
|
+
"status.typing": "Preparando respuesta",
|
|
4449
|
+
"status.uploading": "Subiendo",
|
|
4450
|
+
"modal.newChatTitle": "Iniciar Nuevo Chat",
|
|
4451
|
+
"modal.newChatBody": "Iniciar un nuevo chat borrará tu conversación actual. ¿Continuar?",
|
|
4452
|
+
"modal.cancel": "Cancelar",
|
|
4453
|
+
"modal.confirm": "Confirmar",
|
|
4454
|
+
"composer.placeholder": "Escribe un mensaje...",
|
|
4455
|
+
"composer.send": "Enviar mensaje",
|
|
4456
|
+
"error.fileTooLarge": "Archivo demasiado grande",
|
|
4457
|
+
"error.totalTooLarge": "Tamaño total de archivos demasiado grande",
|
|
4458
|
+
"error.unsupportedType": "Tipo de archivo no soportado",
|
|
4459
|
+
"error.connection": "Error de conexión. Por favor, inténtalo de nuevo.",
|
|
4460
|
+
"error.sessionExpired": "Sesión expirada. Por favor, inicia un nuevo chat.",
|
|
4461
|
+
"branding.poweredBy": "Desarrollado por",
|
|
4462
|
+
"branding.buttonText": "",
|
|
4463
|
+
"branding.headerText": "",
|
|
4464
|
+
"content.welcomeMessages": [
|
|
4465
|
+
],
|
|
4466
|
+
"content.starterQuestions": [
|
|
4467
|
+
]
|
|
4468
|
+
};
|
|
4469
|
+
|
|
4470
|
+
var fr = {
|
|
4471
|
+
"launcher.open": "Ouvrir le chat",
|
|
4472
|
+
"window.close": "Fermer",
|
|
4473
|
+
"window.newChat": "Nouveau chat",
|
|
4474
|
+
"window.fullscreen": "Plein écran",
|
|
4475
|
+
"window.exitFullscreen": "Quitter le plein écran",
|
|
4476
|
+
"attach.add": "Joindre des fichiers",
|
|
4477
|
+
"attach.remove": "Supprimer le fichier",
|
|
4478
|
+
"attach.success": "Fichier joint",
|
|
4479
|
+
"status.starting": "Démarrage du chat...",
|
|
4480
|
+
"status.typing": "Préparation de la réponse",
|
|
4481
|
+
"status.uploading": "Téléversement",
|
|
4482
|
+
"modal.newChatTitle": "Nouveau Chat",
|
|
4483
|
+
"modal.newChatBody": "Démarrer un nouveau chat effacera votre conversation actuelle. Continuer?",
|
|
4484
|
+
"modal.cancel": "Annuler",
|
|
4485
|
+
"modal.confirm": "Confirmer",
|
|
4486
|
+
"composer.placeholder": "Tapez un message...",
|
|
4487
|
+
"composer.send": "Envoyer le message",
|
|
4488
|
+
"error.fileTooLarge": "Fichier trop volumineux",
|
|
4489
|
+
"error.totalTooLarge": "Taille totale des fichiers trop importante",
|
|
4490
|
+
"error.unsupportedType": "Type de fichier non pris en charge",
|
|
4491
|
+
"error.connection": "Erreur de connexion. Veuillez réessayer.",
|
|
4492
|
+
"error.sessionExpired": "Session expirée. Veuillez démarrer un nouveau chat.",
|
|
4493
|
+
"branding.poweredBy": "Propulsé par",
|
|
4494
|
+
"branding.buttonText": "",
|
|
4495
|
+
"branding.headerText": "",
|
|
4496
|
+
"content.welcomeMessages": [
|
|
4497
|
+
],
|
|
4498
|
+
"content.starterQuestions": [
|
|
4499
|
+
]
|
|
4500
|
+
};
|
|
4501
|
+
|
|
4502
|
+
var hi = {
|
|
4503
|
+
"launcher.open": "चैट खोलें",
|
|
4504
|
+
"window.close": "बंद करें",
|
|
4505
|
+
"window.newChat": "नई चैट शुरू करें",
|
|
4506
|
+
"window.fullscreen": "पूर्ण स्क्रीन पर जाएं",
|
|
4507
|
+
"window.exitFullscreen": "पूर्ण स्क्रीन से बाहर आएं",
|
|
4508
|
+
"attach.add": "फ़ाइलें संलग्न करें",
|
|
4509
|
+
"attach.remove": "फ़ाइल हटाएँ",
|
|
4510
|
+
"attach.success": "फ़ाइल संलग्न की गई",
|
|
4511
|
+
"status.starting": "चैट शुरू हो रही है...",
|
|
4512
|
+
"status.typing": "जवाब तैयार किया जा रहा है",
|
|
4513
|
+
"status.uploading": "अपलोड हो रहा है",
|
|
4514
|
+
"modal.newChatTitle": "नई चैट शुरू करें",
|
|
4515
|
+
"modal.newChatBody": "नई चैट शुरू करने से आपकी मौजूदा बातचीत हट जाएगी। क्या आप जारी रखना चाहते हैं?",
|
|
4516
|
+
"modal.cancel": "रद्द करें",
|
|
4517
|
+
"modal.confirm": "पुष्टि करें",
|
|
4518
|
+
"composer.placeholder": "संदेश लिखें...",
|
|
4519
|
+
"composer.send": "संदेश भेजें",
|
|
4520
|
+
"error.fileTooLarge": "फ़ाइल बहुत बड़ी है",
|
|
4521
|
+
"error.totalTooLarge": "कुल फ़ाइल आकार बहुत बड़ा है",
|
|
4522
|
+
"error.unsupportedType": "फ़ाइल प्रकार समर्थित नहीं है",
|
|
4523
|
+
"error.connection": "कनेक्शन त्रुटि। कृपया पुनः प्रयास करें।",
|
|
4524
|
+
"error.sessionExpired": "सत्र समाप्त हो गया है। कृपया नई चैट शुरू करें।",
|
|
4525
|
+
"branding.poweredBy": "द्वारा संचालित",
|
|
4526
|
+
"branding.buttonText": "",
|
|
4527
|
+
"branding.headerText": "",
|
|
4528
|
+
"content.welcomeMessages": [
|
|
4529
|
+
],
|
|
4530
|
+
"content.starterQuestions": [
|
|
4531
|
+
]
|
|
4532
|
+
};
|
|
4533
|
+
|
|
4534
|
+
var it = {
|
|
4535
|
+
"launcher.open": "Apri chat",
|
|
4536
|
+
"window.close": "Chiudi",
|
|
4537
|
+
"window.newChat": "Avvia nuova chat",
|
|
4538
|
+
"window.fullscreen": "Schermo intero",
|
|
4539
|
+
"window.exitFullscreen": "Esci da schermo intero",
|
|
4540
|
+
"attach.add": "Allega file",
|
|
4541
|
+
"attach.remove": "Rimuovi file",
|
|
4542
|
+
"attach.success": "File allegato",
|
|
4543
|
+
"status.starting": "Avvio della chat...",
|
|
4544
|
+
"status.typing": "Preparazione della risposta",
|
|
4545
|
+
"status.uploading": "Caricamento",
|
|
4546
|
+
"modal.newChatTitle": "Avvia nuova chat",
|
|
4547
|
+
"modal.newChatBody": "Avviare una nuova chat cancellerà la conversazione attuale. Continuare?",
|
|
4548
|
+
"modal.cancel": "Annulla",
|
|
4549
|
+
"modal.confirm": "Conferma",
|
|
4550
|
+
"composer.placeholder": "Scrivi un messaggio...",
|
|
4551
|
+
"composer.send": "Invia messaggio",
|
|
4552
|
+
"error.fileTooLarge": "File troppo grande",
|
|
4553
|
+
"error.totalTooLarge": "Dimensione totale del file troppo grande",
|
|
4554
|
+
"error.unsupportedType": "Tipo di file non supportato",
|
|
4555
|
+
"error.connection": "Errore di connessione. Riprova.",
|
|
4556
|
+
"error.sessionExpired": "Sessione scaduta. Avvia una nuova chat.",
|
|
4557
|
+
"branding.poweredBy": "Offerto da",
|
|
4558
|
+
"branding.buttonText": "",
|
|
4559
|
+
"branding.headerText": "",
|
|
4560
|
+
"content.welcomeMessages": [
|
|
4561
|
+
],
|
|
4562
|
+
"content.starterQuestions": [
|
|
4563
|
+
]
|
|
4564
|
+
};
|
|
4565
|
+
|
|
4566
|
+
var pt = {
|
|
4567
|
+
"launcher.open": "Abrir chat",
|
|
4568
|
+
"window.close": "Fechar",
|
|
4569
|
+
"window.newChat": "Iniciar novo chat",
|
|
4570
|
+
"window.fullscreen": "Entrar em tela cheia",
|
|
4571
|
+
"window.exitFullscreen": "Sair da tela cheia",
|
|
4572
|
+
"attach.add": "Anexar arquivos",
|
|
4573
|
+
"attach.remove": "Remover arquivo",
|
|
4574
|
+
"attach.success": "Arquivo anexado",
|
|
4575
|
+
"status.starting": "Iniciando chat...",
|
|
4576
|
+
"status.typing": "Preparando resposta",
|
|
4577
|
+
"status.uploading": "Carregando",
|
|
4578
|
+
"modal.newChatTitle": "Iniciar novo chat",
|
|
4579
|
+
"modal.newChatBody": "Iniciar um novo chat apagará sua conversa atual. Deseja continuar?",
|
|
4580
|
+
"modal.cancel": "Cancelar",
|
|
4581
|
+
"modal.confirm": "Confirmar",
|
|
4582
|
+
"composer.placeholder": "Digite uma mensagem...",
|
|
4583
|
+
"composer.send": "Enviar mensagem",
|
|
4584
|
+
"error.fileTooLarge": "Arquivo muito grande",
|
|
4585
|
+
"error.totalTooLarge": "Tamanho total do arquivo muito grande",
|
|
4586
|
+
"error.unsupportedType": "Tipo de arquivo não suportado",
|
|
4587
|
+
"error.connection": "Erro de conexão. Por favor, tente novamente.",
|
|
4588
|
+
"error.sessionExpired": "Sessão expirada. Por favor, inicie um novo chat.",
|
|
4589
|
+
"branding.poweredBy": "Desenvolvido por",
|
|
4590
|
+
"branding.buttonText": "",
|
|
4591
|
+
"branding.headerText": "",
|
|
4592
|
+
"content.welcomeMessages": [
|
|
4593
|
+
],
|
|
4594
|
+
"content.starterQuestions": [
|
|
4595
|
+
]
|
|
4596
|
+
};
|
|
4597
|
+
|
|
4598
|
+
var sw = {
|
|
4599
|
+
"launcher.open": "Fungua gumzo",
|
|
4600
|
+
"window.close": "Funga",
|
|
4601
|
+
"window.newChat": "Anza gumzo jipya",
|
|
4602
|
+
"window.fullscreen": "Ingiza skrini nzima",
|
|
4603
|
+
"window.exitFullscreen": "Toka kwenye skrini nzima",
|
|
4604
|
+
"attach.add": "Ambatanisha faili",
|
|
4605
|
+
"attach.remove": "Ondoa faili",
|
|
4606
|
+
"attach.success": "Faili limeambatanishwa",
|
|
4607
|
+
"status.starting": "Inaanzisha gumzo...",
|
|
4608
|
+
"status.typing": "Inatayarisha jibu",
|
|
4609
|
+
"status.uploading": "Inapakia",
|
|
4610
|
+
"modal.newChatTitle": "Anza gumzo jipya",
|
|
4611
|
+
"modal.newChatBody": "Kuanza gumzo jipya kutafuta gumzo lako la sasa. Je, ungependa kuendelea?",
|
|
4612
|
+
"modal.cancel": "Ghairi",
|
|
4613
|
+
"modal.confirm": "Thibitisha",
|
|
4614
|
+
"composer.placeholder": "Andika ujumbe...",
|
|
4615
|
+
"composer.send": "Tuma ujumbe",
|
|
4616
|
+
"error.fileTooLarge": "Faili ni kubwa sana",
|
|
4617
|
+
"error.totalTooLarge": "Jumla ya ukubwa wa faili ni kubwa sana",
|
|
4618
|
+
"error.unsupportedType": "Aina ya faili haitumiki",
|
|
4619
|
+
"error.connection": "Hitilafu ya muunganisho. Tafadhali jaribu tena.",
|
|
4620
|
+
"error.sessionExpired": "Kipindi kimeisha muda wake. Tafadhali anza gumzo jipya.",
|
|
4621
|
+
"branding.poweredBy": "Inaendeshwa na",
|
|
4622
|
+
"branding.buttonText": "",
|
|
4623
|
+
"branding.headerText": "",
|
|
4624
|
+
"content.welcomeMessages": [
|
|
4625
|
+
],
|
|
4626
|
+
"content.starterQuestions": [
|
|
4627
|
+
]
|
|
4628
|
+
};
|
|
4629
|
+
|
|
4630
|
+
var uk = {
|
|
4631
|
+
"launcher.open": "Відкрити чат",
|
|
4632
|
+
"window.close": "Закрити",
|
|
4633
|
+
"window.newChat": "Почати новий чат",
|
|
4634
|
+
"window.fullscreen": "На весь екран",
|
|
4635
|
+
"window.exitFullscreen": "Вийти з повного екрану",
|
|
4636
|
+
"attach.add": "Прикріпити файли",
|
|
4637
|
+
"attach.remove": "Видалити файл",
|
|
4638
|
+
"attach.success": "Файл прикріплено",
|
|
4639
|
+
"status.starting": "Запуск чату...",
|
|
4640
|
+
"status.typing": "Готується відповідь",
|
|
4641
|
+
"status.uploading": "Завантаження",
|
|
4642
|
+
"modal.newChatTitle": "Почати новий чат",
|
|
4643
|
+
"modal.newChatBody": "Початок нового чату видалить вашу поточну розмову. Продовжити?",
|
|
4644
|
+
"modal.cancel": "Скасувати",
|
|
4645
|
+
"modal.confirm": "Підтвердити",
|
|
4646
|
+
"composer.placeholder": "Введіть повідомлення...",
|
|
4647
|
+
"composer.send": "Надіслати повідомлення",
|
|
4648
|
+
"error.fileTooLarge": "Файл занадто великий",
|
|
4649
|
+
"error.totalTooLarge": "Загальний розмір файлів занадто великий",
|
|
4650
|
+
"error.unsupportedType": "Непідтримуваний тип файлу",
|
|
4651
|
+
"error.connection": "Помилка з'єднання. Будь ласка, спробуйте ще раз.",
|
|
4652
|
+
"error.sessionExpired": "Сесія завершилася. Будь ласка, почніть новий чат.",
|
|
4653
|
+
"branding.poweredBy": "Працює на",
|
|
4654
|
+
"branding.buttonText": "",
|
|
4655
|
+
"branding.headerText": "",
|
|
4656
|
+
"content.welcomeMessages": [
|
|
4657
|
+
],
|
|
4658
|
+
"content.starterQuestions": [
|
|
4659
|
+
]
|
|
4660
|
+
};
|
|
4661
|
+
|
|
4662
|
+
/**
|
|
4663
|
+
* Translation utilities for the chat widget
|
|
4664
|
+
*/
|
|
4665
|
+
// Default (English) translations
|
|
4666
|
+
const defaultTranslations = en;
|
|
4667
|
+
// Available translations map
|
|
4668
|
+
const translationFiles = {
|
|
4669
|
+
ar: ar,
|
|
4670
|
+
en: en,
|
|
4671
|
+
es: es,
|
|
4672
|
+
fr: fr,
|
|
4673
|
+
hi: hi,
|
|
4674
|
+
it: it,
|
|
4675
|
+
pt: pt,
|
|
4676
|
+
sw: sw,
|
|
4677
|
+
uk: uk,
|
|
4678
|
+
};
|
|
4679
|
+
function getBrowserLanguage() {
|
|
4680
|
+
if (typeof navigator !== 'undefined') {
|
|
4681
|
+
const lang = navigator.language || navigator.userLanguage;
|
|
4682
|
+
if (lang) {
|
|
4683
|
+
return lang.split('-')[0].toLowerCase();
|
|
4684
|
+
}
|
|
4685
|
+
}
|
|
4686
|
+
return 'en';
|
|
4687
|
+
}
|
|
4688
|
+
function resolveLanguage(langProp) {
|
|
4689
|
+
if (langProp) {
|
|
4690
|
+
return langProp.toLowerCase();
|
|
4691
|
+
}
|
|
4692
|
+
return getBrowserLanguage();
|
|
4693
|
+
}
|
|
4694
|
+
async function loadTranslations(language) {
|
|
4695
|
+
return translationFiles[language] || defaultTranslations;
|
|
4696
|
+
}
|
|
4697
|
+
/**
|
|
4698
|
+
* Overrides matching keys
|
|
4699
|
+
*/
|
|
4700
|
+
function mergeTranslations(baseTranslations, customTranslations) {
|
|
4701
|
+
return Object.assign(Object.assign({}, baseTranslations), customTranslations);
|
|
4702
|
+
}
|
|
4703
|
+
class TranslationManager {
|
|
4704
|
+
constructor(language, customTranslations) {
|
|
4705
|
+
this.translations = defaultTranslations;
|
|
4706
|
+
this.language = 'en';
|
|
4707
|
+
this.language = resolveLanguage(language);
|
|
4708
|
+
this.loadTranslations(customTranslations);
|
|
4709
|
+
}
|
|
4710
|
+
async loadTranslations(customTranslations) {
|
|
4711
|
+
let baseTranslations;
|
|
4712
|
+
try {
|
|
4713
|
+
baseTranslations = await loadTranslations(this.language);
|
|
4714
|
+
}
|
|
4715
|
+
catch (error) {
|
|
4716
|
+
console.error('Failed to load translations:', error);
|
|
4717
|
+
baseTranslations = defaultTranslations;
|
|
4718
|
+
}
|
|
4719
|
+
this.translations = customTranslations
|
|
4720
|
+
? mergeTranslations(baseTranslations, customTranslations)
|
|
4721
|
+
: baseTranslations;
|
|
4722
|
+
}
|
|
4723
|
+
get(key, override) {
|
|
4724
|
+
var _a;
|
|
4725
|
+
if (override !== undefined && override !== null) {
|
|
4726
|
+
return override;
|
|
4727
|
+
}
|
|
4728
|
+
const value = (_a = this.translations[key]) !== null && _a !== void 0 ? _a : defaultTranslations[key];
|
|
4729
|
+
if (Array.isArray(value)) {
|
|
4730
|
+
return value.length > 0 ? value[0] : undefined;
|
|
4731
|
+
}
|
|
4732
|
+
return value !== null && value !== void 0 ? value : undefined;
|
|
4733
|
+
}
|
|
4734
|
+
getAll() {
|
|
4735
|
+
return this.translations;
|
|
4736
|
+
}
|
|
4737
|
+
getArray(key) {
|
|
4738
|
+
const value = this.translations[key] || defaultTranslations[key];
|
|
4739
|
+
if (Array.isArray(value)) {
|
|
4740
|
+
return value;
|
|
4741
|
+
}
|
|
4742
|
+
if (typeof value === 'string') {
|
|
4743
|
+
return [value];
|
|
4744
|
+
}
|
|
4745
|
+
return [];
|
|
4746
|
+
}
|
|
4747
|
+
getLanguage() {
|
|
4748
|
+
return this.language;
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4317
4752
|
/*! js-cookie v3.0.5 | MIT */
|
|
4318
4753
|
/* eslint-disable no-var */
|
|
4319
4754
|
function assign (target) {
|
|
@@ -4456,70 +4891,298 @@ function getCSRFToken(apiBaseUrl) {
|
|
|
4456
4891
|
return api.get('csrftoken');
|
|
4457
4892
|
}
|
|
4458
4893
|
function currentDomainMatchesApiBaseUrl(apiBaseUrl) {
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4894
|
+
let apiBase;
|
|
4895
|
+
try {
|
|
4896
|
+
apiBase = new URL(apiBaseUrl);
|
|
4897
|
+
}
|
|
4898
|
+
catch (_a) {
|
|
4462
4899
|
return false;
|
|
4463
4900
|
}
|
|
4464
|
-
return
|
|
4901
|
+
return window.location.origin === apiBase.origin;
|
|
4465
4902
|
}
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4903
|
+
|
|
4904
|
+
class ChatSessionService {
|
|
4905
|
+
constructor(options) {
|
|
4906
|
+
var _a, _b, _c, _d;
|
|
4907
|
+
this.apiBaseUrl = options.apiBaseUrl;
|
|
4908
|
+
this.embedKey = options.embedKey;
|
|
4909
|
+
this.widgetVersion = options.widgetVersion;
|
|
4910
|
+
this.csrfTokenProvider = (_a = options.csrfTokenProvider) !== null && _a !== void 0 ? _a : getCSRFToken;
|
|
4911
|
+
this.taskPollingIntervalMs = (_b = options.taskPollingIntervalMs) !== null && _b !== void 0 ? _b : 1000;
|
|
4912
|
+
this.taskPollingMaxAttempts = (_c = options.taskPollingMaxAttempts) !== null && _c !== void 0 ? _c : 120;
|
|
4913
|
+
this.messagePollingIntervalMs = (_d = options.messagePollingIntervalMs) !== null && _d !== void 0 ? _d : 30000;
|
|
4914
|
+
}
|
|
4915
|
+
async startSession(requestBody) {
|
|
4916
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/start/`, {
|
|
4917
|
+
method: 'POST',
|
|
4918
|
+
headers: this.getJsonHeaders(),
|
|
4919
|
+
body: JSON.stringify(requestBody),
|
|
4920
|
+
});
|
|
4921
|
+
if (!response.ok) {
|
|
4922
|
+
throw new Error(`Failed to start session: ${response.statusText}`);
|
|
4923
|
+
}
|
|
4924
|
+
return response.json();
|
|
4470
4925
|
}
|
|
4471
|
-
|
|
4472
|
-
|
|
4926
|
+
async sendMessage(sessionId, payload) {
|
|
4927
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {
|
|
4928
|
+
method: 'POST',
|
|
4929
|
+
headers: this.getJsonHeaders(),
|
|
4930
|
+
body: JSON.stringify(payload),
|
|
4931
|
+
});
|
|
4932
|
+
if (!response.ok) {
|
|
4933
|
+
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
4934
|
+
}
|
|
4935
|
+
return response.json();
|
|
4936
|
+
}
|
|
4937
|
+
async pollTaskOnce(sessionId, taskId) {
|
|
4938
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`);
|
|
4939
|
+
if (!response.ok) {
|
|
4940
|
+
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
4941
|
+
}
|
|
4942
|
+
return response.json();
|
|
4943
|
+
}
|
|
4944
|
+
pollTask(sessionId, taskId, callbacks) {
|
|
4945
|
+
let attempts = 0;
|
|
4946
|
+
let cancelled = false;
|
|
4947
|
+
let timeoutId;
|
|
4948
|
+
const scheduleNextPoll = () => {
|
|
4949
|
+
timeoutId = setTimeout(() => {
|
|
4950
|
+
void poll();
|
|
4951
|
+
}, this.taskPollingIntervalMs);
|
|
4952
|
+
};
|
|
4953
|
+
const poll = async () => {
|
|
4954
|
+
if (cancelled) {
|
|
4955
|
+
return;
|
|
4956
|
+
}
|
|
4957
|
+
try {
|
|
4958
|
+
const data = await this.pollTaskOnce(sessionId, taskId);
|
|
4959
|
+
if (data.error) {
|
|
4960
|
+
throw new Error(data.error);
|
|
4961
|
+
}
|
|
4962
|
+
if (data.status === 'complete' && data.message) {
|
|
4963
|
+
callbacks.onMessage(data.message);
|
|
4964
|
+
return;
|
|
4965
|
+
}
|
|
4966
|
+
attempts += 1;
|
|
4967
|
+
if (attempts >= this.taskPollingMaxAttempts) {
|
|
4968
|
+
if (callbacks.onTimeout) {
|
|
4969
|
+
callbacks.onTimeout();
|
|
4970
|
+
}
|
|
4971
|
+
return;
|
|
4972
|
+
}
|
|
4973
|
+
scheduleNextPoll();
|
|
4974
|
+
}
|
|
4975
|
+
catch (error) {
|
|
4976
|
+
if (callbacks.onError) {
|
|
4977
|
+
callbacks.onError(error instanceof Error ? error : new Error('Failed to get response'));
|
|
4978
|
+
}
|
|
4979
|
+
}
|
|
4980
|
+
};
|
|
4981
|
+
void poll();
|
|
4982
|
+
return {
|
|
4983
|
+
cancel: () => {
|
|
4984
|
+
cancelled = true;
|
|
4985
|
+
if (timeoutId) {
|
|
4986
|
+
clearTimeout(timeoutId);
|
|
4987
|
+
}
|
|
4988
|
+
},
|
|
4989
|
+
};
|
|
4990
|
+
}
|
|
4991
|
+
async fetchMessages(sessionId, since) {
|
|
4992
|
+
const url = new URL(`${this.apiBaseUrl}/api/chat/${sessionId}/poll/`);
|
|
4993
|
+
if (since) {
|
|
4994
|
+
url.searchParams.set('since', since);
|
|
4995
|
+
}
|
|
4996
|
+
const response = await fetch(url.toString());
|
|
4997
|
+
if (!response.ok) {
|
|
4998
|
+
throw new Error(`Failed to poll messages: ${response.statusText}`);
|
|
4999
|
+
}
|
|
5000
|
+
return response.json();
|
|
5001
|
+
}
|
|
5002
|
+
startMessagePolling(sessionId, callbacks) {
|
|
5003
|
+
const poll = async () => {
|
|
5004
|
+
try {
|
|
5005
|
+
const since = callbacks.getSince();
|
|
5006
|
+
const data = await this.fetchMessages(sessionId, since);
|
|
5007
|
+
if (data.messages.length > 0) {
|
|
5008
|
+
callbacks.onMessages(data.messages);
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
catch (error) {
|
|
5012
|
+
if (callbacks.onError) {
|
|
5013
|
+
callbacks.onError(error instanceof Error ? error : new Error('Failed to poll messages'));
|
|
5014
|
+
}
|
|
5015
|
+
}
|
|
5016
|
+
};
|
|
5017
|
+
// perform an initial poll immediately
|
|
5018
|
+
void poll();
|
|
5019
|
+
this.messagePollingTimer = setInterval(() => {
|
|
5020
|
+
void poll();
|
|
5021
|
+
}, this.messagePollingIntervalMs);
|
|
5022
|
+
return {
|
|
5023
|
+
stop: () => this.stopMessagePolling(),
|
|
5024
|
+
};
|
|
5025
|
+
}
|
|
5026
|
+
stopMessagePolling() {
|
|
5027
|
+
if (this.messagePollingTimer) {
|
|
5028
|
+
clearInterval(this.messagePollingTimer);
|
|
5029
|
+
this.messagePollingTimer = undefined;
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
getJsonHeaders() {
|
|
5033
|
+
const headers = {
|
|
5034
|
+
'Content-Type': 'application/json',
|
|
5035
|
+
'x-ocs-widget-version': this.widgetVersion,
|
|
5036
|
+
};
|
|
5037
|
+
const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
|
|
5038
|
+
if (csrfToken) {
|
|
5039
|
+
headers['X-CSRFToken'] = csrfToken;
|
|
5040
|
+
}
|
|
5041
|
+
if (this.embedKey) {
|
|
5042
|
+
headers['X-Embed-Key'] = this.embedKey;
|
|
5043
|
+
}
|
|
5044
|
+
return headers;
|
|
4473
5045
|
}
|
|
4474
5046
|
}
|
|
4475
5047
|
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
5048
|
+
class FileAttachmentManager {
|
|
5049
|
+
constructor(config) {
|
|
5050
|
+
this.supportedExtensions = config.supportedExtensions;
|
|
5051
|
+
this.maxFileSizeMb = config.maxFileSizeMb;
|
|
5052
|
+
this.maxTotalSizeMb = config.maxTotalSizeMb;
|
|
5053
|
+
}
|
|
5054
|
+
addFiles(existingFiles, files) {
|
|
5055
|
+
const newSelected = [];
|
|
5056
|
+
const fileArray = Array.from(files instanceof FileList ? Array.from(files) : files);
|
|
5057
|
+
let totalSize = existingFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
5058
|
+
for (const file of fileArray) {
|
|
5059
|
+
const extension = this.getFileExtension(file.name);
|
|
5060
|
+
if (!this.supportedExtensions.includes(extension)) {
|
|
5061
|
+
newSelected.push({ file, error: `File type ${extension} not supported` });
|
|
5062
|
+
continue;
|
|
5063
|
+
}
|
|
5064
|
+
const fileSizeMb = this.bytesToMb(file.size);
|
|
5065
|
+
if (fileSizeMb > this.maxFileSizeMb) {
|
|
5066
|
+
newSelected.push({ file, error: `File exceeds ${this.maxFileSizeMb}MB limit` });
|
|
5067
|
+
continue;
|
|
5068
|
+
}
|
|
5069
|
+
totalSize += file.size;
|
|
5070
|
+
const totalSizeMb = this.bytesToMb(totalSize);
|
|
5071
|
+
if (totalSizeMb > this.maxTotalSizeMb) {
|
|
5072
|
+
newSelected.push({ file, error: `Total size exceeds ${this.maxTotalSizeMb}MB limit` });
|
|
5073
|
+
continue;
|
|
5074
|
+
}
|
|
5075
|
+
newSelected.push({ file });
|
|
4488
5076
|
}
|
|
5077
|
+
return [...existingFiles, ...newSelected];
|
|
4489
5078
|
}
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
5079
|
+
removeFile(existingFiles, index) {
|
|
5080
|
+
return existingFiles.filter((_, i) => i !== index);
|
|
5081
|
+
}
|
|
5082
|
+
markPendingFilesWithError(existingFiles, errorMessage) {
|
|
5083
|
+
return existingFiles.map(file => {
|
|
5084
|
+
if (!file.error && !file.uploaded) {
|
|
5085
|
+
return Object.assign(Object.assign({}, file), { error: errorMessage });
|
|
5086
|
+
}
|
|
5087
|
+
return file;
|
|
5088
|
+
});
|
|
5089
|
+
}
|
|
5090
|
+
async uploadPendingFiles(existingFiles, context) {
|
|
5091
|
+
if (existingFiles.length === 0) {
|
|
5092
|
+
return { selectedFiles: existingFiles, uploadedIds: [] };
|
|
5093
|
+
}
|
|
5094
|
+
const uploadCandidates = existingFiles.filter(file => !file.error && !file.uploaded);
|
|
5095
|
+
const uploadedIds = existingFiles
|
|
5096
|
+
.filter(file => file.uploaded)
|
|
5097
|
+
.map(file => file.uploaded.id);
|
|
5098
|
+
if (uploadCandidates.length === 0) {
|
|
5099
|
+
return { selectedFiles: existingFiles, uploadedIds };
|
|
5100
|
+
}
|
|
5101
|
+
const formData = new FormData();
|
|
5102
|
+
for (const file of uploadCandidates) {
|
|
5103
|
+
formData.append('files', file.file);
|
|
5104
|
+
}
|
|
5105
|
+
formData.append('participant_remote_id', context.participantId);
|
|
5106
|
+
if (context.participantName) {
|
|
5107
|
+
formData.append('participant_name', context.participantName);
|
|
5108
|
+
}
|
|
5109
|
+
try {
|
|
5110
|
+
const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
|
|
5111
|
+
method: 'POST',
|
|
5112
|
+
body: formData,
|
|
5113
|
+
});
|
|
5114
|
+
if (!response.ok) {
|
|
5115
|
+
const errorData = await this.safeJson(response);
|
|
5116
|
+
const errorMessage = (errorData && typeof errorData === 'object' && 'error' in errorData && errorData.error) ||
|
|
5117
|
+
'Failed to upload files';
|
|
5118
|
+
return {
|
|
5119
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5120
|
+
uploadedIds,
|
|
5121
|
+
errorMessage,
|
|
5122
|
+
};
|
|
5123
|
+
}
|
|
5124
|
+
const data = await this.safeJson(response);
|
|
5125
|
+
if (!data || typeof data !== 'object' || !Array.isArray(data.files)) {
|
|
5126
|
+
const errorMessage = 'Unexpected upload response shape';
|
|
5127
|
+
return {
|
|
5128
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5129
|
+
uploadedIds,
|
|
5130
|
+
errorMessage,
|
|
5131
|
+
};
|
|
5132
|
+
}
|
|
5133
|
+
const uploadedFiles = data.files;
|
|
5134
|
+
let index = 0;
|
|
5135
|
+
const updatedSelected = existingFiles.map(file => {
|
|
5136
|
+
if (!file.error && !file.uploaded) {
|
|
5137
|
+
const uploaded = uploadedFiles[index];
|
|
5138
|
+
index += 1;
|
|
5139
|
+
return Object.assign(Object.assign({}, file), { uploaded });
|
|
5140
|
+
}
|
|
5141
|
+
return file;
|
|
5142
|
+
});
|
|
5143
|
+
uploadedIds.push(...uploadedFiles.map(file => file.id));
|
|
5144
|
+
return { selectedFiles: updatedSelected, uploadedIds };
|
|
5145
|
+
}
|
|
5146
|
+
catch (error) {
|
|
5147
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
5148
|
+
return {
|
|
5149
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5150
|
+
uploadedIds,
|
|
5151
|
+
errorMessage,
|
|
5152
|
+
};
|
|
4494
5153
|
}
|
|
4495
5154
|
}
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
const percentToFloat = (percentageString) => {
|
|
4499
|
-
const numericValue = parseFloat(percentageString);
|
|
4500
|
-
if (isNaN(numericValue)) {
|
|
4501
|
-
return NaN;
|
|
5155
|
+
bytesToMb(bytes) {
|
|
5156
|
+
return bytes / (1024 * 1024);
|
|
4502
5157
|
}
|
|
4503
|
-
|
|
4504
|
-
|
|
5158
|
+
getFileExtension(filename) {
|
|
5159
|
+
const parts = filename.split('.');
|
|
5160
|
+
const ext = parts.pop();
|
|
5161
|
+
return ext ? `.${ext.toLowerCase()}` : '';
|
|
5162
|
+
}
|
|
5163
|
+
async safeJson(response) {
|
|
5164
|
+
try {
|
|
5165
|
+
return await response.json();
|
|
5166
|
+
}
|
|
5167
|
+
catch (_a) {
|
|
5168
|
+
return undefined;
|
|
5169
|
+
}
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
4505
5172
|
|
|
4506
|
-
const ocsChatCss = "*, ::before, ::after {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-gradient-from-position: ;\n --tw-gradient-via-position: ;\n --tw-gradient-to-position: ;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n --tw-contain-size: ;\n --tw-contain-layout: ;\n --tw-contain-paint: ;\n --tw-contain-style: ;\n}\n\n::backdrop {\n --tw-border-spacing-x: 0;\n --tw-border-spacing-y: 0;\n --tw-translate-x: 0;\n --tw-translate-y: 0;\n --tw-rotate: 0;\n --tw-skew-x: 0;\n --tw-skew-y: 0;\n --tw-scale-x: 1;\n --tw-scale-y: 1;\n --tw-pan-x: ;\n --tw-pan-y: ;\n --tw-pinch-zoom: ;\n --tw-scroll-snap-strictness: proximity;\n --tw-gradient-from-position: ;\n --tw-gradient-via-position: ;\n --tw-gradient-to-position: ;\n --tw-ordinal: ;\n --tw-slashed-zero: ;\n --tw-numeric-figure: ;\n --tw-numeric-spacing: ;\n --tw-numeric-fraction: ;\n --tw-ring-inset: ;\n --tw-ring-offset-width: 0px;\n --tw-ring-offset-color: #fff;\n --tw-ring-color: rgb(59 130 246 / 0.5);\n --tw-ring-offset-shadow: 0 0 #0000;\n --tw-ring-shadow: 0 0 #0000;\n --tw-shadow: 0 0 #0000;\n --tw-shadow-colored: 0 0 #0000;\n --tw-blur: ;\n --tw-brightness: ;\n --tw-contrast: ;\n --tw-grayscale: ;\n --tw-hue-rotate: ;\n --tw-invert: ;\n --tw-saturate: ;\n --tw-sepia: ;\n --tw-drop-shadow: ;\n --tw-backdrop-blur: ;\n --tw-backdrop-brightness: ;\n --tw-backdrop-contrast: ;\n --tw-backdrop-grayscale: ;\n --tw-backdrop-hue-rotate: ;\n --tw-backdrop-invert: ;\n --tw-backdrop-opacity: ;\n --tw-backdrop-saturate: ;\n --tw-backdrop-sepia: ;\n --tw-contain-size: ;\n --tw-contain-layout: ;\n --tw-contain-paint: ;\n --tw-contain-style: ;\n}/*\n! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com\n*//*\n1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4)\n2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116)\n*/\n\n*,\n::before,\n::after {\n box-sizing: border-box; /* 1 */\n border-width: 0; /* 2 */\n border-style: solid; /* 2 */\n border-color: #e5e7eb; /* 2 */\n}\n\n::before,\n::after {\n --tw-content: '';\n}\n\n/*\n1. Use a consistent sensible line-height in all browsers.\n2. Prevent adjustments of font size after orientation changes in iOS.\n3. Use a more readable tab size.\n4. Use the user's configured `sans` font-family by default.\n5. Use the user's configured `sans` font-feature-settings by default.\n6. Use the user's configured `sans` font-variation-settings by default.\n7. Disable tap highlights on iOS\n*/\n\nhtml,\n:host {\n line-height: 1.5; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n -moz-tab-size: 4; /* 3 */\n -o-tab-size: 4;\n tab-size: 4; /* 3 */\n font-family: ui-sans-serif, system-ui, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\"; /* 4 */\n font-feature-settings: normal; /* 5 */\n font-variation-settings: normal; /* 6 */\n -webkit-tap-highlight-color: transparent; /* 7 */\n}\n\n/*\n1. Remove the margin in all browsers.\n2. Inherit line-height from `html` so users can set them as a class directly on the `html` element.\n*/\n\nbody {\n margin: 0; /* 1 */\n line-height: inherit; /* 2 */\n}\n\n/*\n1. Add the correct height in Firefox.\n2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655)\n3. Ensure horizontal rules are visible by default.\n*/\n\nhr {\n height: 0; /* 1 */\n color: inherit; /* 2 */\n border-top-width: 1px; /* 3 */\n}\n\n/*\nAdd the correct text decoration in Chrome, Edge, and Safari.\n*/\n\nabbr:where([title]) {\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted;\n}\n\n/*\nRemove the default font size and weight for headings.\n*/\n\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-size: inherit;\n font-weight: inherit;\n}\n\n/*\nReset links to optimize for opt-in styling instead of opt-out.\n*/\n\na {\n color: inherit;\n text-decoration: inherit;\n}\n\n/*\nAdd the correct font weight in Edge and Safari.\n*/\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/*\n1. Use the user's configured `mono` font-family by default.\n2. Use the user's configured `mono` font-feature-settings by default.\n3. Use the user's configured `mono` font-variation-settings by default.\n4. Correct the odd `em` font sizing in all browsers.\n*/\n\ncode,\nkbd,\nsamp,\npre {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace; /* 1 */\n font-feature-settings: normal; /* 2 */\n font-variation-settings: normal; /* 3 */\n font-size: 1em; /* 4 */\n}\n\n/*\nAdd the correct font size in all browsers.\n*/\n\nsmall {\n font-size: 80%;\n}\n\n/*\nPrevent `sub` and `sup` elements from affecting the line height in all browsers.\n*/\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/*\n1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297)\n2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016)\n3. Remove gaps between table borders by default.\n*/\n\ntable {\n text-indent: 0; /* 1 */\n border-color: inherit; /* 2 */\n border-collapse: collapse; /* 3 */\n}\n\n/*\n1. Change the font styles in all browsers.\n2. Remove the margin in Firefox and Safari.\n3. Remove default padding in all browsers.\n*/\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-feature-settings: inherit; /* 1 */\n font-variation-settings: inherit; /* 1 */\n font-size: 100%; /* 1 */\n font-weight: inherit; /* 1 */\n line-height: inherit; /* 1 */\n letter-spacing: inherit; /* 1 */\n color: inherit; /* 1 */\n margin: 0; /* 2 */\n padding: 0; /* 3 */\n}\n\n/*\nRemove the inheritance of text transform in Edge and Firefox.\n*/\n\nbutton,\nselect {\n text-transform: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Remove default button styles.\n*/\n\nbutton,\ninput:where([type='button']),\ninput:where([type='reset']),\ninput:where([type='submit']) {\n -webkit-appearance: button; /* 1 */\n background-color: transparent; /* 2 */\n background-image: none; /* 2 */\n}\n\n/*\nUse the modern Firefox focus style for all focusable elements.\n*/\n\n:-moz-focusring {\n outline: auto;\n}\n\n/*\nRemove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737)\n*/\n\n:-moz-ui-invalid {\n box-shadow: none;\n}\n\n/*\nAdd the correct vertical alignment in Chrome and Firefox.\n*/\n\nprogress {\n vertical-align: baseline;\n}\n\n/*\nCorrect the cursor style of increment and decrement buttons in Safari.\n*/\n\n::-webkit-inner-spin-button,\n::-webkit-outer-spin-button {\n height: auto;\n}\n\n/*\n1. Correct the odd appearance in Chrome and Safari.\n2. Correct the outline style in Safari.\n*/\n\n[type='search'] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/*\nRemove the inner padding in Chrome and Safari on macOS.\n*/\n\n::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/*\n1. Correct the inability to style clickable types in iOS and Safari.\n2. Change font properties to `inherit` in Safari.\n*/\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/*\nAdd the correct display in Chrome and Safari.\n*/\n\nsummary {\n display: list-item;\n}\n\n/*\nRemoves the default spacing and border for appropriate elements.\n*/\n\nblockquote,\ndl,\ndd,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\nhr,\nfigure,\np,\npre {\n margin: 0;\n}\n\nfieldset {\n margin: 0;\n padding: 0;\n}\n\nlegend {\n padding: 0;\n}\n\nol,\nul,\nmenu {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n\n/*\nReset default styling for dialogs.\n*/\ndialog {\n padding: 0;\n}\n\n/*\nPrevent resizing textareas horizontally by default.\n*/\n\ntextarea {\n resize: vertical;\n}\n\n/*\n1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300)\n2. Set the default placeholder color to the user's configured gray 400 color.\n*/\n\ninput::-moz-placeholder, textarea::-moz-placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\ninput::placeholder,\ntextarea::placeholder {\n opacity: 1; /* 1 */\n color: #9ca3af; /* 2 */\n}\n\n/*\nSet the default cursor for buttons.\n*/\n\nbutton,\n[role=\"button\"] {\n cursor: pointer;\n}\n\n/*\nMake sure disabled buttons don't get the pointer cursor.\n*/\n:disabled {\n cursor: default;\n}\n\n/*\n1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14)\n2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210)\n This can trigger a poorly considered lint error in some tools but is included by design.\n*/\n\nimg,\nsvg,\nvideo,\ncanvas,\naudio,\niframe,\nembed,\nobject {\n display: block; /* 1 */\n vertical-align: middle; /* 2 */\n}\n\n/*\nConstrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14)\n*/\n\nimg,\nvideo {\n max-width: 100%;\n height: auto;\n}\n\n/* Make elements with the HTML hidden attribute stay hidden by default */\n[hidden]:where(:not([hidden=\"until-found\"])) {\n display: none;\n}\n.container {\n width: 100%;\n}\n@media (min-width: 640px) {\n\n .container {\n max-width: 640px;\n }\n}\n@media (min-width: 768px) {\n\n .container {\n max-width: 768px;\n }\n}\n@media (min-width: 1024px) {\n\n .container {\n max-width: 1024px;\n }\n}\n@media (min-width: 1280px) {\n\n .container {\n max-width: 1280px;\n }\n}\n@media (min-width: 1536px) {\n\n .container {\n max-width: 1536px;\n }\n}\n#ocs-chat-window {\n z-index: var(--chat-z-index);\n font-size: var(--chat-window-font-size);\n }\n.starter-question {\n border-radius: 0.5rem;\n text-align: left;\n transition-duration: 200ms;\n padding: 0.75em;\n background-color: var(--starter-question-bg-color);\n border: 1px solid var(--starter-question-border-color);\n color: var(--starter-question-text-color);\n}\n.starter-question:hover {\n background-color: var(--starter-question-bg-hover-color);\n border-color: var(--starter-question-border-hover-color);\n }\n.chat-btn-text,\n .chat-btn-icon {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n border-radius: 0.5rem;\n border-width: 0px;\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: all;\n transition-duration: 200ms;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n}\n.chat-btn-text:hover,\n .chat-btn-icon:hover {\n --tw-scale-x: 1.05;\n --tw-scale-y: 1.05;\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.chat-btn-text,\n .chat-btn-icon {\n background-color: var(--button-background-color, white);\n border: 1px solid var(--button-border-color);\n z-index: var(--chat-z-index, 50);\n font-size: var(--button-font-size);\n padding: 0.5em;\n }\n.chat-btn-text:hover, .chat-btn-icon:hover {\n color: var(--button-text-color-hover, #1d4ed8);\n border: 1px solid var(--button-border-color-hover);\n }\n/* Button with text and icon */\n.chat-btn-text {\n display: flex;\n align-items: center;\n gap: 8px;\n color: var(--button-text-color, #111827);\n}\n.chat-btn-text span {\n white-space: nowrap;\n font-weight: 500;\n}\n.chat-btn-text img {\n flex-shrink: 0;\n -o-object-fit: contain;\n object-fit: contain;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n}\n/* Icon-only button */\n.chat-btn-icon {\n }\n.chat-btn-icon img {\n -o-object-fit: contain;\n object-fit: contain;\n width: var(--button-icon-size);\n height: var(--button-icon-size);\n}\n.chat-btn-text.round,\n .chat-btn-icon.round {\n border-radius: 9999px;\n}\n/* Error message styling */\n.error-message {\n padding: 0.5em;\n color: var(--error-text-color);\n }\n/* Chat window positioning classes */\n.chat-window-fullscreen {\n position: fixed;\n inset: 0px;\n z-index: 9999;\n display: flex;\n height: 100%;\n max-height: 100%;\n width: 100%;\n flex-direction: column;\n overflow: hidden;\n border-radius: 0px;\n border-width: 0px;\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n background-color: var(--chat-window-bg-color);\n max-width: var(--chat-window-fullscreen-width);\n}\n.chat-window-normal {\n position: fixed;\n display: flex;\n height: 100vh;\n min-height: 300px;\n width: 100vw;\n min-width: 300px;\n max-width: 1024px;\n flex-direction: column;\n overflow: hidden;\n border-radius: 0.5rem;\n}\n@media (min-width: 640px) {\n\n .chat-window-normal {\n height: var(--chat-window-height);\n width: var(--chat-window-width);\n }\n}\n.chat-window-normal {\n background-color: var(--chat-window-bg-color);\n border: 1px solid var(--chat-window-border-color);\n }\n.chat-window-dragging {\n cursor: grabbing;\n --tw-shadow: 0 25px 50px -12px rgb(0 0 0 / 0.25);\n --tw-shadow-colored: 0 25px 50px -12px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.chat-window-normal:not(.chat-window-dragging) {\n --tw-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 10px 15px -3px var(--tw-shadow-color), 0 4px 6px -4px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n transition-property: box-shadow;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n}\n/* Header/drag bar classes */\n.chat-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 150ms;\n padding: 0.5em;\n background-color: var(--header-bg-color);\n border-bottom: 1px solid var(--header-border-color);\n font-size: var(--header-font-size);\n}\n.header-text {\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--header-text-font-size);\n color: var(--header-text-color);\n}\n.chat-header:hover,\n .chat-header:active {\n background-color: var(--header-bg-hover-color);\n }\n.chat-header-draggable {\n cursor: grab;\n}\n.chat-header-dragging {\n cursor: grabbing;\n}\n.drag-indicator {\n display: none;\n}\n@media (min-width: 640px) {\n\n .drag-indicator {\n display: flex;\n }\n}\n.drag-dots {\n pointer-events: none;\n margin-left: 2px;\n display: flex;\n gap: 2px;\n}\n.header-buttons {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n/* Header button classes */\n.header-button {\n border-radius: 0.375rem;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.375em;\n color: var(--header-button-text-color);\n}\n.header-button svg {\n width: var(--header-button-icon-size);\n height: var(--header-button-icon-size);\n }\n.header-button:hover {\n background-color: var(--header-button-bg-hover-color);\n }\n.fullscreen-button {\n display: none;\n}\n@media (min-width: 640px) {\n\n .fullscreen-button {\n display: block;\n }\n}\n/* Chat content area */\n.chat-content {\n display: flex;\n flex-grow: 1;\n flex-direction: column;\n overflow: hidden;\n}\n/* Loading state */\n.loading-container {\n display: flex;\n flex-grow: 1;\n align-items: center;\n justify-content: center;\n}\n.loading-text {\n margin-left: 2px;\n color: var(--loading-text-color);\n }\n/* Messages container */\n.messages-container {\n flex-grow: 1;\n}\n.messages-container > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.messages-container {\n overflow-y: auto;\n}\n.messages-container::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\n.messages-container::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\n.messages-container::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\n.messages-container::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n.messages-container {\n padding: 1em;\n }\n/* Message bubbles */\n.message-row {\n display: flex;\n}\n.message-row-user {\n justify-content: flex-end;\n}\n.message-row-assistant {\n justify-content: flex-start;\n}\n.message-bubble {\n border-radius: 0.5rem;\n padding: 0.5em 1em;\n}\n.message-bubble-user {\n background-color: var(--message-user-bg-color);\n color: var(--message-user-text-color);\n }\n.message-bubble-assistant {\n background-color: var(--message-assistant-bg-color);\n color: var(--message-assistant-text-color);\n }\n.message-bubble-system {\n background-color: var(--message-system-bg-color);\n color: var(--message-system-text-color);\n }\n.message-timestamp {\n margin-top: 4px;\n opacity: 0.7;\n font-size: var(--chat-window-font-size-sm);\n}\n.message-attachments {\n margin-top: 8px;\n}\n.message-attachments > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));\n}\n/* Welcome messages */\n.welcome-messages > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n/* Typing indicator */\n.typing-indicator {\n height: 0.375rem;\n width: 100%;\n overflow: hidden;\n}\n.typing-progress {\n height: 100%;\n width: 100%;\n transform-origin: 0% 50%;\n}\n@keyframes progress {\n\n 0% {\n transform: translateX(0) scaleX(0);\n }\n\n 10% {\n transform: translateX(0) scaleX(0.3);\n }\n\n 50% {\n transform: translateX(100%) scaleX(0.3);\n }\n\n 90% {\n transform: translateX(0) scaleX(0.3);\n }\n\n 100% {\n transform: translateX(0) scaleX(0);\n }\n}\n.typing-progress {\n animation: progress 3s infinite linear;\n border-radius: 0.5rem;\n background-color: var(--typing-progress-bg-color);\n}\n.typing-text {\n width: 100%;\n justify-content: center;\n opacity: 0.7;\n font-size: var(--chat-window-font-size-sm);\n}\n@keyframes dots {\n\n 0%, 20% {\n color: rgba(0,0,0,0);\n text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0);\n }\n\n 40% {\n color: black;\n text-shadow: .25em 0 0 rgba(0,0,0,0), .5em 0 0 rgba(0,0,0,0);\n }\n\n 60% {\n text-shadow: .25em 0 0 black, .5em 0 0 rgba(0,0,0,0);\n }\n\n 80%, 100% {\n text-shadow: .25em 0 0 black, .5em 0 0 black;\n }\n}\n.typing-dots {\n animation: dots 1s steps(5, end) infinite;\n}\n.typing-dots:after {\n content: ' .';\n}\n/* Starter questions */\n.starter-questions > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.5rem * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.5rem * var(--tw-space-y-reverse));\n}\n.starter-questions {\n padding: 1em;\n }\n.starter-question-row {\n display: flex;\n justify-content: flex-end;\n}\n/* Input area */\n.input-area {\n padding: 1em 1em 0 1em;\n background-color: var(--input-bg-color);\n border-top: 1px solid var(--input-border-color);\n }\n.input-container {\n display: flex;\n gap: 8px;\n}\n.message-textarea {\n flex-grow: 1;\n resize: none;\n border-radius: 0.375rem;\n border-width: 1px;\n --tw-border-opacity: 1;\n border-color: rgb(209 213 219 / var(--tw-border-opacity, 1));\n}\n.message-textarea:focus {\n outline-color: #93c5fd;\n}\n.message-textarea {\n background-color: var(--input-bg-color);\n padding: 0.5em 0.75em;\n color: var(--input-text-color);\n border: 1px solid var(--input-border-color);\n }\n.message-textarea:focus {\n outline-color: var(--input-outline-focus-color);\n }\n.send-button {\n border-radius: 0.375rem;\n font-weight: 500;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.5em 1em;\n}\n.send-button-enabled {\n background-color: var(--send-button-bg-color);\n color: var(--send-button-text-color);\n }\n.send-button-enabled:hover {\n background-color: var(--send-button-bg-hover-color);\n }\n.send-button-disabled {\n cursor: not-allowed;\n background-color: var(--send-button-bg-disabled-color);\n color: var(--send-button-text-disabled-color);\n}\n/* Confirmation dialog */\n.confirmation-overlay {\n position: fixed;\n inset: 0px;\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--confirmation-overlay-bg-color);\n z-index: 9999;\n}\n.confirmation-dialog {\n margin-left: 1rem;\n margin-right: 1rem;\n width: 100%;\n max-width: 24rem;\n background-color: var(--confirmation-dialog-bg-color);\n border: 1px solid var(--confirmation-dialog-border-color);\n border-radius: 0.75em;\n box-shadow: 0 0.625em 1.5625em var(--confirmation-dialog-shadow-color);\n}\n.confirmation-content {\n padding: 1.5em;\n }\n.confirmation-title {\n margin-bottom: 0.5rem;\n font-weight: 600;\n color: var(--confirmation-title-color);\n font-size: var(--confirmation-title-font-size);\n}\n.confirmation-message {\n margin-bottom: 1rem;\n color: var(--confirmation-message-color);\n font-size: var(--confirmation-message-font-size);\n}\n.confirmation-buttons {\n display: flex;\n justify-content: flex-end;\n gap: 0.75em;\n}\n.confirmation-button {\n border-radius: 0.375rem;\n font-weight: 500;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n padding: 0.5em 1em;\n}\n.confirmation-button-cancel {\n background-color: var(--confirmation-button-cancel-bg-color);\n color: var(--confirmation-button-cancel-text-color);\n }\n.confirmation-button-cancel:hover {\n background-color: var(--confirmation-button-cancel-bg-hover-color);\n }\n.confirmation-button-confirm {\n background-color: var(--confirmation-button-confirm-bg-color);\n color: var(--confirmation-button-confirm-text-color);\n }\n.confirmation-button-confirm:hover {\n background-color: var(--confirmation-button-confirm-bg-hover-color);\n }\n.\\!visible {\n visibility: visible !important;\n}\n.visible {\n visibility: visible;\n}\n.static {\n position: static;\n}\n.relative {\n position: relative;\n}\n.flex {\n display: flex;\n}\n.table {\n display: table;\n}\n.hidden {\n display: none;\n}\n.w-full {\n width: 100%;\n}\n.transform {\n transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y));\n}\n.resize {\n resize: both;\n}\n.items-center {\n align-items: center;\n}\n.justify-center {\n justify-content: center;\n}\n.gap-\\[0\\.5em\\] {\n gap: 0.5em;\n}\n.space-y-\\[0\\.25em\\] > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25em * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25em * var(--tw-space-y-reverse));\n}\n.border {\n border-width: 1px;\n}\n.py-\\[2px\\] {\n padding-top: 2px;\n padding-bottom: 2px;\n}\n.text-\\[0\\.8em\\] {\n font-size: 0.8em;\n}\n.font-light {\n font-weight: 300;\n}\n.text-slate-500 {\n --tw-text-opacity: 1;\n color: rgb(100 116 139 / var(--tw-text-opacity, 1));\n}\n.underline {\n text-decoration-line: underline;\n}\n.shadow {\n --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);\n --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);\n box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);\n}\n.filter {\n filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);\n}\n:host {\n /**\n * @prop --chat-z-index: Z-index for chat widget (50)\n *\n * @prop --button-background-color: Button background color (#ffffff)\n * @prop --button-background-color-hover: Button background color on hover (#f3f4f6)\n * @prop --button-text-color: Button text color (#111827)\n * @prop --button-text-color-hover: Button text color on hover (#1d4ed8)\n * @prop --button-border-color: Button border color (#6b7280)\n * @prop --button-border-color-hover: Button border color on hover (#374151)\n * @prop --button-font-size: Button text font size (0.875em)\n * @prop --button-icon-size: Button icon size (1.5em)\n *\n * @prop --chat-window-height: Chat window height in pixels or percent (60%)\n * @prop --chat-window-width: Chat window width in pixels or percent (25%)\n * @prop --chat-window-fullscreen-width: Chat window fullscreen width in pixels or percent (80%)\n * @prop --chat-window-bg-color: Chat window background color (#ffffff)\n * @prop --chat-window-border-color: Chat window border color (#d1d5db)\n * @prop --chat-window-shadow-color: Chat window shadow color (rgba(0, 0, 0, 0.1))\n * @prop --chat-window-font-size: Default font size for text in the chat window (0.875em)\n * @prop --chat-window-font-size-sm: Font size for small text in the chat window (0.75em)\n *\n * @prop --header-bg-color: Header background color (transparent)\n * @prop --header-bg-hover-color: Header background color on hover (#f9fafb)\n * @prop --header-border-color: Header border color (#f3f4f6)\n * @prop --header-button-text-color: Header button text color (#6b7280)\n * @prop --header-button-bg-hover-color: Header button background on hover (#f3f4f6)\n * @prop --header-font-size: Header font size (1em)\n * @prop --header-button-icon-size: Icon size for buttons in the header (1.5em)\n * @prop --header-text-font-size: Font size for the text in the header (1em)\n * @prop --header-text-color: Color for the text in the header (#525762)\n *\n * @prop --starter-question-bg-color: Starter question background color (transparent)\n * @prop --starter-question-bg-hover-color: Starter question background on hover (#eff6ff)\n * @prop --starter-question-text-color: Starter question text color (#3b82f6)\n * @prop --starter-question-border-color: Starter question border color (#3b82f6)\n * @prop --starter-question-border-hover-color: Starter question border on hover (#2563eb)\n *\n * @prop --message-user-bg-color: User message background color (#e4edfb)\n * @prop --message-user-text-color: User message text color (#1f2937)\n * @prop --message-user-link-color: User message link color (#155dfc)\n\n * @prop --message-assistant-bg-color: Assistant message background color (#eae7e8)\n * @prop --message-assistant-text-color: Assistant message text color (--message-user-text-color)\n * @prop --message-assistant-link-color: Assistant message link color (--message-user-link-color)\n\n * @prop --message-system-bg-color: System message background color (#fbe4f8)\n * @prop --message-system-text-color: System message text color (--message-user-text-color)\n * @prop --message-system-link-color: System message link color (--message-user-link-color)\n\n * @prop --message-timestamp-color: User message timestamp color (rgba(255, 255, 255, 0.7))\n * @prop --message-timestamp-assistant-color: Assistant message timestamp color (rgba(75, 85, 99, 0.7))\n *\n * @prop --input-bg-color: Input area background color (transparent)\n * @prop --input-border-color: Input field border color (#d1d5db)\n * @prop --input-text-color: Input text color (#111827)\n * @prop --input-placeholder-color: Input placeholder text color (#6b7280)\n * @prop --input-outline-focus-color: Input field focus ring color (#3b82f6)\n *\n * @prop --send-button-bg-color: Send button background color (#3b82f6)\n * @prop --send-button-bg-hover-color: Send button background on hover (#2563eb)\n * @prop --send-button-text-color: Send button text color (#ffffff)\n * @prop --send-button-bg-disabled-color: Send button background when disabled (#d1d5db)\n * @prop --send-button-text-disabled-color: Send button text when disabled (#6b7280)\n *\n * @prop --loading-text-color: Loading text color (#6b7280)\n * @prop --loading-spinner-track-color: Loading spinner track color (#e5e7eb)\n * @prop --loading-spinner-fill-color: Loading spinner fill color (#3b82f6)\n * @prop --loading-spinner-size: Loading spinner size (1.25em)\n *\n * @prop --typing-progress-bg-color: Typing progress bar background color (#ade3ff)\n *\n * @prop --scrollbar-track-color: Scrollbar track color (#f3f4f6)\n * @prop --scrollbar-thumb-color: Scrollbar thumb color (#d1d5db)\n * @prop --scrollbar-thumb-hover-color: Scrollbar thumb hover color (#9ca3af)\n *\n * @prop --error-text-color: Error text color (#ef4444)\n * @prop --success-text-color: Success text color (#10b981)\n *\n * @prop --code-bg-user-color: Code background in user messages (--message-user-bg-color + 20% white)\n * @prop --code-text-user-color: Code text color in user messages (--message-user-text-color)\n * @prop --code-border-user-color: Code border in user messages (--message-user-bg-color + 20% black)\n * @prop --code-bg-assistant-color: Code background in assistant messages (--message-assistant-bg-color + 50% white)\n * @prop --code-text-assistant-color: Code text color in assistant messages (--message-assistant-text-color)\n * @prop --code-border-assistant-color: Code border in assistant messages (--message-assistant-bg-color + 10% black)\n *\n * @prop --confirmation-overlay-bg-color: Confirmation dialog overlay background color (rgba(0, 0, 0, 0.5))\n * @prop --confirmation-dialog-bg-color: Confirmation dialog background color (uses --chat-window-bg-color)\n * @prop --confirmation-dialog-border-color: Confirmation dialog border color (uses --chat-window-border-color)\n * @prop --confirmation-dialog-shadow-color: Confirmation dialog shadow color (uses --chat-window-shadow-color)\n * @prop --confirmation-title-color: Confirmation dialog title text color (uses #111827)\n * @prop --confirmation-title-font-size: Confirmation dialog title font size (1.125em)\n * @prop --confirmation-message-color: Confirmation dialog message text color (uses --loading-text-color)\n * @prop --confirmation-message-font-size: Confirmation dialog message font size (uses 1em)\n * @prop --confirmation-button-cancel-bg-color: Cancel button background color (uses --button-background-color-hover)\n * @prop --confirmation-button-cancel-bg-hover-color: Cancel button background on hover (uses #e5e7eb)\n * @prop --confirmation-button-cancel-text-color: Cancel button text color (uses --header-button-text-color)\n * @prop --confirmation-button-confirm-bg-color: Confirm button background color (uses --error-text-color)\n * @prop --confirmation-button-confirm-bg-hover-color: Confirm button background on hover (uses --error-text-color)\n * @prop --confirmation-button-confirm-text-color: Confirm button text color (uses --send-button-text-color)\n * @prop --file-attachment-button-bg-color: Attach file button background color (transparent)\n * @prop --file-attachment-button-bg-hover-color: Attach file button background hover color (--header-button-bg-hover-color)\n * @prop --file-attachment-button-text-color: Attach file button text color (--header-button-text-color)\n * @prop --file-attachment-button-text-disabled-color: Attach file button disabled text color (--send-button-text-disabled-color)\n *\n * @prop --selected-files-bg-color: Selected files container background color (--chat-window-bg-color)\n * @prop --selected-files-border-color: Selected files container border color (--header-border-color)\n *\n * @prop --selected-file-bg-color: Selected file item background color (--message-system-bg-color)\n * @prop --selected-file-font-size: Selected file item font size (--chat-window-font-size-sm)\n * @prop --selected-file-name-color: Selected file name color (--message-assistant-text-color)\n * @prop --selected-file-size-color: Selected file size display color (--input-placeholder-color)\n * @prop --selected-file-icon-size: Selected file item icon size (1.25em)\n * @prop --selected-file-remove-icon-color: Selected file remove icon color (--error-text-color)\n * @prop --selected-file-remove-icon-hover-color: Selected file remove icon hover (#dc2626)\n *\n * @prop --message-attachment-icon-size: Message attachment icon size (1em)\n */\n /* Global variables */\n --chat-z-index: 50;\n\n /* Button variables */\n --button-background-color: #ffffff;\n --button-background-color-hover: #f3f4f6;\n --button-text-color: #111827;\n --button-text-color-hover: #1d4ed8;\n --button-border-color: #d1d5db;\n --button-border-color-hover: #6b7280;\n --button-font-size: 1em; /* text-sm */\n --button-icon-size: 1.5em;\n\n /* Chat window variables */\n --chat-window-height: 60%;\n --chat-window-width: 25%;\n --chat-window-fullscreen-width: 80%;\n --chat-window-bg-color: #ffffff;\n --chat-window-border-color: #d1d5db;\n --chat-window-shadow-color: rgba(0, 0, 0, 0.1);\n --chat-window-font-size: 0.875em; /* text-sm */\n --chat-window-font-size-sm: 0.75em; /* text-xs */\n\n /* Header variables */\n --header-bg-color: transparent;\n --header-bg-hover-color: #f9fafb;\n --header-border-color: #f3f4f6;\n --header-button-text-color: #6b7280;\n --header-button-bg-hover-color: #f3f4f6;\n --header-font-size: 1em;\n --header-text-font-size: 1em;\n --header-text-color: #525762;\n --header-button-icon-size: 1.5em;\n\n /* Starter question variables */\n --starter-question-bg-color: transparent;\n --starter-question-bg-hover-color: #eff6ff;\n --starter-question-text-color: #3b82f6;\n --starter-question-border-color: #3b82f6;\n --starter-question-border-hover-color: #2563eb;\n\n /* Message bubble variables */\n --message-user-bg-color: #e4edfb;\n --message-user-text-color: #1f2937;\n --message-user-link-color: #155dfc;\n\n --message-assistant-bg-color: #eae7e8;\n --message-assistant-text-color: var(--message-user-text-color);\n --message-assistant-link-color: var(--message-user-link-color);\n\n --message-system-bg-color: #fbe4f8;\n --message-system-text-color: var(--message-user-text-color);\n --message-system-link-color: var(--message-user-link-color);\n\n --message-timestamp-color: rgba(255, 255, 255, 0.7);\n --message-timestamp-assistant-color: rgba(75, 85, 99, 0.7);\n\n /* Input area variables */\n --input-bg-color: transparent;\n --input-border-color: #d1d5db;\n --input-text-color: #111827;\n --input-placeholder-color: #6b7280;\n --input-outline-focus-color: #3b82f6;\n\n /* Send button variables */\n --send-button-bg-color: #3b82f6;\n --send-button-bg-hover-color: #2563eb;\n --send-button-text-color: #ffffff;\n --send-button-bg-disabled-color: #d1d5db;\n --send-button-text-disabled-color: #6b7280;\n\n /* Loading variables */\n --loading-text-color: #6b7280;\n --loading-spinner-track-color: #e5e7eb;\n --loading-spinner-fill-color: #3b82f6;\n --loading-spinner-size: 1.25em;\n\n /* Typing indicator variables */\n --typing-progress-bg-color: #ade3ff;\n\n /* Scrollbar variables */\n --scrollbar-track-color: #f3f4f6;\n --scrollbar-thumb-color: #d1d5db;\n --scrollbar-thumb-hover-color: #9ca3af;\n\n /* Error variables */\n --error-text-color: #ef4444;\n --success-text-color: #10b981; /* Complementary green to existing blue palette */;\n\n /* Markdown code variables */\n --code-bg-user-color: color-mix(in srgb, var(--message-user-bg-color) 80%, white 20%);\n --code-text-user-color: var(--message-user-text-color);\n --code-border-user-color: color-mix(in srgb, var(--message-user-bg-color) 90%, black 10%);\n --code-bg-assistant-color: color-mix(in srgb, var(--message-assistant-bg-color) 50%, white 50%);\n --code-text-assistant-color: var(--message-assistant-text-color);\n --code-border-assistant-color: color-mix(in srgb, var(--message-assistant-bg-color) 90%, black 10%);;\n\n --confirmation-overlay-bg-color: rgba(0, 0, 0, 0.5);\n --confirmation-dialog-bg-color: var(--chat-window-bg-color);\n --confirmation-dialog-border-color: var(--chat-window-border-color);\n --confirmation-dialog-shadow-color: var(--chat-window-shadow-color);\n --confirmation-title-color: #111827;\n --confirmation-title-font-size: 1.125em;\n --confirmation-message-color: var(--loading-text-color);\n --confirmation-message-font-size: 1em;\n --confirmation-button-cancel-bg-color: var(--button-background-color-hover);\n --confirmation-button-cancel-bg-hover-color: #e5e7eb;\n --confirmation-button-cancel-text-color: var(--header-button-text-color);\n --confirmation-button-confirm-bg-color: var(--error-text-color);\n --confirmation-button-confirm-bg-hover-color: var(--error-text-color);\n --confirmation-button-confirm-text-color: var(--send-button-text-color);\n\n /* File upload variables */\n --file-attachment-button-bg-color: transparent;\n --file-attachment-button-bg-hover-color: var(--header-button-bg-hover-color); /* #f3f4f6 */\n --file-attachment-button-text-color: var(--header-button-text-color); /* #6b7280 */\n --file-attachment-button-text-disabled-color: var(--send-button-text-disabled-color); /* #6b7280 */\n\n /* Selected files variables */\n --selected-files-bg-color: var(--chat-window-bg-color); /* transparent */\n --selected-files-border-color: var(--header-border-color); /* #f3f4f6 */\n\n /* Selected file item variables */\n --selected-file-bg-color: var(--message-system-bg-color); /* #f3f4f6 */\n\n /* Selected file text variables */\n --selected-file-font-size: var(--chat-window-font-size-sm);\n --selected-file-name-color: var(--message-assistant-text-color); /* #1f2937 */\n --selected-file-size-color: var(--input-placeholder-color); /* #6b7280 */\n\n /* Selected file icon variables */\n --selected-file-icon-size: 1.25em;\n --selected-file-remove-icon-color: var(--error-text-color); /* #ef4444 */\n --selected-file-remove-icon-hover-color: #dc2626; /* Darker red for hover */\n\n /* Message attachment variables */\n --message-attachment-icon-size: 1em;\n\n display: block;\n position: fixed;\n right: 30px;\n bottom: 30px;\n}\ntextarea {\n max-height: 8rem;\n min-height: 2.5rem;\n resize: none;\n overflow-y: auto;\n}\ntextarea::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\ntextarea::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\ntextarea::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\ntextarea::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n@keyframes spin {\n\n to {\n transform: rotate(360deg);\n }\n}\n.loading-spinner {\n animation: spin 1s linear infinite;\n border-radius: 9999px;\n border-width: 2px;\n border-color: var(--loading-spinner-track-color);\n border-top-color: var(--loading-spinner-fill-color);\n width: var(--loading-spinner-size);\n height: var(--loading-spinner-size);\n}\n.overflow-y-auto::-webkit-scrollbar {\n height: 0.375rem;\n width: 0.375rem;\n}\n.overflow-y-auto::-webkit-scrollbar-track {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-track-color);\n}\n.overflow-y-auto::-webkit-scrollbar-thumb {\n border-radius: 0.25rem;\n background-color: var(--scrollbar-thumb-color);\n}\n.overflow-y-auto::-webkit-scrollbar-thumb:hover {\n background-color: var(--scrollbar-thumb-hover-color);\n}\n/* Markdown content styling for chat messages */\n.chat-markdown {\n color: var(--tw-prose-body);\n max-width: 65ch;\n}\n.chat-markdown :where(p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n}\n.chat-markdown :where([class~=\"lead\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-lead);\n font-size: 1.25em;\n line-height: 1.6;\n margin-top: 1.2em;\n margin-bottom: 1.2em;\n}\n.chat-markdown :where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-links);\n text-decoration: underline;\n font-weight: 500;\n}\n.chat-markdown :where(strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-bold);\n font-weight: 600;\n}\n.chat-markdown :where(a strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(blockquote strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(thead th strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: decimal;\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(ol[type=\"A\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-alpha;\n}\n.chat-markdown :where(ol[type=\"a\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-alpha;\n}\n.chat-markdown :where(ol[type=\"A\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-alpha;\n}\n.chat-markdown :where(ol[type=\"a\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-alpha;\n}\n.chat-markdown :where(ol[type=\"I\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-roman;\n}\n.chat-markdown :where(ol[type=\"i\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-roman;\n}\n.chat-markdown :where(ol[type=\"I\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: upper-roman;\n}\n.chat-markdown :where(ol[type=\"i\" s]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: lower-roman;\n}\n.chat-markdown :where(ol[type=\"1\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: decimal;\n}\n.chat-markdown :where(ul):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n list-style-type: disc;\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::marker {\n font-weight: 400;\n color: var(--tw-prose-counters);\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::marker {\n color: var(--tw-prose-bullets);\n}\n.chat-markdown :where(dt):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n margin-top: 1.25em;\n}\n.chat-markdown :where(hr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-color: var(--tw-prose-hr);\n border-top-width: 1px;\n margin-top: 3em;\n margin-bottom: 3em;\n}\n.chat-markdown :where(blockquote):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 500;\n font-style: italic;\n color: var(--tw-prose-quotes);\n border-inline-start-width: 0.25rem;\n border-inline-start-color: var(--tw-prose-quote-borders);\n quotes: \"\\201C\"\"\\201D\"\"\\2018\"\"\\2019\";\n margin-top: 1.6em;\n margin-bottom: 1.6em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(blockquote p:first-of-type):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: open-quote;\n}\n.chat-markdown :where(blockquote p:last-of-type):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: close-quote;\n}\n.chat-markdown :where(h1):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 800;\n font-size: 2.25em;\n margin-top: 0;\n margin-bottom: 0.8888889em;\n line-height: 1.1111111;\n}\n.chat-markdown :where(h1 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 900;\n color: inherit;\n}\n.chat-markdown :where(h2):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 700;\n font-size: 1.5em;\n margin-top: 2em;\n margin-bottom: 1em;\n line-height: 1.3333333;\n}\n.chat-markdown :where(h2 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 800;\n color: inherit;\n}\n.chat-markdown :where(h3):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n font-size: 1.25em;\n margin-top: 1.6em;\n margin-bottom: 0.6em;\n line-height: 1.6;\n}\n.chat-markdown :where(h3 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 700;\n color: inherit;\n}\n.chat-markdown :where(h4):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n margin-top: 1.5em;\n margin-bottom: 0.5em;\n line-height: 1.5;\n}\n.chat-markdown :where(h4 strong):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 700;\n color: inherit;\n}\n.chat-markdown :where(img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(picture):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n display: block;\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(video):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(kbd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-weight: 500;\n font-family: inherit;\n color: var(--tw-prose-kbd);\n box-shadow: 0 0 0 1px rgb(var(--tw-prose-kbd-shadows) / 10%), 0 3px 0 rgb(var(--tw-prose-kbd-shadows) / 10%);\n font-size: 0.875em;\n border-radius: 0.3125rem;\n padding-top: 0.1875em;\n padding-inline-end: 0.375em;\n padding-bottom: 0.1875em;\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-code);\n font-weight: 600;\n font-size: 0.875em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: \"`\";\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: \"`\";\n}\n.chat-markdown :where(a code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(h1 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(h2 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n font-size: 0.875em;\n}\n.chat-markdown :where(h3 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n font-size: 0.9em;\n}\n.chat-markdown :where(h4 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(blockquote code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(thead th code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: inherit;\n}\n.chat-markdown :where(pre):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-pre-code);\n background-color: var(--tw-prose-pre-bg);\n overflow-x: auto;\n font-weight: 400;\n font-size: 0.875em;\n line-height: 1.7142857;\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n border-radius: 0.375rem;\n padding-top: 0.8571429em;\n padding-inline-end: 1.1428571em;\n padding-bottom: 0.8571429em;\n padding-inline-start: 1.1428571em;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n background-color: transparent;\n border-width: 0;\n border-radius: 0;\n padding: 0;\n font-weight: inherit;\n color: inherit;\n font-size: inherit;\n font-family: inherit;\n line-height: inherit;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::before {\n content: none;\n}\n.chat-markdown :where(pre code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))::after {\n content: none;\n}\n.chat-markdown :where(table):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n width: 100%;\n table-layout: auto;\n margin-top: 2em;\n margin-bottom: 2em;\n font-size: 0.875em;\n line-height: 1.7142857;\n}\n.chat-markdown :where(thead):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 1px;\n border-bottom-color: var(--tw-prose-th-borders);\n}\n.chat-markdown :where(thead th):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-headings);\n font-weight: 600;\n vertical-align: bottom;\n padding-inline-end: 0.5714286em;\n padding-bottom: 0.5714286em;\n padding-inline-start: 0.5714286em;\n}\n.chat-markdown :where(tbody tr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 1px;\n border-bottom-color: var(--tw-prose-td-borders);\n}\n.chat-markdown :where(tbody tr:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-bottom-width: 0;\n}\n.chat-markdown :where(tbody td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n vertical-align: baseline;\n}\n.chat-markdown :where(tfoot):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n border-top-width: 1px;\n border-top-color: var(--tw-prose-th-borders);\n}\n.chat-markdown :where(tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n vertical-align: top;\n}\n.chat-markdown :where(th, td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n text-align: start;\n}\n.chat-markdown :where(figure > *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(figcaption):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n color: var(--tw-prose-captions);\n font-size: 0.875em;\n line-height: 1.4285714;\n margin-top: 0.8571429em;\n}\n.chat-markdown {\n --tw-prose-body: #374151;\n --tw-prose-headings: #111827;\n --tw-prose-lead: #4b5563;\n --tw-prose-links: #111827;\n --tw-prose-bold: #111827;\n --tw-prose-counters: #6b7280;\n --tw-prose-bullets: #d1d5db;\n --tw-prose-hr: #e5e7eb;\n --tw-prose-quotes: #111827;\n --tw-prose-quote-borders: #e5e7eb;\n --tw-prose-captions: #6b7280;\n --tw-prose-kbd: #111827;\n --tw-prose-kbd-shadows: 17 24 39;\n --tw-prose-code: #111827;\n --tw-prose-pre-code: #e5e7eb;\n --tw-prose-pre-bg: #1f2937;\n --tw-prose-th-borders: #d1d5db;\n --tw-prose-td-borders: #e5e7eb;\n --tw-prose-invert-body: #d1d5db;\n --tw-prose-invert-headings: #fff;\n --tw-prose-invert-lead: #9ca3af;\n --tw-prose-invert-links: #fff;\n --tw-prose-invert-bold: #fff;\n --tw-prose-invert-counters: #9ca3af;\n --tw-prose-invert-bullets: #4b5563;\n --tw-prose-invert-hr: #374151;\n --tw-prose-invert-quotes: #f3f4f6;\n --tw-prose-invert-quote-borders: #374151;\n --tw-prose-invert-captions: #9ca3af;\n --tw-prose-invert-kbd: #fff;\n --tw-prose-invert-kbd-shadows: 255 255 255;\n --tw-prose-invert-code: #fff;\n --tw-prose-invert-pre-code: #d1d5db;\n --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);\n --tw-prose-invert-th-borders: #4b5563;\n --tw-prose-invert-td-borders: #374151;\n font-size: 1rem;\n line-height: 1.75;\n}\n.chat-markdown :where(picture > img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5em;\n margin-bottom: 0.5em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.375em;\n}\n.chat-markdown :where(.prose > ul > li p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.75em;\n margin-bottom: 0.75em;\n}\n.chat-markdown :where(.prose > ul > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n}\n.chat-markdown :where(.prose > ul > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(.prose > ol > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n}\n.chat-markdown :where(.prose > ol > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.75em;\n margin-bottom: 0.75em;\n}\n.chat-markdown :where(dl):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.25em;\n margin-bottom: 1.25em;\n}\n.chat-markdown :where(dd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5em;\n padding-inline-start: 1.625em;\n}\n.chat-markdown :where(hr + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h2 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h3 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h4 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(thead th:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(thead th:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(tbody td, tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-top: 0.5714286em;\n padding-inline-end: 0.5714286em;\n padding-bottom: 0.5714286em;\n padding-inline-start: 0.5714286em;\n}\n.chat-markdown :where(tbody td:first-child, tfoot td:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(tbody td:last-child, tfoot td:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(figure):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2em;\n margin-bottom: 2em;\n}\n.chat-markdown :where(.prose > :first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(.prose > :last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 0;\n}\n.chat-markdown {\n font-size: 0.875rem;\n line-height: 1.7142857;\n}\n.chat-markdown :where(p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where([class~=\"lead\"]):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.2857143em;\n line-height: 1.5555556;\n margin-top: 0.8888889em;\n margin-bottom: 0.8888889em;\n}\n.chat-markdown :where(blockquote):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.3333333em;\n margin-bottom: 1.3333333em;\n padding-inline-start: 1.1111111em;\n}\n.chat-markdown :where(h1):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 2.1428571em;\n margin-top: 0;\n margin-bottom: 0.8em;\n line-height: 1.2;\n}\n.chat-markdown :where(h2):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.4285714em;\n margin-top: 1.6em;\n margin-bottom: 0.8em;\n line-height: 1.4;\n}\n.chat-markdown :where(h3):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 1.2857143em;\n margin-top: 1.5555556em;\n margin-bottom: 0.4444444em;\n line-height: 1.5555556;\n}\n.chat-markdown :where(h4):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.4285714em;\n margin-bottom: 0.5714286em;\n line-height: 1.4285714;\n}\n.chat-markdown :where(img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(picture):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(picture > img):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(video):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(kbd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n border-radius: 0.3125rem;\n padding-top: 0.1428571em;\n padding-inline-end: 0.3571429em;\n padding-bottom: 0.1428571em;\n padding-inline-start: 0.3571429em;\n}\n.chat-markdown :where(code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n}\n.chat-markdown :where(h2 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.9em;\n}\n.chat-markdown :where(h3 code):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8888889em;\n}\n.chat-markdown :where(pre):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.6666667;\n margin-top: 1.6666667em;\n margin-bottom: 1.6666667em;\n border-radius: 0.25rem;\n padding-top: 0.6666667em;\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(ul):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.2857143em;\n margin-bottom: 0.2857143em;\n}\n.chat-markdown :where(ol > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.4285714em;\n}\n.chat-markdown :where(ul > li):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0.4285714em;\n}\n.chat-markdown :where(.prose-sm > ul > li p):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5714286em;\n margin-bottom: 0.5714286em;\n}\n.chat-markdown :where(.prose-sm > ul > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ul > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ol > li > p:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(.prose-sm > ol > li > p:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(ul ul, ul ol, ol ul, ol ol):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.5714286em;\n margin-bottom: 0.5714286em;\n}\n.chat-markdown :where(dl):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n margin-bottom: 1.1428571em;\n}\n.chat-markdown :where(dt):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.1428571em;\n}\n.chat-markdown :where(dd):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0.2857143em;\n padding-inline-start: 1.5714286em;\n}\n.chat-markdown :where(hr):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 2.8571429em;\n margin-bottom: 2.8571429em;\n}\n.chat-markdown :where(hr + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h2 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h3 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(h4 + *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(table):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.5;\n}\n.chat-markdown :where(thead th):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(thead th:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(thead th:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(tbody td, tfoot td):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-top: 0.6666667em;\n padding-inline-end: 1em;\n padding-bottom: 0.6666667em;\n padding-inline-start: 1em;\n}\n.chat-markdown :where(tbody td:first-child, tfoot td:first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-start: 0;\n}\n.chat-markdown :where(tbody td:last-child, tfoot td:last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n padding-inline-end: 0;\n}\n.chat-markdown :where(figure):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 1.7142857em;\n margin-bottom: 1.7142857em;\n}\n.chat-markdown :where(figure > *):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n margin-bottom: 0;\n}\n.chat-markdown :where(figcaption):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n font-size: 0.8571429em;\n line-height: 1.3333333;\n margin-top: 0.6666667em;\n}\n.chat-markdown :where(.prose-sm > :first-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-top: 0;\n}\n.chat-markdown :where(.prose-sm > :last-child):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *)) {\n margin-bottom: 0;\n}\n.chat-markdown {\n --tw-prose-body: #374151;\n --tw-prose-headings: #111827;\n --tw-prose-lead: #4b5563;\n --tw-prose-links: #111827;\n --tw-prose-bold: #111827;\n --tw-prose-counters: #6b7280;\n --tw-prose-bullets: #d1d5db;\n --tw-prose-hr: #e5e7eb;\n --tw-prose-quotes: #111827;\n --tw-prose-quote-borders: #e5e7eb;\n --tw-prose-captions: #6b7280;\n --tw-prose-kbd: #111827;\n --tw-prose-kbd-shadows: 17 24 39;\n --tw-prose-code: #111827;\n --tw-prose-pre-code: #e5e7eb;\n --tw-prose-pre-bg: #1f2937;\n --tw-prose-th-borders: #d1d5db;\n --tw-prose-td-borders: #e5e7eb;\n --tw-prose-invert-body: #d1d5db;\n --tw-prose-invert-headings: #fff;\n --tw-prose-invert-lead: #9ca3af;\n --tw-prose-invert-links: #fff;\n --tw-prose-invert-bold: #fff;\n --tw-prose-invert-counters: #9ca3af;\n --tw-prose-invert-bullets: #4b5563;\n --tw-prose-invert-hr: #374151;\n --tw-prose-invert-quotes: #f3f4f6;\n --tw-prose-invert-quote-borders: #374151;\n --tw-prose-invert-captions: #9ca3af;\n --tw-prose-invert-kbd: #fff;\n --tw-prose-invert-kbd-shadows: 255 255 255;\n --tw-prose-invert-code: #fff;\n --tw-prose-invert-pre-code: #d1d5db;\n --tw-prose-invert-pre-bg: rgb(0 0 0 / 50%);\n --tw-prose-invert-th-borders: #4b5563;\n --tw-prose-invert-td-borders: #374151;\n max-width: none;\n}\n.chat-markdown :is(:where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))) {\n text-decoration-line: none;\n}\n.chat-markdown :is(:where(a):not(:where([class~=\"not-prose\"],[class~=\"not-prose\"] *))):hover {\n text-decoration-line: underline;\n}\n.chat-markdown {\n font-size: 1em;\n}\n/* override spacing */\n.chat-markdown > * {\n margin-top: 0.1em;\n margin-bottom: 0.1em;\n}\n.message-bubble-assistant .chat-markdown {\n --tw-prose-body: var(--message-assistant-text-color);\n --tw-prose-headings: var(--message-assistant-text-color);\n --tw-prose-lead: var(--message-assistant-text-color);\n --tw-prose-links: var(--message-assistant-link-color);\n --tw-prose-bold: var(--message-assistant-text-color);\n --tw-prose-counters: var(--message-assistant-text-color);\n --tw-prose-bullets: var(--message-assistant-text-color);\n --tw-prose-hr: var(--message-assistant-text-color);\n --tw-prose-quotes: var(--message-assistant-text-color);\n --tw-prose-quote-borders: var(--message-assistant-text-color);\n --tw-prose-captions: var(--message-assistant-text-color);\n --tw-prose-kbd: var(--message-assistant-text-color);\n --tw-prose-kbd-shadows: var(--message-assistant-text-color);\n --tw-prose-code: var(--code-text-assistant-color);\n --tw-prose-pre-code: var(--code-text-assistant-color);\n --tw-prose-pre-bg: var(--code-bg-assistant-color);\n --tw-prose-th-borders: var(--message-assistant-text-color);\n --tw-prose-td-borders: var(--message-assistant-text-color);\n}\n.message-bubble-user .chat-markdown {\n --tw-prose-body: var(--message-user-text-color);\n --tw-prose-headings: var(--message-user-text-color);\n --tw-prose-lead: var(--message-user-text-color);\n --tw-prose-links: var(--message-user-link-color);\n --tw-prose-bold: var(--message-user-text-color);\n --tw-prose-counters: var(--message-user-text-color);\n --tw-prose-bullets: var(--message-user-text-color);\n --tw-prose-hr: var(--message-user-text-color);\n --tw-prose-quotes: var(--message-user-text-color);\n --tw-prose-quote-borders: var(--message-user-text-color);\n --tw-prose-captions: var(--message-user-text-color);\n --tw-prose-kbd: var(--message-user-text-color);\n --tw-prose-kbd-shadows: var(--message-user-text-color);\n --tw-prose-code: var(--code-text-user-color);\n --tw-prose-pre-code: var(--code-text-user-color);\n --tw-prose-pre-bg: var(--code-bg-user-color);\n --tw-prose-th-borders: var(--message-user-text-color);\n --tw-prose-td-borders: var(--message-user-text-color);\n}\n.message-bubble-system .chat-markdown {\n --tw-prose-body: var(--message-system-text-color);\n --tw-prose-headings: var(--message-system-text-color);\n --tw-prose-lead: var(--message-system-text-color);\n --tw-prose-links: var(--message-system-link-color);\n --tw-prose-bold: var(--message-system-text-color);\n --tw-prose-counters: var(--message-system-text-color);\n --tw-prose-bullets: var(--message-system-text-color);\n --tw-prose-hr: var(--message-system-text-color);\n --tw-prose-quotes: var(--message-system-text-color);\n --tw-prose-quote-borders: var(--message-system-text-color);\n --tw-prose-captions: var(--message-system-text-color);\n --tw-prose-kbd: var(--message-system-text-color);\n --tw-prose-kbd-shadows: var(--message-system-text-color);\n --tw-prose-code: var(--message-system-text-color);\n --tw-prose-pre-code: var(--message-system-text-color);\n --tw-prose-pre-bg: var(--message-system-text-color);\n --tw-prose-th-borders: var(--message-system-text-color);\n --tw-prose-td-borders: var(--message-system-text-color);\n}\n.message-bubble-user .chat-markdown pre {\n border: 1px solid var(--code-border-user-color);\n}\n.message-bubble-assistant .chat-markdown pre {\n border: 1px solid var(--code-border-assistant-color);\n}\n.loading:after {\n content: ' .';\n}\n/* File Upload Button */\n.file-attachment-button {\n border-radius: 0.375rem;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n}\n.file-attachment-button:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n.file-attachment-button {\n padding: 0.375em;\n background-color: var(--file-attachment-button-bg-color);\n color: var(--file-attachment-button-text-color);\n}\n.file-attachment-button svg {\n width: 1.5em;\n height: 1.5em;\n}\n.file-attachment-button:hover:not(:disabled) {\n background-color: var(--file-attachment-button-bg-hover-color);\n}\n.file-attachment-button:disabled {\n color: var(--file-attachment-button-text-disabled-color);\n}\n/* Selected Files Container */\n.selected-files-container {\n padding: 1em 1em 0.5em 1em;\n background-color: var(--selected-files-bg-color);\n border-top: 1px solid var(--selected-files-border-color);\n}\n/* Selected File Item */\n.selected-file-item {\n display: flex;\n align-items: center;\n justify-content: space-between;\n background-color: var(--selected-file-bg-color);\n border-radius: 0.375em;\n padding: 0.25em 0.5em;\n font-size: var(--selected-file-font-size);\n color: var(--selected-file-name-color);\n}\n.selected-file-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.selected-file-icon svg {\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-size {\n color: var(--selected-file-size-color);\n}\n.selected-file-error {\n color: var(--error-text-color);\n}\n.selected-file-success-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--success-text-color);\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-remove-button {\n font-weight: 700;\n transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;\n transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);\n transition-duration: 200ms;\n color: var(--selected-file-remove-icon-color);\n padding: 0.375em;\n}\n.selected-file-remove-button svg {\n width: var(--selected-file-icon-size);\n height: var(--selected-file-icon-size);\n}\n.selected-file-remove-button:hover {\n color: var(--selected-file-remove-icon-hover-color);\n}\n/* Message Attachments */\n.message-attachments {\n margin-top: 0.5em;\n}\n.message-attachments > :not([hidden]) ~ :not([hidden]) {\n --tw-space-y-reverse: 0;\n margin-top: calc(0.25em * calc(1 - var(--tw-space-y-reverse)));\n margin-bottom: calc(0.25em * var(--tw-space-y-reverse));\n}\n.message-attachments {\n font-size: var(--chat-window-font-size-sm);\n}\n.message-attachment-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: var(--message-attachment-icon-size);\n height: var(--message-attachment-icon-size);\n}\n/* Update Send Button for Upload State */\n.send-button-disabled {\n cursor: not-allowed;\n background-color: var(--send-button-bg-disabled-color);\n color: var(--send-button-text-disabled-color);\n}\n";
|
|
5173
|
+
const ocsChatCss = "/*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{@supports ((-webkit-hyphens:none) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,::backdrop,:after,:before{--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-duration:initial;--tw-ease:initial;--tw-scale-x:1;--tw-scale-y:1;--tw-scale-z:1}}}@layer theme{:host,:root{--font-sans:ui-sans-serif,system-ui,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;--color-blue-300:oklch(80.9% .105 251.813);--color-slate-500:oklch(55.4% .046 257.417);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--spacing:.25rem;--breakpoint-lg:64rem;--container-sm:24rem;--font-weight-light:300;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--radius-sm:.25rem;--radius-md:.375rem;--radius-lg:.5rem;--ease-in-out:cubic-bezier(.4,0,.2,1);--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--animate-progress:progress 3s infinite linear;--animate-dots:dots 1s steps(5,end)infinite;--transform-origin-left-right:0% 50%}}@layer base{*,::backdrop,:after,:before{border:0 solid;border-color:var(--color-gray-200,currentcolor);box-sizing:border-box;margin:0;padding:0}::file-selector-button{-webkit-appearance:button;-moz-appearance:button;appearance:button;background-color:#0000;border:0 solid;border-color:var(--color-gray-200,currentcolor);border-radius:0;box-sizing:border-box;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;margin:0;margin-inline-end:4px;opacity:1;padding:0}:host,html{-webkit-text-size-adjust:100%;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-tap-highlight-color:transparent}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-size:1em;font-variation-settings:var(--default-mono-font-variation-settings,normal)}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}menu,ol,ul{list-style:none}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}button,input,optgroup,select,textarea{background-color:#0000;border-radius:0;color:inherit;font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;opacity:1}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::-moz-placeholder{opacity:1}::placeholder{opacity:1}@supports (not (-webkit-appearance:-apple-pay-button)) or (contain-intrinsic-size:1px){::-moz-placeholder{color:currentColor}::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::-moz-placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex;padding-block:0}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field,::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-meridiem-field,::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){-webkit-appearance:button;-moz-appearance:button;appearance:button}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.visible{visibility:visible}.fixed{position:fixed}.relative{position:relative}.static{position:static}.container{width:100%}.flex{display:flex}.hidden{display:none}.w-full{width:100%}.transform{transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,)}.resize{resize:both}.items-center{align-items:center}.justify-center{justify-content:center}.gap-\\[0\\.5em\\]{gap:.5em}:where(.space-y-\\[0\\.25em\\]>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(.25em*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(.25em*var(--tw-space-y-reverse))}.border{border-style:var(--tw-border-style);border-width:1px}.py-\\[2px\\]{padding-block:2px}.text-\\[0\\.8em\\]{font-size:.8em}.font-light{--tw-font-weight:var(--font-weight-light);font-weight:var(--font-weight-light)}.text-slate-500{color:var(--color-slate-500)}.underline{text-decoration-line:underline}.shadow{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a),0 1px 2px -1px var(--tw-shadow-color,#0000001a)}.ring,.shadow{box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.ring{--tw-ring-shadow:var(--tw-ring-inset,)0 0 0 calc(1px + var(--tw-ring-offset-width))var(--tw-ring-color,currentcolor)}} /*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components; /*! tailwindcss v4.1.12 | MIT License | https://tailwindcss.com */@layer properties{}@layer base{}@layer components{#ocs-chat-window{font-size:var(--chat-window-font-size);z-index:var(--chat-z-index)}.starter-question{border-radius:var(--radius-lg);text-align:left;--tw-duration:.2s;background-color:var(--starter-question-bg-color);border:1px solid var(--starter-question-border-color);color:var(--starter-question-text-color);padding:.75em;transition-duration:.2s}.starter-question:hover{background-color:var(--starter-question-bg-hover-color);border-color:var(--starter-question-border-hover-color)}.chat-btn-text{border-radius:var(--radius-lg);border-style:var(--tw-border-style);transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;--tw-ease:var(--ease-in-out);align-items:center;background-color:var(--button-background-color,#fff);border-width:0;border:1px solid var(--button-border-color);color:var(--button-text-color,#111827);display:flex;font-size:var(--button-font-size);gap:8px;padding:.5em;transition-duration:.2s;transition-timing-function:var(--ease-in-out);z-index:var(--chat-z-index,50)}.chat-btn-text:hover{border:1px solid var(--button-border-color-hover);color:var(--button-text-color-hover,#1d4ed8)}.chat-btn-text span{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);white-space:nowrap}.chat-btn-text img{flex-shrink:0;height:var(--button-icon-size);-o-object-fit:contain;object-fit:contain;width:var(--button-icon-size)}.chat-btn-text.round{border-radius:3.40282e+38px}.chat-btn-icon{border-radius:var(--radius-lg);border-style:var(--tw-border-style);transform:var(--tw-rotate-x,)var(--tw-rotate-y,)var(--tw-rotate-z,)var(--tw-skew-x,)var(--tw-skew-y,);--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:all;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;--tw-ease:var(--ease-in-out);background-color:var(--button-background-color,#fff);border-width:0;border:1px solid var(--button-border-color);font-size:var(--button-font-size);padding:.5em;transition-duration:.2s;transition-timing-function:var(--ease-in-out);z-index:var(--chat-z-index,50)}.chat-btn-icon:hover{border:1px solid var(--button-border-color-hover);color:var(--button-text-color-hover,#1d4ed8)}.chat-btn-icon img{height:var(--button-icon-size);-o-object-fit:contain;object-fit:contain;width:var(--button-icon-size)}.chat-btn-icon.round,.round .chat-btn-icon,.round.chat-btn-text{border-radius:3.40282e+38px}.error-message{color:var(--error-text-color);padding:.5em}.chat-window-fullscreen{border-style:var(--tw-border-style);inset:calc(var(--spacing)*0);z-index:9999;--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow);height:100%;max-height:100%;transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));width:100%;--tw-duration:.2s;border-radius:0;border-width:0;max-width:var(--chat-window-fullscreen-width);transition-duration:.2s}.chat-window-fullscreen,.chat-window-normal{background-color:var(--chat-window-bg-color);display:flex;flex-direction:column;overflow:hidden;position:fixed}.chat-window-normal{border:1px solid var(--chat-window-border-color);border-radius:var(--radius-lg);height:100vh;max-width:var(--breakpoint-lg);min-height:300px;min-width:300px;width:100vw}.chat-window-normal:not(.chat-window-dragging){--tw-shadow:0 10px 15px -3px var(--tw-shadow-color,#0000001a),0 4px 6px -4px var(--tw-shadow-color,#0000001a);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:box-shadow;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;transition-duration:.2s}.chat-window-dragging,.chat-window-normal:not(.chat-window-dragging){box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.chat-window-dragging{cursor:grabbing;--tw-shadow:0 25px 50px -12px var(--tw-shadow-color,#00000040)}.chat-header{transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.15s;align-items:center;background-color:var(--header-bg-color);border-bottom:1px solid var(--header-border-color);display:flex;font-size:var(--header-font-size);justify-content:space-between;padding:.5em;transition-duration:.15s}.chat-header:active,.chat-header:hover{background-color:var(--header-bg-hover-color)}.header-text{align-items:center;color:var(--header-text-color);display:flex;font-size:var(--header-text-font-size);justify-content:center}.chat-header-draggable{cursor:grab}.chat-header-dragging{cursor:grabbing}.drag-indicator{display:none}.drag-dots{display:flex;gap:2px;margin-left:2px;pointer-events:none}.header-buttons{align-items:center;display:flex;gap:4px}.header-button{border-radius:var(--radius-md);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;color:var(--header-button-text-color);padding:.375em;transition-duration:.2s}.header-button svg{height:var(--header-button-icon-size);width:var(--header-button-icon-size)}.header-button:hover{background-color:var(--header-button-bg-hover-color)}.fullscreen-button{display:none}.chat-content{display:flex;flex-direction:column;flex-grow:1;overflow:hidden}.loading-container{align-items:center;display:flex;flex-grow:1;justify-content:center}.loading-text{color:var(--loading-text-color);margin-left:2px}.messages-container{flex-grow:1;overflow-y:auto;padding:1em}:where(.messages-container>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.message-row{display:flex}.message-row-user{justify-content:flex-end}.message-row-assistant{justify-content:flex-start}.message-bubble{border-radius:var(--radius-lg);padding:.5em 1em}.message-bubble-user{background-color:var(--message-user-bg-color);color:var(--message-user-text-color)}.message-bubble-assistant{background-color:var(--message-assistant-bg-color);color:var(--message-assistant-text-color)}.message-bubble-system{background-color:var(--message-system-bg-color);color:var(--message-system-text-color)}.message-timestamp{font-size:var(--chat-window-font-size-sm);margin-top:4px;opacity:.7}.message-attachments{margin-top:8px}:where(.message-attachments>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*1*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*1*var(--tw-space-y-reverse))}.attachment-link{display:block;text-decoration-line:underline}:where(.welcome-messages>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.typing-indicator{height:calc(var(--spacing)*1.5);overflow:hidden;width:100%}.typing-progress{animation:var(--animate-progress);background-color:var(--typing-progress-bg-color);border-radius:var(--radius-lg);height:100%;transform-origin:var(--transform-origin-left-right);width:100%}.typing-text{font-size:var(--chat-window-font-size-sm);justify-content:center;opacity:.7;width:100%}.typing-dots{animation:var(--animate-dots)}:where(.starter-questions>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(var(--spacing)*2*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(var(--spacing)*2*var(--tw-space-y-reverse))}.starter-questions{padding:1em}.starter-question-row{display:flex;justify-content:flex-end}.input-area{background-color:var(--input-bg-color);border-top:1px solid var(--input-border-color);padding:1em 1em 0}.input-container{display:flex;gap:8px}.message-textarea{background-color:var(--input-bg-color);border-color:var(--color-gray-300);border-radius:var(--radius-md);border-style:var(--tw-border-style);border-width:1px;border:1px solid var(--input-border-color);color:var(--input-text-color);flex-grow:1;padding:.5em .75em;resize:none}.message-textarea:focus{outline-color:var(--input-outline-focus-color)}.send-button{border-radius:var(--radius-md);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;padding:.5em 1em;transition-duration:.2s}.send-button-enabled{background-color:var(--send-button-bg-color);color:var(--send-button-text-color)}.send-button-enabled:hover{background-color:var(--send-button-bg-hover-color)}.send-button-disabled{background-color:var(--send-button-bg-disabled-color);color:var(--send-button-text-disabled-color);cursor:not-allowed}.confirmation-overlay{align-items:center;background-color:var(--confirmation-overlay-bg-color);display:flex;inset:calc(var(--spacing)*0);justify-content:center;position:fixed;z-index:9999}.confirmation-dialog{background-color:var(--confirmation-dialog-bg-color);border:1px solid var(--confirmation-dialog-border-color);border-radius:.75em;box-shadow:0 .625em 1.5625em var(--confirmation-dialog-shadow-color);margin-inline:calc(var(--spacing)*4);max-width:var(--container-sm);width:100%}.confirmation-content{padding:1.5em}.confirmation-title{margin-bottom:calc(var(--spacing)*2);--tw-font-weight:var(--font-weight-semibold);color:var(--confirmation-title-color);font-size:var(--confirmation-title-font-size);font-weight:var(--font-weight-semibold)}.confirmation-message{color:var(--confirmation-message-color);font-size:var(--confirmation-message-font-size);margin-bottom:calc(var(--spacing)*4)}.confirmation-buttons{display:flex;gap:.75em;justify-content:flex-end}.confirmation-button{border-radius:var(--radius-md);--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;padding:.5em 1em;transition-duration:.2s}.confirmation-button-cancel{background-color:var(--confirmation-button-cancel-bg-color);color:var(--confirmation-button-cancel-text-color)}.confirmation-button-cancel:hover{background-color:var(--confirmation-button-cancel-bg-hover-color)}.confirmation-button-confirm{background-color:var(--confirmation-button-confirm-bg-color);color:var(--confirmation-button-confirm-text-color)}.confirmation-button-confirm:hover{background-color:var(--confirmation-button-confirm-bg-hover-color)}}@layer utilities{:host{--chat-z-index:50;--button-background-color:#fff;--button-background-color-hover:#f3f4f6;--button-text-color:#111827;--button-text-color-hover:#1d4ed8;--button-border-color:#d1d5db;--button-border-color-hover:#6b7280;--button-font-size:1em;--button-icon-size:1.5em;--chat-window-height:60%;--chat-window-width:25%;--chat-window-fullscreen-width:80%;--chat-window-bg-color:#fff;--chat-window-border-color:#d1d5db;--chat-window-shadow-color:#0000001a;--chat-window-font-size:.875em;--chat-window-font-size-sm:.75em;--header-bg-color:transparent;--header-bg-hover-color:#f9fafb;--header-border-color:#f3f4f6;--header-button-text-color:#6b7280;--header-button-bg-hover-color:#f3f4f6;--header-font-size:1em;--header-text-font-size:1em;--header-text-color:#525762;--header-button-icon-size:1.5em;--starter-question-bg-color:transparent;--starter-question-bg-hover-color:#eff6ff;--starter-question-text-color:#3b82f6;--starter-question-border-color:#3b82f6;--starter-question-border-hover-color:#2563eb;--message-user-bg-color:#e4edfb;--message-user-text-color:#1f2937;--message-user-link-color:#155dfc;--message-assistant-bg-color:#eae7e8;--message-assistant-text-color:var(--message-user-text-color);--message-assistant-link-color:var(--message-user-link-color);--message-system-bg-color:#fbe4f8;--message-system-text-color:var(--message-user-text-color);--message-system-link-color:var(--message-user-link-color);--message-timestamp-color:#ffffffb3;--message-timestamp-assistant-color:#4b5563b3;--input-bg-color:transparent;--input-border-color:#d1d5db;--input-text-color:#111827;--input-placeholder-color:#6b7280;--input-outline-focus-color:#3b82f6;--send-button-bg-color:#3b82f6;--send-button-bg-hover-color:#2563eb;--send-button-text-color:#fff;--send-button-bg-disabled-color:#d1d5db;--send-button-text-disabled-color:#6b7280;--loading-text-color:#6b7280;--loading-spinner-track-color:#e5e7eb;--loading-spinner-fill-color:#3b82f6;--loading-spinner-size:1.25em;--typing-progress-bg-color:#ade3ff;--scrollbar-track-color:#f3f4f6;--scrollbar-thumb-color:#d1d5db;--scrollbar-thumb-hover-color:#9ca3af;--error-text-color:#ef4444;--success-text-color:#10b981;--code-bg-user-color:var(--message-user-bg-color);--code-text-user-color:var(--message-user-text-color);--code-border-user-color:var(--message-user-bg-color);--code-bg-assistant-color:var(--message-assistant-bg-color);--code-text-assistant-color:var(--message-assistant-text-color);--code-border-assistant-color:var(--message-assistant-bg-color);--confirmation-overlay-bg-color:#00000080;--confirmation-dialog-bg-color:var(--chat-window-bg-color);--confirmation-dialog-border-color:var(--chat-window-border-color);--confirmation-dialog-shadow-color:var(--chat-window-shadow-color);--confirmation-title-color:#111827;--confirmation-title-font-size:1.125em;--confirmation-message-color:var(--loading-text-color);--confirmation-message-font-size:1em;--confirmation-button-cancel-bg-color:var(--button-background-color-hover);--confirmation-button-cancel-bg-hover-color:#e5e7eb;--confirmation-button-cancel-text-color:var(--header-button-text-color);--confirmation-button-confirm-bg-color:var(--error-text-color);--confirmation-button-confirm-bg-hover-color:var(--error-text-color);--confirmation-button-confirm-text-color:var(--send-button-text-color);--file-attachment-button-bg-color:transparent;--file-attachment-button-bg-hover-color:var(--header-button-bg-hover-color);--file-attachment-button-text-color:var(--header-button-text-color);--file-attachment-button-text-disabled-color:var(--send-button-text-disabled-color);--selected-files-bg-color:var(--chat-window-bg-color);--selected-files-border-color:var(--header-border-color);--selected-file-bg-color:var(--message-system-bg-color);--selected-file-font-size:var(--chat-window-font-size-sm);--selected-file-name-color:var(--message-assistant-text-color);--selected-file-size-color:var(--input-placeholder-color);--selected-file-icon-size:1.25em;--selected-file-remove-icon-color:var(--error-text-color);--selected-file-remove-icon-hover-color:#dc2626;--message-attachment-icon-size:1em;bottom:30px;display:block;position:fixed;right:30px}@supports (color:color-mix(in lab,red,red)){:host{--code-bg-user-color:color-mix(in srgb,var(--message-user-bg-color)80%,#fff 20%);--code-border-user-color:color-mix(in srgb,var(--message-user-bg-color)90%,#000 10%);--code-bg-assistant-color:color-mix(in srgb,var(--message-assistant-bg-color)50%,#fff 50%);--code-border-assistant-color:color-mix(in srgb,var(--message-assistant-bg-color)90%,#000 10%)}}}textarea{max-height:calc(var(--spacing)*32);min-height:calc(var(--spacing)*10);overflow-y:auto;resize:none}.loading-spinner{animation:var(--animate-spin);border-color:var(--loading-spinner-track-color);border-radius:3.40282e+38px;border-style:var(--tw-border-style);border-top-color:var(--loading-spinner-fill-color);border-width:2px;height:var(--loading-spinner-size);width:var(--loading-spinner-size)}.overflow-y-auto::-webkit-scrollbar{height:calc(var(--spacing)*1.5);width:calc(var(--spacing)*1.5)}.overflow-y-auto::-webkit-scrollbar-track{background-color:var(--scrollbar-track-color);border-radius:var(--radius-sm)}.overflow-y-auto::-webkit-scrollbar-thumb{background-color:var(--scrollbar-thumb-color);border-radius:var(--radius-sm)}.overflow-y-auto::-webkit-scrollbar-thumb:hover{background-color:var(--scrollbar-thumb-hover-color)}.chat-markdown{color:var(--tw-prose-body);font-size:1rem;font-size:.875rem;line-height:1.75;line-height:1.71429;max-width:65ch;--tw-prose-body:oklch(37.3% .034 259.733);--tw-prose-headings:oklch(21% .034 264.665);--tw-prose-lead:oklch(44.6% .03 256.802);--tw-prose-links:oklch(21% .034 264.665);--tw-prose-bold:oklch(21% .034 264.665);--tw-prose-counters:oklch(55.1% .027 264.364);--tw-prose-bullets:oklch(87.2% .01 258.338);--tw-prose-hr:oklch(92.8% .006 264.531);--tw-prose-quotes:oklch(21% .034 264.665);--tw-prose-quote-borders:oklch(92.8% .006 264.531);--tw-prose-captions:oklch(55.1% .027 264.364);--tw-prose-kbd:oklch(21% .034 264.665);--tw-prose-kbd-shadows:NaN NaN NaN;--tw-prose-code:oklch(21% .034 264.665);--tw-prose-pre-code:oklch(92.8% .006 264.531);--tw-prose-pre-bg:oklch(27.8% .033 256.848);--tw-prose-th-borders:oklch(87.2% .01 258.338);--tw-prose-td-borders:oklch(92.8% .006 264.531);--tw-prose-invert-body:oklch(87.2% .01 258.338);--tw-prose-invert-headings:#fff;--tw-prose-invert-lead:oklch(70.7% .022 261.325);--tw-prose-invert-links:#fff;--tw-prose-invert-bold:#fff;--tw-prose-invert-counters:oklch(70.7% .022 261.325);--tw-prose-invert-bullets:oklch(44.6% .03 256.802);--tw-prose-invert-hr:oklch(37.3% .034 259.733);--tw-prose-invert-quotes:oklch(96.7% .003 264.542);--tw-prose-invert-quote-borders:oklch(37.3% .034 259.733);--tw-prose-invert-captions:oklch(70.7% .022 261.325);--tw-prose-invert-kbd:#fff;--tw-prose-invert-kbd-shadows:255 255 255;--tw-prose-invert-code:#fff;--tw-prose-invert-pre-code:oklch(87.2% .01 258.338);--tw-prose-invert-pre-bg:#00000080;--tw-prose-invert-th-borders:oklch(44.6% .03 256.802);--tw-prose-invert-td-borders:oklch(37.3% .034 259.733);font-size:1em;max-width:none}.chat-markdown :where([class~=lead]):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-lead);font-size:1.25em;font-size:1.28571em;line-height:1.6;line-height:1.55556;margin-bottom:.888889em;margin-top:.888889em}.chat-markdown :where(a):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-links);font-weight:500;text-decoration:underline;text-decoration-line:none}.chat-markdown :where(strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-bold);font-weight:600}.chat-markdown :where(a strong):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(blockquote strong):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(thead th strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.chat-markdown :where(ol[type=A]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.chat-markdown :where(ol[type=a]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.chat-markdown :where(ol[type=A s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-alpha}.chat-markdown :where(ol[type=a s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-alpha}.chat-markdown :where(ol[type=I]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.chat-markdown :where(ol[type=i]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.chat-markdown :where(ol[type=I s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:upper-roman}.chat-markdown :where(ol[type=i s]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:lower-roman}.chat-markdown :where(ol[type=\"1\"]):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:decimal}.chat-markdown :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){list-style-type:disc;margin-bottom:1.25em;margin-top:1.25em;padding-inline-start:1.625em}.chat-markdown :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-counters);font-weight:400}.chat-markdown :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *))::marker{color:var(--tw-prose-bullets)}.chat-markdown :where(dt):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;margin-top:1.14286em}.chat-markdown :where(hr):not(:where([class~=not-prose],[class~=not-prose] *)){border-color:var(--tw-prose-hr);border-top-width:1px;margin-bottom:2.85714em;margin-top:2.85714em}.chat-markdown :where(blockquote):not(:where([class~=not-prose],[class~=not-prose] *)){border-inline-start-color:var(--tw-prose-quote-borders);border-inline-start-width:.25rem;color:var(--tw-prose-quotes);font-style:italic;font-weight:500;margin-bottom:1.33333em;margin-top:1.33333em;padding-inline-start:1em;padding-inline-start:1.11111em;quotes:\"\u201C\"\"\u201D\"\"\u2018\"\"\u2019\"}.chat-markdown :where(blockquote p:first-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:open-quote}.chat-markdown :where(blockquote p:last-of-type):not(:where([class~=not-prose],[class~=not-prose] *)):after{content:close-quote}.chat-markdown :where(h1):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:2.25em;font-size:2.14286em;font-weight:800;line-height:1.11111;line-height:1.2;margin-bottom:.8em;margin-top:0}.chat-markdown :where(h1 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:900}.chat-markdown :where(h2):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.5em;font-size:1.42857em;font-weight:700;line-height:1.33333;line-height:1.4;margin-bottom:.8em;margin-top:1.6em}.chat-markdown :where(h2 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:800}.chat-markdown :where(h3):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-size:1.25em;font-size:1.28571em;font-weight:600;line-height:1.6;line-height:1.55556;margin-bottom:.444444em;margin-top:1.55556em}.chat-markdown :where(h3 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.chat-markdown :where(h4):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;line-height:1.5;line-height:1.42857;margin-bottom:.571429em;margin-top:1.42857em}.chat-markdown :where(h4 strong):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-weight:700}.chat-markdown :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){display:block;margin-bottom:2em;margin-top:2em}.chat-markdown :where(kbd):not(:where([class~=not-prose],[class~=not-prose] *)){border-radius:.3125rem;box-shadow:0 0 0 1px rgb(var(--tw-prose-kbd-shadows)/10%),0 3px 0 rgb(var(--tw-prose-kbd-shadows)/10%);color:var(--tw-prose-kbd);font-family:inherit;font-size:.875em;font-size:.857143em;font-weight:500;padding-inline-end:.375em;padding-inline-end:.357143em;padding-bottom:.142857em;padding-inline-start:.375em;padding-top:.142857em;padding-inline-start:.357143em}.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-code);font-size:.875em;font-size:.857143em;font-weight:600}.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):after,.chat-markdown :where(code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:\"\\`\"}.chat-markdown :where(a code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h1 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(h2 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.875em;font-size:.9em}.chat-markdown :where(h3 code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit;font-size:.9em;font-size:.888889em}.chat-markdown :where(blockquote code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4 code):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(thead th code):not(:where([class~=not-prose],[class~=not-prose] *)){color:inherit}.chat-markdown :where(pre):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:var(--tw-prose-pre-bg);border-radius:.375rem;border-radius:.25rem;color:var(--tw-prose-pre-code);font-size:.875em;font-size:.857143em;font-weight:400;line-height:1.71429;line-height:1.66667;margin-bottom:1.66667em;margin-top:1.66667em;overflow-x:auto;padding-inline-end:1.14286em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:1.14286em;padding-top:.666667em;padding-inline-start:1em}.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)){background-color:#0000;border-radius:0;border-width:0;color:inherit;font-family:inherit;font-size:inherit;font-weight:inherit;line-height:inherit;padding:0}.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):after,.chat-markdown :where(pre code):not(:where([class~=not-prose],[class~=not-prose] *)):before{content:none}.chat-markdown :where(table):not(:where([class~=not-prose],[class~=not-prose] *)){font-size:.875em;font-size:.857143em;line-height:1.71429;line-height:1.5;margin-bottom:2em;margin-top:2em;table-layout:auto;width:100%}.chat-markdown :where(thead):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-th-borders);border-bottom-width:1px}.chat-markdown :where(thead th):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-headings);font-weight:600;padding-inline-end:.571429em;padding-inline-end:1em;padding-bottom:.666667em;padding-inline-start:.571429em;padding-inline-start:1em;vertical-align:bottom}.chat-markdown :where(tbody tr):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-color:var(--tw-prose-td-borders);border-bottom-width:1px}.chat-markdown :where(tbody tr:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){border-bottom-width:0}.chat-markdown :where(tbody td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:baseline}.chat-markdown :where(tfoot):not(:where([class~=not-prose],[class~=not-prose] *)){border-top-color:var(--tw-prose-th-borders);border-top-width:1px}.chat-markdown :where(tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){vertical-align:top}.chat-markdown :where(th,td):not(:where([class~=not-prose],[class~=not-prose] *)){text-align:start}.chat-markdown :where(figcaption):not(:where([class~=not-prose],[class~=not-prose] *)){color:var(--tw-prose-captions);font-size:.875em;font-size:.857143em;line-height:1.42857;line-height:1.33333;margin-top:.666667em}.chat-markdown :where(.prose>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.75em;margin-top:.75em}.chat-markdown :where(.prose>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.chat-markdown :where(.prose>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.chat-markdown :where(.prose>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.25em}.chat-markdown :where(.prose>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.25em}.chat-markdown :where(.prose>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(.prose>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.chat-markdown :where(p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em}.chat-markdown :where(img):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(picture):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(picture>img):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.chat-markdown :where(video):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(ol):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(ul):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em;padding-inline-start:1.57143em}.chat-markdown :where(li):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.285714em;margin-top:.285714em}.chat-markdown :where(ol>li):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(ul>li):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:.428571em}.chat-markdown :where(.prose-sm>ul>li p):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.571429em;margin-top:.571429em}.chat-markdown :where(.prose-sm>ul>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.chat-markdown :where(.prose-sm>ul>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.chat-markdown :where(.prose-sm>ol>li>p:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:1.14286em}.chat-markdown :where(.prose-sm>ol>li>p:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em}.chat-markdown :where(ul ul,ul ol,ol ul,ol ol):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:.571429em;margin-top:.571429em}.chat-markdown :where(dl):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.14286em;margin-top:1.14286em}.chat-markdown :where(dd):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:.285714em;padding-inline-start:1.57143em}.chat-markdown :where(h2+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h3+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(h4+*):not(:where([class~=not-prose],[class~=not-prose] *)),.chat-markdown :where(hr+*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(thead th:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.chat-markdown :where(thead th:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.chat-markdown :where(tbody td,tfoot td):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:1em;padding-bottom:.666667em;padding-top:.666667em;padding-inline-start:1em}.chat-markdown :where(tbody td:first-child,tfoot td:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-start:0}.chat-markdown :where(tbody td:last-child,tfoot td:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){padding-inline-end:0}.chat-markdown :where(figure):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:1.71429em;margin-top:1.71429em}.chat-markdown :where(figure>*):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0;margin-top:0}.chat-markdown :where(.prose-sm>:first-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-top:0}.chat-markdown :where(.prose-sm>:last-child):not(:where([class~=not-prose],[class~=not-prose] *)){margin-bottom:0}.chat-markdown>*{margin-bottom:.1em;margin-top:.1em}.message-bubble-assistant .chat-markdown{--tw-prose-body:var(--message-assistant-text-color);--tw-prose-headings:var(--message-assistant-text-color);--tw-prose-lead:var(--message-assistant-text-color);--tw-prose-links:var(--message-assistant-link-color);--tw-prose-bold:var(--message-assistant-text-color);--tw-prose-counters:var(--message-assistant-text-color);--tw-prose-bullets:var(--message-assistant-text-color);--tw-prose-hr:var(--message-assistant-text-color);--tw-prose-quotes:var(--message-assistant-text-color);--tw-prose-quote-borders:var(--message-assistant-text-color);--tw-prose-captions:var(--message-assistant-text-color);--tw-prose-kbd:var(--message-assistant-text-color);--tw-prose-kbd-shadows:var(--message-assistant-text-color);--tw-prose-code:var(--code-text-assistant-color);--tw-prose-pre-code:var(--code-text-assistant-color);--tw-prose-pre-bg:var(--code-bg-assistant-color);--tw-prose-th-borders:var(--message-assistant-text-color);--tw-prose-td-borders:var(--message-assistant-text-color)}.message-bubble-user .chat-markdown{--tw-prose-body:var(--message-user-text-color);--tw-prose-headings:var(--message-user-text-color);--tw-prose-lead:var(--message-user-text-color);--tw-prose-links:var(--message-user-link-color);--tw-prose-bold:var(--message-user-text-color);--tw-prose-counters:var(--message-user-text-color);--tw-prose-bullets:var(--message-user-text-color);--tw-prose-hr:var(--message-user-text-color);--tw-prose-quotes:var(--message-user-text-color);--tw-prose-quote-borders:var(--message-user-text-color);--tw-prose-captions:var(--message-user-text-color);--tw-prose-kbd:var(--message-user-text-color);--tw-prose-kbd-shadows:var(--message-user-text-color);--tw-prose-code:var(--code-text-user-color);--tw-prose-pre-code:var(--code-text-user-color);--tw-prose-pre-bg:var(--code-bg-user-color);--tw-prose-th-borders:var(--message-user-text-color);--tw-prose-td-borders:var(--message-user-text-color)}.message-bubble-system .chat-markdown{--tw-prose-body:var(--message-system-text-color);--tw-prose-headings:var(--message-system-text-color);--tw-prose-lead:var(--message-system-text-color);--tw-prose-links:var(--message-system-link-color);--tw-prose-bold:var(--message-system-text-color);--tw-prose-counters:var(--message-system-text-color);--tw-prose-bullets:var(--message-system-text-color);--tw-prose-hr:var(--message-system-text-color);--tw-prose-quotes:var(--message-system-text-color);--tw-prose-quote-borders:var(--message-system-text-color);--tw-prose-captions:var(--message-system-text-color);--tw-prose-kbd:var(--message-system-text-color);--tw-prose-kbd-shadows:var(--message-system-text-color);--tw-prose-code:var(--message-system-text-color);--tw-prose-pre-code:var(--message-system-text-color);--tw-prose-pre-bg:var(--message-system-text-color);--tw-prose-th-borders:var(--message-system-text-color);--tw-prose-td-borders:var(--message-system-text-color)}.message-bubble-user .chat-markdown pre{border:1px solid var(--code-border-user-color)}.message-bubble-assistant .chat-markdown pre{border:1px solid var(--code-border-assistant-color)}.loading:after{content:\" .\"}.file-attachment-button{border-radius:var(--radius-md);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;background-color:var(--file-attachment-button-bg-color);color:var(--file-attachment-button-text-color);padding:.375em;transition-duration:.2s}.file-attachment-button:disabled{color:var(--file-attachment-button-text-disabled-color);cursor:not-allowed;opacity:.5}.file-attachment-button svg{height:1.5em;width:1.5em}.file-attachment-button:hover:not(:disabled){background-color:var(--file-attachment-button-bg-hover-color)}.selected-files-container{background-color:var(--selected-files-bg-color);border-top:1px solid var(--selected-files-border-color);padding:1em 1em .5em}.selected-file-item{align-items:center;background-color:var(--selected-file-bg-color);border-radius:.375em;color:var(--selected-file-name-color);display:flex;font-size:var(--selected-file-font-size);justify-content:space-between;padding:.25em .5em}.selected-file-icon{align-items:center;display:flex;justify-content:center}.selected-file-icon svg{height:var(--selected-file-icon-size);width:var(--selected-file-icon-size)}.selected-file-size{color:var(--selected-file-size-color)}.selected-file-error{color:var(--error-text-color)}.selected-file-success-icon{align-items:center;color:var(--success-text-color);display:flex;height:var(--selected-file-icon-size);justify-content:center;width:var(--selected-file-icon-size)}.selected-file-remove-button{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold);transition-duration:var(--tw-duration,var(--default-transition-duration));transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));--tw-duration:.2s;color:var(--selected-file-remove-icon-color);padding:.375em;transition-duration:.2s}.selected-file-remove-button svg{height:var(--selected-file-icon-size);width:var(--selected-file-icon-size)}.selected-file-remove-button:hover{color:var(--selected-file-remove-icon-hover-color)}.message-attachments{font-size:var(--chat-window-font-size-sm);margin-top:.5em}:where(.message-attachments>:not(:last-child)){--tw-space-y-reverse:0;margin-block-end:calc(.25em*(1 - var(--tw-space-y-reverse)));margin-block-start:calc(.25em*var(--tw-space-y-reverse))}.message-attachment-icon{align-items:center;display:flex;height:var(--message-attachment-icon-size);justify-content:center;width:var(--message-attachment-icon-size)}.send-button-disabled{background-color:var(--send-button-bg-disabled-color);color:var(--send-button-text-disabled-color);cursor:not-allowed}@property --tw-rotate-x{syntax:\"*\";inherits:false}@property --tw-rotate-y{syntax:\"*\";inherits:false}@property --tw-rotate-z{syntax:\"*\";inherits:false}@property --tw-skew-x{syntax:\"*\";inherits:false}@property --tw-skew-y{syntax:\"*\";inherits:false}@property --tw-space-y-reverse{syntax:\"*\";inherits:false;initial-value:0}@property --tw-border-style{syntax:\"*\";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:\"*\";inherits:false}@property --tw-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:\"*\";inherits:false}@property --tw-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:\"*\";inherits:false}@property --tw-inset-shadow-alpha{syntax:\"<percentage>\";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:\"*\";inherits:false}@property --tw-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:\"*\";inherits:false}@property --tw-inset-ring-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:\"*\";inherits:false}@property --tw-ring-offset-width{syntax:\"<length>\";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:\"*\";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:\"*\";inherits:false;initial-value:0 0 #0000}@property --tw-duration{syntax:\"*\";inherits:false}@property --tw-ease{syntax:\"*\";inherits:false}@property --tw-scale-x{syntax:\"*\";inherits:false;initial-value:1}@property --tw-scale-y{syntax:\"*\";inherits:false;initial-value:1}@property --tw-scale-z{syntax:\"*\";inherits:false;initial-value:1}@keyframes spin{to{transform:rotate(1turn)}}@keyframes progress{0%{transform:translate(0)scaleX(0)}10%{transform:translate(0)scaleX(.3)}50%{transform:translate(100%)scaleX(.3)}90%{transform:translate(0)scaleX(.3)}to{transform:translate(0)scaleX(0)}}@keyframes dots{0%,20%{color:#0000;text-shadow:.25em 0 #0000,.5em 0 #0000}40%{color:#000;text-shadow:.25em 0 #0000,.5em 0 #0000}60%{text-shadow:.25em 0 #000,.5em 0 #0000}80%,to{text-shadow:.25em 0 #000,.5em 0 #000}}@media (min-width:40rem){.container{max-width:40rem}.chat-window-normal{height:var(--chat-window-height);width:var(--chat-window-width)}.drag-indicator{display:flex}.fullscreen-button{display:block}}@media (min-width:48rem){.container{max-width:48rem}}@media (min-width:64rem){.container{max-width:64rem}}@media (min-width:80rem){.container{max-width:80rem}}@media (min-width:96rem){.container{max-width:96rem}}@media (hover:hover){.chat-btn-icon:hover,.chat-btn-text:hover{--tw-scale-x:105%;--tw-scale-y:105%;--tw-scale-z:105%;scale:var(--tw-scale-x)var(--tw-scale-y)}.attachment-link:hover{text-decoration-line:none}.chat-markdown :where(a):not(:where([class~=not-prose],[class~=not-prose] *)):hover{text-decoration-line:underline}}";
|
|
4507
5174
|
|
|
4508
5175
|
const OcsChat = class {
|
|
4509
5176
|
constructor(hostRef) {
|
|
4510
5177
|
index.registerInstance(this, hostRef);
|
|
4511
5178
|
/**
|
|
4512
|
-
* The base URL for the API
|
|
5179
|
+
* The base URL for the API.
|
|
4513
5180
|
*/
|
|
4514
|
-
this.apiBaseUrl = "https://
|
|
5181
|
+
this.apiBaseUrl = "https://www.openchatstudio.com";
|
|
4515
5182
|
/**
|
|
4516
5183
|
* The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
|
|
4517
5184
|
*/
|
|
4518
5185
|
this.buttonShape = 'square';
|
|
4519
|
-
/**
|
|
4520
|
-
* The message to display in the new chat confirmation dialog.
|
|
4521
|
-
*/
|
|
4522
|
-
this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
|
|
4523
5186
|
/**
|
|
4524
5187
|
* Whether the chat widget is visible on load.
|
|
4525
5188
|
*/
|
|
@@ -4545,10 +5208,6 @@ const OcsChat = class {
|
|
|
4545
5208
|
* Allow the user to attach files to their messages.
|
|
4546
5209
|
*/
|
|
4547
5210
|
this.allowAttachments = false;
|
|
4548
|
-
/**
|
|
4549
|
-
* The text to display while the assistant is typing/preparing a response.
|
|
4550
|
-
*/
|
|
4551
|
-
this.typingIndicatorText = "Preparing response";
|
|
4552
5211
|
this.error = "";
|
|
4553
5212
|
this.messages = [];
|
|
4554
5213
|
this.isLoading = false;
|
|
@@ -4565,6 +5224,20 @@ const OcsChat = class {
|
|
|
4565
5224
|
this.showNewChatConfirmation = false;
|
|
4566
5225
|
this.selectedFiles = [];
|
|
4567
5226
|
this.isUploadingFiles = false;
|
|
5227
|
+
this.buttonPosition = { x: 30, y: 30 };
|
|
5228
|
+
this.buttonHorizontalSide = 'right';
|
|
5229
|
+
this.buttonVerticalSide = 'bottom';
|
|
5230
|
+
this.isButtonDragging = false;
|
|
5231
|
+
this.buttonWasDragged = false;
|
|
5232
|
+
this.translationManager = new TranslationManager();
|
|
5233
|
+
this.attachmentManager = new FileAttachmentManager({
|
|
5234
|
+
supportedExtensions: OcsChat.SUPPORTED_FILE_EXTENSIONS,
|
|
5235
|
+
maxFileSizeMb: OcsChat.MAX_FILE_SIZE_MB,
|
|
5236
|
+
maxTotalSizeMb: OcsChat.MAX_TOTAL_SIZE_MB,
|
|
5237
|
+
});
|
|
5238
|
+
this.buttonDragOffset = { x: 0, y: 0 };
|
|
5239
|
+
this.rafId = null;
|
|
5240
|
+
this.buttonListenersAttached = false;
|
|
4568
5241
|
this.chatWindowHeight = 600;
|
|
4569
5242
|
this.chatWindowWidth = 450;
|
|
4570
5243
|
this.chatWindowFullscreenWidth = 1024;
|
|
@@ -4613,15 +5286,101 @@ const OcsChat = class {
|
|
|
4613
5286
|
this.endDrag();
|
|
4614
5287
|
};
|
|
4615
5288
|
this.handleWindowResize = () => {
|
|
5289
|
+
var _a, _b;
|
|
4616
5290
|
this.positionInitialized = false;
|
|
4617
5291
|
this.initializePosition();
|
|
5292
|
+
// Revalidate button position after resize to keep it within viewport bounds
|
|
5293
|
+
if (this.isButtonDraggable()) {
|
|
5294
|
+
const windowWidth = window.innerWidth;
|
|
5295
|
+
const windowHeight = window.innerHeight;
|
|
5296
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
5297
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
5298
|
+
const minPadding = 10;
|
|
5299
|
+
this.buttonPosition = {
|
|
5300
|
+
x: Math.max(minPadding, Math.min(this.buttonPosition.x, windowWidth - buttonWidth - minPadding)),
|
|
5301
|
+
y: Math.max(minPadding, Math.min(this.buttonPosition.y, windowHeight - buttonHeight - minPadding))
|
|
5302
|
+
};
|
|
5303
|
+
this.updateHostPosition();
|
|
5304
|
+
}
|
|
5305
|
+
};
|
|
5306
|
+
this.handleButtonMouseDown = (event) => {
|
|
5307
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
5308
|
+
return;
|
|
5309
|
+
event.preventDefault();
|
|
5310
|
+
event.stopPropagation();
|
|
5311
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5312
|
+
if (!pointer)
|
|
5313
|
+
return;
|
|
5314
|
+
this.isButtonDragging = true;
|
|
5315
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
5316
|
+
const rect = this.host.getBoundingClientRect();
|
|
5317
|
+
this.buttonDragOffset = {
|
|
5318
|
+
x: pointer.clientX - rect.left,
|
|
5319
|
+
y: pointer.clientY - rect.top
|
|
5320
|
+
};
|
|
5321
|
+
this.addButtonEventListeners();
|
|
5322
|
+
};
|
|
5323
|
+
this.handleButtonTouchStart = (event) => {
|
|
5324
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
5325
|
+
return;
|
|
5326
|
+
event.preventDefault();
|
|
5327
|
+
event.stopPropagation();
|
|
5328
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5329
|
+
if (!pointer)
|
|
5330
|
+
return;
|
|
5331
|
+
this.isButtonDragging = true;
|
|
5332
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
5333
|
+
const rect = this.host.getBoundingClientRect();
|
|
5334
|
+
this.buttonDragOffset = {
|
|
5335
|
+
x: pointer.clientX - rect.left,
|
|
5336
|
+
y: pointer.clientY - rect.top
|
|
5337
|
+
};
|
|
5338
|
+
this.addButtonEventListeners();
|
|
5339
|
+
};
|
|
5340
|
+
this.handleButtonMouseMove = (event) => {
|
|
5341
|
+
if (!this.isButtonDragging)
|
|
5342
|
+
return;
|
|
5343
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5344
|
+
if (!pointer)
|
|
5345
|
+
return;
|
|
5346
|
+
this.updateButtonPosition(pointer);
|
|
5347
|
+
};
|
|
5348
|
+
this.handleButtonTouchMove = (event) => {
|
|
5349
|
+
if (!this.isButtonDragging)
|
|
5350
|
+
return;
|
|
5351
|
+
event.preventDefault();
|
|
5352
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5353
|
+
if (!pointer)
|
|
5354
|
+
return;
|
|
5355
|
+
this.updateButtonPosition(pointer);
|
|
5356
|
+
};
|
|
5357
|
+
this.handleButtonMouseUp = () => {
|
|
5358
|
+
if (this.isButtonDragging) {
|
|
5359
|
+
this.isButtonDragging = false;
|
|
5360
|
+
this.removeButtonEventListeners();
|
|
5361
|
+
}
|
|
5362
|
+
};
|
|
5363
|
+
this.handleButtonTouchEnd = () => {
|
|
5364
|
+
if (this.isButtonDragging) {
|
|
5365
|
+
this.isButtonDragging = false;
|
|
5366
|
+
this.removeButtonEventListeners();
|
|
5367
|
+
}
|
|
5368
|
+
};
|
|
5369
|
+
this.handleButtonClick = () => {
|
|
5370
|
+
// Only toggle visibility if the button wasn't dragged
|
|
5371
|
+
if (!this.buttonWasDragged) {
|
|
5372
|
+
this.toggleWindowVisibility();
|
|
5373
|
+
}
|
|
5374
|
+
// Reset the flag after handling the click
|
|
5375
|
+
this.buttonWasDragged = false;
|
|
4618
5376
|
};
|
|
4619
5377
|
}
|
|
4620
|
-
componentWillLoad() {
|
|
5378
|
+
async componentWillLoad() {
|
|
4621
5379
|
if (!this.chatbotId) {
|
|
4622
5380
|
this.error = 'Chatbot ID is required';
|
|
4623
5381
|
return;
|
|
4624
5382
|
}
|
|
5383
|
+
await this.initializeTranslations();
|
|
4625
5384
|
// Always try to load existing session if localStorage is available
|
|
4626
5385
|
if (this.persistentSession && this.isLocalStorageAvailable()) {
|
|
4627
5386
|
const { sessionId, messages } = this.loadSessionFromStorage();
|
|
@@ -4641,6 +5400,8 @@ const OcsChat = class {
|
|
|
4641
5400
|
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
4642
5401
|
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
4643
5402
|
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
5403
|
+
// Initialize button position from computed styles
|
|
5404
|
+
this.initializeButtonPosition();
|
|
4644
5405
|
if (this.visible) {
|
|
4645
5406
|
this.initializePosition();
|
|
4646
5407
|
}
|
|
@@ -4650,15 +5411,29 @@ const OcsChat = class {
|
|
|
4650
5411
|
}
|
|
4651
5412
|
else if (this.visible && this.sessionId) {
|
|
4652
5413
|
// Resume polling for existing session
|
|
4653
|
-
this.
|
|
5414
|
+
this.startMessagePolling();
|
|
4654
5415
|
}
|
|
4655
5416
|
window.addEventListener('resize', this.handleWindowResize);
|
|
4656
5417
|
}
|
|
4657
5418
|
disconnectedCallback() {
|
|
4658
5419
|
this.cleanup();
|
|
4659
5420
|
this.removeEventListeners();
|
|
5421
|
+
this.removeButtonEventListeners();
|
|
4660
5422
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
4661
5423
|
}
|
|
5424
|
+
getChatService() {
|
|
5425
|
+
if (!this.chatService) {
|
|
5426
|
+
this.chatService = new ChatSessionService({
|
|
5427
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
5428
|
+
embedKey: this.embedKey,
|
|
5429
|
+
widgetVersion: index.Env.version,
|
|
5430
|
+
taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
|
|
5431
|
+
taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
|
|
5432
|
+
messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
|
|
5433
|
+
});
|
|
5434
|
+
}
|
|
5435
|
+
return this.chatService;
|
|
5436
|
+
}
|
|
4662
5437
|
addErrorMessage(errorText) {
|
|
4663
5438
|
const errorMessage = {
|
|
4664
5439
|
created_at: new Date().toISOString(),
|
|
@@ -4702,25 +5477,34 @@ const OcsChat = class {
|
|
|
4702
5477
|
parseStarterQuestions() {
|
|
4703
5478
|
this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
|
|
4704
5479
|
}
|
|
4705
|
-
|
|
4706
|
-
|
|
4707
|
-
|
|
4708
|
-
|
|
5480
|
+
async initializeTranslations() {
|
|
5481
|
+
let customTranslationsObj;
|
|
5482
|
+
if (this.translationsUrl) {
|
|
5483
|
+
customTranslationsObj = await this.loadTranslationsFromUrl(this.translationsUrl);
|
|
4709
5484
|
}
|
|
4710
|
-
this.
|
|
5485
|
+
this.translationManager = new TranslationManager(this.language, customTranslationsObj);
|
|
4711
5486
|
}
|
|
4712
|
-
|
|
4713
|
-
|
|
5487
|
+
async loadTranslationsFromUrl(url) {
|
|
5488
|
+
try {
|
|
5489
|
+
const response = await fetch(url);
|
|
5490
|
+
if (!response.ok) {
|
|
5491
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
5492
|
+
}
|
|
5493
|
+
const translations = await response.json();
|
|
5494
|
+
return translations;
|
|
5495
|
+
}
|
|
5496
|
+
catch (error) {
|
|
5497
|
+
console.error('Error loading translations from URL:', error);
|
|
5498
|
+
return defaultTranslations;
|
|
5499
|
+
}
|
|
4714
5500
|
}
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
if (csrfToken) {
|
|
4721
|
-
headers['X-CSRFToken'] = csrfToken;
|
|
5501
|
+
cleanup() {
|
|
5502
|
+
this.stopMessagePolling();
|
|
5503
|
+
if (this.taskPollingHandle) {
|
|
5504
|
+
this.taskPollingHandle.cancel();
|
|
5505
|
+
this.taskPollingHandle = undefined;
|
|
4722
5506
|
}
|
|
4723
|
-
|
|
5507
|
+
this.currentPollTaskId = '';
|
|
4724
5508
|
}
|
|
4725
5509
|
async startSession() {
|
|
4726
5510
|
try {
|
|
@@ -4737,94 +5521,38 @@ const OcsChat = class {
|
|
|
4737
5521
|
if (this.userName) {
|
|
4738
5522
|
requestBody.participant_name = this.userName;
|
|
4739
5523
|
}
|
|
4740
|
-
const
|
|
4741
|
-
method: 'POST',
|
|
4742
|
-
headers: this.getApiHeaders(),
|
|
4743
|
-
body: JSON.stringify(requestBody)
|
|
4744
|
-
});
|
|
4745
|
-
if (!response.ok) {
|
|
4746
|
-
this.handleError(`Failed to start session: ${response.statusText}`);
|
|
4747
|
-
return;
|
|
4748
|
-
}
|
|
4749
|
-
const data = await response.json();
|
|
5524
|
+
const data = await this.getChatService().startSession(requestBody);
|
|
4750
5525
|
this.sessionId = data.session_id;
|
|
4751
5526
|
this.saveSessionToStorage();
|
|
4752
5527
|
// Handle seed message if present
|
|
4753
5528
|
if (data.seed_message_task_id) {
|
|
4754
|
-
this.
|
|
4755
|
-
|
|
4756
|
-
|
|
5529
|
+
this.startTaskPolling(data.seed_message_task_id);
|
|
5530
|
+
}
|
|
5531
|
+
else {
|
|
5532
|
+
this.startMessagePolling();
|
|
4757
5533
|
}
|
|
4758
|
-
// Start polling for messages
|
|
4759
|
-
this.startPolling();
|
|
4760
5534
|
}
|
|
4761
|
-
catch (
|
|
5535
|
+
catch (_error) {
|
|
4762
5536
|
this.handleError('Failed to start chat session');
|
|
4763
5537
|
}
|
|
4764
5538
|
finally {
|
|
4765
5539
|
this.isLoading = false;
|
|
4766
5540
|
}
|
|
4767
5541
|
}
|
|
4768
|
-
markPendingFilesWithError(errorMessage) {
|
|
4769
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
4770
|
-
if (!sf.error && !sf.uploaded) {
|
|
4771
|
-
return Object.assign(Object.assign({}, sf), { error: errorMessage });
|
|
4772
|
-
}
|
|
4773
|
-
return sf;
|
|
4774
|
-
});
|
|
4775
|
-
}
|
|
4776
5542
|
async uploadFiles() {
|
|
4777
5543
|
if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
|
|
4778
5544
|
return [];
|
|
4779
5545
|
}
|
|
4780
5546
|
this.isUploadingFiles = true;
|
|
4781
|
-
const uploadedIds = [];
|
|
4782
5547
|
try {
|
|
4783
|
-
const
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
}
|
|
4792
|
-
}
|
|
4793
|
-
// Add user ID and name to the form data
|
|
4794
|
-
const userId = this.getOrGenerateUserId();
|
|
4795
|
-
formData.append('participant_remote_id', userId);
|
|
4796
|
-
if (this.userName) {
|
|
4797
|
-
formData.append('participant_name', this.userName);
|
|
4798
|
-
}
|
|
4799
|
-
// Only upload if there are new files
|
|
4800
|
-
if (formData.has('files')) {
|
|
4801
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
|
|
4802
|
-
method: 'POST',
|
|
4803
|
-
body: formData,
|
|
4804
|
-
});
|
|
4805
|
-
if (!response.ok) {
|
|
4806
|
-
const errorData = await response.json();
|
|
4807
|
-
const errorMessage = errorData.error || 'Failed to upload files';
|
|
4808
|
-
this.markPendingFilesWithError(errorMessage);
|
|
4809
|
-
return uploadedIds;
|
|
4810
|
-
}
|
|
4811
|
-
const data = await response.json();
|
|
4812
|
-
// Update selected files with upload results
|
|
4813
|
-
let fileIndex = 0;
|
|
4814
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
4815
|
-
if (!sf.error && !sf.uploaded) {
|
|
4816
|
-
return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
|
|
4817
|
-
}
|
|
4818
|
-
return sf;
|
|
4819
|
-
});
|
|
4820
|
-
uploadedIds.push(...data.files.map((f) => f.id));
|
|
4821
|
-
}
|
|
4822
|
-
return uploadedIds;
|
|
4823
|
-
}
|
|
4824
|
-
catch (error) {
|
|
4825
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
4826
|
-
this.markPendingFilesWithError(errorMessage);
|
|
4827
|
-
return uploadedIds;
|
|
5548
|
+
const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
|
|
5549
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
5550
|
+
sessionId: this.sessionId,
|
|
5551
|
+
participantId: this.getOrGenerateUserId(),
|
|
5552
|
+
participantName: this.userName,
|
|
5553
|
+
});
|
|
5554
|
+
this.selectedFiles = uploadResult.selectedFiles;
|
|
5555
|
+
return uploadResult.uploadedIds;
|
|
4828
5556
|
}
|
|
4829
5557
|
finally {
|
|
4830
5558
|
this.isUploadingFiles = false;
|
|
@@ -4877,27 +5605,15 @@ const OcsChat = class {
|
|
|
4877
5605
|
this.selectedFiles = []; // Clear selected files after sending
|
|
4878
5606
|
}
|
|
4879
5607
|
this.scrollToBottom();
|
|
4880
|
-
// Start typing indicator - it will stay on during task polling
|
|
4881
|
-
this.isTyping = true;
|
|
4882
5608
|
const requestBody = { message: message.trim() };
|
|
4883
5609
|
if (this.allowAttachments && attachmentIds.length > 0) {
|
|
4884
5610
|
requestBody.attachment_ids = attachmentIds;
|
|
4885
5611
|
}
|
|
4886
|
-
const
|
|
4887
|
-
method: 'POST',
|
|
4888
|
-
headers: this.getApiHeaders(),
|
|
4889
|
-
body: JSON.stringify(requestBody)
|
|
4890
|
-
});
|
|
4891
|
-
if (!response.ok) {
|
|
4892
|
-
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
4893
|
-
}
|
|
4894
|
-
const data = await response.json();
|
|
5612
|
+
const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
|
|
4895
5613
|
if (data.status === 'error') {
|
|
4896
5614
|
throw new Error(data.error || 'Failed to send message');
|
|
4897
5615
|
}
|
|
4898
|
-
|
|
4899
|
-
this.currentPollTaskId = data.task_id;
|
|
4900
|
-
await this.pollTaskResponse();
|
|
5616
|
+
this.startTaskPolling(data.task_id);
|
|
4901
5617
|
}
|
|
4902
5618
|
catch (error) {
|
|
4903
5619
|
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
@@ -4907,110 +5623,6 @@ const OcsChat = class {
|
|
|
4907
5623
|
handleStarterQuestionClick(question) {
|
|
4908
5624
|
this.sendMessage(question);
|
|
4909
5625
|
}
|
|
4910
|
-
async pollTaskResponse() {
|
|
4911
|
-
if (!this.sessionId || !this.currentPollTaskId)
|
|
4912
|
-
return;
|
|
4913
|
-
// Stop message polling while task polling is active
|
|
4914
|
-
this.pauseMessagePolling();
|
|
4915
|
-
let attempts = 0;
|
|
4916
|
-
const poll = async () => {
|
|
4917
|
-
if (!this.sessionId || !this.currentPollTaskId)
|
|
4918
|
-
return;
|
|
4919
|
-
try {
|
|
4920
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
|
|
4921
|
-
if (!response.ok) {
|
|
4922
|
-
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
4923
|
-
}
|
|
4924
|
-
const data = await response.json();
|
|
4925
|
-
if (data.error) {
|
|
4926
|
-
throw new Error(data.error);
|
|
4927
|
-
}
|
|
4928
|
-
if (data.status === 'complete' && data.message) {
|
|
4929
|
-
this.messages = [...this.messages, data.message];
|
|
4930
|
-
this.saveSessionToStorage();
|
|
4931
|
-
this.scrollToBottom();
|
|
4932
|
-
// Task polling complete, clear typing indicator and resume message polling
|
|
4933
|
-
this.isTyping = false;
|
|
4934
|
-
this.currentPollTaskId = '';
|
|
4935
|
-
this.resumeMessagePolling();
|
|
4936
|
-
this.focusInput();
|
|
4937
|
-
return;
|
|
4938
|
-
}
|
|
4939
|
-
if (data.status === 'processing' && attempts < OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
4940
|
-
attempts++;
|
|
4941
|
-
setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
|
|
4942
|
-
}
|
|
4943
|
-
else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
4944
|
-
// Task polling timed out - add timeout message and resume polling
|
|
4945
|
-
const timeoutMessage = {
|
|
4946
|
-
created_at: new Date().toISOString(),
|
|
4947
|
-
role: 'system',
|
|
4948
|
-
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
4949
|
-
attachments: []
|
|
4950
|
-
};
|
|
4951
|
-
this.messages = [...this.messages, timeoutMessage];
|
|
4952
|
-
this.saveSessionToStorage();
|
|
4953
|
-
this.scrollToBottom();
|
|
4954
|
-
// Clear typing indicator and resume message polling
|
|
4955
|
-
this.isTyping = false;
|
|
4956
|
-
this.currentPollTaskId = '';
|
|
4957
|
-
this.resumeMessagePolling();
|
|
4958
|
-
this.focusInput();
|
|
4959
|
-
}
|
|
4960
|
-
}
|
|
4961
|
-
catch (error) {
|
|
4962
|
-
const errorText = error instanceof Error ? error.message : 'Failed to get response';
|
|
4963
|
-
this.handleError(errorText);
|
|
4964
|
-
// Clear states and resume polling
|
|
4965
|
-
this.currentPollTaskId = '';
|
|
4966
|
-
this.resumeMessagePolling();
|
|
4967
|
-
}
|
|
4968
|
-
};
|
|
4969
|
-
await poll();
|
|
4970
|
-
}
|
|
4971
|
-
startPolling() {
|
|
4972
|
-
if (this.pollingIntervalRef)
|
|
4973
|
-
return;
|
|
4974
|
-
this.pollingIntervalRef = setInterval(async () => {
|
|
4975
|
-
// Only poll for messages if not currently polling for a task
|
|
4976
|
-
if (!this.currentPollTaskId) {
|
|
4977
|
-
await this.pollForMessages();
|
|
4978
|
-
}
|
|
4979
|
-
}, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
|
|
4980
|
-
}
|
|
4981
|
-
pauseMessagePolling() {
|
|
4982
|
-
if (this.pollingIntervalRef) {
|
|
4983
|
-
clearInterval(this.pollingIntervalRef);
|
|
4984
|
-
this.pollingIntervalRef = undefined;
|
|
4985
|
-
}
|
|
4986
|
-
}
|
|
4987
|
-
resumeMessagePolling() {
|
|
4988
|
-
// Resume message polling after task polling is complete
|
|
4989
|
-
this.startPolling();
|
|
4990
|
-
}
|
|
4991
|
-
async pollForMessages() {
|
|
4992
|
-
if (!this.sessionId)
|
|
4993
|
-
return;
|
|
4994
|
-
try {
|
|
4995
|
-
const url = new URL(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/poll/`);
|
|
4996
|
-
if (this.messages && this.messages.length > 0) {
|
|
4997
|
-
url.searchParams.set('since', this.messages.at(-1).created_at);
|
|
4998
|
-
}
|
|
4999
|
-
const response = await fetch(url.toString());
|
|
5000
|
-
if (!response.ok)
|
|
5001
|
-
return; // Silently fail for polling
|
|
5002
|
-
const data = await response.json();
|
|
5003
|
-
if (data.messages.length > 0) {
|
|
5004
|
-
this.messages = [...this.messages, ...data.messages];
|
|
5005
|
-
this.saveSessionToStorage();
|
|
5006
|
-
this.scrollToBottom();
|
|
5007
|
-
this.focusInput();
|
|
5008
|
-
}
|
|
5009
|
-
}
|
|
5010
|
-
catch (_a) {
|
|
5011
|
-
// Silently fail for polling
|
|
5012
|
-
}
|
|
5013
|
-
}
|
|
5014
5626
|
/**
|
|
5015
5627
|
* Scroll the message container to the bottom.
|
|
5016
5628
|
* @param forceEnd When `false`, scroll the top of the last message into view.
|
|
@@ -5055,50 +5667,18 @@ const OcsChat = class {
|
|
|
5055
5667
|
this.messageInput = event.target.value;
|
|
5056
5668
|
}
|
|
5057
5669
|
handleFileSelect(event) {
|
|
5058
|
-
var _a;
|
|
5059
5670
|
if (!this.allowAttachments)
|
|
5060
5671
|
return;
|
|
5061
5672
|
const input = event.target;
|
|
5062
5673
|
if (!input.files || input.files.length === 0)
|
|
5063
5674
|
return;
|
|
5064
|
-
|
|
5065
|
-
let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
5066
|
-
for (let i = 0; i < input.files.length; i++) {
|
|
5067
|
-
const file = input.files[i];
|
|
5068
|
-
const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
|
|
5069
|
-
if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
|
|
5070
|
-
newFiles.push({
|
|
5071
|
-
file,
|
|
5072
|
-
error: `File type ${ext} not supported`
|
|
5073
|
-
});
|
|
5074
|
-
continue;
|
|
5075
|
-
}
|
|
5076
|
-
const fileSizeMB = file.size / (1024 * 1024);
|
|
5077
|
-
if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
|
|
5078
|
-
newFiles.push({
|
|
5079
|
-
file,
|
|
5080
|
-
error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
|
|
5081
|
-
});
|
|
5082
|
-
continue;
|
|
5083
|
-
}
|
|
5084
|
-
totalSize += file.size;
|
|
5085
|
-
const totalSizeMB = totalSize / (1024 * 1024);
|
|
5086
|
-
if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
|
|
5087
|
-
newFiles.push({
|
|
5088
|
-
file,
|
|
5089
|
-
error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
|
|
5090
|
-
});
|
|
5091
|
-
continue;
|
|
5092
|
-
}
|
|
5093
|
-
newFiles.push({ file });
|
|
5094
|
-
}
|
|
5095
|
-
this.selectedFiles = [...this.selectedFiles, ...newFiles];
|
|
5675
|
+
this.selectedFiles = this.attachmentManager.addFiles(this.selectedFiles, input.files);
|
|
5096
5676
|
input.value = '';
|
|
5097
5677
|
}
|
|
5098
5678
|
removeSelectedFile(index) {
|
|
5099
5679
|
if (!this.allowAttachments)
|
|
5100
5680
|
return;
|
|
5101
|
-
this.selectedFiles = this.
|
|
5681
|
+
this.selectedFiles = this.attachmentManager.removeFile(this.selectedFiles, index);
|
|
5102
5682
|
}
|
|
5103
5683
|
formatFileSize(bytes) {
|
|
5104
5684
|
if (bytes === 0)
|
|
@@ -5125,6 +5705,11 @@ const OcsChat = class {
|
|
|
5125
5705
|
* @param visible - The new value for the field.
|
|
5126
5706
|
*/
|
|
5127
5707
|
async visibilityHandler(visible) {
|
|
5708
|
+
if (this.isButtonDragging) {
|
|
5709
|
+
this.isButtonDragging = false;
|
|
5710
|
+
this.buttonWasDragged = false;
|
|
5711
|
+
this.removeButtonEventListeners();
|
|
5712
|
+
}
|
|
5128
5713
|
if (visible) {
|
|
5129
5714
|
this.initializePosition();
|
|
5130
5715
|
}
|
|
@@ -5132,11 +5717,86 @@ const OcsChat = class {
|
|
|
5132
5717
|
await this.startSession();
|
|
5133
5718
|
}
|
|
5134
5719
|
else if (!visible) {
|
|
5135
|
-
this.
|
|
5720
|
+
this.stopMessagePolling();
|
|
5136
5721
|
}
|
|
5137
5722
|
else {
|
|
5138
5723
|
this.scrollToBottom(true);
|
|
5139
|
-
this.
|
|
5724
|
+
this.startMessagePolling();
|
|
5725
|
+
}
|
|
5726
|
+
}
|
|
5727
|
+
startTaskPolling(taskId) {
|
|
5728
|
+
if (!this.sessionId)
|
|
5729
|
+
return;
|
|
5730
|
+
this.currentPollTaskId = taskId;
|
|
5731
|
+
this.isTyping = true;
|
|
5732
|
+
this.stopMessagePolling();
|
|
5733
|
+
if (this.taskPollingHandle) {
|
|
5734
|
+
this.taskPollingHandle.cancel();
|
|
5735
|
+
}
|
|
5736
|
+
this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
|
|
5737
|
+
onMessage: (message) => {
|
|
5738
|
+
this.messages = [...this.messages, message];
|
|
5739
|
+
this.saveSessionToStorage();
|
|
5740
|
+
this.scrollToBottom();
|
|
5741
|
+
this.isTyping = false;
|
|
5742
|
+
this.currentPollTaskId = '';
|
|
5743
|
+
this.taskPollingHandle = undefined;
|
|
5744
|
+
this.startMessagePolling();
|
|
5745
|
+
this.focusInput();
|
|
5746
|
+
},
|
|
5747
|
+
onTimeout: () => {
|
|
5748
|
+
const timeoutMessage = {
|
|
5749
|
+
created_at: new Date().toISOString(),
|
|
5750
|
+
role: 'system',
|
|
5751
|
+
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
5752
|
+
attachments: []
|
|
5753
|
+
};
|
|
5754
|
+
this.messages = [...this.messages, timeoutMessage];
|
|
5755
|
+
this.saveSessionToStorage();
|
|
5756
|
+
this.scrollToBottom();
|
|
5757
|
+
this.isTyping = false;
|
|
5758
|
+
this.currentPollTaskId = '';
|
|
5759
|
+
this.taskPollingHandle = undefined;
|
|
5760
|
+
this.startMessagePolling();
|
|
5761
|
+
this.focusInput();
|
|
5762
|
+
},
|
|
5763
|
+
onError: (error) => {
|
|
5764
|
+
this.handleError(error.message);
|
|
5765
|
+
this.taskPollingHandle = undefined;
|
|
5766
|
+
this.startMessagePolling();
|
|
5767
|
+
}
|
|
5768
|
+
});
|
|
5769
|
+
}
|
|
5770
|
+
startMessagePolling() {
|
|
5771
|
+
if (!this.sessionId || this.currentPollTaskId || !this.visible) {
|
|
5772
|
+
return;
|
|
5773
|
+
}
|
|
5774
|
+
if (this.messagePollingHandle) {
|
|
5775
|
+
return;
|
|
5776
|
+
}
|
|
5777
|
+
this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
|
|
5778
|
+
getSince: () => { var _a; return this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined; },
|
|
5779
|
+
onMessages: (messages) => {
|
|
5780
|
+
if (messages.length === 0)
|
|
5781
|
+
return;
|
|
5782
|
+
this.messages = [...this.messages, ...messages];
|
|
5783
|
+
this.saveSessionToStorage();
|
|
5784
|
+
this.scrollToBottom();
|
|
5785
|
+
this.focusInput();
|
|
5786
|
+
},
|
|
5787
|
+
onError: () => {
|
|
5788
|
+
// Silently ignore polling errors to match previous behaviour
|
|
5789
|
+
}
|
|
5790
|
+
});
|
|
5791
|
+
}
|
|
5792
|
+
stopMessagePolling() {
|
|
5793
|
+
var _a;
|
|
5794
|
+
if (this.messagePollingHandle) {
|
|
5795
|
+
this.messagePollingHandle.stop();
|
|
5796
|
+
this.messagePollingHandle = undefined;
|
|
5797
|
+
}
|
|
5798
|
+
else {
|
|
5799
|
+
(_a = this.chatService) === null || _a === void 0 ? void 0 : _a.stopMessagePolling();
|
|
5140
5800
|
}
|
|
5141
5801
|
}
|
|
5142
5802
|
setPosition(position) {
|
|
@@ -5157,7 +5817,6 @@ const OcsChat = class {
|
|
|
5157
5817
|
const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
|
|
5158
5818
|
const centeredX = (windowWidth - actualChatWidth) / 2;
|
|
5159
5819
|
const maxOffset = (windowWidth - actualChatWidth) / 2;
|
|
5160
|
-
console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
|
|
5161
5820
|
return { windowWidth, actualChatWidth, centeredX, maxOffset };
|
|
5162
5821
|
}
|
|
5163
5822
|
getPositionStyles() {
|
|
@@ -5279,25 +5938,181 @@ const OcsChat = class {
|
|
|
5279
5938
|
document.removeEventListener('touchmove', this.handleTouchMove);
|
|
5280
5939
|
document.removeEventListener('touchend', this.handleTouchEnd);
|
|
5281
5940
|
}
|
|
5282
|
-
|
|
5283
|
-
|
|
5941
|
+
// Button positioning and drag handlers
|
|
5942
|
+
initializeButtonPosition() {
|
|
5943
|
+
const computedStyle = getComputedStyle(this.host);
|
|
5944
|
+
const position = computedStyle.getPropertyValue('position');
|
|
5945
|
+
// Only enable dragging if the host element is positioned fixed
|
|
5946
|
+
if (position !== 'fixed') {
|
|
5947
|
+
return;
|
|
5948
|
+
}
|
|
5949
|
+
const rect = this.host.getBoundingClientRect();
|
|
5950
|
+
const windowWidth = window.innerWidth;
|
|
5951
|
+
const windowHeight = window.innerHeight;
|
|
5952
|
+
const left = computedStyle.getPropertyValue('left');
|
|
5953
|
+
const right = computedStyle.getPropertyValue('right');
|
|
5954
|
+
const top = computedStyle.getPropertyValue('top');
|
|
5955
|
+
const bottom = computedStyle.getPropertyValue('bottom');
|
|
5956
|
+
const hasLeft = !this.isAutoPosition(left);
|
|
5957
|
+
const hasTop = !this.isAutoPosition(top);
|
|
5958
|
+
this.buttonHorizontalSide = hasLeft ? 'left' : 'right';
|
|
5959
|
+
this.buttonVerticalSide = hasTop ? 'top' : 'bottom';
|
|
5960
|
+
const resolvedRight = this.getNumericPositionValue(right, Math.max(0, windowWidth - rect.right));
|
|
5961
|
+
const resolvedLeft = this.getNumericPositionValue(left, Math.max(0, rect.left));
|
|
5962
|
+
const resolvedBottom = this.getNumericPositionValue(bottom, Math.max(0, windowHeight - rect.bottom));
|
|
5963
|
+
const resolvedTop = this.getNumericPositionValue(top, Math.max(0, rect.top));
|
|
5964
|
+
const horizontalValue = this.buttonHorizontalSide === 'left' ? resolvedLeft : resolvedRight;
|
|
5965
|
+
const verticalValue = this.buttonVerticalSide === 'top' ? resolvedTop : resolvedBottom;
|
|
5966
|
+
this.buttonPosition = {
|
|
5967
|
+
x: horizontalValue,
|
|
5968
|
+
y: verticalValue
|
|
5969
|
+
};
|
|
5970
|
+
// Apply the position to the host
|
|
5971
|
+
this.updateHostPosition();
|
|
5972
|
+
}
|
|
5973
|
+
updateHostPosition() {
|
|
5974
|
+
this.host.style.position = 'fixed';
|
|
5975
|
+
if (this.buttonHorizontalSide === 'left') {
|
|
5976
|
+
this.host.style.left = `${this.buttonPosition.x}px`;
|
|
5977
|
+
this.host.style.right = 'auto';
|
|
5978
|
+
}
|
|
5979
|
+
else {
|
|
5980
|
+
this.host.style.right = `${this.buttonPosition.x}px`;
|
|
5981
|
+
this.host.style.left = 'auto';
|
|
5982
|
+
}
|
|
5983
|
+
if (this.buttonVerticalSide === 'top') {
|
|
5984
|
+
this.host.style.top = `${this.buttonPosition.y}px`;
|
|
5985
|
+
this.host.style.bottom = 'auto';
|
|
5986
|
+
}
|
|
5987
|
+
else {
|
|
5988
|
+
this.host.style.bottom = `${this.buttonPosition.y}px`;
|
|
5989
|
+
this.host.style.top = 'auto';
|
|
5990
|
+
}
|
|
5991
|
+
}
|
|
5992
|
+
isButtonDraggable() {
|
|
5993
|
+
const computedStyle = getComputedStyle(this.host);
|
|
5994
|
+
return computedStyle.getPropertyValue('position') === 'fixed';
|
|
5995
|
+
}
|
|
5996
|
+
updateButtonPosition(pointer) {
|
|
5997
|
+
var _a, _b;
|
|
5998
|
+
const windowWidth = window.innerWidth;
|
|
5999
|
+
const windowHeight = window.innerHeight;
|
|
6000
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
6001
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
6002
|
+
const minPadding = 10;
|
|
6003
|
+
const candidateLeft = pointer.clientX - this.buttonDragOffset.x;
|
|
6004
|
+
const candidateTop = pointer.clientY - this.buttonDragOffset.y;
|
|
6005
|
+
const minLeft = minPadding;
|
|
6006
|
+
const maxLeft = windowWidth - buttonWidth - minPadding;
|
|
6007
|
+
const minTop = minPadding;
|
|
6008
|
+
const maxTop = windowHeight - buttonHeight - minPadding;
|
|
6009
|
+
const constrainedLeft = Math.max(minLeft, Math.min(candidateLeft, maxLeft));
|
|
6010
|
+
const constrainedTop = Math.max(minTop, Math.min(candidateTop, maxTop));
|
|
6011
|
+
const newHorizontalValue = this.buttonHorizontalSide === 'left'
|
|
6012
|
+
? constrainedLeft
|
|
6013
|
+
: Math.max(minPadding, windowWidth - (constrainedLeft + buttonWidth));
|
|
6014
|
+
const newVerticalValue = this.buttonVerticalSide === 'top'
|
|
6015
|
+
? constrainedTop
|
|
6016
|
+
: Math.max(minPadding, windowHeight - (constrainedTop + buttonHeight));
|
|
6017
|
+
if (newHorizontalValue !== this.buttonPosition.x || newVerticalValue !== this.buttonPosition.y) {
|
|
6018
|
+
this.buttonWasDragged = true;
|
|
6019
|
+
this.buttonPosition = { x: newHorizontalValue, y: newVerticalValue };
|
|
6020
|
+
if (this.rafId === null) {
|
|
6021
|
+
this.rafId = requestAnimationFrame(() => {
|
|
6022
|
+
this.updateHostPosition();
|
|
6023
|
+
this.rafId = null;
|
|
6024
|
+
});
|
|
6025
|
+
}
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
6028
|
+
addButtonEventListeners() {
|
|
6029
|
+
if (this.buttonListenersAttached) {
|
|
6030
|
+
return;
|
|
6031
|
+
}
|
|
6032
|
+
document.addEventListener('mousemove', this.handleButtonMouseMove);
|
|
6033
|
+
document.addEventListener('mouseup', this.handleButtonMouseUp);
|
|
6034
|
+
document.addEventListener('touchmove', this.handleButtonTouchMove, { passive: false });
|
|
6035
|
+
document.addEventListener('touchend', this.handleButtonTouchEnd);
|
|
6036
|
+
this.buttonListenersAttached = true;
|
|
6037
|
+
}
|
|
6038
|
+
removeButtonEventListeners() {
|
|
6039
|
+
if (!this.buttonListenersAttached) {
|
|
6040
|
+
return;
|
|
6041
|
+
}
|
|
6042
|
+
if (this.rafId !== null) {
|
|
6043
|
+
cancelAnimationFrame(this.rafId);
|
|
6044
|
+
this.rafId = null;
|
|
6045
|
+
}
|
|
6046
|
+
document.removeEventListener('mousemove', this.handleButtonMouseMove);
|
|
6047
|
+
document.removeEventListener('mouseup', this.handleButtonMouseUp);
|
|
6048
|
+
document.removeEventListener('touchmove', this.handleButtonTouchMove);
|
|
6049
|
+
document.removeEventListener('touchend', this.handleButtonTouchEnd);
|
|
6050
|
+
this.buttonListenersAttached = false;
|
|
6051
|
+
}
|
|
6052
|
+
isAutoPosition(value) {
|
|
6053
|
+
const trimmed = value.trim();
|
|
6054
|
+
return trimmed === '' || trimmed === 'auto';
|
|
6055
|
+
}
|
|
6056
|
+
parsePixelValue(value) {
|
|
6057
|
+
const trimmed = value.trim();
|
|
6058
|
+
if (trimmed === '' || trimmed === 'auto') {
|
|
6059
|
+
return null;
|
|
6060
|
+
}
|
|
6061
|
+
if (trimmed.endsWith('px')) {
|
|
6062
|
+
const parsed = parseFloat(trimmed);
|
|
6063
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
6064
|
+
}
|
|
6065
|
+
const numeric = Number(trimmed);
|
|
6066
|
+
if (Number.isFinite(numeric)) {
|
|
6067
|
+
return numeric;
|
|
6068
|
+
}
|
|
6069
|
+
return null;
|
|
6070
|
+
}
|
|
6071
|
+
getNumericPositionValue(value, fallback) {
|
|
6072
|
+
const parsed = this.parsePixelValue(value);
|
|
6073
|
+
if (parsed !== null) {
|
|
6074
|
+
return parsed;
|
|
6075
|
+
}
|
|
6076
|
+
return fallback;
|
|
6077
|
+
}
|
|
6078
|
+
getWelcomeMessages() {
|
|
6079
|
+
const translated = this.translationManager.getArray("content.welcomeMessages");
|
|
6080
|
+
return translated && translated.length > 0
|
|
6081
|
+
? translated
|
|
6082
|
+
: this.parsedWelcomeMessages;
|
|
6083
|
+
}
|
|
6084
|
+
getStarterQuestions() {
|
|
6085
|
+
const translated = this.translationManager.getArray("content.starterQuestions");
|
|
6086
|
+
return translated && translated.length > 0
|
|
6087
|
+
? translated
|
|
6088
|
+
: this.parsedStarterQuestions;
|
|
5284
6089
|
}
|
|
5285
6090
|
getButtonClasses() {
|
|
5286
|
-
const
|
|
6091
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
6092
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
5287
6093
|
const baseClass = hasText ? 'chat-btn-text' : 'chat-btn-icon';
|
|
5288
6094
|
const shapeClass = this.buttonShape === 'round' ? 'round' : '';
|
|
5289
6095
|
return `${baseClass} ${shapeClass}`.trim();
|
|
5290
6096
|
}
|
|
5291
6097
|
renderButton() {
|
|
5292
|
-
|
|
6098
|
+
var _a;
|
|
6099
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
6100
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
5293
6101
|
const hasCustomIcon = this.iconUrl && this.iconUrl.trim();
|
|
5294
|
-
const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
|
|
5295
6102
|
const buttonClasses = this.getButtonClasses();
|
|
6103
|
+
const finalButtonText = buttonText !== null && buttonText !== void 0 ? buttonText : '';
|
|
6104
|
+
const openLabel = (_a = this.translationManager.get('launcher.open')) !== null && _a !== void 0 ? _a : '';
|
|
6105
|
+
const buttonAriaLabel = finalButtonText ? `${openLabel} - ${finalButtonText}` : openLabel;
|
|
6106
|
+
// Only show drag cursor if button is draggable
|
|
6107
|
+
const isDraggable = this.isButtonDraggable();
|
|
6108
|
+
const buttonStyle = isDraggable ? {
|
|
6109
|
+
cursor: this.isButtonDragging ? 'grabbing' : 'grab',
|
|
6110
|
+
} : {};
|
|
5296
6111
|
if (hasText) {
|
|
5297
|
-
return (index.h("button", { class: buttonClasses, onClick: () => this.
|
|
6112
|
+
return (index.h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": buttonAriaLabel, title: finalButtonText || openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? index.h("img", { src: this.iconUrl, alt: "" }) : index.h(OcsWidgetAvatar, null), index.h("span", null, finalButtonText), isDraggable && (index.h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
5298
6113
|
}
|
|
5299
6114
|
else {
|
|
5300
|
-
return (index.h("button", { class: buttonClasses, onClick: () => this.
|
|
6115
|
+
return (index.h("button", { ref: (el) => this.buttonRef = el, class: buttonClasses, "aria-label": openLabel, title: openLabel, style: buttonStyle, onClick: () => this.handleButtonClick(), onMouseDown: (e) => this.handleButtonMouseDown(e), onTouchStart: (e) => this.handleButtonTouchStart(e), "aria-grabbed": this.isButtonDragging, "aria-describedby": isDraggable ? "chat-button-drag-hint" : undefined }, hasCustomIcon ? index.h("img", { src: this.iconUrl, alt: "" }) : index.h(OcsWidgetAvatar, null), isDraggable && (index.h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
5301
6116
|
}
|
|
5302
6117
|
}
|
|
5303
6118
|
getStorageKeys() {
|
|
@@ -5433,18 +6248,18 @@ const OcsChat = class {
|
|
|
5433
6248
|
if (this.error && !this.sessionId) {
|
|
5434
6249
|
return (index.h(index.Host, null, index.h("p", { class: "error-message" }, this.error)));
|
|
5435
6250
|
}
|
|
5436
|
-
return (index.h(index.Host, null, this.renderButton(), this.visible && (index.h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, index.h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, index.h("div", { class: "drag-indicator" }, index.h("div", { class: "drag-dots header-button" }, index.h(GripDotsVerticalIcon, null))), index.h("div", { class: "header-text" }, this.headerText), index.h("div", { class: "header-buttons" }, this.messages.length > 0 && (index.h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title:
|
|
6251
|
+
return (index.h(index.Host, null, this.renderButton(), this.visible && (index.h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, index.h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, index.h("div", { class: "drag-indicator" }, index.h("div", { class: "drag-dots header-button" }, index.h(GripDotsVerticalIcon, null))), index.h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), index.h("div", { class: "header-buttons" }, this.messages.length > 0 && (index.h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, index.h(PlusWithCircleIcon, null))), this.allowFullScreen && index.h("button", { class: "header-button fullscreen-button", onClick: () => this.toggleFullscreen(), title: this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen'), "aria-label": this.isFullscreen ? this.translationManager.get('window.exitFullscreen') : this.translationManager.get('window.fullscreen') }, this.isFullscreen ? index.h(ArrowsPointingInIcon, null) : index.h(ArrowsPointingOutIcon, null)), index.h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.close') }, index.h(XMarkIcon, null)))), this.showNewChatConfirmation && (index.h("div", { class: "confirmation-overlay" }, index.h("div", { class: "confirmation-dialog" }, index.h("div", { class: "confirmation-content" }, index.h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), index.h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), index.h("div", { class: "confirmation-buttons" }, index.h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), index.h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), index.h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (index.h("div", { class: "loading-container" }, index.h("div", { class: "loading-spinner" }), index.h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (index.h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (index.h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index$1) => (index.h("div", { key: `welcome-${index$1}`, class: "message-row message-row-assistant" }, index.h("div", { class: "message-bubble message-bubble-assistant" }, index.h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message) }))))))), this.messages.map((message, index$1) => (index.h("div", { key: index$1, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, index.h("div", { class: `message-bubble ${message.role === 'user'
|
|
5437
6252
|
? 'message-bubble-user'
|
|
5438
6253
|
: message.role === 'assistant'
|
|
5439
6254
|
? 'message-bubble-assistant'
|
|
5440
|
-
: 'message-bubble-system'}` }, index.h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (index.h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (index.h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, index.h("span", { class: "message-attachment-icon" }, index.h(PaperClipIcon, null)), index.h("span", { class: "message-attachment-name" }, attachment.name)))))), index.h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (index.h("div", null, index.h("div", { class: "typing-indicator" }, index.h("div", { class: "typing-progress" })), index.h("div", { class: "typing-text" }, index.h("span", null, this.typingIndicatorText), index.h("span", { class: "typing-dots" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (index.h("div", { class: "starter-questions" }, this.
|
|
6255
|
+
: 'message-bubble-system'}` }, index.h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (index.h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (index.h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, index.h("span", { class: "message-attachment-icon" }, index.h(PaperClipIcon, null)), index.h("span", { class: "message-attachment-name" }, attachment.name)))))), index.h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (index.h("div", null, index.h("div", { class: "typing-indicator" }, index.h("div", { class: "typing-progress" })), index.h("div", { class: "typing-text" }, index.h("span", null, this.translationManager.get('status.typing', this.typingIndicatorText)), index.h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (index.h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index$1) => (index.h("div", { key: `starter-${index$1}`, class: "starter-question-row" }, index.h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (index.h("div", { class: "selected-files-container" }, index.h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index$1) => (index.h("div", { key: index$1, class: "selected-file-item" }, index.h("div", { class: "flex items-center gap-[0.5em]" }, index.h("span", { class: "selected-file-icon" }, index.h(PaperClipIcon, null)), index.h("span", null, selectedFile.file.name), index.h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (index.h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (index.h("span", { class: "selected-file-success-icon" }, index.h(CheckDocumentIcon, null)))), index.h("button", { onClick: () => this.removeSelectedFile(index$1), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, index.h(XIcon, null)))))))), this.sessionId && (index.h("div", { class: "input-area" }, index.h("div", { class: "input-container" }, index.h("textarea", { ref: (el) => this.textareaRef = el, class: "message-textarea", rows: 1, placeholder: this.translationManager.get('composer.placeholder'), value: this.messageInput, onInput: (e) => this.handleInputChange(e), onKeyPress: (e) => this.handleKeyPress(e), disabled: this.isTyping || this.isUploadingFiles }), this.allowAttachments && (index.h("input", { ref: (el) => {
|
|
5441
6256
|
// Unclear why but after removing all attachments this is being set to `null`.
|
|
5442
6257
|
if (el) {
|
|
5443
6258
|
this.fileInputRef = el;
|
|
5444
6259
|
}
|
|
5445
|
-
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (index.h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title:
|
|
6260
|
+
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (index.h("button", { class: "file-attachment-button", onClick: () => { var _a; return (_a = this.fileInputRef) === null || _a === void 0 ? void 0 : _a.click(); }, disabled: this.isTyping || this.isUploadingFiles, title: this.translationManager.get('attach.add'), "aria-label": this.translationManager.get('attach.add') }, index.h(PaperClipIcon, null))), index.h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
|
|
5446
6261
|
? 'send-button-enabled'
|
|
5447
|
-
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? '
|
|
6262
|
+
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? `${this.translationManager.get('status.uploading')}...` : this.translationManager.get('composer.send'))))), index.h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, index.h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", index.h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
|
|
5448
6263
|
}
|
|
5449
6264
|
get host() { return index.getElement(this); }
|
|
5450
6265
|
static get watchers() { return {
|