open-chat-studio-widget 0.4.8 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -20
- package/dist/cjs/{index-AhSI5tER.js → index-CC3Krx2K.js} +4 -2
- package/dist/cjs/index-CC3Krx2K.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-BF7CYZiN.js} +4 -3
- package/dist/esm/index-BF7CYZiN.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-400b1f47.entry.js +4 -0
- package/dist/open-chat-studio-widget/p-400b1f47.entry.js.map +1 -0
- package/dist/open-chat-studio-widget/p-BF7CYZiN.js +3 -0
- package/dist/open-chat-studio-widget/p-BF7CYZiN.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,5 +1,17 @@
|
|
|
1
|
-
import { h, r as registerInstance, H as Host, g as getElement } from './index-
|
|
2
|
-
|
|
1
|
+
import { h, r as registerInstance, E as Env, H as Host, g as getElement } from './index-BF7CYZiN.js';
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
|
+
const OcsWidgetAvatar = () => {
|
|
5
|
+
return h("svg", { width: "24", height: "24", viewBox: "0 0 500 500", fill: "currentColor", xmlns: "http://www.w3.org/2000/svg" },
|
|
6
|
+
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" }),
|
|
7
|
+
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" }),
|
|
8
|
+
h("rect", { x: "289.475", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
|
|
9
|
+
h("rect", { x: "161.184", y: "184.808", width: "61.9019", height: "115.73", rx: "30.951" }),
|
|
10
|
+
h("path", { d: "M325.658 483.553V414.58V401.316H148.027L325.658 483.553Z" }));
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Heroicon: x-mark
|
|
14
|
+
*/
|
|
3
15
|
const XMarkIcon = () => {
|
|
4
16
|
return h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
5
17
|
h("path", { "stroke-linecap": "round", "stroke-linejoin": "round", d: "M6 18 18 6M6 6l12 12" }));
|
|
@@ -13,22 +25,37 @@ const GripDotsVerticalIcon = () => {
|
|
|
13
25
|
h("circle", { cx: "16", cy: "12", r: "1.5" }),
|
|
14
26
|
h("circle", { cx: "16", cy: "18", r: "1.5" })));
|
|
15
27
|
};
|
|
28
|
+
/**
|
|
29
|
+
* Heroicon: plus-circle
|
|
30
|
+
*/
|
|
16
31
|
const PlusWithCircleIcon = () => {
|
|
17
32
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
18
33
|
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" })));
|
|
19
34
|
};
|
|
35
|
+
/**
|
|
36
|
+
* Heroicon: arrows-pointing-out
|
|
37
|
+
*/
|
|
20
38
|
const ArrowsPointingOutIcon = () => {
|
|
21
39
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
22
40
|
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" })));
|
|
23
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* Heroicon: arrows-pointing-in
|
|
44
|
+
*/
|
|
24
45
|
const ArrowsPointingInIcon = () => {
|
|
25
46
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
26
47
|
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" })));
|
|
27
48
|
};
|
|
49
|
+
/**
|
|
50
|
+
* Heroicon: paper-clip
|
|
51
|
+
*/
|
|
28
52
|
const PaperClipIcon = () => {
|
|
29
53
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
30
54
|
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" })));
|
|
31
55
|
};
|
|
56
|
+
/**
|
|
57
|
+
* Heroicon: document-check
|
|
58
|
+
*/
|
|
32
59
|
const CheckDocumentIcon = () => {
|
|
33
60
|
return (h("svg", { xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", "stroke-width": "1.5", stroke: "currentColor" },
|
|
34
61
|
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" })));
|
|
@@ -4299,7 +4326,7 @@ function renderMarkdownSync(content) {
|
|
|
4299
4326
|
'href', 'target', 'rel', 'class', 'src', 'alt', 'title',
|
|
4300
4327
|
'width', 'height', 'align', 'colspan', 'rowspan'
|
|
4301
4328
|
],
|
|
4302
|
-
ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z
|
|
4329
|
+
ALLOWED_URI_REGEXP: /^(?:(?:https?):|[^a-z]|[a-z+.-]+(?:[^a-z+.\-:]|$))/i,
|
|
4303
4330
|
ADD_ATTR: ['target'],
|
|
4304
4331
|
FORBID_TAGS: ['script', 'style', 'form', 'input', 'button'],
|
|
4305
4332
|
FORBID_ATTR: ['onclick', 'onload', 'onerror', 'onmouseover'],
|
|
@@ -4312,6 +4339,414 @@ function renderMarkdownSync(content) {
|
|
|
4312
4339
|
}
|
|
4313
4340
|
}
|
|
4314
4341
|
|
|
4342
|
+
/**
|
|
4343
|
+
* Convert a CSS percentage (60%) or pixel (10px) value to pixels.
|
|
4344
|
+
* @param value The CSS string value
|
|
4345
|
+
* @param maxValue The max value to use when converting from a percentage
|
|
4346
|
+
* @param defaultValue The default value if the CSS value is neither a percentage nor a pixel value.
|
|
4347
|
+
*/
|
|
4348
|
+
const varToPixels = (value, maxValue, defaultValue) => {
|
|
4349
|
+
value = value.trim();
|
|
4350
|
+
if (value.includes("%")) {
|
|
4351
|
+
const percent = percentToFloat(value);
|
|
4352
|
+
if (!isNaN(percent)) {
|
|
4353
|
+
return maxValue * percent;
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
else if (value.includes("px")) {
|
|
4357
|
+
const pixels = parseFloat(value);
|
|
4358
|
+
if (!isNaN(pixels)) {
|
|
4359
|
+
return pixels;
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
return defaultValue;
|
|
4363
|
+
};
|
|
4364
|
+
const percentToFloat = (percentageString) => {
|
|
4365
|
+
const numericValue = parseFloat(percentageString);
|
|
4366
|
+
if (isNaN(numericValue)) {
|
|
4367
|
+
return NaN;
|
|
4368
|
+
}
|
|
4369
|
+
return numericValue / 100;
|
|
4370
|
+
};
|
|
4371
|
+
|
|
4372
|
+
var ar = {
|
|
4373
|
+
"launcher.open": "فتح المحادثة",
|
|
4374
|
+
"window.close": "إغلاق",
|
|
4375
|
+
"window.newChat": "بدء محادثة جديدة",
|
|
4376
|
+
"window.fullscreen": "دخول وضع ملء الشاشة",
|
|
4377
|
+
"window.exitFullscreen": "الخروج من وضع ملء الشاشة",
|
|
4378
|
+
"attach.add": "إرفاق ملفات",
|
|
4379
|
+
"attach.remove": "إزالة الملف",
|
|
4380
|
+
"attach.success": "تم إرفاق الملف",
|
|
4381
|
+
"status.starting": "جارٍ بدء المحادثة...",
|
|
4382
|
+
"status.typing": "جارٍ تحضير الرد",
|
|
4383
|
+
"status.uploading": "جارٍ التحميل",
|
|
4384
|
+
"modal.newChatTitle": "بدء محادثة جديدة",
|
|
4385
|
+
"modal.newChatBody": "بدء محادثة جديدة سيؤدي إلى مسح المحادثة الحالية. هل ترغب بالمتابعة؟",
|
|
4386
|
+
"modal.cancel": "إلغاء",
|
|
4387
|
+
"modal.confirm": "تأكيد",
|
|
4388
|
+
"composer.placeholder": "اكتب رسالة...",
|
|
4389
|
+
"composer.send": "إرسال الرسالة",
|
|
4390
|
+
"error.fileTooLarge": "الملف كبير جدًا",
|
|
4391
|
+
"error.totalTooLarge": "إجمالي حجم الملفات كبير جدًا",
|
|
4392
|
+
"error.unsupportedType": "نوع الملف غير مدعوم",
|
|
4393
|
+
"error.connection": "خطأ في الاتصال. يرجى المحاولة مرة أخرى.",
|
|
4394
|
+
"error.sessionExpired": "انتهت صلاحية الجلسة. يرجى بدء محادثة جديدة.",
|
|
4395
|
+
"branding.poweredBy": "مدعوم من",
|
|
4396
|
+
"branding.buttonText": "",
|
|
4397
|
+
"branding.headerText": "",
|
|
4398
|
+
"content.welcomeMessages": [
|
|
4399
|
+
],
|
|
4400
|
+
"content.starterQuestions": [
|
|
4401
|
+
]
|
|
4402
|
+
};
|
|
4403
|
+
|
|
4404
|
+
var en = {
|
|
4405
|
+
"launcher.open": "Open chat",
|
|
4406
|
+
"window.close": "Close",
|
|
4407
|
+
"window.newChat": "Start new chat",
|
|
4408
|
+
"window.fullscreen": "Enter fullscreen",
|
|
4409
|
+
"window.exitFullscreen": "Exit fullscreen",
|
|
4410
|
+
"attach.add": "Attach files",
|
|
4411
|
+
"attach.remove": "Remove file",
|
|
4412
|
+
"attach.success": "File attached",
|
|
4413
|
+
"status.starting": "Starting chat...",
|
|
4414
|
+
"status.typing": "Preparing response",
|
|
4415
|
+
"status.uploading": "Uploading",
|
|
4416
|
+
"modal.newChatTitle": "Start New Chat",
|
|
4417
|
+
"modal.newChatBody": "Starting a new chat will clear your current conversation. Continue?",
|
|
4418
|
+
"modal.cancel": "Cancel",
|
|
4419
|
+
"modal.confirm": "Confirm",
|
|
4420
|
+
"composer.placeholder": "Type a message...",
|
|
4421
|
+
"composer.send": "Send message",
|
|
4422
|
+
"error.fileTooLarge": "File too large",
|
|
4423
|
+
"error.totalTooLarge": "Total file size too large",
|
|
4424
|
+
"error.unsupportedType": "Unsupported file type",
|
|
4425
|
+
"error.connection": "Connection error. Please try again.",
|
|
4426
|
+
"error.sessionExpired": "Session expired. Please start a new chat.",
|
|
4427
|
+
"branding.poweredBy": "Powered by",
|
|
4428
|
+
"branding.buttonText": "",
|
|
4429
|
+
"branding.headerText": "",
|
|
4430
|
+
"content.welcomeMessages": [
|
|
4431
|
+
],
|
|
4432
|
+
"content.starterQuestions": [
|
|
4433
|
+
]
|
|
4434
|
+
};
|
|
4435
|
+
|
|
4436
|
+
var es = {
|
|
4437
|
+
"launcher.open": "Abrir chat",
|
|
4438
|
+
"window.close": "Cerrar",
|
|
4439
|
+
"window.newChat": "Iniciar nuevo chat",
|
|
4440
|
+
"window.fullscreen": "Pantalla completa",
|
|
4441
|
+
"window.exitFullscreen": "Salir de pantalla completa",
|
|
4442
|
+
"attach.add": "Adjuntar archivos",
|
|
4443
|
+
"attach.remove": "Eliminar archivo",
|
|
4444
|
+
"attach.success": "Archivo adjunto",
|
|
4445
|
+
"status.starting": "Iniciando chat...",
|
|
4446
|
+
"status.typing": "Preparando respuesta",
|
|
4447
|
+
"status.uploading": "Subiendo",
|
|
4448
|
+
"modal.newChatTitle": "Iniciar Nuevo Chat",
|
|
4449
|
+
"modal.newChatBody": "Iniciar un nuevo chat borrará tu conversación actual. ¿Continuar?",
|
|
4450
|
+
"modal.cancel": "Cancelar",
|
|
4451
|
+
"modal.confirm": "Confirmar",
|
|
4452
|
+
"composer.placeholder": "Escribe un mensaje...",
|
|
4453
|
+
"composer.send": "Enviar mensaje",
|
|
4454
|
+
"error.fileTooLarge": "Archivo demasiado grande",
|
|
4455
|
+
"error.totalTooLarge": "Tamaño total de archivos demasiado grande",
|
|
4456
|
+
"error.unsupportedType": "Tipo de archivo no soportado",
|
|
4457
|
+
"error.connection": "Error de conexión. Por favor, inténtalo de nuevo.",
|
|
4458
|
+
"error.sessionExpired": "Sesión expirada. Por favor, inicia un nuevo chat.",
|
|
4459
|
+
"branding.poweredBy": "Desarrollado por",
|
|
4460
|
+
"branding.buttonText": "",
|
|
4461
|
+
"branding.headerText": "",
|
|
4462
|
+
"content.welcomeMessages": [
|
|
4463
|
+
],
|
|
4464
|
+
"content.starterQuestions": [
|
|
4465
|
+
]
|
|
4466
|
+
};
|
|
4467
|
+
|
|
4468
|
+
var fr = {
|
|
4469
|
+
"launcher.open": "Ouvrir le chat",
|
|
4470
|
+
"window.close": "Fermer",
|
|
4471
|
+
"window.newChat": "Nouveau chat",
|
|
4472
|
+
"window.fullscreen": "Plein écran",
|
|
4473
|
+
"window.exitFullscreen": "Quitter le plein écran",
|
|
4474
|
+
"attach.add": "Joindre des fichiers",
|
|
4475
|
+
"attach.remove": "Supprimer le fichier",
|
|
4476
|
+
"attach.success": "Fichier joint",
|
|
4477
|
+
"status.starting": "Démarrage du chat...",
|
|
4478
|
+
"status.typing": "Préparation de la réponse",
|
|
4479
|
+
"status.uploading": "Téléversement",
|
|
4480
|
+
"modal.newChatTitle": "Nouveau Chat",
|
|
4481
|
+
"modal.newChatBody": "Démarrer un nouveau chat effacera votre conversation actuelle. Continuer?",
|
|
4482
|
+
"modal.cancel": "Annuler",
|
|
4483
|
+
"modal.confirm": "Confirmer",
|
|
4484
|
+
"composer.placeholder": "Tapez un message...",
|
|
4485
|
+
"composer.send": "Envoyer le message",
|
|
4486
|
+
"error.fileTooLarge": "Fichier trop volumineux",
|
|
4487
|
+
"error.totalTooLarge": "Taille totale des fichiers trop importante",
|
|
4488
|
+
"error.unsupportedType": "Type de fichier non pris en charge",
|
|
4489
|
+
"error.connection": "Erreur de connexion. Veuillez réessayer.",
|
|
4490
|
+
"error.sessionExpired": "Session expirée. Veuillez démarrer un nouveau chat.",
|
|
4491
|
+
"branding.poweredBy": "Propulsé par",
|
|
4492
|
+
"branding.buttonText": "",
|
|
4493
|
+
"branding.headerText": "",
|
|
4494
|
+
"content.welcomeMessages": [
|
|
4495
|
+
],
|
|
4496
|
+
"content.starterQuestions": [
|
|
4497
|
+
]
|
|
4498
|
+
};
|
|
4499
|
+
|
|
4500
|
+
var hi = {
|
|
4501
|
+
"launcher.open": "चैट खोलें",
|
|
4502
|
+
"window.close": "बंद करें",
|
|
4503
|
+
"window.newChat": "नई चैट शुरू करें",
|
|
4504
|
+
"window.fullscreen": "पूर्ण स्क्रीन पर जाएं",
|
|
4505
|
+
"window.exitFullscreen": "पूर्ण स्क्रीन से बाहर आएं",
|
|
4506
|
+
"attach.add": "फ़ाइलें संलग्न करें",
|
|
4507
|
+
"attach.remove": "फ़ाइल हटाएँ",
|
|
4508
|
+
"attach.success": "फ़ाइल संलग्न की गई",
|
|
4509
|
+
"status.starting": "चैट शुरू हो रही है...",
|
|
4510
|
+
"status.typing": "जवाब तैयार किया जा रहा है",
|
|
4511
|
+
"status.uploading": "अपलोड हो रहा है",
|
|
4512
|
+
"modal.newChatTitle": "नई चैट शुरू करें",
|
|
4513
|
+
"modal.newChatBody": "नई चैट शुरू करने से आपकी मौजूदा बातचीत हट जाएगी। क्या आप जारी रखना चाहते हैं?",
|
|
4514
|
+
"modal.cancel": "रद्द करें",
|
|
4515
|
+
"modal.confirm": "पुष्टि करें",
|
|
4516
|
+
"composer.placeholder": "संदेश लिखें...",
|
|
4517
|
+
"composer.send": "संदेश भेजें",
|
|
4518
|
+
"error.fileTooLarge": "फ़ाइल बहुत बड़ी है",
|
|
4519
|
+
"error.totalTooLarge": "कुल फ़ाइल आकार बहुत बड़ा है",
|
|
4520
|
+
"error.unsupportedType": "फ़ाइल प्रकार समर्थित नहीं है",
|
|
4521
|
+
"error.connection": "कनेक्शन त्रुटि। कृपया पुनः प्रयास करें।",
|
|
4522
|
+
"error.sessionExpired": "सत्र समाप्त हो गया है। कृपया नई चैट शुरू करें।",
|
|
4523
|
+
"branding.poweredBy": "द्वारा संचालित",
|
|
4524
|
+
"branding.buttonText": "",
|
|
4525
|
+
"branding.headerText": "",
|
|
4526
|
+
"content.welcomeMessages": [
|
|
4527
|
+
],
|
|
4528
|
+
"content.starterQuestions": [
|
|
4529
|
+
]
|
|
4530
|
+
};
|
|
4531
|
+
|
|
4532
|
+
var it = {
|
|
4533
|
+
"launcher.open": "Apri chat",
|
|
4534
|
+
"window.close": "Chiudi",
|
|
4535
|
+
"window.newChat": "Avvia nuova chat",
|
|
4536
|
+
"window.fullscreen": "Schermo intero",
|
|
4537
|
+
"window.exitFullscreen": "Esci da schermo intero",
|
|
4538
|
+
"attach.add": "Allega file",
|
|
4539
|
+
"attach.remove": "Rimuovi file",
|
|
4540
|
+
"attach.success": "File allegato",
|
|
4541
|
+
"status.starting": "Avvio della chat...",
|
|
4542
|
+
"status.typing": "Preparazione della risposta",
|
|
4543
|
+
"status.uploading": "Caricamento",
|
|
4544
|
+
"modal.newChatTitle": "Avvia nuova chat",
|
|
4545
|
+
"modal.newChatBody": "Avviare una nuova chat cancellerà la conversazione attuale. Continuare?",
|
|
4546
|
+
"modal.cancel": "Annulla",
|
|
4547
|
+
"modal.confirm": "Conferma",
|
|
4548
|
+
"composer.placeholder": "Scrivi un messaggio...",
|
|
4549
|
+
"composer.send": "Invia messaggio",
|
|
4550
|
+
"error.fileTooLarge": "File troppo grande",
|
|
4551
|
+
"error.totalTooLarge": "Dimensione totale del file troppo grande",
|
|
4552
|
+
"error.unsupportedType": "Tipo di file non supportato",
|
|
4553
|
+
"error.connection": "Errore di connessione. Riprova.",
|
|
4554
|
+
"error.sessionExpired": "Sessione scaduta. Avvia una nuova chat.",
|
|
4555
|
+
"branding.poweredBy": "Offerto da",
|
|
4556
|
+
"branding.buttonText": "",
|
|
4557
|
+
"branding.headerText": "",
|
|
4558
|
+
"content.welcomeMessages": [
|
|
4559
|
+
],
|
|
4560
|
+
"content.starterQuestions": [
|
|
4561
|
+
]
|
|
4562
|
+
};
|
|
4563
|
+
|
|
4564
|
+
var pt = {
|
|
4565
|
+
"launcher.open": "Abrir chat",
|
|
4566
|
+
"window.close": "Fechar",
|
|
4567
|
+
"window.newChat": "Iniciar novo chat",
|
|
4568
|
+
"window.fullscreen": "Entrar em tela cheia",
|
|
4569
|
+
"window.exitFullscreen": "Sair da tela cheia",
|
|
4570
|
+
"attach.add": "Anexar arquivos",
|
|
4571
|
+
"attach.remove": "Remover arquivo",
|
|
4572
|
+
"attach.success": "Arquivo anexado",
|
|
4573
|
+
"status.starting": "Iniciando chat...",
|
|
4574
|
+
"status.typing": "Preparando resposta",
|
|
4575
|
+
"status.uploading": "Carregando",
|
|
4576
|
+
"modal.newChatTitle": "Iniciar novo chat",
|
|
4577
|
+
"modal.newChatBody": "Iniciar um novo chat apagará sua conversa atual. Deseja continuar?",
|
|
4578
|
+
"modal.cancel": "Cancelar",
|
|
4579
|
+
"modal.confirm": "Confirmar",
|
|
4580
|
+
"composer.placeholder": "Digite uma mensagem...",
|
|
4581
|
+
"composer.send": "Enviar mensagem",
|
|
4582
|
+
"error.fileTooLarge": "Arquivo muito grande",
|
|
4583
|
+
"error.totalTooLarge": "Tamanho total do arquivo muito grande",
|
|
4584
|
+
"error.unsupportedType": "Tipo de arquivo não suportado",
|
|
4585
|
+
"error.connection": "Erro de conexão. Por favor, tente novamente.",
|
|
4586
|
+
"error.sessionExpired": "Sessão expirada. Por favor, inicie um novo chat.",
|
|
4587
|
+
"branding.poweredBy": "Desenvolvido por",
|
|
4588
|
+
"branding.buttonText": "",
|
|
4589
|
+
"branding.headerText": "",
|
|
4590
|
+
"content.welcomeMessages": [
|
|
4591
|
+
],
|
|
4592
|
+
"content.starterQuestions": [
|
|
4593
|
+
]
|
|
4594
|
+
};
|
|
4595
|
+
|
|
4596
|
+
var sw = {
|
|
4597
|
+
"launcher.open": "Fungua gumzo",
|
|
4598
|
+
"window.close": "Funga",
|
|
4599
|
+
"window.newChat": "Anza gumzo jipya",
|
|
4600
|
+
"window.fullscreen": "Ingiza skrini nzima",
|
|
4601
|
+
"window.exitFullscreen": "Toka kwenye skrini nzima",
|
|
4602
|
+
"attach.add": "Ambatanisha faili",
|
|
4603
|
+
"attach.remove": "Ondoa faili",
|
|
4604
|
+
"attach.success": "Faili limeambatanishwa",
|
|
4605
|
+
"status.starting": "Inaanzisha gumzo...",
|
|
4606
|
+
"status.typing": "Inatayarisha jibu",
|
|
4607
|
+
"status.uploading": "Inapakia",
|
|
4608
|
+
"modal.newChatTitle": "Anza gumzo jipya",
|
|
4609
|
+
"modal.newChatBody": "Kuanza gumzo jipya kutafuta gumzo lako la sasa. Je, ungependa kuendelea?",
|
|
4610
|
+
"modal.cancel": "Ghairi",
|
|
4611
|
+
"modal.confirm": "Thibitisha",
|
|
4612
|
+
"composer.placeholder": "Andika ujumbe...",
|
|
4613
|
+
"composer.send": "Tuma ujumbe",
|
|
4614
|
+
"error.fileTooLarge": "Faili ni kubwa sana",
|
|
4615
|
+
"error.totalTooLarge": "Jumla ya ukubwa wa faili ni kubwa sana",
|
|
4616
|
+
"error.unsupportedType": "Aina ya faili haitumiki",
|
|
4617
|
+
"error.connection": "Hitilafu ya muunganisho. Tafadhali jaribu tena.",
|
|
4618
|
+
"error.sessionExpired": "Kipindi kimeisha muda wake. Tafadhali anza gumzo jipya.",
|
|
4619
|
+
"branding.poweredBy": "Inaendeshwa na",
|
|
4620
|
+
"branding.buttonText": "",
|
|
4621
|
+
"branding.headerText": "",
|
|
4622
|
+
"content.welcomeMessages": [
|
|
4623
|
+
],
|
|
4624
|
+
"content.starterQuestions": [
|
|
4625
|
+
]
|
|
4626
|
+
};
|
|
4627
|
+
|
|
4628
|
+
var uk = {
|
|
4629
|
+
"launcher.open": "Відкрити чат",
|
|
4630
|
+
"window.close": "Закрити",
|
|
4631
|
+
"window.newChat": "Почати новий чат",
|
|
4632
|
+
"window.fullscreen": "На весь екран",
|
|
4633
|
+
"window.exitFullscreen": "Вийти з повного екрану",
|
|
4634
|
+
"attach.add": "Прикріпити файли",
|
|
4635
|
+
"attach.remove": "Видалити файл",
|
|
4636
|
+
"attach.success": "Файл прикріплено",
|
|
4637
|
+
"status.starting": "Запуск чату...",
|
|
4638
|
+
"status.typing": "Готується відповідь",
|
|
4639
|
+
"status.uploading": "Завантаження",
|
|
4640
|
+
"modal.newChatTitle": "Почати новий чат",
|
|
4641
|
+
"modal.newChatBody": "Початок нового чату видалить вашу поточну розмову. Продовжити?",
|
|
4642
|
+
"modal.cancel": "Скасувати",
|
|
4643
|
+
"modal.confirm": "Підтвердити",
|
|
4644
|
+
"composer.placeholder": "Введіть повідомлення...",
|
|
4645
|
+
"composer.send": "Надіслати повідомлення",
|
|
4646
|
+
"error.fileTooLarge": "Файл занадто великий",
|
|
4647
|
+
"error.totalTooLarge": "Загальний розмір файлів занадто великий",
|
|
4648
|
+
"error.unsupportedType": "Непідтримуваний тип файлу",
|
|
4649
|
+
"error.connection": "Помилка з'єднання. Будь ласка, спробуйте ще раз.",
|
|
4650
|
+
"error.sessionExpired": "Сесія завершилася. Будь ласка, почніть новий чат.",
|
|
4651
|
+
"branding.poweredBy": "Працює на",
|
|
4652
|
+
"branding.buttonText": "",
|
|
4653
|
+
"branding.headerText": "",
|
|
4654
|
+
"content.welcomeMessages": [
|
|
4655
|
+
],
|
|
4656
|
+
"content.starterQuestions": [
|
|
4657
|
+
]
|
|
4658
|
+
};
|
|
4659
|
+
|
|
4660
|
+
/**
|
|
4661
|
+
* Translation utilities for the chat widget
|
|
4662
|
+
*/
|
|
4663
|
+
// Default (English) translations
|
|
4664
|
+
const defaultTranslations = en;
|
|
4665
|
+
// Available translations map
|
|
4666
|
+
const translationFiles = {
|
|
4667
|
+
ar: ar,
|
|
4668
|
+
en: en,
|
|
4669
|
+
es: es,
|
|
4670
|
+
fr: fr,
|
|
4671
|
+
hi: hi,
|
|
4672
|
+
it: it,
|
|
4673
|
+
pt: pt,
|
|
4674
|
+
sw: sw,
|
|
4675
|
+
uk: uk,
|
|
4676
|
+
};
|
|
4677
|
+
function getBrowserLanguage() {
|
|
4678
|
+
if (typeof navigator !== 'undefined') {
|
|
4679
|
+
const lang = navigator.language || navigator.userLanguage;
|
|
4680
|
+
if (lang) {
|
|
4681
|
+
return lang.split('-')[0].toLowerCase();
|
|
4682
|
+
}
|
|
4683
|
+
}
|
|
4684
|
+
return 'en';
|
|
4685
|
+
}
|
|
4686
|
+
function resolveLanguage(langProp) {
|
|
4687
|
+
if (langProp) {
|
|
4688
|
+
return langProp.toLowerCase();
|
|
4689
|
+
}
|
|
4690
|
+
return getBrowserLanguage();
|
|
4691
|
+
}
|
|
4692
|
+
async function loadTranslations(language) {
|
|
4693
|
+
return translationFiles[language] || defaultTranslations;
|
|
4694
|
+
}
|
|
4695
|
+
/**
|
|
4696
|
+
* Overrides matching keys
|
|
4697
|
+
*/
|
|
4698
|
+
function mergeTranslations(baseTranslations, customTranslations) {
|
|
4699
|
+
return Object.assign(Object.assign({}, baseTranslations), customTranslations);
|
|
4700
|
+
}
|
|
4701
|
+
class TranslationManager {
|
|
4702
|
+
constructor(language, customTranslations) {
|
|
4703
|
+
this.translations = defaultTranslations;
|
|
4704
|
+
this.language = 'en';
|
|
4705
|
+
this.language = resolveLanguage(language);
|
|
4706
|
+
this.loadTranslations(customTranslations);
|
|
4707
|
+
}
|
|
4708
|
+
async loadTranslations(customTranslations) {
|
|
4709
|
+
let baseTranslations;
|
|
4710
|
+
try {
|
|
4711
|
+
baseTranslations = await loadTranslations(this.language);
|
|
4712
|
+
}
|
|
4713
|
+
catch (error) {
|
|
4714
|
+
console.error('Failed to load translations:', error);
|
|
4715
|
+
baseTranslations = defaultTranslations;
|
|
4716
|
+
}
|
|
4717
|
+
this.translations = customTranslations
|
|
4718
|
+
? mergeTranslations(baseTranslations, customTranslations)
|
|
4719
|
+
: baseTranslations;
|
|
4720
|
+
}
|
|
4721
|
+
get(key, override) {
|
|
4722
|
+
var _a;
|
|
4723
|
+
if (override !== undefined && override !== null) {
|
|
4724
|
+
return override;
|
|
4725
|
+
}
|
|
4726
|
+
const value = (_a = this.translations[key]) !== null && _a !== void 0 ? _a : defaultTranslations[key];
|
|
4727
|
+
if (Array.isArray(value)) {
|
|
4728
|
+
return value.length > 0 ? value[0] : undefined;
|
|
4729
|
+
}
|
|
4730
|
+
return value !== null && value !== void 0 ? value : undefined;
|
|
4731
|
+
}
|
|
4732
|
+
getAll() {
|
|
4733
|
+
return this.translations;
|
|
4734
|
+
}
|
|
4735
|
+
getArray(key) {
|
|
4736
|
+
const value = this.translations[key] || defaultTranslations[key];
|
|
4737
|
+
if (Array.isArray(value)) {
|
|
4738
|
+
return value;
|
|
4739
|
+
}
|
|
4740
|
+
if (typeof value === 'string') {
|
|
4741
|
+
return [value];
|
|
4742
|
+
}
|
|
4743
|
+
return [];
|
|
4744
|
+
}
|
|
4745
|
+
getLanguage() {
|
|
4746
|
+
return this.language;
|
|
4747
|
+
}
|
|
4748
|
+
}
|
|
4749
|
+
|
|
4315
4750
|
/*! js-cookie v3.0.5 | MIT */
|
|
4316
4751
|
/* eslint-disable no-var */
|
|
4317
4752
|
function assign (target) {
|
|
@@ -4454,70 +4889,298 @@ function getCSRFToken(apiBaseUrl) {
|
|
|
4454
4889
|
return api.get('csrftoken');
|
|
4455
4890
|
}
|
|
4456
4891
|
function currentDomainMatchesApiBaseUrl(apiBaseUrl) {
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4892
|
+
let apiBase;
|
|
4893
|
+
try {
|
|
4894
|
+
apiBase = new URL(apiBaseUrl);
|
|
4895
|
+
}
|
|
4896
|
+
catch (_a) {
|
|
4460
4897
|
return false;
|
|
4461
4898
|
}
|
|
4462
|
-
return
|
|
4899
|
+
return window.location.origin === apiBase.origin;
|
|
4463
4900
|
}
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4901
|
+
|
|
4902
|
+
class ChatSessionService {
|
|
4903
|
+
constructor(options) {
|
|
4904
|
+
var _a, _b, _c, _d;
|
|
4905
|
+
this.apiBaseUrl = options.apiBaseUrl;
|
|
4906
|
+
this.embedKey = options.embedKey;
|
|
4907
|
+
this.widgetVersion = options.widgetVersion;
|
|
4908
|
+
this.csrfTokenProvider = (_a = options.csrfTokenProvider) !== null && _a !== void 0 ? _a : getCSRFToken;
|
|
4909
|
+
this.taskPollingIntervalMs = (_b = options.taskPollingIntervalMs) !== null && _b !== void 0 ? _b : 1000;
|
|
4910
|
+
this.taskPollingMaxAttempts = (_c = options.taskPollingMaxAttempts) !== null && _c !== void 0 ? _c : 120;
|
|
4911
|
+
this.messagePollingIntervalMs = (_d = options.messagePollingIntervalMs) !== null && _d !== void 0 ? _d : 30000;
|
|
4912
|
+
}
|
|
4913
|
+
async startSession(requestBody) {
|
|
4914
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/start/`, {
|
|
4915
|
+
method: 'POST',
|
|
4916
|
+
headers: this.getJsonHeaders(),
|
|
4917
|
+
body: JSON.stringify(requestBody),
|
|
4918
|
+
});
|
|
4919
|
+
if (!response.ok) {
|
|
4920
|
+
throw new Error(`Failed to start session: ${response.statusText}`);
|
|
4921
|
+
}
|
|
4922
|
+
return response.json();
|
|
4468
4923
|
}
|
|
4469
|
-
|
|
4470
|
-
|
|
4924
|
+
async sendMessage(sessionId, payload) {
|
|
4925
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/message/`, {
|
|
4926
|
+
method: 'POST',
|
|
4927
|
+
headers: this.getJsonHeaders(),
|
|
4928
|
+
body: JSON.stringify(payload),
|
|
4929
|
+
});
|
|
4930
|
+
if (!response.ok) {
|
|
4931
|
+
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
4932
|
+
}
|
|
4933
|
+
return response.json();
|
|
4934
|
+
}
|
|
4935
|
+
async pollTaskOnce(sessionId, taskId) {
|
|
4936
|
+
const response = await fetch(`${this.apiBaseUrl}/api/chat/${sessionId}/${taskId}/poll/`);
|
|
4937
|
+
if (!response.ok) {
|
|
4938
|
+
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
4939
|
+
}
|
|
4940
|
+
return response.json();
|
|
4941
|
+
}
|
|
4942
|
+
pollTask(sessionId, taskId, callbacks) {
|
|
4943
|
+
let attempts = 0;
|
|
4944
|
+
let cancelled = false;
|
|
4945
|
+
let timeoutId;
|
|
4946
|
+
const scheduleNextPoll = () => {
|
|
4947
|
+
timeoutId = setTimeout(() => {
|
|
4948
|
+
void poll();
|
|
4949
|
+
}, this.taskPollingIntervalMs);
|
|
4950
|
+
};
|
|
4951
|
+
const poll = async () => {
|
|
4952
|
+
if (cancelled) {
|
|
4953
|
+
return;
|
|
4954
|
+
}
|
|
4955
|
+
try {
|
|
4956
|
+
const data = await this.pollTaskOnce(sessionId, taskId);
|
|
4957
|
+
if (data.error) {
|
|
4958
|
+
throw new Error(data.error);
|
|
4959
|
+
}
|
|
4960
|
+
if (data.status === 'complete' && data.message) {
|
|
4961
|
+
callbacks.onMessage(data.message);
|
|
4962
|
+
return;
|
|
4963
|
+
}
|
|
4964
|
+
attempts += 1;
|
|
4965
|
+
if (attempts >= this.taskPollingMaxAttempts) {
|
|
4966
|
+
if (callbacks.onTimeout) {
|
|
4967
|
+
callbacks.onTimeout();
|
|
4968
|
+
}
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
scheduleNextPoll();
|
|
4972
|
+
}
|
|
4973
|
+
catch (error) {
|
|
4974
|
+
if (callbacks.onError) {
|
|
4975
|
+
callbacks.onError(error instanceof Error ? error : new Error('Failed to get response'));
|
|
4976
|
+
}
|
|
4977
|
+
}
|
|
4978
|
+
};
|
|
4979
|
+
void poll();
|
|
4980
|
+
return {
|
|
4981
|
+
cancel: () => {
|
|
4982
|
+
cancelled = true;
|
|
4983
|
+
if (timeoutId) {
|
|
4984
|
+
clearTimeout(timeoutId);
|
|
4985
|
+
}
|
|
4986
|
+
},
|
|
4987
|
+
};
|
|
4988
|
+
}
|
|
4989
|
+
async fetchMessages(sessionId, since) {
|
|
4990
|
+
const url = new URL(`${this.apiBaseUrl}/api/chat/${sessionId}/poll/`);
|
|
4991
|
+
if (since) {
|
|
4992
|
+
url.searchParams.set('since', since);
|
|
4993
|
+
}
|
|
4994
|
+
const response = await fetch(url.toString());
|
|
4995
|
+
if (!response.ok) {
|
|
4996
|
+
throw new Error(`Failed to poll messages: ${response.statusText}`);
|
|
4997
|
+
}
|
|
4998
|
+
return response.json();
|
|
4999
|
+
}
|
|
5000
|
+
startMessagePolling(sessionId, callbacks) {
|
|
5001
|
+
const poll = async () => {
|
|
5002
|
+
try {
|
|
5003
|
+
const since = callbacks.getSince();
|
|
5004
|
+
const data = await this.fetchMessages(sessionId, since);
|
|
5005
|
+
if (data.messages.length > 0) {
|
|
5006
|
+
callbacks.onMessages(data.messages);
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
catch (error) {
|
|
5010
|
+
if (callbacks.onError) {
|
|
5011
|
+
callbacks.onError(error instanceof Error ? error : new Error('Failed to poll messages'));
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
};
|
|
5015
|
+
// perform an initial poll immediately
|
|
5016
|
+
void poll();
|
|
5017
|
+
this.messagePollingTimer = setInterval(() => {
|
|
5018
|
+
void poll();
|
|
5019
|
+
}, this.messagePollingIntervalMs);
|
|
5020
|
+
return {
|
|
5021
|
+
stop: () => this.stopMessagePolling(),
|
|
5022
|
+
};
|
|
5023
|
+
}
|
|
5024
|
+
stopMessagePolling() {
|
|
5025
|
+
if (this.messagePollingTimer) {
|
|
5026
|
+
clearInterval(this.messagePollingTimer);
|
|
5027
|
+
this.messagePollingTimer = undefined;
|
|
5028
|
+
}
|
|
5029
|
+
}
|
|
5030
|
+
getJsonHeaders() {
|
|
5031
|
+
const headers = {
|
|
5032
|
+
'Content-Type': 'application/json',
|
|
5033
|
+
'x-ocs-widget-version': this.widgetVersion,
|
|
5034
|
+
};
|
|
5035
|
+
const csrfToken = this.csrfTokenProvider(this.apiBaseUrl);
|
|
5036
|
+
if (csrfToken) {
|
|
5037
|
+
headers['X-CSRFToken'] = csrfToken;
|
|
5038
|
+
}
|
|
5039
|
+
if (this.embedKey) {
|
|
5040
|
+
headers['X-Embed-Key'] = this.embedKey;
|
|
5041
|
+
}
|
|
5042
|
+
return headers;
|
|
4471
5043
|
}
|
|
4472
5044
|
}
|
|
4473
5045
|
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
5046
|
+
class FileAttachmentManager {
|
|
5047
|
+
constructor(config) {
|
|
5048
|
+
this.supportedExtensions = config.supportedExtensions;
|
|
5049
|
+
this.maxFileSizeMb = config.maxFileSizeMb;
|
|
5050
|
+
this.maxTotalSizeMb = config.maxTotalSizeMb;
|
|
5051
|
+
}
|
|
5052
|
+
addFiles(existingFiles, files) {
|
|
5053
|
+
const newSelected = [];
|
|
5054
|
+
const fileArray = Array.from(files instanceof FileList ? Array.from(files) : files);
|
|
5055
|
+
let totalSize = existingFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
5056
|
+
for (const file of fileArray) {
|
|
5057
|
+
const extension = this.getFileExtension(file.name);
|
|
5058
|
+
if (!this.supportedExtensions.includes(extension)) {
|
|
5059
|
+
newSelected.push({ file, error: `File type ${extension} not supported` });
|
|
5060
|
+
continue;
|
|
5061
|
+
}
|
|
5062
|
+
const fileSizeMb = this.bytesToMb(file.size);
|
|
5063
|
+
if (fileSizeMb > this.maxFileSizeMb) {
|
|
5064
|
+
newSelected.push({ file, error: `File exceeds ${this.maxFileSizeMb}MB limit` });
|
|
5065
|
+
continue;
|
|
5066
|
+
}
|
|
5067
|
+
totalSize += file.size;
|
|
5068
|
+
const totalSizeMb = this.bytesToMb(totalSize);
|
|
5069
|
+
if (totalSizeMb > this.maxTotalSizeMb) {
|
|
5070
|
+
newSelected.push({ file, error: `Total size exceeds ${this.maxTotalSizeMb}MB limit` });
|
|
5071
|
+
continue;
|
|
5072
|
+
}
|
|
5073
|
+
newSelected.push({ file });
|
|
4486
5074
|
}
|
|
5075
|
+
return [...existingFiles, ...newSelected];
|
|
4487
5076
|
}
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
5077
|
+
removeFile(existingFiles, index) {
|
|
5078
|
+
return existingFiles.filter((_, i) => i !== index);
|
|
5079
|
+
}
|
|
5080
|
+
markPendingFilesWithError(existingFiles, errorMessage) {
|
|
5081
|
+
return existingFiles.map(file => {
|
|
5082
|
+
if (!file.error && !file.uploaded) {
|
|
5083
|
+
return Object.assign(Object.assign({}, file), { error: errorMessage });
|
|
5084
|
+
}
|
|
5085
|
+
return file;
|
|
5086
|
+
});
|
|
5087
|
+
}
|
|
5088
|
+
async uploadPendingFiles(existingFiles, context) {
|
|
5089
|
+
if (existingFiles.length === 0) {
|
|
5090
|
+
return { selectedFiles: existingFiles, uploadedIds: [] };
|
|
5091
|
+
}
|
|
5092
|
+
const uploadCandidates = existingFiles.filter(file => !file.error && !file.uploaded);
|
|
5093
|
+
const uploadedIds = existingFiles
|
|
5094
|
+
.filter(file => file.uploaded)
|
|
5095
|
+
.map(file => file.uploaded.id);
|
|
5096
|
+
if (uploadCandidates.length === 0) {
|
|
5097
|
+
return { selectedFiles: existingFiles, uploadedIds };
|
|
5098
|
+
}
|
|
5099
|
+
const formData = new FormData();
|
|
5100
|
+
for (const file of uploadCandidates) {
|
|
5101
|
+
formData.append('files', file.file);
|
|
5102
|
+
}
|
|
5103
|
+
formData.append('participant_remote_id', context.participantId);
|
|
5104
|
+
if (context.participantName) {
|
|
5105
|
+
formData.append('participant_name', context.participantName);
|
|
5106
|
+
}
|
|
5107
|
+
try {
|
|
5108
|
+
const response = await fetch(`${context.apiBaseUrl}/api/chat/${context.sessionId}/upload/`, {
|
|
5109
|
+
method: 'POST',
|
|
5110
|
+
body: formData,
|
|
5111
|
+
});
|
|
5112
|
+
if (!response.ok) {
|
|
5113
|
+
const errorData = await this.safeJson(response);
|
|
5114
|
+
const errorMessage = (errorData && typeof errorData === 'object' && 'error' in errorData && errorData.error) ||
|
|
5115
|
+
'Failed to upload files';
|
|
5116
|
+
return {
|
|
5117
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5118
|
+
uploadedIds,
|
|
5119
|
+
errorMessage,
|
|
5120
|
+
};
|
|
5121
|
+
}
|
|
5122
|
+
const data = await this.safeJson(response);
|
|
5123
|
+
if (!data || typeof data !== 'object' || !Array.isArray(data.files)) {
|
|
5124
|
+
const errorMessage = 'Unexpected upload response shape';
|
|
5125
|
+
return {
|
|
5126
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5127
|
+
uploadedIds,
|
|
5128
|
+
errorMessage,
|
|
5129
|
+
};
|
|
5130
|
+
}
|
|
5131
|
+
const uploadedFiles = data.files;
|
|
5132
|
+
let index = 0;
|
|
5133
|
+
const updatedSelected = existingFiles.map(file => {
|
|
5134
|
+
if (!file.error && !file.uploaded) {
|
|
5135
|
+
const uploaded = uploadedFiles[index];
|
|
5136
|
+
index += 1;
|
|
5137
|
+
return Object.assign(Object.assign({}, file), { uploaded });
|
|
5138
|
+
}
|
|
5139
|
+
return file;
|
|
5140
|
+
});
|
|
5141
|
+
uploadedIds.push(...uploadedFiles.map(file => file.id));
|
|
5142
|
+
return { selectedFiles: updatedSelected, uploadedIds };
|
|
5143
|
+
}
|
|
5144
|
+
catch (error) {
|
|
5145
|
+
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
5146
|
+
return {
|
|
5147
|
+
selectedFiles: this.markPendingFilesWithError(existingFiles, errorMessage),
|
|
5148
|
+
uploadedIds,
|
|
5149
|
+
errorMessage,
|
|
5150
|
+
};
|
|
4492
5151
|
}
|
|
4493
5152
|
}
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
const percentToFloat = (percentageString) => {
|
|
4497
|
-
const numericValue = parseFloat(percentageString);
|
|
4498
|
-
if (isNaN(numericValue)) {
|
|
4499
|
-
return NaN;
|
|
5153
|
+
bytesToMb(bytes) {
|
|
5154
|
+
return bytes / (1024 * 1024);
|
|
4500
5155
|
}
|
|
4501
|
-
|
|
4502
|
-
|
|
5156
|
+
getFileExtension(filename) {
|
|
5157
|
+
const parts = filename.split('.');
|
|
5158
|
+
const ext = parts.pop();
|
|
5159
|
+
return ext ? `.${ext.toLowerCase()}` : '';
|
|
5160
|
+
}
|
|
5161
|
+
async safeJson(response) {
|
|
5162
|
+
try {
|
|
5163
|
+
return await response.json();
|
|
5164
|
+
}
|
|
5165
|
+
catch (_a) {
|
|
5166
|
+
return undefined;
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
}
|
|
4503
5170
|
|
|
4504
|
-
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";
|
|
5171
|
+
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}}";
|
|
4505
5172
|
|
|
4506
5173
|
const OcsChat = class {
|
|
4507
5174
|
constructor(hostRef) {
|
|
4508
5175
|
registerInstance(this, hostRef);
|
|
4509
5176
|
/**
|
|
4510
|
-
* The base URL for the API
|
|
5177
|
+
* The base URL for the API.
|
|
4511
5178
|
*/
|
|
4512
|
-
this.apiBaseUrl = "https://
|
|
5179
|
+
this.apiBaseUrl = "https://www.openchatstudio.com";
|
|
4513
5180
|
/**
|
|
4514
5181
|
* The shape of the chat button. 'round' makes it circular, 'square' keeps it rectangular.
|
|
4515
5182
|
*/
|
|
4516
5183
|
this.buttonShape = 'square';
|
|
4517
|
-
/**
|
|
4518
|
-
* The message to display in the new chat confirmation dialog.
|
|
4519
|
-
*/
|
|
4520
|
-
this.newChatConfirmationMessage = "Starting a new chat will clear your current conversation. Continue?";
|
|
4521
5184
|
/**
|
|
4522
5185
|
* Whether the chat widget is visible on load.
|
|
4523
5186
|
*/
|
|
@@ -4543,10 +5206,6 @@ const OcsChat = class {
|
|
|
4543
5206
|
* Allow the user to attach files to their messages.
|
|
4544
5207
|
*/
|
|
4545
5208
|
this.allowAttachments = false;
|
|
4546
|
-
/**
|
|
4547
|
-
* The text to display while the assistant is typing/preparing a response.
|
|
4548
|
-
*/
|
|
4549
|
-
this.typingIndicatorText = "Preparing response";
|
|
4550
5209
|
this.error = "";
|
|
4551
5210
|
this.messages = [];
|
|
4552
5211
|
this.isLoading = false;
|
|
@@ -4563,6 +5222,20 @@ const OcsChat = class {
|
|
|
4563
5222
|
this.showNewChatConfirmation = false;
|
|
4564
5223
|
this.selectedFiles = [];
|
|
4565
5224
|
this.isUploadingFiles = false;
|
|
5225
|
+
this.buttonPosition = { x: 30, y: 30 };
|
|
5226
|
+
this.buttonHorizontalSide = 'right';
|
|
5227
|
+
this.buttonVerticalSide = 'bottom';
|
|
5228
|
+
this.isButtonDragging = false;
|
|
5229
|
+
this.buttonWasDragged = false;
|
|
5230
|
+
this.translationManager = new TranslationManager();
|
|
5231
|
+
this.attachmentManager = new FileAttachmentManager({
|
|
5232
|
+
supportedExtensions: OcsChat.SUPPORTED_FILE_EXTENSIONS,
|
|
5233
|
+
maxFileSizeMb: OcsChat.MAX_FILE_SIZE_MB,
|
|
5234
|
+
maxTotalSizeMb: OcsChat.MAX_TOTAL_SIZE_MB,
|
|
5235
|
+
});
|
|
5236
|
+
this.buttonDragOffset = { x: 0, y: 0 };
|
|
5237
|
+
this.rafId = null;
|
|
5238
|
+
this.buttonListenersAttached = false;
|
|
4566
5239
|
this.chatWindowHeight = 600;
|
|
4567
5240
|
this.chatWindowWidth = 450;
|
|
4568
5241
|
this.chatWindowFullscreenWidth = 1024;
|
|
@@ -4611,15 +5284,101 @@ const OcsChat = class {
|
|
|
4611
5284
|
this.endDrag();
|
|
4612
5285
|
};
|
|
4613
5286
|
this.handleWindowResize = () => {
|
|
5287
|
+
var _a, _b;
|
|
4614
5288
|
this.positionInitialized = false;
|
|
4615
5289
|
this.initializePosition();
|
|
5290
|
+
// Revalidate button position after resize to keep it within viewport bounds
|
|
5291
|
+
if (this.isButtonDraggable()) {
|
|
5292
|
+
const windowWidth = window.innerWidth;
|
|
5293
|
+
const windowHeight = window.innerHeight;
|
|
5294
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
5295
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
5296
|
+
const minPadding = 10;
|
|
5297
|
+
this.buttonPosition = {
|
|
5298
|
+
x: Math.max(minPadding, Math.min(this.buttonPosition.x, windowWidth - buttonWidth - minPadding)),
|
|
5299
|
+
y: Math.max(minPadding, Math.min(this.buttonPosition.y, windowHeight - buttonHeight - minPadding))
|
|
5300
|
+
};
|
|
5301
|
+
this.updateHostPosition();
|
|
5302
|
+
}
|
|
5303
|
+
};
|
|
5304
|
+
this.handleButtonMouseDown = (event) => {
|
|
5305
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
5306
|
+
return;
|
|
5307
|
+
event.preventDefault();
|
|
5308
|
+
event.stopPropagation();
|
|
5309
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5310
|
+
if (!pointer)
|
|
5311
|
+
return;
|
|
5312
|
+
this.isButtonDragging = true;
|
|
5313
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
5314
|
+
const rect = this.host.getBoundingClientRect();
|
|
5315
|
+
this.buttonDragOffset = {
|
|
5316
|
+
x: pointer.clientX - rect.left,
|
|
5317
|
+
y: pointer.clientY - rect.top
|
|
5318
|
+
};
|
|
5319
|
+
this.addButtonEventListeners();
|
|
5320
|
+
};
|
|
5321
|
+
this.handleButtonTouchStart = (event) => {
|
|
5322
|
+
if (!this.buttonRef || !this.isButtonDraggable())
|
|
5323
|
+
return;
|
|
5324
|
+
event.preventDefault();
|
|
5325
|
+
event.stopPropagation();
|
|
5326
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5327
|
+
if (!pointer)
|
|
5328
|
+
return;
|
|
5329
|
+
this.isButtonDragging = true;
|
|
5330
|
+
this.buttonWasDragged = false; // Reset the drag flag
|
|
5331
|
+
const rect = this.host.getBoundingClientRect();
|
|
5332
|
+
this.buttonDragOffset = {
|
|
5333
|
+
x: pointer.clientX - rect.left,
|
|
5334
|
+
y: pointer.clientY - rect.top
|
|
5335
|
+
};
|
|
5336
|
+
this.addButtonEventListeners();
|
|
5337
|
+
};
|
|
5338
|
+
this.handleButtonMouseMove = (event) => {
|
|
5339
|
+
if (!this.isButtonDragging)
|
|
5340
|
+
return;
|
|
5341
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5342
|
+
if (!pointer)
|
|
5343
|
+
return;
|
|
5344
|
+
this.updateButtonPosition(pointer);
|
|
5345
|
+
};
|
|
5346
|
+
this.handleButtonTouchMove = (event) => {
|
|
5347
|
+
if (!this.isButtonDragging)
|
|
5348
|
+
return;
|
|
5349
|
+
event.preventDefault();
|
|
5350
|
+
const pointer = this.getPointerCoordinates(event);
|
|
5351
|
+
if (!pointer)
|
|
5352
|
+
return;
|
|
5353
|
+
this.updateButtonPosition(pointer);
|
|
5354
|
+
};
|
|
5355
|
+
this.handleButtonMouseUp = () => {
|
|
5356
|
+
if (this.isButtonDragging) {
|
|
5357
|
+
this.isButtonDragging = false;
|
|
5358
|
+
this.removeButtonEventListeners();
|
|
5359
|
+
}
|
|
5360
|
+
};
|
|
5361
|
+
this.handleButtonTouchEnd = () => {
|
|
5362
|
+
if (this.isButtonDragging) {
|
|
5363
|
+
this.isButtonDragging = false;
|
|
5364
|
+
this.removeButtonEventListeners();
|
|
5365
|
+
}
|
|
5366
|
+
};
|
|
5367
|
+
this.handleButtonClick = () => {
|
|
5368
|
+
// Only toggle visibility if the button wasn't dragged
|
|
5369
|
+
if (!this.buttonWasDragged) {
|
|
5370
|
+
this.toggleWindowVisibility();
|
|
5371
|
+
}
|
|
5372
|
+
// Reset the flag after handling the click
|
|
5373
|
+
this.buttonWasDragged = false;
|
|
4616
5374
|
};
|
|
4617
5375
|
}
|
|
4618
|
-
componentWillLoad() {
|
|
5376
|
+
async componentWillLoad() {
|
|
4619
5377
|
if (!this.chatbotId) {
|
|
4620
5378
|
this.error = 'Chatbot ID is required';
|
|
4621
5379
|
return;
|
|
4622
5380
|
}
|
|
5381
|
+
await this.initializeTranslations();
|
|
4623
5382
|
// Always try to load existing session if localStorage is available
|
|
4624
5383
|
if (this.persistentSession && this.isLocalStorageAvailable()) {
|
|
4625
5384
|
const { sessionId, messages } = this.loadSessionFromStorage();
|
|
@@ -4639,6 +5398,8 @@ const OcsChat = class {
|
|
|
4639
5398
|
this.chatWindowHeight = varToPixels(windowHeightVar, window.innerHeight, this.chatWindowHeight);
|
|
4640
5399
|
this.chatWindowWidth = varToPixels(windowWidthVar, window.innerWidth, this.chatWindowWidth);
|
|
4641
5400
|
this.chatWindowFullscreenWidth = varToPixels(fullscreenWidthVar, window.innerWidth, this.chatWindowFullscreenWidth);
|
|
5401
|
+
// Initialize button position from computed styles
|
|
5402
|
+
this.initializeButtonPosition();
|
|
4642
5403
|
if (this.visible) {
|
|
4643
5404
|
this.initializePosition();
|
|
4644
5405
|
}
|
|
@@ -4648,15 +5409,29 @@ const OcsChat = class {
|
|
|
4648
5409
|
}
|
|
4649
5410
|
else if (this.visible && this.sessionId) {
|
|
4650
5411
|
// Resume polling for existing session
|
|
4651
|
-
this.
|
|
5412
|
+
this.startMessagePolling();
|
|
4652
5413
|
}
|
|
4653
5414
|
window.addEventListener('resize', this.handleWindowResize);
|
|
4654
5415
|
}
|
|
4655
5416
|
disconnectedCallback() {
|
|
4656
5417
|
this.cleanup();
|
|
4657
5418
|
this.removeEventListeners();
|
|
5419
|
+
this.removeButtonEventListeners();
|
|
4658
5420
|
window.removeEventListener('resize', this.handleWindowResize);
|
|
4659
5421
|
}
|
|
5422
|
+
getChatService() {
|
|
5423
|
+
if (!this.chatService) {
|
|
5424
|
+
this.chatService = new ChatSessionService({
|
|
5425
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
5426
|
+
embedKey: this.embedKey,
|
|
5427
|
+
widgetVersion: Env.version,
|
|
5428
|
+
taskPollingIntervalMs: OcsChat.TASK_POLLING_INTERVAL_MS,
|
|
5429
|
+
taskPollingMaxAttempts: OcsChat.TASK_POLLING_MAX_ATTEMPTS,
|
|
5430
|
+
messagePollingIntervalMs: OcsChat.MESSAGE_POLLING_INTERVAL_MS,
|
|
5431
|
+
});
|
|
5432
|
+
}
|
|
5433
|
+
return this.chatService;
|
|
5434
|
+
}
|
|
4660
5435
|
addErrorMessage(errorText) {
|
|
4661
5436
|
const errorMessage = {
|
|
4662
5437
|
created_at: new Date().toISOString(),
|
|
@@ -4700,25 +5475,34 @@ const OcsChat = class {
|
|
|
4700
5475
|
parseStarterQuestions() {
|
|
4701
5476
|
this.parsedStarterQuestions = this.parseJSONProp(this.starterQuestions, 'starter questions');
|
|
4702
5477
|
}
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
4706
|
-
|
|
5478
|
+
async initializeTranslations() {
|
|
5479
|
+
let customTranslationsObj;
|
|
5480
|
+
if (this.translationsUrl) {
|
|
5481
|
+
customTranslationsObj = await this.loadTranslationsFromUrl(this.translationsUrl);
|
|
4707
5482
|
}
|
|
4708
|
-
this.
|
|
5483
|
+
this.translationManager = new TranslationManager(this.language, customTranslationsObj);
|
|
4709
5484
|
}
|
|
4710
|
-
|
|
4711
|
-
|
|
5485
|
+
async loadTranslationsFromUrl(url) {
|
|
5486
|
+
try {
|
|
5487
|
+
const response = await fetch(url);
|
|
5488
|
+
if (!response.ok) {
|
|
5489
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
5490
|
+
}
|
|
5491
|
+
const translations = await response.json();
|
|
5492
|
+
return translations;
|
|
5493
|
+
}
|
|
5494
|
+
catch (error) {
|
|
5495
|
+
console.error('Error loading translations from URL:', error);
|
|
5496
|
+
return defaultTranslations;
|
|
5497
|
+
}
|
|
4712
5498
|
}
|
|
4713
|
-
|
|
4714
|
-
|
|
4715
|
-
|
|
4716
|
-
|
|
4717
|
-
|
|
4718
|
-
if (csrfToken) {
|
|
4719
|
-
headers['X-CSRFToken'] = csrfToken;
|
|
5499
|
+
cleanup() {
|
|
5500
|
+
this.stopMessagePolling();
|
|
5501
|
+
if (this.taskPollingHandle) {
|
|
5502
|
+
this.taskPollingHandle.cancel();
|
|
5503
|
+
this.taskPollingHandle = undefined;
|
|
4720
5504
|
}
|
|
4721
|
-
|
|
5505
|
+
this.currentPollTaskId = '';
|
|
4722
5506
|
}
|
|
4723
5507
|
async startSession() {
|
|
4724
5508
|
try {
|
|
@@ -4735,94 +5519,38 @@ const OcsChat = class {
|
|
|
4735
5519
|
if (this.userName) {
|
|
4736
5520
|
requestBody.participant_name = this.userName;
|
|
4737
5521
|
}
|
|
4738
|
-
const
|
|
4739
|
-
method: 'POST',
|
|
4740
|
-
headers: this.getApiHeaders(),
|
|
4741
|
-
body: JSON.stringify(requestBody)
|
|
4742
|
-
});
|
|
4743
|
-
if (!response.ok) {
|
|
4744
|
-
this.handleError(`Failed to start session: ${response.statusText}`);
|
|
4745
|
-
return;
|
|
4746
|
-
}
|
|
4747
|
-
const data = await response.json();
|
|
5522
|
+
const data = await this.getChatService().startSession(requestBody);
|
|
4748
5523
|
this.sessionId = data.session_id;
|
|
4749
5524
|
this.saveSessionToStorage();
|
|
4750
5525
|
// Handle seed message if present
|
|
4751
5526
|
if (data.seed_message_task_id) {
|
|
4752
|
-
this.
|
|
4753
|
-
|
|
4754
|
-
|
|
5527
|
+
this.startTaskPolling(data.seed_message_task_id);
|
|
5528
|
+
}
|
|
5529
|
+
else {
|
|
5530
|
+
this.startMessagePolling();
|
|
4755
5531
|
}
|
|
4756
|
-
// Start polling for messages
|
|
4757
|
-
this.startPolling();
|
|
4758
5532
|
}
|
|
4759
|
-
catch (
|
|
5533
|
+
catch (_error) {
|
|
4760
5534
|
this.handleError('Failed to start chat session');
|
|
4761
5535
|
}
|
|
4762
5536
|
finally {
|
|
4763
5537
|
this.isLoading = false;
|
|
4764
5538
|
}
|
|
4765
5539
|
}
|
|
4766
|
-
markPendingFilesWithError(errorMessage) {
|
|
4767
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
4768
|
-
if (!sf.error && !sf.uploaded) {
|
|
4769
|
-
return Object.assign(Object.assign({}, sf), { error: errorMessage });
|
|
4770
|
-
}
|
|
4771
|
-
return sf;
|
|
4772
|
-
});
|
|
4773
|
-
}
|
|
4774
5540
|
async uploadFiles() {
|
|
4775
5541
|
if (this.selectedFiles.length === 0 || !this.sessionId || !this.allowAttachments) {
|
|
4776
5542
|
return [];
|
|
4777
5543
|
}
|
|
4778
5544
|
this.isUploadingFiles = true;
|
|
4779
|
-
const uploadedIds = [];
|
|
4780
5545
|
try {
|
|
4781
|
-
const
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
}
|
|
4790
|
-
}
|
|
4791
|
-
// Add user ID and name to the form data
|
|
4792
|
-
const userId = this.getOrGenerateUserId();
|
|
4793
|
-
formData.append('participant_remote_id', userId);
|
|
4794
|
-
if (this.userName) {
|
|
4795
|
-
formData.append('participant_name', this.userName);
|
|
4796
|
-
}
|
|
4797
|
-
// Only upload if there are new files
|
|
4798
|
-
if (formData.has('files')) {
|
|
4799
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/upload/`, {
|
|
4800
|
-
method: 'POST',
|
|
4801
|
-
body: formData,
|
|
4802
|
-
});
|
|
4803
|
-
if (!response.ok) {
|
|
4804
|
-
const errorData = await response.json();
|
|
4805
|
-
const errorMessage = errorData.error || 'Failed to upload files';
|
|
4806
|
-
this.markPendingFilesWithError(errorMessage);
|
|
4807
|
-
return uploadedIds;
|
|
4808
|
-
}
|
|
4809
|
-
const data = await response.json();
|
|
4810
|
-
// Update selected files with upload results
|
|
4811
|
-
let fileIndex = 0;
|
|
4812
|
-
this.selectedFiles = this.selectedFiles.map(sf => {
|
|
4813
|
-
if (!sf.error && !sf.uploaded) {
|
|
4814
|
-
return Object.assign(Object.assign({}, sf), { uploaded: data.files[fileIndex++] });
|
|
4815
|
-
}
|
|
4816
|
-
return sf;
|
|
4817
|
-
});
|
|
4818
|
-
uploadedIds.push(...data.files.map((f) => f.id));
|
|
4819
|
-
}
|
|
4820
|
-
return uploadedIds;
|
|
4821
|
-
}
|
|
4822
|
-
catch (error) {
|
|
4823
|
-
const errorMessage = error instanceof Error ? error.message : 'Failed to upload files';
|
|
4824
|
-
this.markPendingFilesWithError(errorMessage);
|
|
4825
|
-
return uploadedIds;
|
|
5546
|
+
const uploadResult = await this.attachmentManager.uploadPendingFiles(this.selectedFiles, {
|
|
5547
|
+
apiBaseUrl: this.apiBaseUrl || 'https://www.openchatstudio.com',
|
|
5548
|
+
sessionId: this.sessionId,
|
|
5549
|
+
participantId: this.getOrGenerateUserId(),
|
|
5550
|
+
participantName: this.userName,
|
|
5551
|
+
});
|
|
5552
|
+
this.selectedFiles = uploadResult.selectedFiles;
|
|
5553
|
+
return uploadResult.uploadedIds;
|
|
4826
5554
|
}
|
|
4827
5555
|
finally {
|
|
4828
5556
|
this.isUploadingFiles = false;
|
|
@@ -4875,27 +5603,15 @@ const OcsChat = class {
|
|
|
4875
5603
|
this.selectedFiles = []; // Clear selected files after sending
|
|
4876
5604
|
}
|
|
4877
5605
|
this.scrollToBottom();
|
|
4878
|
-
// Start typing indicator - it will stay on during task polling
|
|
4879
|
-
this.isTyping = true;
|
|
4880
5606
|
const requestBody = { message: message.trim() };
|
|
4881
5607
|
if (this.allowAttachments && attachmentIds.length > 0) {
|
|
4882
5608
|
requestBody.attachment_ids = attachmentIds;
|
|
4883
5609
|
}
|
|
4884
|
-
const
|
|
4885
|
-
method: 'POST',
|
|
4886
|
-
headers: this.getApiHeaders(),
|
|
4887
|
-
body: JSON.stringify(requestBody)
|
|
4888
|
-
});
|
|
4889
|
-
if (!response.ok) {
|
|
4890
|
-
throw new Error(`Failed to send message: ${response.statusText}`);
|
|
4891
|
-
}
|
|
4892
|
-
const data = await response.json();
|
|
5610
|
+
const data = await this.getChatService().sendMessage(this.sessionId, requestBody);
|
|
4893
5611
|
if (data.status === 'error') {
|
|
4894
5612
|
throw new Error(data.error || 'Failed to send message');
|
|
4895
5613
|
}
|
|
4896
|
-
|
|
4897
|
-
this.currentPollTaskId = data.task_id;
|
|
4898
|
-
await this.pollTaskResponse();
|
|
5614
|
+
this.startTaskPolling(data.task_id);
|
|
4899
5615
|
}
|
|
4900
5616
|
catch (error) {
|
|
4901
5617
|
const errorText = error instanceof Error ? error.message : 'Failed to send message';
|
|
@@ -4905,110 +5621,6 @@ const OcsChat = class {
|
|
|
4905
5621
|
handleStarterQuestionClick(question) {
|
|
4906
5622
|
this.sendMessage(question);
|
|
4907
5623
|
}
|
|
4908
|
-
async pollTaskResponse() {
|
|
4909
|
-
if (!this.sessionId || !this.currentPollTaskId)
|
|
4910
|
-
return;
|
|
4911
|
-
// Stop message polling while task polling is active
|
|
4912
|
-
this.pauseMessagePolling();
|
|
4913
|
-
let attempts = 0;
|
|
4914
|
-
const poll = async () => {
|
|
4915
|
-
if (!this.sessionId || !this.currentPollTaskId)
|
|
4916
|
-
return;
|
|
4917
|
-
try {
|
|
4918
|
-
const response = await fetch(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/${this.currentPollTaskId}/poll/`);
|
|
4919
|
-
if (!response.ok) {
|
|
4920
|
-
throw new Error(`Failed to poll task: ${response.statusText}`);
|
|
4921
|
-
}
|
|
4922
|
-
const data = await response.json();
|
|
4923
|
-
if (data.error) {
|
|
4924
|
-
throw new Error(data.error);
|
|
4925
|
-
}
|
|
4926
|
-
if (data.status === 'complete' && data.message) {
|
|
4927
|
-
this.messages = [...this.messages, data.message];
|
|
4928
|
-
this.saveSessionToStorage();
|
|
4929
|
-
this.scrollToBottom();
|
|
4930
|
-
// Task polling complete, clear typing indicator and resume message polling
|
|
4931
|
-
this.isTyping = false;
|
|
4932
|
-
this.currentPollTaskId = '';
|
|
4933
|
-
this.resumeMessagePolling();
|
|
4934
|
-
this.focusInput();
|
|
4935
|
-
return;
|
|
4936
|
-
}
|
|
4937
|
-
if (data.status === 'processing' && attempts < OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
4938
|
-
attempts++;
|
|
4939
|
-
setTimeout(poll, OcsChat.TASK_POLLING_INTERVAL_MS);
|
|
4940
|
-
}
|
|
4941
|
-
else if (attempts >= OcsChat.TASK_POLLING_MAX_ATTEMPTS) {
|
|
4942
|
-
// Task polling timed out - add timeout message and resume polling
|
|
4943
|
-
const timeoutMessage = {
|
|
4944
|
-
created_at: new Date().toISOString(),
|
|
4945
|
-
role: 'system',
|
|
4946
|
-
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
4947
|
-
attachments: []
|
|
4948
|
-
};
|
|
4949
|
-
this.messages = [...this.messages, timeoutMessage];
|
|
4950
|
-
this.saveSessionToStorage();
|
|
4951
|
-
this.scrollToBottom();
|
|
4952
|
-
// Clear typing indicator and resume message polling
|
|
4953
|
-
this.isTyping = false;
|
|
4954
|
-
this.currentPollTaskId = '';
|
|
4955
|
-
this.resumeMessagePolling();
|
|
4956
|
-
this.focusInput();
|
|
4957
|
-
}
|
|
4958
|
-
}
|
|
4959
|
-
catch (error) {
|
|
4960
|
-
const errorText = error instanceof Error ? error.message : 'Failed to get response';
|
|
4961
|
-
this.handleError(errorText);
|
|
4962
|
-
// Clear states and resume polling
|
|
4963
|
-
this.currentPollTaskId = '';
|
|
4964
|
-
this.resumeMessagePolling();
|
|
4965
|
-
}
|
|
4966
|
-
};
|
|
4967
|
-
await poll();
|
|
4968
|
-
}
|
|
4969
|
-
startPolling() {
|
|
4970
|
-
if (this.pollingIntervalRef)
|
|
4971
|
-
return;
|
|
4972
|
-
this.pollingIntervalRef = setInterval(async () => {
|
|
4973
|
-
// Only poll for messages if not currently polling for a task
|
|
4974
|
-
if (!this.currentPollTaskId) {
|
|
4975
|
-
await this.pollForMessages();
|
|
4976
|
-
}
|
|
4977
|
-
}, OcsChat.MESSAGE_POLLING_INTERVAL_MS);
|
|
4978
|
-
}
|
|
4979
|
-
pauseMessagePolling() {
|
|
4980
|
-
if (this.pollingIntervalRef) {
|
|
4981
|
-
clearInterval(this.pollingIntervalRef);
|
|
4982
|
-
this.pollingIntervalRef = undefined;
|
|
4983
|
-
}
|
|
4984
|
-
}
|
|
4985
|
-
resumeMessagePolling() {
|
|
4986
|
-
// Resume message polling after task polling is complete
|
|
4987
|
-
this.startPolling();
|
|
4988
|
-
}
|
|
4989
|
-
async pollForMessages() {
|
|
4990
|
-
if (!this.sessionId)
|
|
4991
|
-
return;
|
|
4992
|
-
try {
|
|
4993
|
-
const url = new URL(`${this.getApiBaseUrl()}/api/chat/${this.sessionId}/poll/`);
|
|
4994
|
-
if (this.messages && this.messages.length > 0) {
|
|
4995
|
-
url.searchParams.set('since', this.messages.at(-1).created_at);
|
|
4996
|
-
}
|
|
4997
|
-
const response = await fetch(url.toString());
|
|
4998
|
-
if (!response.ok)
|
|
4999
|
-
return; // Silently fail for polling
|
|
5000
|
-
const data = await response.json();
|
|
5001
|
-
if (data.messages.length > 0) {
|
|
5002
|
-
this.messages = [...this.messages, ...data.messages];
|
|
5003
|
-
this.saveSessionToStorage();
|
|
5004
|
-
this.scrollToBottom();
|
|
5005
|
-
this.focusInput();
|
|
5006
|
-
}
|
|
5007
|
-
}
|
|
5008
|
-
catch (_a) {
|
|
5009
|
-
// Silently fail for polling
|
|
5010
|
-
}
|
|
5011
|
-
}
|
|
5012
5624
|
/**
|
|
5013
5625
|
* Scroll the message container to the bottom.
|
|
5014
5626
|
* @param forceEnd When `false`, scroll the top of the last message into view.
|
|
@@ -5053,50 +5665,18 @@ const OcsChat = class {
|
|
|
5053
5665
|
this.messageInput = event.target.value;
|
|
5054
5666
|
}
|
|
5055
5667
|
handleFileSelect(event) {
|
|
5056
|
-
var _a;
|
|
5057
5668
|
if (!this.allowAttachments)
|
|
5058
5669
|
return;
|
|
5059
5670
|
const input = event.target;
|
|
5060
5671
|
if (!input.files || input.files.length === 0)
|
|
5061
5672
|
return;
|
|
5062
|
-
|
|
5063
|
-
let totalSize = this.selectedFiles.reduce((sum, f) => sum + f.file.size, 0);
|
|
5064
|
-
for (let i = 0; i < input.files.length; i++) {
|
|
5065
|
-
const file = input.files[i];
|
|
5066
|
-
const ext = '.' + ((_a = file.name.split('.').pop()) === null || _a === void 0 ? void 0 : _a.toLowerCase());
|
|
5067
|
-
if (!OcsChat.SUPPORTED_FILE_EXTENSIONS.includes(ext)) {
|
|
5068
|
-
newFiles.push({
|
|
5069
|
-
file,
|
|
5070
|
-
error: `File type ${ext} not supported`
|
|
5071
|
-
});
|
|
5072
|
-
continue;
|
|
5073
|
-
}
|
|
5074
|
-
const fileSizeMB = file.size / (1024 * 1024);
|
|
5075
|
-
if (fileSizeMB > OcsChat.MAX_FILE_SIZE_MB) {
|
|
5076
|
-
newFiles.push({
|
|
5077
|
-
file,
|
|
5078
|
-
error: `File exceeds ${OcsChat.MAX_FILE_SIZE_MB}MB limit`
|
|
5079
|
-
});
|
|
5080
|
-
continue;
|
|
5081
|
-
}
|
|
5082
|
-
totalSize += file.size;
|
|
5083
|
-
const totalSizeMB = totalSize / (1024 * 1024);
|
|
5084
|
-
if (totalSizeMB > OcsChat.MAX_TOTAL_SIZE_MB) {
|
|
5085
|
-
newFiles.push({
|
|
5086
|
-
file,
|
|
5087
|
-
error: `Total size exceeds ${OcsChat.MAX_TOTAL_SIZE_MB}MB limit`
|
|
5088
|
-
});
|
|
5089
|
-
continue;
|
|
5090
|
-
}
|
|
5091
|
-
newFiles.push({ file });
|
|
5092
|
-
}
|
|
5093
|
-
this.selectedFiles = [...this.selectedFiles, ...newFiles];
|
|
5673
|
+
this.selectedFiles = this.attachmentManager.addFiles(this.selectedFiles, input.files);
|
|
5094
5674
|
input.value = '';
|
|
5095
5675
|
}
|
|
5096
5676
|
removeSelectedFile(index) {
|
|
5097
5677
|
if (!this.allowAttachments)
|
|
5098
5678
|
return;
|
|
5099
|
-
this.selectedFiles = this.
|
|
5679
|
+
this.selectedFiles = this.attachmentManager.removeFile(this.selectedFiles, index);
|
|
5100
5680
|
}
|
|
5101
5681
|
formatFileSize(bytes) {
|
|
5102
5682
|
if (bytes === 0)
|
|
@@ -5123,6 +5703,11 @@ const OcsChat = class {
|
|
|
5123
5703
|
* @param visible - The new value for the field.
|
|
5124
5704
|
*/
|
|
5125
5705
|
async visibilityHandler(visible) {
|
|
5706
|
+
if (this.isButtonDragging) {
|
|
5707
|
+
this.isButtonDragging = false;
|
|
5708
|
+
this.buttonWasDragged = false;
|
|
5709
|
+
this.removeButtonEventListeners();
|
|
5710
|
+
}
|
|
5126
5711
|
if (visible) {
|
|
5127
5712
|
this.initializePosition();
|
|
5128
5713
|
}
|
|
@@ -5130,11 +5715,86 @@ const OcsChat = class {
|
|
|
5130
5715
|
await this.startSession();
|
|
5131
5716
|
}
|
|
5132
5717
|
else if (!visible) {
|
|
5133
|
-
this.
|
|
5718
|
+
this.stopMessagePolling();
|
|
5134
5719
|
}
|
|
5135
5720
|
else {
|
|
5136
5721
|
this.scrollToBottom(true);
|
|
5137
|
-
this.
|
|
5722
|
+
this.startMessagePolling();
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
startTaskPolling(taskId) {
|
|
5726
|
+
if (!this.sessionId)
|
|
5727
|
+
return;
|
|
5728
|
+
this.currentPollTaskId = taskId;
|
|
5729
|
+
this.isTyping = true;
|
|
5730
|
+
this.stopMessagePolling();
|
|
5731
|
+
if (this.taskPollingHandle) {
|
|
5732
|
+
this.taskPollingHandle.cancel();
|
|
5733
|
+
}
|
|
5734
|
+
this.taskPollingHandle = this.getChatService().pollTask(this.sessionId, taskId, {
|
|
5735
|
+
onMessage: (message) => {
|
|
5736
|
+
this.messages = [...this.messages, message];
|
|
5737
|
+
this.saveSessionToStorage();
|
|
5738
|
+
this.scrollToBottom();
|
|
5739
|
+
this.isTyping = false;
|
|
5740
|
+
this.currentPollTaskId = '';
|
|
5741
|
+
this.taskPollingHandle = undefined;
|
|
5742
|
+
this.startMessagePolling();
|
|
5743
|
+
this.focusInput();
|
|
5744
|
+
},
|
|
5745
|
+
onTimeout: () => {
|
|
5746
|
+
const timeoutMessage = {
|
|
5747
|
+
created_at: new Date().toISOString(),
|
|
5748
|
+
role: 'system',
|
|
5749
|
+
content: 'The response is taking longer than expected. The system may be experiencing delays. Please try sending your message again.',
|
|
5750
|
+
attachments: []
|
|
5751
|
+
};
|
|
5752
|
+
this.messages = [...this.messages, timeoutMessage];
|
|
5753
|
+
this.saveSessionToStorage();
|
|
5754
|
+
this.scrollToBottom();
|
|
5755
|
+
this.isTyping = false;
|
|
5756
|
+
this.currentPollTaskId = '';
|
|
5757
|
+
this.taskPollingHandle = undefined;
|
|
5758
|
+
this.startMessagePolling();
|
|
5759
|
+
this.focusInput();
|
|
5760
|
+
},
|
|
5761
|
+
onError: (error) => {
|
|
5762
|
+
this.handleError(error.message);
|
|
5763
|
+
this.taskPollingHandle = undefined;
|
|
5764
|
+
this.startMessagePolling();
|
|
5765
|
+
}
|
|
5766
|
+
});
|
|
5767
|
+
}
|
|
5768
|
+
startMessagePolling() {
|
|
5769
|
+
if (!this.sessionId || this.currentPollTaskId || !this.visible) {
|
|
5770
|
+
return;
|
|
5771
|
+
}
|
|
5772
|
+
if (this.messagePollingHandle) {
|
|
5773
|
+
return;
|
|
5774
|
+
}
|
|
5775
|
+
this.messagePollingHandle = this.getChatService().startMessagePolling(this.sessionId, {
|
|
5776
|
+
getSince: () => { var _a; return this.messages.length > 0 ? (_a = this.messages.at(-1)) === null || _a === void 0 ? void 0 : _a.created_at : undefined; },
|
|
5777
|
+
onMessages: (messages) => {
|
|
5778
|
+
if (messages.length === 0)
|
|
5779
|
+
return;
|
|
5780
|
+
this.messages = [...this.messages, ...messages];
|
|
5781
|
+
this.saveSessionToStorage();
|
|
5782
|
+
this.scrollToBottom();
|
|
5783
|
+
this.focusInput();
|
|
5784
|
+
},
|
|
5785
|
+
onError: () => {
|
|
5786
|
+
// Silently ignore polling errors to match previous behaviour
|
|
5787
|
+
}
|
|
5788
|
+
});
|
|
5789
|
+
}
|
|
5790
|
+
stopMessagePolling() {
|
|
5791
|
+
var _a;
|
|
5792
|
+
if (this.messagePollingHandle) {
|
|
5793
|
+
this.messagePollingHandle.stop();
|
|
5794
|
+
this.messagePollingHandle = undefined;
|
|
5795
|
+
}
|
|
5796
|
+
else {
|
|
5797
|
+
(_a = this.chatService) === null || _a === void 0 ? void 0 : _a.stopMessagePolling();
|
|
5138
5798
|
}
|
|
5139
5799
|
}
|
|
5140
5800
|
setPosition(position) {
|
|
@@ -5155,7 +5815,6 @@ const OcsChat = class {
|
|
|
5155
5815
|
const actualChatWidth = Math.min(windowWidth, this.chatWindowFullscreenWidth);
|
|
5156
5816
|
const centeredX = (windowWidth - actualChatWidth) / 2;
|
|
5157
5817
|
const maxOffset = (windowWidth - actualChatWidth) / 2;
|
|
5158
|
-
console.log(windowWidth, actualChatWidth, centeredX, maxOffset);
|
|
5159
5818
|
return { windowWidth, actualChatWidth, centeredX, maxOffset };
|
|
5160
5819
|
}
|
|
5161
5820
|
getPositionStyles() {
|
|
@@ -5277,25 +5936,181 @@ const OcsChat = class {
|
|
|
5277
5936
|
document.removeEventListener('touchmove', this.handleTouchMove);
|
|
5278
5937
|
document.removeEventListener('touchend', this.handleTouchEnd);
|
|
5279
5938
|
}
|
|
5280
|
-
|
|
5281
|
-
|
|
5939
|
+
// Button positioning and drag handlers
|
|
5940
|
+
initializeButtonPosition() {
|
|
5941
|
+
const computedStyle = getComputedStyle(this.host);
|
|
5942
|
+
const position = computedStyle.getPropertyValue('position');
|
|
5943
|
+
// Only enable dragging if the host element is positioned fixed
|
|
5944
|
+
if (position !== 'fixed') {
|
|
5945
|
+
return;
|
|
5946
|
+
}
|
|
5947
|
+
const rect = this.host.getBoundingClientRect();
|
|
5948
|
+
const windowWidth = window.innerWidth;
|
|
5949
|
+
const windowHeight = window.innerHeight;
|
|
5950
|
+
const left = computedStyle.getPropertyValue('left');
|
|
5951
|
+
const right = computedStyle.getPropertyValue('right');
|
|
5952
|
+
const top = computedStyle.getPropertyValue('top');
|
|
5953
|
+
const bottom = computedStyle.getPropertyValue('bottom');
|
|
5954
|
+
const hasLeft = !this.isAutoPosition(left);
|
|
5955
|
+
const hasTop = !this.isAutoPosition(top);
|
|
5956
|
+
this.buttonHorizontalSide = hasLeft ? 'left' : 'right';
|
|
5957
|
+
this.buttonVerticalSide = hasTop ? 'top' : 'bottom';
|
|
5958
|
+
const resolvedRight = this.getNumericPositionValue(right, Math.max(0, windowWidth - rect.right));
|
|
5959
|
+
const resolvedLeft = this.getNumericPositionValue(left, Math.max(0, rect.left));
|
|
5960
|
+
const resolvedBottom = this.getNumericPositionValue(bottom, Math.max(0, windowHeight - rect.bottom));
|
|
5961
|
+
const resolvedTop = this.getNumericPositionValue(top, Math.max(0, rect.top));
|
|
5962
|
+
const horizontalValue = this.buttonHorizontalSide === 'left' ? resolvedLeft : resolvedRight;
|
|
5963
|
+
const verticalValue = this.buttonVerticalSide === 'top' ? resolvedTop : resolvedBottom;
|
|
5964
|
+
this.buttonPosition = {
|
|
5965
|
+
x: horizontalValue,
|
|
5966
|
+
y: verticalValue
|
|
5967
|
+
};
|
|
5968
|
+
// Apply the position to the host
|
|
5969
|
+
this.updateHostPosition();
|
|
5970
|
+
}
|
|
5971
|
+
updateHostPosition() {
|
|
5972
|
+
this.host.style.position = 'fixed';
|
|
5973
|
+
if (this.buttonHorizontalSide === 'left') {
|
|
5974
|
+
this.host.style.left = `${this.buttonPosition.x}px`;
|
|
5975
|
+
this.host.style.right = 'auto';
|
|
5976
|
+
}
|
|
5977
|
+
else {
|
|
5978
|
+
this.host.style.right = `${this.buttonPosition.x}px`;
|
|
5979
|
+
this.host.style.left = 'auto';
|
|
5980
|
+
}
|
|
5981
|
+
if (this.buttonVerticalSide === 'top') {
|
|
5982
|
+
this.host.style.top = `${this.buttonPosition.y}px`;
|
|
5983
|
+
this.host.style.bottom = 'auto';
|
|
5984
|
+
}
|
|
5985
|
+
else {
|
|
5986
|
+
this.host.style.bottom = `${this.buttonPosition.y}px`;
|
|
5987
|
+
this.host.style.top = 'auto';
|
|
5988
|
+
}
|
|
5989
|
+
}
|
|
5990
|
+
isButtonDraggable() {
|
|
5991
|
+
const computedStyle = getComputedStyle(this.host);
|
|
5992
|
+
return computedStyle.getPropertyValue('position') === 'fixed';
|
|
5993
|
+
}
|
|
5994
|
+
updateButtonPosition(pointer) {
|
|
5995
|
+
var _a, _b;
|
|
5996
|
+
const windowWidth = window.innerWidth;
|
|
5997
|
+
const windowHeight = window.innerHeight;
|
|
5998
|
+
const buttonWidth = ((_a = this.buttonRef) === null || _a === void 0 ? void 0 : _a.offsetWidth) || 60;
|
|
5999
|
+
const buttonHeight = ((_b = this.buttonRef) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 60;
|
|
6000
|
+
const minPadding = 10;
|
|
6001
|
+
const candidateLeft = pointer.clientX - this.buttonDragOffset.x;
|
|
6002
|
+
const candidateTop = pointer.clientY - this.buttonDragOffset.y;
|
|
6003
|
+
const minLeft = minPadding;
|
|
6004
|
+
const maxLeft = windowWidth - buttonWidth - minPadding;
|
|
6005
|
+
const minTop = minPadding;
|
|
6006
|
+
const maxTop = windowHeight - buttonHeight - minPadding;
|
|
6007
|
+
const constrainedLeft = Math.max(minLeft, Math.min(candidateLeft, maxLeft));
|
|
6008
|
+
const constrainedTop = Math.max(minTop, Math.min(candidateTop, maxTop));
|
|
6009
|
+
const newHorizontalValue = this.buttonHorizontalSide === 'left'
|
|
6010
|
+
? constrainedLeft
|
|
6011
|
+
: Math.max(minPadding, windowWidth - (constrainedLeft + buttonWidth));
|
|
6012
|
+
const newVerticalValue = this.buttonVerticalSide === 'top'
|
|
6013
|
+
? constrainedTop
|
|
6014
|
+
: Math.max(minPadding, windowHeight - (constrainedTop + buttonHeight));
|
|
6015
|
+
if (newHorizontalValue !== this.buttonPosition.x || newVerticalValue !== this.buttonPosition.y) {
|
|
6016
|
+
this.buttonWasDragged = true;
|
|
6017
|
+
this.buttonPosition = { x: newHorizontalValue, y: newVerticalValue };
|
|
6018
|
+
if (this.rafId === null) {
|
|
6019
|
+
this.rafId = requestAnimationFrame(() => {
|
|
6020
|
+
this.updateHostPosition();
|
|
6021
|
+
this.rafId = null;
|
|
6022
|
+
});
|
|
6023
|
+
}
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
addButtonEventListeners() {
|
|
6027
|
+
if (this.buttonListenersAttached) {
|
|
6028
|
+
return;
|
|
6029
|
+
}
|
|
6030
|
+
document.addEventListener('mousemove', this.handleButtonMouseMove);
|
|
6031
|
+
document.addEventListener('mouseup', this.handleButtonMouseUp);
|
|
6032
|
+
document.addEventListener('touchmove', this.handleButtonTouchMove, { passive: false });
|
|
6033
|
+
document.addEventListener('touchend', this.handleButtonTouchEnd);
|
|
6034
|
+
this.buttonListenersAttached = true;
|
|
6035
|
+
}
|
|
6036
|
+
removeButtonEventListeners() {
|
|
6037
|
+
if (!this.buttonListenersAttached) {
|
|
6038
|
+
return;
|
|
6039
|
+
}
|
|
6040
|
+
if (this.rafId !== null) {
|
|
6041
|
+
cancelAnimationFrame(this.rafId);
|
|
6042
|
+
this.rafId = null;
|
|
6043
|
+
}
|
|
6044
|
+
document.removeEventListener('mousemove', this.handleButtonMouseMove);
|
|
6045
|
+
document.removeEventListener('mouseup', this.handleButtonMouseUp);
|
|
6046
|
+
document.removeEventListener('touchmove', this.handleButtonTouchMove);
|
|
6047
|
+
document.removeEventListener('touchend', this.handleButtonTouchEnd);
|
|
6048
|
+
this.buttonListenersAttached = false;
|
|
6049
|
+
}
|
|
6050
|
+
isAutoPosition(value) {
|
|
6051
|
+
const trimmed = value.trim();
|
|
6052
|
+
return trimmed === '' || trimmed === 'auto';
|
|
6053
|
+
}
|
|
6054
|
+
parsePixelValue(value) {
|
|
6055
|
+
const trimmed = value.trim();
|
|
6056
|
+
if (trimmed === '' || trimmed === 'auto') {
|
|
6057
|
+
return null;
|
|
6058
|
+
}
|
|
6059
|
+
if (trimmed.endsWith('px')) {
|
|
6060
|
+
const parsed = parseFloat(trimmed);
|
|
6061
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
6062
|
+
}
|
|
6063
|
+
const numeric = Number(trimmed);
|
|
6064
|
+
if (Number.isFinite(numeric)) {
|
|
6065
|
+
return numeric;
|
|
6066
|
+
}
|
|
6067
|
+
return null;
|
|
6068
|
+
}
|
|
6069
|
+
getNumericPositionValue(value, fallback) {
|
|
6070
|
+
const parsed = this.parsePixelValue(value);
|
|
6071
|
+
if (parsed !== null) {
|
|
6072
|
+
return parsed;
|
|
6073
|
+
}
|
|
6074
|
+
return fallback;
|
|
6075
|
+
}
|
|
6076
|
+
getWelcomeMessages() {
|
|
6077
|
+
const translated = this.translationManager.getArray("content.welcomeMessages");
|
|
6078
|
+
return translated && translated.length > 0
|
|
6079
|
+
? translated
|
|
6080
|
+
: this.parsedWelcomeMessages;
|
|
6081
|
+
}
|
|
6082
|
+
getStarterQuestions() {
|
|
6083
|
+
const translated = this.translationManager.getArray("content.starterQuestions");
|
|
6084
|
+
return translated && translated.length > 0
|
|
6085
|
+
? translated
|
|
6086
|
+
: this.parsedStarterQuestions;
|
|
5282
6087
|
}
|
|
5283
6088
|
getButtonClasses() {
|
|
5284
|
-
const
|
|
6089
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
6090
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
5285
6091
|
const baseClass = hasText ? 'chat-btn-text' : 'chat-btn-icon';
|
|
5286
6092
|
const shapeClass = this.buttonShape === 'round' ? 'round' : '';
|
|
5287
6093
|
return `${baseClass} ${shapeClass}`.trim();
|
|
5288
6094
|
}
|
|
5289
6095
|
renderButton() {
|
|
5290
|
-
|
|
6096
|
+
var _a;
|
|
6097
|
+
const buttonText = this.translationManager.get('branding.buttonText', this.buttonText);
|
|
6098
|
+
const hasText = !!(buttonText && buttonText.trim());
|
|
5291
6099
|
const hasCustomIcon = this.iconUrl && this.iconUrl.trim();
|
|
5292
|
-
const iconSrc = hasCustomIcon ? this.iconUrl : this.getDefaultIconUrl();
|
|
5293
6100
|
const buttonClasses = this.getButtonClasses();
|
|
6101
|
+
const finalButtonText = buttonText !== null && buttonText !== void 0 ? buttonText : '';
|
|
6102
|
+
const openLabel = (_a = this.translationManager.get('launcher.open')) !== null && _a !== void 0 ? _a : '';
|
|
6103
|
+
const buttonAriaLabel = finalButtonText ? `${openLabel} - ${finalButtonText}` : openLabel;
|
|
6104
|
+
// Only show drag cursor if button is draggable
|
|
6105
|
+
const isDraggable = this.isButtonDraggable();
|
|
6106
|
+
const buttonStyle = isDraggable ? {
|
|
6107
|
+
cursor: this.isButtonDragging ? 'grabbing' : 'grab',
|
|
6108
|
+
} : {};
|
|
5294
6109
|
if (hasText) {
|
|
5295
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
6110
|
+
return (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 ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), h("span", null, finalButtonText), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
5296
6111
|
}
|
|
5297
6112
|
else {
|
|
5298
|
-
return (h("button", { class: buttonClasses, onClick: () => this.
|
|
6113
|
+
return (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 ? h("img", { src: this.iconUrl, alt: "" }) : h(OcsWidgetAvatar, null), isDraggable && (h("span", { id: "chat-button-drag-hint", style: { display: 'none' } }, "Draggable. Use mouse or touch to reposition."))));
|
|
5299
6114
|
}
|
|
5300
6115
|
}
|
|
5301
6116
|
getStorageKeys() {
|
|
@@ -5431,18 +6246,18 @@ const OcsChat = class {
|
|
|
5431
6246
|
if (this.error && !this.sessionId) {
|
|
5432
6247
|
return (h(Host, null, h("p", { class: "error-message" }, this.error)));
|
|
5433
6248
|
}
|
|
5434
|
-
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.headerText), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title:
|
|
6249
|
+
return (h(Host, null, this.renderButton(), this.visible && (h("div", { ref: (el) => this.chatWindowRef = el, id: "ocs-chat-window", class: this.getPositionClasses(), style: this.getPositionStyles() }, h("div", { class: `chat-header ${this.isDragging ? 'chat-header-dragging' : 'chat-header-draggable'}`, onMouseDown: this.handleMouseDown, onTouchStart: this.handleTouchStart }, h("div", { class: "drag-indicator" }, h("div", { class: "drag-dots header-button" }, h(GripDotsVerticalIcon, null))), h("div", { class: "header-text" }, this.translationManager.get('branding.headerText', this.headerText)), h("div", { class: "header-buttons" }, this.messages.length > 0 && (h("button", { class: "header-button", onClick: () => this.showConfirmationDialog(), title: this.translationManager.get('window.newChat'), "aria-label": this.translationManager.get('window.newChat') }, h(PlusWithCircleIcon, null))), this.allowFullScreen && 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 ? h(ArrowsPointingInIcon, null) : h(ArrowsPointingOutIcon, null)), h("button", { class: "header-button", onClick: () => this.visible = false, "aria-label": this.translationManager.get('window.close') }, h(XMarkIcon, null)))), this.showNewChatConfirmation && (h("div", { class: "confirmation-overlay" }, h("div", { class: "confirmation-dialog" }, h("div", { class: "confirmation-content" }, h("h3", { class: "confirmation-title" }, this.translationManager.get('modal.newChatTitle')), h("p", { class: "confirmation-message" }, this.translationManager.get('modal.newChatBody', this.newChatConfirmationMessage)), h("div", { class: "confirmation-buttons" }, h("button", { class: "confirmation-button confirmation-button-cancel", onClick: () => this.hideConfirmationDialog() }, this.translationManager.get('modal.cancel')), h("button", { class: "confirmation-button confirmation-button-confirm", onClick: () => this.confirmNewChat() }, this.translationManager.get('modal.confirm'))))))), h("div", { class: "chat-content" }, this.isLoading && !this.sessionId && (h("div", { class: "loading-container" }, h("div", { class: "loading-spinner" }), h("span", { class: "loading-text" }, this.translationManager.get('status.starting')))), (h("div", { ref: (el) => this.messageListRef = el, class: "messages-container" }, this.messages.length === 0 && this.parsedWelcomeMessages.length > 0 && (h("div", { class: "welcome-messages" }, this.getWelcomeMessages().map((message, index) => (h("div", { key: `welcome-${index}`, class: "message-row message-row-assistant" }, h("div", { class: "message-bubble message-bubble-assistant" }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message) }))))))), this.messages.map((message, index) => (h("div", { key: index, class: `message-row ${message.role === 'user' ? 'message-row-user' : 'message-row-assistant'}` }, h("div", { class: `message-bubble ${message.role === 'user'
|
|
5435
6250
|
? 'message-bubble-user'
|
|
5436
6251
|
: message.role === 'assistant'
|
|
5437
6252
|
? 'message-bubble-assistant'
|
|
5438
|
-
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.typingIndicatorText), h("span", { class: "typing-dots" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.
|
|
6253
|
+
: 'message-bubble-system'}` }, h("div", { class: "chat-markdown", innerHTML: renderMarkdownSync(message.content) }), message.attachments && message.attachments.length > 0 && (h("div", { class: "message-attachments" }, message.attachments.map((attachment, attachmentIndex) => (h("div", { key: attachmentIndex, class: "flex items-center gap-[0.5em]" }, h("span", { class: "message-attachment-icon" }, h(PaperClipIcon, null)), h("span", { class: "message-attachment-name" }, attachment.name)))))), h("div", { class: "message-timestamp" }, this.formatTime(message.created_at)))))), this.isTyping && (h("div", null, h("div", { class: "typing-indicator" }, h("div", { class: "typing-progress" })), h("div", { class: "typing-text" }, h("span", null, this.translationManager.get('status.typing', this.typingIndicatorText)), h("span", { class: "typing-dots loading" })))))), this.messages.length === 0 && this.parsedStarterQuestions.length > 0 && (h("div", { class: "starter-questions" }, this.getStarterQuestions().map((question, index) => (h("div", { key: `starter-${index}`, class: "starter-question-row" }, h("button", { class: "starter-question", onClick: () => this.handleStarterQuestionClick(question) }, question)))))), this.allowAttachments && this.selectedFiles.length > 0 && (h("div", { class: "selected-files-container" }, h("div", { class: "space-y-[0.25em]" }, this.selectedFiles.map((selectedFile, index) => (h("div", { key: index, class: "selected-file-item" }, h("div", { class: "flex items-center gap-[0.5em]" }, h("span", { class: "selected-file-icon" }, h(PaperClipIcon, null)), h("span", null, selectedFile.file.name), h("span", { class: "selected-file-size" }, "(", this.formatFileSize(selectedFile.file.size), ")"), selectedFile.error && (h("span", { class: "selected-file-error" }, selectedFile.error)), selectedFile.uploaded && (h("span", { class: "selected-file-success-icon" }, h(CheckDocumentIcon, null)))), h("button", { onClick: () => this.removeSelectedFile(index), class: "selected-file-remove-button", "aria-label": this.translationManager.get('attach.remove') }, h(XIcon, null)))))))), this.sessionId && (h("div", { class: "input-area" }, h("div", { class: "input-container" }, 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 && (h("input", { ref: (el) => {
|
|
5439
6254
|
// Unclear why but after removing all attachments this is being set to `null`.
|
|
5440
6255
|
if (el) {
|
|
5441
6256
|
this.fileInputRef = el;
|
|
5442
6257
|
}
|
|
5443
|
-
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (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:
|
|
6258
|
+
}, id: "ocs-file-input", type: "file", multiple: true, accept: OcsChat.SUPPORTED_FILE_EXTENSIONS.join(','), onChange: (e) => this.handleFileSelect(e), class: "hidden" })), this.allowAttachments && (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') }, h(PaperClipIcon, null))), h("button", { class: `send-button ${!this.isTyping && !!this.messageInput.trim()
|
|
5444
6259
|
? 'send-button-enabled'
|
|
5445
|
-
: 'send-button-disabled'}`, onClick: () => this.sendMessage(this.messageInput), disabled: this.isTyping || this.isUploadingFiles || !this.messageInput.trim() }, this.isUploadingFiles ? '
|
|
6260
|
+
: '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'))))), h("div", { class: "flex items-center justify-center text-[0.8em] font-light w-full text-slate-500 py-[2px]" }, h("p", null, this.translationManager.get('branding.poweredBy'), ' ', " ", h("a", { class: "underline", href: "https://www.dimagi.com", target: "_blank" }, "Dimagi"))))))));
|
|
5446
6261
|
}
|
|
5447
6262
|
get host() { return getElement(this); }
|
|
5448
6263
|
static get watchers() { return {
|