Update templates/index.html
Browse files- templates/index.html +180 -21
templates/index.html
CHANGED
|
@@ -333,6 +333,90 @@
|
|
| 333 |
}
|
| 334 |
pre:hover .code-copy-btn { opacity: 0.7; }
|
| 335 |
pre:hover .code-copy-btn:hover { opacity: 1; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
</style>
|
| 337 |
</head>
|
| 338 |
<body class="bg-gray-50 text-gray-900 antialiased">
|
|
@@ -451,23 +535,25 @@
|
|
| 451 |
</div>
|
| 452 |
</div>
|
| 453 |
</div>
|
| 454 |
-
<!-- Formulaire de chat -->
|
| 455 |
<form id="chat-form" class="p-3 sm:p-4 bg-white dark:bg-gray-900">
|
| 456 |
<div class="relative">
|
| 457 |
-
<
|
| 458 |
-
type="text"
|
| 459 |
id="prompt"
|
| 460 |
name="prompt"
|
| 461 |
-
class="chat-input w-full pl-4 pr-12 py-3 rounded-full border focus:outline-none text-sm sm:text-base"
|
| 462 |
placeholder="Posez votre question à Mariam..."
|
| 463 |
-
autocomplete="off"
|
| 464 |
-
|
| 465 |
-
|
| 466 |
-
|
| 467 |
-
|
| 468 |
-
|
| 469 |
-
|
| 470 |
-
|
|
|
|
|
|
|
|
|
|
| 471 |
</div>
|
| 472 |
<div class="text-xs text-center mt-2 text-gray-400 dark:text-gray-500">
|
| 473 |
Appuyez sur <kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded border border-gray-300 dark:border-gray-700">Entrée</kbd> pour envoyer • <kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded border border-gray-300 dark:border-gray-700">Shift+Entrée</kbd> pour une nouvelle ligne
|
|
@@ -526,6 +612,23 @@
|
|
| 526 |
themeToggleBtn.addEventListener('click', toggleTheme);
|
| 527 |
initializeTheme();
|
| 528 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 529 |
// Défilement vers le bas
|
| 530 |
function scrollToBottom(smooth = true) {
|
| 531 |
setTimeout(() => {
|
|
@@ -588,6 +691,22 @@
|
|
| 588 |
`;
|
| 589 |
}
|
| 590 |
messageWrapper.innerHTML = html;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 591 |
chatMessages.insertBefore(messageWrapper, loadingIndicator);
|
| 592 |
scrollToBottom();
|
| 593 |
}
|
|
@@ -713,6 +832,25 @@
|
|
| 713 |
}
|
| 714 |
clearFileButton.addEventListener('click', clearFileInput);
|
| 715 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 716 |
// Soumission du formulaire
|
| 717 |
chatForm.addEventListener('submit', async (e) => {
|
| 718 |
e.preventDefault();
|
|
@@ -746,6 +884,7 @@
|
|
| 746 |
formData.append('advanced_reasoning', useAdvanced);
|
| 747 |
showLoading(true);
|
| 748 |
promptInput.value = '';
|
|
|
|
| 749 |
clearFileInput();
|
| 750 |
advancedToggle.checked = false;
|
| 751 |
if (useAdvanced) startAdvancedCooldownTimer();
|
|
@@ -819,17 +958,37 @@
|
|
| 819 |
});
|
| 820 |
});
|
| 821 |
|
| 822 |
-
|
| 823 |
-
|
| 824 |
-
|
| 825 |
-
|
| 826 |
-
|
| 827 |
-
|
|
|
|
| 828 |
});
|
| 829 |
|
| 830 |
-
|
| 831 |
-
|
| 832 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 833 |
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
| 834 |
prefersDarkScheme.addEventListener('change', (e) => {
|
| 835 |
if (!localStorage.theme) {
|
|
|
|
| 333 |
}
|
| 334 |
pre:hover .code-copy-btn { opacity: 0.7; }
|
| 335 |
pre:hover .code-copy-btn:hover { opacity: 1; }
|
| 336 |
+
|
| 337 |
+
/* Styles pour améliorer les tableaux Markdown */
|
| 338 |
+
.prose table {
|
| 339 |
+
width: 100%;
|
| 340 |
+
border-collapse: collapse;
|
| 341 |
+
margin: 1rem 0;
|
| 342 |
+
overflow-x: auto;
|
| 343 |
+
display: block;
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
.prose table th,
|
| 347 |
+
.prose table td {
|
| 348 |
+
border: 1px solid #e2e8f0;
|
| 349 |
+
padding: 0.5rem 0.75rem;
|
| 350 |
+
text-align: left;
|
| 351 |
+
}
|
| 352 |
+
|
| 353 |
+
.dark .prose table th,
|
| 354 |
+
.dark .prose table td {
|
| 355 |
+
border-color: #334155;
|
| 356 |
+
}
|
| 357 |
+
|
| 358 |
+
.prose table thead {
|
| 359 |
+
background-color: #f8fafc;
|
| 360 |
+
font-weight: 600;
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
.dark .prose table thead {
|
| 364 |
+
background-color: #1e293b;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
.prose table tbody tr:nth-child(even) {
|
| 368 |
+
background-color: #f8fafc;
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
.dark .prose table tbody tr:nth-child(even) {
|
| 372 |
+
background-color: #1e293b;
|
| 373 |
+
}
|
| 374 |
+
|
| 375 |
+
/* Pour le textarea qui s'adapte au contenu */
|
| 376 |
+
.chat-textarea {
|
| 377 |
+
resize: none;
|
| 378 |
+
min-height: 40px;
|
| 379 |
+
max-height: 200px;
|
| 380 |
+
overflow-y: auto;
|
| 381 |
+
line-height: 1.5;
|
| 382 |
+
width: 100%;
|
| 383 |
+
border-radius: 9999px;
|
| 384 |
+
padding-top: 0.75rem;
|
| 385 |
+
padding-bottom: 0.75rem;
|
| 386 |
+
}
|
| 387 |
+
|
| 388 |
+
/* Ajustements pour le responsive */
|
| 389 |
+
@media (max-width: 640px) {
|
| 390 |
+
.message-bubble {
|
| 391 |
+
max-width: 90%;
|
| 392 |
+
padding: 0.75rem 0.875rem;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
.chat-textarea {
|
| 396 |
+
max-height: 120px;
|
| 397 |
+
font-size: 0.95rem;
|
| 398 |
+
padding-top: 0.625rem;
|
| 399 |
+
padding-bottom: 0.625rem;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
.prose table {
|
| 403 |
+
font-size: 0.85rem;
|
| 404 |
+
}
|
| 405 |
+
|
| 406 |
+
.prose table th,
|
| 407 |
+
.prose table td {
|
| 408 |
+
padding: 0.375rem 0.5rem;
|
| 409 |
+
}
|
| 410 |
+
|
| 411 |
+
.send-button-wrapper {
|
| 412 |
+
top: 0;
|
| 413 |
+
right: 0;
|
| 414 |
+
height: 100%;
|
| 415 |
+
display: flex;
|
| 416 |
+
align-items: center;
|
| 417 |
+
padding-right: 0.5rem;
|
| 418 |
+
}
|
| 419 |
+
}
|
| 420 |
</style>
|
| 421 |
</head>
|
| 422 |
<body class="bg-gray-50 text-gray-900 antialiased">
|
|
|
|
| 535 |
</div>
|
| 536 |
</div>
|
| 537 |
</div>
|
| 538 |
+
<!-- Formulaire de chat avec textarea au lieu d'input -->
|
| 539 |
<form id="chat-form" class="p-3 sm:p-4 bg-white dark:bg-gray-900">
|
| 540 |
<div class="relative">
|
| 541 |
+
<textarea
|
|
|
|
| 542 |
id="prompt"
|
| 543 |
name="prompt"
|
| 544 |
+
class="chat-input chat-textarea w-full pl-4 pr-12 py-3 rounded-full border focus:outline-none text-sm sm:text-base"
|
| 545 |
placeholder="Posez votre question à Mariam..."
|
| 546 |
+
autocomplete="off"
|
| 547 |
+
rows="1"></textarea>
|
| 548 |
+
<div class="send-button-wrapper absolute right-2 top-1/2 transform -translate-y-1/2">
|
| 549 |
+
<button
|
| 550 |
+
type="submit"
|
| 551 |
+
id="send-button"
|
| 552 |
+
class="bg-primary-500 hover:bg-primary-600 disabled:bg-primary-300 text-white rounded-full p-2 transition focus:outline-none focus:ring-2 focus:ring-primary-400"
|
| 553 |
+
title="Envoyer le message">
|
| 554 |
+
<i class="fa-solid fa-paper-plane"></i>
|
| 555 |
+
</button>
|
| 556 |
+
</div>
|
| 557 |
</div>
|
| 558 |
<div class="text-xs text-center mt-2 text-gray-400 dark:text-gray-500">
|
| 559 |
Appuyez sur <kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded border border-gray-300 dark:border-gray-700">Entrée</kbd> pour envoyer • <kbd class="px-1.5 py-0.5 bg-gray-100 dark:bg-gray-800 rounded border border-gray-300 dark:border-gray-700">Shift+Entrée</kbd> pour une nouvelle ligne
|
|
|
|
| 612 |
themeToggleBtn.addEventListener('click', toggleTheme);
|
| 613 |
initializeTheme();
|
| 614 |
|
| 615 |
+
// Fonction pour ajuster la hauteur du textarea
|
| 616 |
+
function adjustTextareaHeight(textarea) {
|
| 617 |
+
textarea.style.height = 'auto';
|
| 618 |
+
const newHeight = Math.min(200, textarea.scrollHeight);
|
| 619 |
+
textarea.style.height = newHeight + 'px';
|
| 620 |
+
|
| 621 |
+
// Ajuste la position du bouton d'envoi
|
| 622 |
+
const sendButtonWrapper = document.querySelector('.send-button-wrapper');
|
| 623 |
+
if (sendButtonWrapper) {
|
| 624 |
+
if (window.innerWidth <= 640) {
|
| 625 |
+
sendButtonWrapper.style.top = '';
|
| 626 |
+
} else {
|
| 627 |
+
sendButtonWrapper.style.top = (newHeight / 2) + 'px';
|
| 628 |
+
}
|
| 629 |
+
}
|
| 630 |
+
}
|
| 631 |
+
|
| 632 |
// Défilement vers le bas
|
| 633 |
function scrollToBottom(smooth = true) {
|
| 634 |
setTimeout(() => {
|
|
|
|
| 691 |
`;
|
| 692 |
}
|
| 693 |
messageWrapper.innerHTML = html;
|
| 694 |
+
|
| 695 |
+
// Activer les boutons de copie sur les nouveaux messages
|
| 696 |
+
const copyBtns = messageWrapper.querySelectorAll('.copy-btn');
|
| 697 |
+
copyBtns.forEach(btn => {
|
| 698 |
+
btn.addEventListener('click', function() {
|
| 699 |
+
const textToCopy = this.closest('.message-bubble').querySelector('.prose').innerText;
|
| 700 |
+
navigator.clipboard.writeText(textToCopy).then(() => {
|
| 701 |
+
const originalText = this.innerHTML;
|
| 702 |
+
this.innerHTML = '<i class="fa-solid fa-check mr-1"></i> Copié';
|
| 703 |
+
setTimeout(() => {
|
| 704 |
+
this.innerHTML = originalText;
|
| 705 |
+
}, 2000);
|
| 706 |
+
});
|
| 707 |
+
});
|
| 708 |
+
});
|
| 709 |
+
|
| 710 |
chatMessages.insertBefore(messageWrapper, loadingIndicator);
|
| 711 |
scrollToBottom();
|
| 712 |
}
|
|
|
|
| 832 |
}
|
| 833 |
clearFileButton.addEventListener('click', clearFileInput);
|
| 834 |
|
| 835 |
+
// Événements pour le textarea
|
| 836 |
+
promptInput.addEventListener('input', function() {
|
| 837 |
+
adjustTextareaHeight(this);
|
| 838 |
+
});
|
| 839 |
+
|
| 840 |
+
promptInput.addEventListener('keydown', (e) => {
|
| 841 |
+
if (isComposing) return;
|
| 842 |
+
if (e.key === 'Enter' && !e.shiftKey) {
|
| 843 |
+
e.preventDefault();
|
| 844 |
+
if (!sendButton.disabled) chatForm.dispatchEvent(new Event('submit'));
|
| 845 |
+
} else if (e.key === 'Enter' && e.shiftKey) {
|
| 846 |
+
// Laisser le comportement par défaut (nouvelle ligne)
|
| 847 |
+
setTimeout(() => adjustTextareaHeight(promptInput), 0);
|
| 848 |
+
}
|
| 849 |
+
});
|
| 850 |
+
|
| 851 |
+
promptInput.addEventListener('compositionstart', () => { isComposing = true; });
|
| 852 |
+
promptInput.addEventListener('compositionend', () => { isComposing = false; });
|
| 853 |
+
|
| 854 |
// Soumission du formulaire
|
| 855 |
chatForm.addEventListener('submit', async (e) => {
|
| 856 |
e.preventDefault();
|
|
|
|
| 884 |
formData.append('advanced_reasoning', useAdvanced);
|
| 885 |
showLoading(true);
|
| 886 |
promptInput.value = '';
|
| 887 |
+
promptInput.style.height = 'auto'; // Réinitialiser la hauteur du textarea
|
| 888 |
clearFileInput();
|
| 889 |
advancedToggle.checked = false;
|
| 890 |
if (useAdvanced) startAdvancedCooldownTimer();
|
|
|
|
| 958 |
});
|
| 959 |
});
|
| 960 |
|
| 961 |
+
// Init
|
| 962 |
+
loadChatHistory();
|
| 963 |
+
adjustTextareaHeight(promptInput);
|
| 964 |
+
|
| 965 |
+
// Gérer les changements de taille de l'écran
|
| 966 |
+
window.addEventListener('resize', () => {
|
| 967 |
+
adjustTextareaHeight(promptInput);
|
| 968 |
});
|
| 969 |
|
| 970 |
+
// Observer pour les tableaux Markdown et ajouter une classe spéciale si nécessaire
|
| 971 |
+
const observeMarkdownTables = () => {
|
| 972 |
+
const observer = new MutationObserver(mutations => {
|
| 973 |
+
mutations.forEach(mutation => {
|
| 974 |
+
if (mutation.type === 'childList') {
|
| 975 |
+
const tables = document.querySelectorAll('.prose table:not(.markdown-enhanced)');
|
| 976 |
+
tables.forEach(table => {
|
| 977 |
+
table.classList.add('markdown-enhanced');
|
| 978 |
+
const wrapper = document.createElement('div');
|
| 979 |
+
wrapper.className = 'overflow-x-auto';
|
| 980 |
+
table.parentNode.insertBefore(wrapper, table);
|
| 981 |
+
wrapper.appendChild(table);
|
| 982 |
+
});
|
| 983 |
+
}
|
| 984 |
+
});
|
| 985 |
+
});
|
| 986 |
+
|
| 987 |
+
observer.observe(chatMessages, { childList: true, subtree: true });
|
| 988 |
+
};
|
| 989 |
+
|
| 990 |
+
observeMarkdownTables();
|
| 991 |
+
|
| 992 |
const prefersDarkScheme = window.matchMedia('(prefers-color-scheme: dark)');
|
| 993 |
prefersDarkScheme.addEventListener('change', (e) => {
|
| 994 |
if (!localStorage.theme) {
|