Spaces:
Running
Running
Update templates/index.html
Browse files- templates/index.html +88 -153
templates/index.html
CHANGED
@@ -150,32 +150,36 @@
|
|
150 |
|
151 |
<body class="min-h-screen bg-gradient-to-br from-blue-50 via-white to-blue-50 text-gray-800">
|
152 |
<nav class="glassmorphism sticky top-0 z-50 border-b border-blue-100">
|
153 |
-
|
|
|
154 |
<div class="flex items-center justify-between">
|
155 |
<div class="flex items-center space-x-3 sm:space-x-4">
|
156 |
<div class="bg-gradient-to-r from-blue-600 to-blue-800 rounded-lg p-2 shadow-lg transform hover:scale-110 transition-transform duration-300">
|
157 |
-
<i class="fas fa-robot text-white text-lg sm:text-xl"></i>
|
158 |
</div>
|
159 |
-
<h1 class="text-xl sm:text-2xl font-bold gradient-text">Mariam AI</h1>
|
160 |
</div>
|
161 |
-
<div class="text-xs sm:text-sm text-blue-900 font-medium bg-blue-50 py-1 px-3 sm:px-4 rounded-full shadow-sm hidden sm:block">Assistant Français</div>
|
162 |
-
<div class="text-xs text-blue-900 font-medium bg-blue-50 py-1 px-3 rounded-full shadow-sm sm:hidden">Assistant</div>
|
163 |
</div>
|
164 |
</div>
|
165 |
</nav>
|
166 |
|
167 |
-
|
|
|
168 |
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 sm:gap-8">
|
169 |
<!-- Section Travail Argumentatif -->
|
170 |
<div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in">
|
171 |
-
|
|
|
172 |
<div class="flex items-center space-x-3 sm:space-x-4 mb-6 sm:mb-8">
|
173 |
<div class="bg-blue-100 rounded-lg p-2 sm:p-3 transform rotate-3">
|
174 |
<i class="fas fa-pen-fancy text-blue-600 text-lg sm:text-xl"></i>
|
175 |
</div>
|
176 |
<h2 class="text-xl sm:text-2xl font-bold text-gray-800">Travail Argumentatif</h2>
|
177 |
</div>
|
178 |
-
|
|
|
179 |
<div class="space-y-2">
|
180 |
<label for="sujet-francais" class="block text-sm font-medium text-gray-700 flex items-center">
|
181 |
<i class="fas fa-book-open mr-2 text-blue-500"></i>Sujet <span class="text-red-500 ml-1">*</span>
|
@@ -192,7 +196,7 @@
|
|
192 |
<label class="block text-sm font-medium text-gray-700 flex items-center">
|
193 |
<i class="fas fa-tasks mr-2 text-blue-500"></i>Type d'argumentation
|
194 |
</label>
|
195 |
-
|
196 |
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4">
|
197 |
<label class="relative">
|
198 |
<input type="radio" name="choix" value="Etaye" class="custom-radio absolute opacity-0 w-full h-full cursor-pointer" checked>
|
@@ -249,8 +253,8 @@
|
|
249 |
</div>
|
250 |
</button>
|
251 |
</form>
|
252 |
-
|
253 |
-
<div id="francais-output" class="mt-6 sm:mt-8 p-4 sm:p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner min-h-[150px]">
|
254 |
<!-- Le contenu généré sera inséré ici -->
|
255 |
</div>
|
256 |
</div>
|
@@ -258,7 +262,8 @@
|
|
258 |
|
259 |
<!-- Section Étude de texte -->
|
260 |
<div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in" style="animation-delay: 0.1s;">
|
261 |
-
|
|
|
262 |
<div class="flex items-center space-x-3 sm:space-x-4 mb-6 sm:mb-8">
|
263 |
<div class="bg-blue-100 rounded-lg p-2 sm:p-3 transform -rotate-3">
|
264 |
<i class="fas fa-file-alt text-blue-600 text-lg sm:text-xl"></i>
|
@@ -292,8 +297,8 @@
|
|
292 |
</div>
|
293 |
</button>
|
294 |
</form>
|
295 |
-
{
|
296 |
-
<div id="etude-texte-output" class="mt-6 sm:mt-8 p-4 sm:p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner min-h-[150px]">
|
297 |
<!-- Le contenu analysé sera inséré ici -->
|
298 |
</div>
|
299 |
</div>
|
@@ -343,7 +348,7 @@
|
|
343 |
const dropZone = document.getElementById('drop-zone');
|
344 |
const fileInput = document.getElementById('image-upload');
|
345 |
const imagePreview = document.getElementById('image-preview');
|
346 |
-
if(!dropZone || !fileInput || !imagePreview) return;
|
347 |
|
348 |
dropZone.addEventListener('click', () => fileInput.click());
|
349 |
['dragenter', 'dragover'].forEach(ev => dropZone.addEventListener(ev, highlightDropZone));
|
@@ -401,7 +406,7 @@
|
|
401 |
sauvegardes.push({ titre: titre || "Sauvegarde", contenu, date: dateSauvegarde });
|
402 |
try {
|
403 |
localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
|
404 |
-
displayNotification("Sauvegardé", "success");
|
405 |
afficherSauvegardes();
|
406 |
} catch (e) {
|
407 |
console.error("Erreur sauvegarde localStorage:", e);
|
@@ -411,13 +416,9 @@
|
|
411 |
|
412 |
function displayNotification(message, type = 'success') {
|
413 |
const notification = document.createElement('div');
|
414 |
-
const colors = {
|
415 |
-
success: 'bg-green-50 border-green-200 text-green-700',
|
416 |
-
error: 'bg-red-50 border-red-200 text-red-700',
|
417 |
-
warning: 'bg-yellow-50 border-yellow-200 text-yellow-700'
|
418 |
-
};
|
419 |
const icons = { success: 'fa-check-circle text-green-500', error: 'fa-exclamation-circle text-red-500', warning: 'fa-exclamation-triangle text-yellow-500' };
|
420 |
-
notification.className = `fixed bottom-4 right-4 sm:bottom-6 sm:right-6 border ${colors[type] || colors.success} px-4 py-3 rounded-lg shadow-lg z-[100] flex items-center scale-in max-w-[calc(100%-2rem)] sm:max-w-sm`;
|
421 |
notification.innerHTML = `<i class="fas ${icons[type] || icons.success} mr-3 text-lg flex-shrink-0"></i><span class="text-sm font-medium">${message}</span>`;
|
422 |
document.body.appendChild(notification);
|
423 |
const duration = type === 'error' ? 6000 : 3000;
|
@@ -434,24 +435,15 @@
|
|
434 |
sauvegardes.splice(originalIndex, 1);
|
435 |
localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
|
436 |
afficherSauvegardes();
|
437 |
-
} else {
|
438 |
-
|
439 |
-
displayNotification("Erreur suppression: Index invalide", "error");
|
440 |
-
}
|
441 |
-
} catch (e) {
|
442 |
-
console.error("Erreur suppression sauvegarde:", e);
|
443 |
-
displayNotification("Erreur suppression", "error");
|
444 |
-
}
|
445 |
}
|
446 |
|
447 |
function afficherSauvegardes() {
|
448 |
const backupsList = document.getElementById('backups-list');
|
449 |
if(!backupsList) return;
|
450 |
let sauvegardes = [];
|
451 |
-
try {
|
452 |
-
sauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]');
|
453 |
-
} catch(e) { console.error("Erreur lecture sauvegardes:", e); }
|
454 |
-
|
455 |
sauvegardes.sort((a, b) => new Date(b.date) - new Date(a.date));
|
456 |
backupsList.innerHTML = '';
|
457 |
|
@@ -460,20 +452,20 @@
|
|
460 |
return;
|
461 |
}
|
462 |
|
463 |
-
sauvegardes.forEach((sauvegarde
|
464 |
const date = new Date(sauvegarde.date);
|
465 |
-
const formattedDate = date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short',
|
466 |
-
const displayTitle = (sauvegarde.titre || "Sans titre").length >
|
467 |
|
468 |
const sauvegardeDiv = document.createElement('div');
|
469 |
-
sauvegardeDiv.dataset.originalDate = sauvegarde.date;
|
470 |
sauvegardeDiv.className = 'bg-white rounded-lg shadow-md p-4 relative backup-item hover:bg-blue-50 transition-all duration-200';
|
471 |
sauvegardeDiv.innerHTML = `
|
472 |
<div class="flex items-start cursor-pointer item-header">
|
473 |
<div class="bg-blue-100 rounded-lg p-2 mr-3 flex-shrink-0"> <i class="fas fa-file-alt text-blue-600 text-sm"></i> </div>
|
474 |
<div class="flex-grow overflow-hidden mr-2">
|
475 |
-
<h3 class="text-base
|
476 |
-
<p class="text-xs
|
477 |
</div>
|
478 |
<div class="flex space-x-1 sm:space-x-2 ml-auto flex-shrink-0">
|
479 |
<button class="text-gray-400 hover:text-blue-600 focus:outline-none copy-btn p-1 rounded-full hover:bg-gray-100" title="Copier"> <i class="fas fa-copy text-xs sm:text-sm"></i> </button>
|
@@ -488,41 +480,29 @@
|
|
488 |
|
489 |
headerDiv.addEventListener('click', () => {
|
490 |
const isExpanded = backupContentDiv.classList.contains('backup-content-expanded');
|
491 |
-
document.querySelectorAll('.backup-content-expanded').forEach(content => {
|
492 |
-
if (content !== backupContentDiv) { content.classList.remove('backup-content-expanded'); content.innerHTML = ''; }
|
493 |
-
});
|
494 |
if (!isExpanded) {
|
495 |
-
try { backupContentDiv.innerHTML = marked.parse(sauvegarde.contenu || ''); } catch(e) { backupContentDiv.innerHTML = "Erreur d'affichage
|
496 |
backupContentDiv.classList.add('backup-content-expanded');
|
497 |
-
|
498 |
-
} else {
|
499 |
-
backupContentDiv.classList.remove('backup-content-expanded'); backupContentDiv.innerHTML = '';
|
500 |
-
}
|
501 |
});
|
502 |
|
503 |
sauvegardeDiv.querySelector('.copy-btn').addEventListener('click', (e) => {
|
504 |
e.stopPropagation();
|
505 |
navigator.clipboard.writeText(sauvegarde.contenu || '').then(() => {
|
506 |
-
const icon = e.currentTarget.querySelector('i'); icon.className = 'fas fa-check text-green-500 text-xs sm:text-sm'; setTimeout(() => { icon.className = 'fas fa-copy text-xs sm:text-sm'; },
|
507 |
}).catch(err => { console.error('Copy error:', err); displayNotification("Erreur copie", "error"); });
|
508 |
});
|
509 |
|
510 |
sauvegardeDiv.querySelector('.delete-btn').addEventListener('click', (e) => {
|
511 |
e.stopPropagation();
|
512 |
const itemDate = sauvegardeDiv.dataset.originalDate;
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
try {
|
517 |
-
const originalSauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]');
|
518 |
-
originalIndex = originalSauvegardes.findIndex(s => s.date === itemDate);
|
519 |
-
} catch (err) { console.error("Erreur recherche sauvegarde:", err); }
|
520 |
-
|
521 |
-
|
522 |
-
if (originalIndex === -1) { console.error("Item not found for deletion by date:", itemDate); displayNotification("Erreur suppression", "error"); return; }
|
523 |
|
524 |
const confirmationModal = document.createElement('div');
|
525 |
-
confirmationModal.className = 'fixed inset-0 flex items-center justify-center z-[100] bg-black bg-opacity-50 scale-in p-4';
|
526 |
confirmationModal.innerHTML = `
|
527 |
<div class="bg-white rounded-lg p-5 sm:p-6 max-w-sm w-full shadow-xl">
|
528 |
<div class="flex items-center mb-4"> <div class="bg-red-100 rounded-full p-2 mr-3"><i class="fas fa-exclamation-triangle text-red-500"></i></div> <h3 class="text-base sm:text-lg font-semibold text-gray-800">Confirmation</h3> </div>
|
@@ -538,12 +518,10 @@
|
|
538 |
}
|
539 |
|
540 |
function closeModal(modalElement) {
|
541 |
-
modalElement.style.opacity = '0';
|
542 |
-
modalElement.style.transition = 'opacity 0.3s ease';
|
543 |
setTimeout(() => { if (document.body.contains(modalElement)) document.body.removeChild(modalElement); }, 300);
|
544 |
}
|
545 |
|
546 |
-
|
547 |
// --- Gestion DeepThink ---
|
548 |
function checkDeepThinkAvailability() {
|
549 |
const checkbox = document.getElementById('deepthink-checkbox');
|
@@ -552,17 +530,9 @@
|
|
552 |
try {
|
553 |
const lastUsedDateStr = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
|
554 |
const todayStr = new Date().toISOString().split('T')[0];
|
555 |
-
if (lastUsedDateStr === todayStr) {
|
556 |
-
|
557 |
-
|
558 |
-
} else {
|
559 |
-
checkbox.disabled = false; statusSpan.textContent = ""; statusSpan.classList.remove('text-red-500');
|
560 |
-
}
|
561 |
-
} catch (e) {
|
562 |
-
console.error("Erreur accès localStorage (DeepThink):", e);
|
563 |
-
checkbox.disabled = true; // Disable if error
|
564 |
-
statusSpan.textContent = "(erreur)";
|
565 |
-
}
|
566 |
}
|
567 |
|
568 |
// --- Soumission des formulaires ---
|
@@ -571,15 +541,14 @@
|
|
571 |
const output = document.getElementById('francais-output');
|
572 |
const sujetTextarea = document.getElementById('sujet-francais');
|
573 |
const deepThinkCheckbox = document.getElementById('deepthink-checkbox');
|
574 |
-
const submitButton = form.querySelector('button[type="submit"]');
|
575 |
-
|
576 |
-
if(!form || !output || !sujetTextarea || !deepThinkCheckbox || !submitButton) return; // Safety check
|
577 |
|
578 |
form.addEventListener('submit', async (e) => {
|
579 |
e.preventDefault();
|
580 |
-
const originalButtonContent = submitButton.innerHTML;
|
581 |
-
submitButton.disabled = true;
|
582 |
-
submitButton.innerHTML = `<div class="flex items-center justify-center"><div class="loader"><div></div><div></div><div></div><div></div></div><span class="ml-2">Génération...</span></div>`; //
|
583 |
|
584 |
const sujetValue = sujetTextarea.value.trim();
|
585 |
const isDeepThinkChecked = deepThinkCheckbox.checked;
|
@@ -588,57 +557,40 @@
|
|
588 |
if (!sujetValue) {
|
589 |
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Champ obligatoire</p><p>Veuillez entrer un sujet.</p></div></div>`;
|
590 |
sujetTextarea.focus(); sujetTextarea.classList.add('border-red-500'); setTimeout(() => sujetTextarea.classList.remove('border-red-500'), 3000);
|
591 |
-
submitButton.disabled = false; submitButton.innerHTML = originalButtonContent;
|
592 |
-
return;
|
593 |
}
|
594 |
if (isDeepThinkChecked) {
|
595 |
try {
|
596 |
const lastUsedDateStr = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
|
597 |
const todayStr = new Date().toISOString().split('T')[0];
|
598 |
if (lastUsedDateStr === todayStr) {
|
599 |
-
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Limite atteinte</p><p>DeepThink déjà
|
600 |
-
checkDeepThinkAvailability();
|
601 |
-
submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; // Re-enable button
|
602 |
-
return;
|
603 |
}
|
604 |
-
} catch(e) { /*
|
605 |
}
|
|
|
606 |
|
607 |
-
|
608 |
-
output.innerHTML = `<div class="flex justify-center items-center p-6"><div class="loader"><div></div><div></div><div></div><div></div></div></div>`;
|
609 |
-
|
610 |
-
|
611 |
-
const formData = new FormData(form);
|
612 |
-
formData.append('use_deepthink', isDeepThinkChecked);
|
613 |
-
|
614 |
try {
|
615 |
const response = await fetch('/api/francais', { method: 'POST', body: formData });
|
616 |
const result = await response.json();
|
617 |
if (!response.ok) throw new Error(result.output || `Erreur HTTP ${response.status}`);
|
618 |
|
619 |
-
|
620 |
-
try { output.innerHTML = marked.parse(result.output || ''); } catch (e) { output.innerHTML = "Erreur d'affichage de la réponse."; console.error(e); }
|
621 |
|
622 |
-
const titreSauvegarde = sujetValue.substring(0,
|
623 |
-
const deepThinkSuffix = isDeepThinkChecked ? ' [
|
624 |
sauvegarderReponse(titreSauvegarde + deepThinkSuffix, result.output);
|
625 |
|
626 |
if (isDeepThinkChecked) {
|
627 |
-
try {
|
628 |
-
|
629 |
-
localStorage.setItem(DEEPTHINK_STORAGE_KEY, todayStr);
|
630 |
-
checkDeepThinkAvailability();
|
631 |
-
} catch(e) { console.error("Erreur sauvegarde date DeepThink:", e); }
|
632 |
}
|
633 |
-
// MathJax retiré
|
634 |
-
|
635 |
} catch (error) {
|
636 |
-
console.error("Erreur soumission (
|
637 |
output.innerHTML = `<div class="alert-message alert-danger"><i class="fas fa-exclamation-circle"></i><div><p>Erreur</p><p>${error.message || "Vérifiez la console."}</p></div></div>`;
|
638 |
-
} finally {
|
639 |
-
submitButton.disabled = false; // Always re-enable button
|
640 |
-
submitButton.innerHTML = originalButtonContent; // Restore original content
|
641 |
-
}
|
642 |
});
|
643 |
}
|
644 |
|
@@ -646,45 +598,35 @@
|
|
646 |
const form = document.getElementById('etude-texte-form');
|
647 |
const output = document.getElementById('etude-texte-output');
|
648 |
const fileInput = document.getElementById('image-upload');
|
649 |
-
const submitButton = form.querySelector('button[type="submit"]');
|
650 |
-
|
651 |
-
if(!form || !output || !fileInput || !submitButton) return; // Safety check
|
652 |
|
653 |
form.addEventListener('submit', async (e) => {
|
654 |
e.preventDefault();
|
655 |
-
const originalButtonContent = submitButton.innerHTML;
|
656 |
-
submitButton.disabled = true;
|
657 |
-
submitButton.innerHTML = `<div class="flex items-center justify-center"><div class="loader"><div></div><div></div><div></div><div></div></div><span class="ml-2">Analyse...</span></div>`; //
|
658 |
-
|
659 |
|
660 |
if (uploadedFiles.size === 0) {
|
661 |
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Aucune image</p><p>Ajoutez au moins une image.</p></div></div>`;
|
662 |
-
submitButton.disabled = false; submitButton.innerHTML = originalButtonContent;
|
663 |
-
return;
|
664 |
}
|
665 |
-
|
666 |
-
// Clear previous output and show minimal loader
|
667 |
output.innerHTML = `<div class="flex justify-center items-center p-6"><div class="loader"><div></div><div></div><div></div><div></div></div></div>`;
|
668 |
|
669 |
-
const formData = new FormData();
|
670 |
-
uploadedFiles.forEach((file) => formData.append('images', file, file.name));
|
671 |
try {
|
672 |
const response = await fetch('/api/etude-texte', { method: 'POST', body: formData });
|
673 |
const result = await response.json();
|
674 |
if (!response.ok) throw new Error(result.output || `Erreur HTTP ${response.status}`);
|
675 |
|
676 |
-
try { output.innerHTML = marked.parse(result.output || ''); } catch (e) { output.innerHTML = "Erreur d'affichage
|
677 |
|
678 |
-
const titre = `Analyse
|
679 |
sauvegarderReponse(titre, result.output);
|
680 |
-
// MathJax retiré
|
681 |
} catch (error) {
|
682 |
-
console.error("Erreur soumission (
|
683 |
output.innerHTML = `<div class="alert-message alert-danger"><i class="fas fa-exclamation-circle"></i><div><p>Erreur</p><p>${error.message || "Vérifiez la console."}</p></div></div>`;
|
684 |
-
} finally {
|
685 |
-
submitButton.disabled = false; // Always re-enable button
|
686 |
-
submitButton.innerHTML = originalButtonContent; // Restore original content
|
687 |
-
}
|
688 |
});
|
689 |
}
|
690 |
|
@@ -693,22 +635,18 @@
|
|
693 |
const cards = document.querySelectorAll('.card-hover');
|
694 |
if (!('IntersectionObserver' in window)) { cards.forEach(card => card.style.opacity = '1'); return; }
|
695 |
const observer = new IntersectionObserver((entries) => {
|
696 |
-
entries.forEach((entry) => {
|
697 |
-
|
698 |
-
|
699 |
-
}, { threshold: 0.05 }); // Lower threshold for earlier trigger
|
700 |
-
cards.forEach(card => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; observer.observe(card); }); // Smaller initial translate
|
701 |
}
|
702 |
function enhanceTextareaFocus() {
|
703 |
-
const textarea = document.getElementById('sujet-francais');
|
704 |
-
const counter =
|
705 |
-
if(!textarea || !counter) return;
|
706 |
-
textarea.addEventListener('input', () => { const length = textarea.value.length; counter.textContent = `${length} caractère${length !== 1 ? 's' : ''}`; textarea.classList.remove('border-red-500'); });
|
707 |
}
|
708 |
function enhanceRadioButtons() {
|
709 |
document.querySelectorAll('input[type="radio"] + span').forEach(label => {
|
710 |
const input = label.previousElementSibling; if (input.disabled) return;
|
711 |
-
label.addEventListener('mouseenter', () => { if (!input.checked) label.classList.add('border-blue-400', 'shadow-md', 'transform' ,'-translate-y-px'); });
|
712 |
label.addEventListener('mouseleave', () => { if (!input.checked) label.classList.remove('border-blue-400', 'shadow-md', 'transform', '-translate-y-px'); });
|
713 |
input.addEventListener('change', () => {
|
714 |
const groupName = input.name;
|
@@ -720,7 +658,6 @@
|
|
720 |
});
|
721 |
}
|
722 |
|
723 |
-
|
724 |
// --- Initialisation Générale ---
|
725 |
document.addEventListener('DOMContentLoaded', () => {
|
726 |
initializeFileUpload();
|
@@ -731,23 +668,21 @@
|
|
731 |
enhanceRadioButtons();
|
732 |
checkDeepThinkAvailability();
|
733 |
afficherSauvegardes();
|
734 |
-
// MathJax retiré
|
735 |
|
736 |
-
// Welcome Message
|
737 |
try {
|
738 |
const showWelcome = sessionStorage.getItem('welcomeShown') !== 'true';
|
739 |
if (showWelcome) {
|
740 |
-
const
|
741 |
-
|
742 |
-
document.body.appendChild(
|
743 |
-
const
|
744 |
-
setTimeout(() => {
|
745 |
-
|
746 |
-
setTimeout(() => { if (document.body.contains(
|
747 |
sessionStorage.setItem('welcomeShown', 'true');
|
748 |
}
|
749 |
-
} catch(e) { console.warn("
|
750 |
-
|
751 |
function closeWelcomeMessage(element) {
|
752 |
element.classList.add('opacity-0', 'translate-y-4'); element.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
|
753 |
setTimeout(() => { if (element?.parentElement) element.parentElement.remove(); }, 300);
|
|
|
150 |
|
151 |
<body class="min-h-screen bg-gradient-to-br from-blue-50 via-white to-blue-50 text-gray-800">
|
152 |
<nav class="glassmorphism sticky top-0 z-50 border-b border-blue-100">
|
153 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
154 |
+
<div class="container mx-auto px-4 sm:px-6 py-3 sm:py-4"> <!-- Ajustement padding nav -->
|
155 |
<div class="flex items-center justify-between">
|
156 |
<div class="flex items-center space-x-3 sm:space-x-4">
|
157 |
<div class="bg-gradient-to-r from-blue-600 to-blue-800 rounded-lg p-2 shadow-lg transform hover:scale-110 transition-transform duration-300">
|
158 |
+
<i class="fas fa-robot text-white text-lg sm:text-xl"></i> <!-- Taille icône -->
|
159 |
</div>
|
160 |
+
<h1 class="text-xl sm:text-2xl font-bold gradient-text">Mariam AI</h1> <!-- Taille titre -->
|
161 |
</div>
|
162 |
+
<div class="text-xs sm:text-sm text-blue-900 font-medium bg-blue-50 py-1 px-3 sm:px-4 rounded-full shadow-sm hidden sm:block">Assistant Français</div> <!-- Masqué sur xs -->
|
163 |
+
<div class="text-xs text-blue-900 font-medium bg-blue-50 py-1 px-3 rounded-full shadow-sm sm:hidden">Assistant</div> <!-- Version courte pour xs -->
|
164 |
</div>
|
165 |
</div>
|
166 |
</nav>
|
167 |
|
168 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
169 |
+
<main class="container mx-auto px-4 sm:px-6 py-8 sm:py-12"> <!-- Ajustement padding main -->
|
170 |
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 sm:gap-8">
|
171 |
<!-- Section Travail Argumentatif -->
|
172 |
<div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in">
|
173 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
174 |
+
<div class="p-6 sm:p-8"> <!-- Ajustement padding carte -->
|
175 |
<div class="flex items-center space-x-3 sm:space-x-4 mb-6 sm:mb-8">
|
176 |
<div class="bg-blue-100 rounded-lg p-2 sm:p-3 transform rotate-3">
|
177 |
<i class="fas fa-pen-fancy text-blue-600 text-lg sm:text-xl"></i>
|
178 |
</div>
|
179 |
<h2 class="text-xl sm:text-2xl font-bold text-gray-800">Travail Argumentatif</h2>
|
180 |
</div>
|
181 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
182 |
+
<form id="francais-form" class="space-y-6 sm:space-y-8"> <!-- Ajustement espacement -->
|
183 |
<div class="space-y-2">
|
184 |
<label for="sujet-francais" class="block text-sm font-medium text-gray-700 flex items-center">
|
185 |
<i class="fas fa-book-open mr-2 text-blue-500"></i>Sujet <span class="text-red-500 ml-1">*</span>
|
|
|
196 |
<label class="block text-sm font-medium text-gray-700 flex items-center">
|
197 |
<i class="fas fa-tasks mr-2 text-blue-500"></i>Type d'argumentation
|
198 |
</label>
|
199 |
+
<!-- Grid s'adapte déjà bien (2 cols par défaut, 4 sur sm+) -->
|
200 |
<div class="grid grid-cols-2 sm:grid-cols-4 gap-3 sm:gap-4">
|
201 |
<label class="relative">
|
202 |
<input type="radio" name="choix" value="Etaye" class="custom-radio absolute opacity-0 w-full h-full cursor-pointer" checked>
|
|
|
253 |
</div>
|
254 |
</button>
|
255 |
</form>
|
256 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
257 |
+
<div id="francais-output" class="mt-6 sm:mt-8 p-4 sm:p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner min-h-[150px]"> <!-- Ajustement padding et min-height -->
|
258 |
<!-- Le contenu généré sera inséré ici -->
|
259 |
</div>
|
260 |
</div>
|
|
|
262 |
|
263 |
<!-- Section Étude de texte -->
|
264 |
<div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in" style="animation-delay: 0.1s;">
|
265 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
266 |
+
<div class="p-6 sm:p-8"> <!-- Ajustement padding carte -->
|
267 |
<div class="flex items-center space-x-3 sm:space-x-4 mb-6 sm:mb-8">
|
268 |
<div class="bg-blue-100 rounded-lg p-2 sm:p-3 transform -rotate-3">
|
269 |
<i class="fas fa-file-alt text-blue-600 text-lg sm:text-xl"></i>
|
|
|
297 |
</div>
|
298 |
</button>
|
299 |
</form>
|
300 |
+
<!-- CORRECTION: Remplacement {* *} par <!-- -->
|
301 |
+
<div id="etude-texte-output" class="mt-6 sm:mt-8 p-4 sm:p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner min-h-[150px]"> <!-- Ajustement padding et min-height -->
|
302 |
<!-- Le contenu analysé sera inséré ici -->
|
303 |
</div>
|
304 |
</div>
|
|
|
348 |
const dropZone = document.getElementById('drop-zone');
|
349 |
const fileInput = document.getElementById('image-upload');
|
350 |
const imagePreview = document.getElementById('image-preview');
|
351 |
+
if(!dropZone || !fileInput || !imagePreview) return;
|
352 |
|
353 |
dropZone.addEventListener('click', () => fileInput.click());
|
354 |
['dragenter', 'dragover'].forEach(ev => dropZone.addEventListener(ev, highlightDropZone));
|
|
|
406 |
sauvegardes.push({ titre: titre || "Sauvegarde", contenu, date: dateSauvegarde });
|
407 |
try {
|
408 |
localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
|
409 |
+
displayNotification("Sauvegardé", "success");
|
410 |
afficherSauvegardes();
|
411 |
} catch (e) {
|
412 |
console.error("Erreur sauvegarde localStorage:", e);
|
|
|
416 |
|
417 |
function displayNotification(message, type = 'success') {
|
418 |
const notification = document.createElement('div');
|
419 |
+
const colors = { success: 'bg-green-50 border-green-200 text-green-700', error: 'bg-red-50 border-red-200 text-red-700', warning: 'bg-yellow-50 border-yellow-200 text-yellow-700' };
|
|
|
|
|
|
|
|
|
420 |
const icons = { success: 'fa-check-circle text-green-500', error: 'fa-exclamation-circle text-red-500', warning: 'fa-exclamation-triangle text-yellow-500' };
|
421 |
+
notification.className = `fixed bottom-4 right-4 sm:bottom-6 sm:right-6 border ${colors[type] || colors.success} px-4 py-3 rounded-lg shadow-lg z-[100] flex items-center scale-in max-w-[calc(100%-2rem)] sm:max-w-sm`;
|
422 |
notification.innerHTML = `<i class="fas ${icons[type] || icons.success} mr-3 text-lg flex-shrink-0"></i><span class="text-sm font-medium">${message}</span>`;
|
423 |
document.body.appendChild(notification);
|
424 |
const duration = type === 'error' ? 6000 : 3000;
|
|
|
435 |
sauvegardes.splice(originalIndex, 1);
|
436 |
localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
|
437 |
afficherSauvegardes();
|
438 |
+
} else { console.error("Index suppression invalide:", originalIndex); displayNotification("Erreur suppression", "error"); }
|
439 |
+
} catch (e) { console.error("Erreur suppression sauvegarde:", e); displayNotification("Erreur suppression", "error"); }
|
|
|
|
|
|
|
|
|
|
|
|
|
440 |
}
|
441 |
|
442 |
function afficherSauvegardes() {
|
443 |
const backupsList = document.getElementById('backups-list');
|
444 |
if(!backupsList) return;
|
445 |
let sauvegardes = [];
|
446 |
+
try { sauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]'); } catch(e) { console.error("Erreur lecture sauvegardes:", e); }
|
|
|
|
|
|
|
447 |
sauvegardes.sort((a, b) => new Date(b.date) - new Date(a.date));
|
448 |
backupsList.innerHTML = '';
|
449 |
|
|
|
452 |
return;
|
453 |
}
|
454 |
|
455 |
+
sauvegardes.forEach((sauvegarde) => { // Removed unused index
|
456 |
const date = new Date(sauvegarde.date);
|
457 |
+
const formattedDate = date.toLocaleDateString('fr-FR', { day: 'numeric', month: 'short', hour: '2-digit', minute: '2-digit' }); // Shorter date
|
458 |
+
const displayTitle = (sauvegarde.titre || "Sans titre").length > 40 ? sauvegarde.titre.substring(0, 37) + '...' : (sauvegarde.titre || "Sans titre"); // Shorter title
|
459 |
|
460 |
const sauvegardeDiv = document.createElement('div');
|
461 |
+
sauvegardeDiv.dataset.originalDate = sauvegarde.date;
|
462 |
sauvegardeDiv.className = 'bg-white rounded-lg shadow-md p-4 relative backup-item hover:bg-blue-50 transition-all duration-200';
|
463 |
sauvegardeDiv.innerHTML = `
|
464 |
<div class="flex items-start cursor-pointer item-header">
|
465 |
<div class="bg-blue-100 rounded-lg p-2 mr-3 flex-shrink-0"> <i class="fas fa-file-alt text-blue-600 text-sm"></i> </div>
|
466 |
<div class="flex-grow overflow-hidden mr-2">
|
467 |
+
<h3 class="text-base font-semibold text-gray-800 truncate" title="${sauvegarde.titre || 'Sans titre'}">${displayTitle}</h3>
|
468 |
+
<p class="text-xs text-gray-500 mb-1 flex items-center"> <i class="fas fa-clock text-xs mr-1 text-gray-400"></i> ${formattedDate} </p>
|
469 |
</div>
|
470 |
<div class="flex space-x-1 sm:space-x-2 ml-auto flex-shrink-0">
|
471 |
<button class="text-gray-400 hover:text-blue-600 focus:outline-none copy-btn p-1 rounded-full hover:bg-gray-100" title="Copier"> <i class="fas fa-copy text-xs sm:text-sm"></i> </button>
|
|
|
480 |
|
481 |
headerDiv.addEventListener('click', () => {
|
482 |
const isExpanded = backupContentDiv.classList.contains('backup-content-expanded');
|
483 |
+
document.querySelectorAll('.backup-content-expanded').forEach(content => { if (content !== backupContentDiv) { content.classList.remove('backup-content-expanded'); content.innerHTML = ''; } });
|
|
|
|
|
484 |
if (!isExpanded) {
|
485 |
+
try { backupContentDiv.innerHTML = marked.parse(sauvegarde.contenu || ''); } catch(e) { backupContentDiv.innerHTML = "Erreur d'affichage."; console.error(e); }
|
486 |
backupContentDiv.classList.add('backup-content-expanded');
|
487 |
+
} else { backupContentDiv.classList.remove('backup-content-expanded'); backupContentDiv.innerHTML = ''; }
|
|
|
|
|
|
|
488 |
});
|
489 |
|
490 |
sauvegardeDiv.querySelector('.copy-btn').addEventListener('click', (e) => {
|
491 |
e.stopPropagation();
|
492 |
navigator.clipboard.writeText(sauvegarde.contenu || '').then(() => {
|
493 |
+
const icon = e.currentTarget.querySelector('i'); icon.className = 'fas fa-check text-green-500 text-xs sm:text-sm'; setTimeout(() => { icon.className = 'fas fa-copy text-xs sm:text-sm'; }, 1500); // Shorter duration
|
494 |
}).catch(err => { console.error('Copy error:', err); displayNotification("Erreur copie", "error"); });
|
495 |
});
|
496 |
|
497 |
sauvegardeDiv.querySelector('.delete-btn').addEventListener('click', (e) => {
|
498 |
e.stopPropagation();
|
499 |
const itemDate = sauvegardeDiv.dataset.originalDate;
|
500 |
+
let originalIndex = -1;
|
501 |
+
try { const originalSauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]'); originalIndex = originalSauvegardes.findIndex(s => s.date === itemDate); } catch (err) { console.error("Erreur recherche sauvegarde:", err); }
|
502 |
+
if (originalIndex === -1) { console.error("Item not found by date:", itemDate); displayNotification("Erreur suppression", "error"); return; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
503 |
|
504 |
const confirmationModal = document.createElement('div');
|
505 |
+
confirmationModal.className = 'fixed inset-0 flex items-center justify-center z-[100] bg-black bg-opacity-50 scale-in p-4';
|
506 |
confirmationModal.innerHTML = `
|
507 |
<div class="bg-white rounded-lg p-5 sm:p-6 max-w-sm w-full shadow-xl">
|
508 |
<div class="flex items-center mb-4"> <div class="bg-red-100 rounded-full p-2 mr-3"><i class="fas fa-exclamation-triangle text-red-500"></i></div> <h3 class="text-base sm:text-lg font-semibold text-gray-800">Confirmation</h3> </div>
|
|
|
518 |
}
|
519 |
|
520 |
function closeModal(modalElement) {
|
521 |
+
modalElement.style.opacity = '0'; modalElement.style.transition = 'opacity 0.3s ease';
|
|
|
522 |
setTimeout(() => { if (document.body.contains(modalElement)) document.body.removeChild(modalElement); }, 300);
|
523 |
}
|
524 |
|
|
|
525 |
// --- Gestion DeepThink ---
|
526 |
function checkDeepThinkAvailability() {
|
527 |
const checkbox = document.getElementById('deepthink-checkbox');
|
|
|
530 |
try {
|
531 |
const lastUsedDateStr = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
|
532 |
const todayStr = new Date().toISOString().split('T')[0];
|
533 |
+
if (lastUsedDateStr === todayStr) { checkbox.checked = false; checkbox.disabled = true; statusSpan.textContent = "(utilisé)"; statusSpan.classList.add('text-red-500'); }
|
534 |
+
else { checkbox.disabled = false; statusSpan.textContent = ""; statusSpan.classList.remove('text-red-500'); }
|
535 |
+
} catch (e) { console.error("Erreur localStorage (DeepThink):", e); checkbox.disabled = true; statusSpan.textContent = "(erreur)"; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
536 |
}
|
537 |
|
538 |
// --- Soumission des formulaires ---
|
|
|
541 |
const output = document.getElementById('francais-output');
|
542 |
const sujetTextarea = document.getElementById('sujet-francais');
|
543 |
const deepThinkCheckbox = document.getElementById('deepthink-checkbox');
|
544 |
+
const submitButton = form.querySelector('button[type="submit"]');
|
545 |
+
if(!form || !output || !sujetTextarea || !deepThinkCheckbox || !submitButton) return;
|
|
|
546 |
|
547 |
form.addEventListener('submit', async (e) => {
|
548 |
e.preventDefault();
|
549 |
+
const originalButtonContent = submitButton.innerHTML;
|
550 |
+
submitButton.disabled = true;
|
551 |
+
submitButton.innerHTML = `<div class="flex items-center justify-center"><div class="loader"><div></div><div></div><div></div><div></div></div><span class="ml-2 text-sm sm:text-base">Génération...</span></div>`; // Responsive text
|
552 |
|
553 |
const sujetValue = sujetTextarea.value.trim();
|
554 |
const isDeepThinkChecked = deepThinkCheckbox.checked;
|
|
|
557 |
if (!sujetValue) {
|
558 |
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Champ obligatoire</p><p>Veuillez entrer un sujet.</p></div></div>`;
|
559 |
sujetTextarea.focus(); sujetTextarea.classList.add('border-red-500'); setTimeout(() => sujetTextarea.classList.remove('border-red-500'), 3000);
|
560 |
+
submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; return;
|
|
|
561 |
}
|
562 |
if (isDeepThinkChecked) {
|
563 |
try {
|
564 |
const lastUsedDateStr = localStorage.getItem(DEEPTHINK_STORAGE_KEY);
|
565 |
const todayStr = new Date().toISOString().split('T')[0];
|
566 |
if (lastUsedDateStr === todayStr) {
|
567 |
+
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Limite atteinte</p><p>DeepThink déjà utilisé.</p></div></div>`; // Shorter message
|
568 |
+
checkDeepThinkAvailability(); submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; return;
|
|
|
|
|
569 |
}
|
570 |
+
} catch(e) { /* Proceed without check if localStorage fails */ }
|
571 |
}
|
572 |
+
output.innerHTML = `<div class="flex justify-center items-center p-6"><div class="loader"><div></div><div></div><div></div><div></div></div></div>`;
|
573 |
|
574 |
+
const formData = new FormData(form); formData.append('use_deepthink', isDeepThinkChecked);
|
|
|
|
|
|
|
|
|
|
|
|
|
575 |
try {
|
576 |
const response = await fetch('/api/francais', { method: 'POST', body: formData });
|
577 |
const result = await response.json();
|
578 |
if (!response.ok) throw new Error(result.output || `Erreur HTTP ${response.status}`);
|
579 |
|
580 |
+
try { output.innerHTML = marked.parse(result.output || ''); } catch (e) { output.innerHTML = "Erreur d'affichage."; console.error(e); }
|
|
|
581 |
|
582 |
+
const titreSauvegarde = sujetValue.substring(0, 40) + (sujetValue.length > 40 ? '...' : ''); // Even shorter title
|
583 |
+
const deepThinkSuffix = isDeepThinkChecked ? ' [DT]' : ''; // Shorter suffix
|
584 |
sauvegarderReponse(titreSauvegarde + deepThinkSuffix, result.output);
|
585 |
|
586 |
if (isDeepThinkChecked) {
|
587 |
+
try { const todayStr = new Date().toISOString().split('T')[0]; localStorage.setItem(DEEPTHINK_STORAGE_KEY, todayStr); checkDeepThinkAvailability(); }
|
588 |
+
catch(e) { console.error("Erreur sauvegarde date DT:", e); }
|
|
|
|
|
|
|
589 |
}
|
|
|
|
|
590 |
} catch (error) {
|
591 |
+
console.error("Erreur soumission (fr):", error);
|
592 |
output.innerHTML = `<div class="alert-message alert-danger"><i class="fas fa-exclamation-circle"></i><div><p>Erreur</p><p>${error.message || "Vérifiez la console."}</p></div></div>`;
|
593 |
+
} finally { submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; }
|
|
|
|
|
|
|
594 |
});
|
595 |
}
|
596 |
|
|
|
598 |
const form = document.getElementById('etude-texte-form');
|
599 |
const output = document.getElementById('etude-texte-output');
|
600 |
const fileInput = document.getElementById('image-upload');
|
601 |
+
const submitButton = form.querySelector('button[type="submit"]');
|
602 |
+
if(!form || !output || !fileInput || !submitButton) return;
|
|
|
603 |
|
604 |
form.addEventListener('submit', async (e) => {
|
605 |
e.preventDefault();
|
606 |
+
const originalButtonContent = submitButton.innerHTML;
|
607 |
+
submitButton.disabled = true;
|
608 |
+
submitButton.innerHTML = `<div class="flex items-center justify-center"><div class="loader"><div></div><div></div><div></div><div></div></div><span class="ml-2 text-sm sm:text-base">Analyse...</span></div>`; // Responsive text
|
|
|
609 |
|
610 |
if (uploadedFiles.size === 0) {
|
611 |
output.innerHTML = `<div class="alert-message alert-warning"><i class="fas fa-exclamation-triangle"></i><div><p>Aucune image</p><p>Ajoutez au moins une image.</p></div></div>`;
|
612 |
+
submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; return;
|
|
|
613 |
}
|
|
|
|
|
614 |
output.innerHTML = `<div class="flex justify-center items-center p-6"><div class="loader"><div></div><div></div><div></div><div></div></div></div>`;
|
615 |
|
616 |
+
const formData = new FormData(); uploadedFiles.forEach((file) => formData.append('images', file, file.name));
|
|
|
617 |
try {
|
618 |
const response = await fetch('/api/etude-texte', { method: 'POST', body: formData });
|
619 |
const result = await response.json();
|
620 |
if (!response.ok) throw new Error(result.output || `Erreur HTTP ${response.status}`);
|
621 |
|
622 |
+
try { output.innerHTML = marked.parse(result.output || ''); } catch (e) { output.innerHTML = "Erreur d'affichage."; console.error(e); }
|
623 |
|
624 |
+
const titre = `Analyse img ${new Date().toLocaleDateString('fr-FR', { month: 'short', day: 'numeric' })}`; // Shorter title
|
625 |
sauvegarderReponse(titre, result.output);
|
|
|
626 |
} catch (error) {
|
627 |
+
console.error("Erreur soumission (img):", error);
|
628 |
output.innerHTML = `<div class="alert-message alert-danger"><i class="fas fa-exclamation-circle"></i><div><p>Erreur</p><p>${error.message || "Vérifiez la console."}</p></div></div>`;
|
629 |
+
} finally { submitButton.disabled = false; submitButton.innerHTML = originalButtonContent; }
|
|
|
|
|
|
|
630 |
});
|
631 |
}
|
632 |
|
|
|
635 |
const cards = document.querySelectorAll('.card-hover');
|
636 |
if (!('IntersectionObserver' in window)) { cards.forEach(card => card.style.opacity = '1'); return; }
|
637 |
const observer = new IntersectionObserver((entries) => {
|
638 |
+
entries.forEach((entry) => { if (entry.isIntersecting) { requestAnimationFrame(() => { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; }); observer.unobserve(entry.target); } });
|
639 |
+
}, { threshold: 0.05 });
|
640 |
+
cards.forEach(card => { card.style.opacity = '0'; card.style.transform = 'translateY(20px)'; observer.observe(card); });
|
|
|
|
|
641 |
}
|
642 |
function enhanceTextareaFocus() {
|
643 |
+
const textarea = document.getElementById('sujet-francais'); const counter = document.getElementById('character-count'); if(!textarea || !counter) return;
|
644 |
+
textarea.addEventListener('input', () => { const length = textarea.value.length; counter.textContent = `${length}c`; textarea.classList.remove('border-red-500'); }); // Shorter counter
|
|
|
|
|
645 |
}
|
646 |
function enhanceRadioButtons() {
|
647 |
document.querySelectorAll('input[type="radio"] + span').forEach(label => {
|
648 |
const input = label.previousElementSibling; if (input.disabled) return;
|
649 |
+
label.addEventListener('mouseenter', () => { if (!input.checked) label.classList.add('border-blue-400', 'shadow-md', 'transform' ,'-translate-y-px'); });
|
650 |
label.addEventListener('mouseleave', () => { if (!input.checked) label.classList.remove('border-blue-400', 'shadow-md', 'transform', '-translate-y-px'); });
|
651 |
input.addEventListener('change', () => {
|
652 |
const groupName = input.name;
|
|
|
658 |
});
|
659 |
}
|
660 |
|
|
|
661 |
// --- Initialisation Générale ---
|
662 |
document.addEventListener('DOMContentLoaded', () => {
|
663 |
initializeFileUpload();
|
|
|
668 |
enhanceRadioButtons();
|
669 |
checkDeepThinkAvailability();
|
670 |
afficherSauvegardes();
|
|
|
671 |
|
672 |
+
// Welcome Message
|
673 |
try {
|
674 |
const showWelcome = sessionStorage.getItem('welcomeShown') !== 'true';
|
675 |
if (showWelcome) {
|
676 |
+
const welcomeContainer = document.createElement('div');
|
677 |
+
welcomeContainer.innerHTML = `<div class="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 bg-white rounded-xl shadow-lg p-4 transform transition-all duration-500 opacity-0 translate-y-4 max-w-[calc(100%-2rem)] sm:max-w-xs z-[100]"><div class="flex items-start space-x-3"><div class="bg-gradient-to-r from-blue-500 to-blue-700 rounded-full p-2 mt-1 flex-shrink-0"><i class="fas fa-robot text-white text-lg"></i></div><div><p class="text-sm font-semibold text-gray-800">Bienvenue !</p><p class="text-xs text-gray-500 mt-1">Assistant prêt.</p></div></div><button class="absolute top-1 right-1 text-gray-400 hover:text-gray-600 close-welcome p-1"><i class="fas fa-times text-xs"></i></button></div>`;
|
678 |
+
document.body.appendChild(welcomeContainer);
|
679 |
+
const welcomeMsg = welcomeContainer.firstElementChild;
|
680 |
+
setTimeout(() => { welcomeMsg.classList.remove('opacity-0', 'translate-y-4'); }, 500);
|
681 |
+
welcomeMsg.querySelector('.close-welcome').addEventListener('click', () => closeWelcomeMessage(welcomeMsg));
|
682 |
+
setTimeout(() => { if (document.body.contains(welcomeMsg)) closeWelcomeMessage(welcomeMsg); }, 6000); // Shorter duration
|
683 |
sessionStorage.setItem('welcomeShown', 'true');
|
684 |
}
|
685 |
+
} catch(e) { console.warn("SessionStorage (Welcome):", e); }
|
|
|
686 |
function closeWelcomeMessage(element) {
|
687 |
element.classList.add('opacity-0', 'translate-y-4'); element.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
|
688 |
setTimeout(() => { if (element?.parentElement) element.parentElement.remove(); }, 300);
|