Docfile commited on
Commit
05c4f0f
·
verified ·
1 Parent(s): b7f4801

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +517 -128
templates/index.html CHANGED
@@ -11,15 +11,29 @@
11
  <style>
12
  @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&display=swap');
13
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  body {
15
  font-family: 'Plus Jakarta Sans', sans-serif;
16
  background-color: #fafafa;
 
17
  }
18
 
19
  .glassmorphism {
20
  background: rgba(255, 255, 255, 0.95);
21
  backdrop-filter: blur(10px);
22
  border: 1px solid rgba(255, 255, 255, 0.3);
 
23
  }
24
 
25
  .card-hover {
@@ -32,7 +46,7 @@
32
  }
33
 
34
  .gradient-text {
35
- background: linear-gradient(135deg, #1a365d 0%, #3182ce 100%);
36
  -webkit-background-clip: text;
37
  -webkit-text-fill-color: transparent;
38
  }
@@ -50,90 +64,255 @@
50
  }
51
 
52
  @keyframes bounce {
53
- 0%,
54
- 80%,
55
- 100% {
56
  transform: translateY(0);
57
  }
58
-
59
  40% {
60
  transform: translateY(-6px);
61
  }
62
  }
63
 
64
  .custom-radio:checked+span {
65
- background: linear-gradient(135deg, #1a365d 0%, #3182ce 100%);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  color: white;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
67
  }
68
 
69
  .backup-item {
70
  cursor: pointer;
 
 
 
 
 
 
71
  }
72
 
73
  .backup-content {
74
  display: none;
75
  margin-top: 10px;
 
 
 
76
  }
77
 
78
  .backup-content-expanded {
79
  display: block;
 
80
  }
81
 
82
  /* Styles for multiple image upload */
83
  .image-preview {
84
  display: flex;
85
  flex-wrap: wrap;
86
- gap: 10px;
87
- margin-top: 10px;
88
  }
89
 
90
  .image-preview-item {
91
  position: relative;
92
- width: 100px;
93
- height: 100px;
 
 
 
 
 
 
 
 
94
  }
95
 
96
  .image-preview-item img {
97
  width: 100%;
98
  height: 100%;
99
  object-fit: cover;
100
- border-radius: 5px;
101
  }
102
 
103
  .remove-image {
104
  position: absolute;
105
  top: 5px;
106
  right: 5px;
107
- background-color: rgba(0, 0, 0, 0.5);
108
  color: white;
109
  border: none;
110
  border-radius: 50%;
111
- padding: 2px 6px;
 
 
 
 
112
  cursor: pointer;
113
  font-size: 12px;
 
 
 
 
 
 
114
  }
115
 
116
  .remove-image:hover {
117
- background-color: rgba(0, 0, 0, 0.7);
 
118
  }
119
 
 
 
 
 
 
 
 
 
120
 
121
- /* Style pour préserver les espaces dans le markdown */
122
- .prose {
123
- white-space: pre-wrap; /* preserve line breaks and spaces */
124
- word-wrap: break-word; /* break long words */
125
- overflow-wrap: break-word; /* allow words to break */
126
- }
127
 
128
- /* Style optionnel pour améliorer la lisibilité sur mobile */
129
- @media (max-width: 640px) {
130
- .prose {
131
- font-size: 0.95rem;
132
- line-height: 1.6;
133
- }
134
- }
135
 
136
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  </style>
138
  </head>
139
 
@@ -142,12 +321,12 @@
142
  <div class="container mx-auto px-6 py-4">
143
  <div class="flex items-center justify-between">
144
  <div class="flex items-center space-x-4">
145
- <div class="bg-blue-600 rounded-lg p-2 shadow-lg">
146
  <i class="fas fa-robot text-white text-xl"></i>
147
  </div>
148
  <h1 class="text-2xl font-bold gradient-text">Mariam AI</h1>
149
  </div>
150
- <div class="text-blue-900 font-medium">Assistant Français Intelligent</div>
151
  </div>
152
  </div>
153
  </nav>
@@ -155,29 +334,32 @@
155
  <main class="container mx-auto px-6 py-12">
156
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
157
  <!-- Section Travail Argumentatif -->
158
- <div class="card-hover glassmorphism rounded-2xl overflow-hidden">
159
  <div class="p-8">
160
  <div class="flex items-center space-x-4 mb-8">
161
- <div class="bg-blue-100 rounded-lg p-3">
162
  <i class="fas fa-pen-fancy text-blue-600 text-xl"></i>
163
  </div>
164
  <h2 class="text-2xl font-bold text-gray-800">Travail Argumentatif</h2>
165
  </div>
166
  <form id="francais-form" class="space-y-8">
167
  <div class="space-y-3">
168
- <label for="sujet-francais" class="block text-sm font-medium text-gray-700">
169
  <i class="fas fa-book-open mr-2 text-blue-500"></i>Sujet
170
  </label>
171
- <textarea id="sujet-francais" name="sujet" rows="4"
172
- class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-blue-500 focus:ring-2 focus:ring-blue-200 transition-all duration-200 resize-none"
173
- placeholder="Entrez votre sujet ici..."></textarea>
 
 
 
174
  </div>
175
 
176
  <div class="space-y-4">
177
- <label class="block text-sm font-medium text-gray-700">
178
  <i class="fas fa-tasks mr-2 text-blue-500"></i>Type d'argumentation
179
  </label>
180
- <div class="grid grid-cols-3 gap-4">
181
  <label class="relative">
182
  <input type="radio" name="choix" value="Etaye"
183
  class="custom-radio absolute opacity-0 w-full h-full cursor-pointer" checked>
@@ -202,11 +384,19 @@
202
  Discuter
203
  </span>
204
  </label>
 
 
 
 
 
 
 
 
205
  </div>
206
  </div>
207
 
208
  <div class="space-y-4">
209
- <label class="block text-sm font-medium text-gray-700">
210
  <i class="fas fa-feather-alt mr-2 text-blue-500"></i>Style d'écriture
211
  </label>
212
  <div class="grid grid-cols-2 gap-4">
@@ -237,31 +427,31 @@
237
  </div>
238
  </button>
239
  </form>
240
- <div id="francais-output" class="mt-8 p-6 bg-blue-50 rounded-xl prose max-w-none">
241
  <!-- Le contenu généré sera inséré ici -->
242
  </div>
243
  </div>
244
  </div>
245
 
246
  <!-- Section Étude de texte -->
247
- <div class="card-hover glassmorphism rounded-2xl overflow-hidden">
248
  <div class="p-8">
249
  <div class="flex items-center space-x-4 mb-8">
250
- <div class="bg-blue-100 rounded-lg p-3">
251
  <i class="fas fa-file-alt text-blue-600 text-xl"></i>
252
  </div>
253
  <h2 class="text-2xl font-bold text-gray-800">Étude de texte</h2>
254
  </div>
255
  <form id="etude-texte-form" class="space-y-8" enctype="multipart/form-data">
256
  <div class="space-y-4">
257
- <label class="block text-sm font-medium text-gray-700">
258
  <i class="fas fa-image mr-2 text-blue-500"></i>Image du texte
259
  </label>
260
- <div class="border-3 border-dashed border-gray-300 rounded-xl p-8 text-center cursor-pointer hover:border-blue-400 transition-all duration-200"
261
  id="drop-zone">
262
  <input type="file" id="image-upload" name="images" accept="image/*" class="hidden" multiple>
263
- <div class="space-y-3">
264
- <div class="bg-blue-50 rounded-full w-16 h-16 flex items-center justify-center mx-auto">
265
  <i class="fas fa-cloud-upload-alt text-3xl text-blue-500"></i>
266
  </div>
267
  <p class="text-sm text-gray-600 font-medium">Glissez vos images ici ou cliquez
@@ -280,20 +470,46 @@
280
  </div>
281
  </button>
282
  </form>
283
- <div id="etude-texte-output" class="mt-8 p-6 bg-blue-50 rounded-xl prose max-w-none">
284
  <!-- Le contenu analysé sera inséré ici -->
285
  </div>
286
  </div>
287
  </div>
288
  </div>
289
  <div class="mt-12">
290
- <h2 class="text-2xl font-bold text-gray-800 mb-4">Sauvegardes</h2>
 
 
 
291
  <div id="backups-list" class="space-y-4">
292
  <!-- Les sauvegardes seront listées ici -->
293
  </div>
294
  </div>
295
  </main>
296
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
297
  <script>
298
  function initializeFileUpload() {
299
  const dropZone = document.getElementById('drop-zone');
@@ -336,22 +552,27 @@
336
  const reader = new FileReader();
337
  reader.onload = (e) => {
338
  const previewItem = document.createElement('div');
339
- previewItem.classList.add('image-preview-item');
340
  previewItem.innerHTML = `
341
  <img src="${e.target.result}" alt="${file.name}">
342
- <button class="remove-image" title="Supprimer">×</button>
343
  `;
344
  imagePreview.appendChild(previewItem);
345
 
346
  // Remove image event
347
  previewItem.querySelector('.remove-image').addEventListener('click', () => {
348
- imagePreview.removeChild(previewItem);
 
 
 
 
349
  });
350
  };
351
  reader.readAsDataURL(file);
352
  }
353
  }
354
  }
 
355
  function sauvegarderReponse(titre, contenu) {
356
  const sauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]');
357
  const dateSauvegarde = new Date().toISOString();
@@ -361,6 +582,24 @@
361
  date: dateSauvegarde
362
  });
363
  localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
364
  afficherSauvegardes();
365
  }
366
 
@@ -376,41 +615,129 @@
376
  const backupsList = document.getElementById('backups-list');
377
  backupsList.innerHTML = '';
378
  if (sauvegardes.length === 0) {
379
- backupsList.innerHTML = '<p class="text-gray-600">Aucune sauvegarde pour le moment.</p>';
 
 
 
 
 
 
 
 
380
  return;
381
  }
382
 
383
  sauvegardes.forEach((sauvegarde, index) => {
 
 
 
 
 
 
 
 
 
384
  const sauvegardeDiv = document.createElement('div');
385
- sauvegardeDiv.className = 'bg-white rounded-lg shadow-md p-4 relative backup-item';
386
  sauvegardeDiv.innerHTML = `
387
- <h3 class="text-lg font-semibold text-gray-800">${sauvegarde.titre}</h3>
388
- <p class="text-sm text-gray-600 mb-2">${new Date(sauvegarde.date).toLocaleString()}</p>
389
- <div class="text-sm text-gray-700 backup-content prose max-w-none">${marked.parse(sauvegarde.contenu)}</div>
390
- <button class="absolute top-2 right-2 text-red-500 hover:text-red-700 focus:outline-none" data-index="${index}">
391
- <i class="fas fa-trash"></i>
392
- </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
393
  `;
394
  backupsList.appendChild(sauvegardeDiv);
395
 
396
  // Gestion de l'expansion/contraction du contenu
397
  const backupContentDiv = sauvegardeDiv.querySelector('.backup-content');
398
- const backupItemDiv = sauvegardeDiv; // Utilisez toute la
399
-
400
- backupItemDiv.addEventListener('click', (e) => {
401
- if (e.target.tagName === "BUTTON") return; // Ignorer les clics sur le bouton supprimer
 
 
 
 
 
 
 
402
  backupContentDiv.classList.toggle('backup-content-expanded');
403
- MathJax.typesetPromise([backupContentDiv]); // Re-typer le contenu MathJax si nécessaire
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
  });
405
 
406
- const deleteButton = sauvegardeDiv.querySelector('button');
407
- deleteButton.addEventListener('click', () => {
408
- if (confirm('Êtes-vous sûr de vouloir supprimer cette sauvegarde ?')) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
  supprimerSauvegarde(index);
410
- }
 
 
 
 
411
  });
412
  });
413
-
414
  }
415
 
416
  async function submitFrancaisForm() {
@@ -420,11 +747,14 @@
420
  form.addEventListener('submit', async (e) => {
421
  e.preventDefault();
422
  output.innerHTML = `
423
- <div class="flex items-center justify-center space-x-2 text-blue-600">
424
- <div class="loading-dot">[x] </div>
425
- <div class="loading-dot">[x] </div>
426
- <div class="loading-dot">[x] </div>
427
- <span class="ml-3 text-sm font-medium text-gray-600">Génération en cours...</span>
 
 
 
428
  </div>`;
429
 
430
  const formData = new FormData(form);
@@ -433,16 +763,30 @@
433
  method: 'POST',
434
  body: formData
435
  });
 
 
 
 
 
436
  const result = await response.json();
437
- const sujet = formData.get('sujet');
438
- output.innerHTML = marked.parse(result.output);
439
- sauvegarderReponse(sujet, result.output);
440
- MathJax.typesetPromise([output]);
 
 
 
 
 
 
441
  } catch (error) {
442
  output.innerHTML = `
443
- <div class="flex items-center space-x-2 text-red-500 bg-red-50 p-4 rounded-lg">
444
- <i class="fas fa-exclamation-circle"></i>
445
- <span class="text-sm font-medium">Une erreur est survenue. Veuillez réessayer.</span>
 
 
 
446
  </div>`;
447
  }
448
  });
@@ -454,11 +798,30 @@
454
 
455
  form.addEventListener('submit', async (e) => {
456
  e.preventDefault();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
  output.innerHTML = `
458
- <div class="flex items-center justify-center space-x-2 text-blue-600"> <div class="loading-dot">[x] </div>
459
- <div class="loading-dot">[x] </div>
460
- <div class="loading-dot">[x] </div>
461
- <span class="ml-3 text-sm font-medium text-gray-600">Analyse en cours...</span>
 
 
 
 
 
462
  </div>`;
463
 
464
  const formData = new FormData(form);
@@ -467,19 +830,31 @@
467
  method: 'POST',
468
  body: formData
469
  });
 
 
 
 
 
470
  const result = await response.json();
471
- output.innerHTML = marked.parse(result.output);
472
-
473
- // Titre par défaut pour les analyses d'images
474
- const titre = "Analyse d'image " + new Date().toLocaleString();
475
- sauvegarderReponse(titre, result.output)
476
-
477
- MathJax.typesetPromise([output]);
 
 
 
 
478
  } catch (error) {
479
  output.innerHTML = `
480
- <div class="flex items-center space-x-2 text-red-500 bg-red-50 p-4 rounded-lg">
481
- <i class="fas fa-exclamation-circle"></i>
482
- <span class="text-sm font-medium">Une erreur est survenue. Veuillez réessayer.</span>
 
 
 
483
  </div>`;
484
  }
485
  });
@@ -489,10 +864,12 @@
489
  function animateOnScroll() {
490
  const cards = document.querySelectorAll('.card-hover');
491
  const observer = new IntersectionObserver((entries) => {
492
- entries.forEach(entry => {
493
  if (entry.isIntersecting) {
494
- entry.target.style.opacity = '1';
495
- entry.target.style.transform = 'translateY(0)';
 
 
496
  }
497
  });
498
  }, {
@@ -501,37 +878,40 @@
501
 
502
  cards.forEach(card => {
503
  card.style.opacity = '0';
504
- card.style.transform = 'translateY(20px)';
505
  card.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
506
  observer.observe(card);
507
  });
508
  }
509
 
510
- // Effet de focus amélioré pour les zones de texte
511
  function enhanceTextareaFocus() {
512
- const textareas = document.querySelectorAll('textarea');
513
- textareas.forEach(textarea => {
514
- textarea.addEventListener('focus', () => {
515
- textarea.parentElement.classList.add('ring-2', 'ring-blue-200');
516
- });
517
- textarea.addEventListener('blur', () => {
518
- textarea.parentElement.classList.remove('ring-2', 'ring-blue-200');
519
- });
520
  });
521
  }
522
 
523
  // Effet de hover pour les boutons radio
524
  function enhanceRadioButtons() {
525
- const radioLabels = document.querySelectorAll('input[type="radio"] + span');
526
  radioLabels.forEach(label => {
527
  label.addEventListener('mouseenter', () => {
528
  if (!label.previousElementSibling.checked) {
529
  label.style.borderColor = '#3182ce';
 
 
530
  }
531
  });
 
532
  label.addEventListener('mouseleave', () => {
533
  if (!label.previousElementSibling.checked) {
534
- label.style.borderColor = '#e5e7eb'; // Couleur de bordure par défaut de Tailwind pour les éléments non actifs
 
 
535
  }
536
  });
537
  });
@@ -546,36 +926,45 @@
546
  enhanceTextareaFocus();
547
  enhanceRadioButtons();
548
 
549
- // Message de bienvenue subtil (vous pouvez supprimer cette partie si vous ne la souhaitez pas)
550
  const welcomeMessage = document.createElement('div');
551
  welcomeMessage.innerHTML = `
552
- <div class="fixed bottom-6 right-6 bg-white rounded-xl shadow-lg p-4 transform transition-all duration-500 opacity-0 translate-y-4">
553
- <div class="flex items-center space-x-3">
554
- <div class="bg-blue-100 rounded-lg p-2">
555
- <i class="fas fa-robot text-blue-600"></i>
556
- </div>
557
- <div>
558
- <p class="text-sm font-medium text-gray-800">Bienvenue sur Mariam AI</p>
559
- <p class="text-xs text-gray-500">Je suis pour vous aider</p>
560
- </div>
561
- </div>
562
- </div>
563
- `;
 
 
 
564
  document.body.appendChild(welcomeMessage);
565
 
566
  setTimeout(() => {
567
  welcomeMessage.firstElementChild.classList.remove('opacity-0', 'translate-y-4');
568
  }, 1000);
569
 
570
- setTimeout(() => {
 
571
  welcomeMessage.firstElementChild.classList.add('opacity-0', 'translate-y-4');
572
  setTimeout(() => welcomeMessage.remove(), 500);
573
- }, 5000);
 
 
 
 
 
 
 
574
 
575
  afficherSauvegardes(); // Appel de la fonction pour afficher les sauvegardes
576
  });
577
  </script>
578
- </script>
579
  </body>
580
-
581
- </html>
 
11
  <style>
12
  @import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&display=swap');
13
 
14
+ :root {
15
+ --primary: #3182ce;
16
+ --primary-dark: #1a365d;
17
+ --primary-light: #ebf8ff;
18
+ --secondary: #4a5568;
19
+ --accent: #6366f1;
20
+ --success: #38a169;
21
+ --danger: #e53e3e;
22
+ --background: #f7fafc;
23
+ --card-bg: rgba(255, 255, 255, 0.95);
24
+ }
25
+
26
  body {
27
  font-family: 'Plus Jakarta Sans', sans-serif;
28
  background-color: #fafafa;
29
+ scroll-behavior: smooth;
30
  }
31
 
32
  .glassmorphism {
33
  background: rgba(255, 255, 255, 0.95);
34
  backdrop-filter: blur(10px);
35
  border: 1px solid rgba(255, 255, 255, 0.3);
36
+ box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.07);
37
  }
38
 
39
  .card-hover {
 
46
  }
47
 
48
  .gradient-text {
49
+ background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
50
  -webkit-background-clip: text;
51
  -webkit-text-fill-color: transparent;
52
  }
 
64
  }
65
 
66
  @keyframes bounce {
67
+ 0%, 80%, 100% {
 
 
68
  transform: translateY(0);
69
  }
 
70
  40% {
71
  transform: translateY(-6px);
72
  }
73
  }
74
 
75
  .custom-radio:checked+span {
76
+ background: linear-gradient(135deg, var(--primary-dark) 0%, var(--primary) 100%);
77
+ color: white;
78
+ border-color: var(--primary);
79
+ }
80
+
81
+ .disabled-option {
82
+ background: #f9fafb;
83
+ color: #9ca3af;
84
+ border-color: #e5e7eb;
85
+ cursor: not-allowed;
86
+ position: relative;
87
+ }
88
+
89
+ .coming-soon-badge {
90
+ position: absolute;
91
+ top: -8px;
92
+ right: -8px;
93
+ background: #f97316;
94
  color: white;
95
+ font-size: 8px;
96
+ padding: 2px 6px;
97
+ border-radius: 10px;
98
+ font-weight: 600;
99
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
100
+ }
101
+
102
+ /* Animations */
103
+ @keyframes fadeIn {
104
+ from { opacity: 0; transform: translateY(10px); }
105
+ to { opacity: 1; transform: translateY(0); }
106
+ }
107
+
108
+ .fade-in {
109
+ animation: fadeIn 0.3s ease-out forwards;
110
+ }
111
+
112
+ @keyframes scaleIn {
113
+ from { transform: scale(0.95); opacity: 0; }
114
+ to { transform: scale(1); opacity: 1; }
115
+ }
116
+
117
+ .scale-in {
118
+ animation: scaleIn 0.3s ease-out forwards;
119
  }
120
 
121
  .backup-item {
122
  cursor: pointer;
123
+ transition: all 0.25s ease;
124
+ }
125
+
126
+ .backup-item:hover {
127
+ transform: translateY(-2px);
128
+ box-shadow: 0 6px 12px rgba(0, 0, 0, 0.05);
129
  }
130
 
131
  .backup-content {
132
  display: none;
133
  margin-top: 10px;
134
+ max-height: 0;
135
+ overflow: hidden;
136
+ transition: max-height 0.3s ease;
137
  }
138
 
139
  .backup-content-expanded {
140
  display: block;
141
+ max-height: 2000px;
142
  }
143
 
144
  /* Styles for multiple image upload */
145
  .image-preview {
146
  display: flex;
147
  flex-wrap: wrap;
148
+ gap: 12px;
149
+ margin-top: 15px;
150
  }
151
 
152
  .image-preview-item {
153
  position: relative;
154
+ width: 110px;
155
+ height: 110px;
156
+ border-radius: 8px;
157
+ overflow: hidden;
158
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
159
+ transition: transform 0.2s ease;
160
+ }
161
+
162
+ .image-preview-item:hover {
163
+ transform: scale(1.05);
164
  }
165
 
166
  .image-preview-item img {
167
  width: 100%;
168
  height: 100%;
169
  object-fit: cover;
 
170
  }
171
 
172
  .remove-image {
173
  position: absolute;
174
  top: 5px;
175
  right: 5px;
176
+ background-color: rgba(0, 0, 0, 0.6);
177
  color: white;
178
  border: none;
179
  border-radius: 50%;
180
+ width: 22px;
181
+ height: 22px;
182
+ display: flex;
183
+ align-items: center;
184
+ justify-content: center;
185
  cursor: pointer;
186
  font-size: 12px;
187
+ opacity: 0;
188
+ transition: opacity 0.2s, transform 0.2s;
189
+ }
190
+
191
+ .image-preview-item:hover .remove-image {
192
+ opacity: 1;
193
  }
194
 
195
  .remove-image:hover {
196
+ background-color: rgba(0, 0, 0, 0.8);
197
+ transform: scale(1.1);
198
  }
199
 
200
+ /* Style pour préserver les espaces dans le markdown */
201
+ .prose {
202
+ white-space: pre-wrap;
203
+ word-wrap: break-word;
204
+ overflow-wrap: break-word;
205
+ color: #2d3748;
206
+ line-height: 1.7;
207
+ }
208
 
209
+ .prose h1, .prose h2, .prose h3, .prose h4 {
210
+ color: var(--primary-dark);
211
+ margin-top: 1.5em;
212
+ margin-bottom: 0.5em;
213
+ font-weight: 600;
214
+ }
215
 
216
+ .prose p {
217
+ margin-bottom: 1em;
218
+ }
 
 
 
 
219
 
220
+ .prose ul, .prose ol {
221
+ padding-left: 1.5em;
222
+ margin-bottom: 1em;
223
+ }
224
+
225
+ .prose blockquote {
226
+ border-left: 4px solid var(--primary);
227
+ padding-left: 1em;
228
+ font-style: italic;
229
+ color: var(--secondary);
230
+ margin: 1em 0;
231
+ }
232
+
233
+ /* Loading animation */
234
+ .loader {
235
+ display: inline-block;
236
+ position: relative;
237
+ width: 80px;
238
+ height: 20px;
239
+ }
240
+
241
+ .loader div {
242
+ position: absolute;
243
+ top: 8px;
244
+ width: 13px;
245
+ height: 13px;
246
+ border-radius: 50%;
247
+ background: var(--primary);
248
+ animation-timing-function: cubic-bezier(0, 1, 1, 0);
249
+ }
250
+
251
+ .loader div:nth-child(1) {
252
+ left: 8px;
253
+ animation: loader1 0.6s infinite;
254
+ }
255
+
256
+ .loader div:nth-child(2) {
257
+ left: 8px;
258
+ animation: loader2 0.6s infinite;
259
+ }
260
+
261
+ .loader div:nth-child(3) {
262
+ left: 32px;
263
+ animation: loader2 0.6s infinite;
264
+ }
265
+
266
+ .loader div:nth-child(4) {
267
+ left: 56px;
268
+ animation: loader3 0.6s infinite;
269
+ }
270
+
271
+ @keyframes loader1 {
272
+ 0% {transform: scale(0);}
273
+ 100% {transform: scale(1);}
274
+ }
275
+
276
+ @keyframes loader2 {
277
+ 0% {transform: translate(0, 0);}
278
+ 100% {transform: translate(24px, 0);}
279
+ }
280
+
281
+ @keyframes loader3 {
282
+ 0% {transform: scale(1);}
283
+ 100% {transform: scale(0);}
284
+ }
285
+
286
+ /* Focus styles */
287
+ .focus-ring {
288
+ position: relative;
289
+ }
290
+
291
+ .focus-ring:focus-within::after {
292
+ content: '';
293
+ position: absolute;
294
+ top: -3px;
295
+ left: -3px;
296
+ right: -3px;
297
+ bottom: -3px;
298
+ border-radius: 14px;
299
+ border: 2px solid rgba(59, 130, 246, 0.3);
300
+ pointer-events: none;
301
+ animation: focusIn 0.2s ease-out forwards;
302
+ }
303
+
304
+ @keyframes focusIn {
305
+ from { opacity: 0; transform: scale(0.98); }
306
+ to { opacity: 1; transform: scale(1); }
307
+ }
308
+
309
+ /* Style optionnel pour améliorer la lisibilité sur mobile */
310
+ @media (max-width: 640px) {
311
+ .prose {
312
+ font-size: 0.95rem;
313
+ line-height: 1.6;
314
+ }
315
+ }
316
  </style>
317
  </head>
318
 
 
321
  <div class="container mx-auto px-6 py-4">
322
  <div class="flex items-center justify-between">
323
  <div class="flex items-center space-x-4">
324
+ <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">
325
  <i class="fas fa-robot text-white text-xl"></i>
326
  </div>
327
  <h1 class="text-2xl font-bold gradient-text">Mariam AI</h1>
328
  </div>
329
+ <div class="text-blue-900 font-medium bg-blue-50 py-1 px-4 rounded-full shadow-sm">Assistant Français Intelligent</div>
330
  </div>
331
  </div>
332
  </nav>
 
334
  <main class="container mx-auto px-6 py-12">
335
  <div class="grid grid-cols-1 lg:grid-cols-2 gap-8">
336
  <!-- Section Travail Argumentatif -->
337
+ <div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in">
338
  <div class="p-8">
339
  <div class="flex items-center space-x-4 mb-8">
340
+ <div class="bg-blue-100 rounded-lg p-3 transform rotate-3">
341
  <i class="fas fa-pen-fancy text-blue-600 text-xl"></i>
342
  </div>
343
  <h2 class="text-2xl font-bold text-gray-800">Travail Argumentatif</h2>
344
  </div>
345
  <form id="francais-form" class="space-y-8">
346
  <div class="space-y-3">
347
+ <label for="sujet-francais" class="block text-sm font-medium text-gray-700 flex items-center">
348
  <i class="fas fa-book-open mr-2 text-blue-500"></i>Sujet
349
  </label>
350
+ <div class="focus-ring">
351
+ <textarea id="sujet-francais" name="sujet" rows="4"
352
+ class="w-full px-4 py-3 rounded-xl border-2 border-gray-200 focus:border-blue-500 focus:outline-none transition-all duration-200 resize-none"
353
+ placeholder="Entrez votre sujet ici..."></textarea>
354
+ </div>
355
+ <div class="text-xs text-gray-400 text-right" id="character-count">0 caractères</div>
356
  </div>
357
 
358
  <div class="space-y-4">
359
+ <label class="block text-sm font-medium text-gray-700 flex items-center">
360
  <i class="fas fa-tasks mr-2 text-blue-500"></i>Type d'argumentation
361
  </label>
362
+ <div class="grid grid-cols-2 sm:grid-cols-4 gap-4">
363
  <label class="relative">
364
  <input type="radio" name="choix" value="Etaye"
365
  class="custom-radio absolute opacity-0 w-full h-full cursor-pointer" checked>
 
384
  Discuter
385
  </span>
386
  </label>
387
+ <label class="relative">
388
+ <input type="radio" name="choix" value="dissertation"
389
+ class="absolute opacity-0 w-full h-full" disabled>
390
+ <span class="flex items-center justify-center p-3 border-2 border-gray-200 rounded-xl text-sm font-medium disabled-option">
391
+ Dissertation
392
+ <span class="coming-soon-badge">Bientôt</span>
393
+ </span>
394
+ </label>
395
  </div>
396
  </div>
397
 
398
  <div class="space-y-4">
399
+ <label class="block text-sm font-medium text-gray-700 flex items-center">
400
  <i class="fas fa-feather-alt mr-2 text-blue-500"></i>Style d'écriture
401
  </label>
402
  <div class="grid grid-cols-2 gap-4">
 
427
  </div>
428
  </button>
429
  </form>
430
+ <div id="francais-output" class="mt-8 p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner">
431
  <!-- Le contenu généré sera inséré ici -->
432
  </div>
433
  </div>
434
  </div>
435
 
436
  <!-- Section Étude de texte -->
437
+ <div class="card-hover glassmorphism rounded-2xl overflow-hidden scale-in" style="animation-delay: 0.1s;">
438
  <div class="p-8">
439
  <div class="flex items-center space-x-4 mb-8">
440
+ <div class="bg-blue-100 rounded-lg p-3 transform -rotate-3">
441
  <i class="fas fa-file-alt text-blue-600 text-xl"></i>
442
  </div>
443
  <h2 class="text-2xl font-bold text-gray-800">Étude de texte</h2>
444
  </div>
445
  <form id="etude-texte-form" class="space-y-8" enctype="multipart/form-data">
446
  <div class="space-y-4">
447
+ <label class="block text-sm font-medium text-gray-700 flex items-center">
448
  <i class="fas fa-image mr-2 text-blue-500"></i>Image du texte
449
  </label>
450
+ <div class="border-3 border-dashed border-gray-300 rounded-xl p-8 text-center cursor-pointer hover:border-blue-400 transition-all duration-200 group"
451
  id="drop-zone">
452
  <input type="file" id="image-upload" name="images" accept="image/*" class="hidden" multiple>
453
+ <div class="space-y-4">
454
+ <div class="bg-blue-50 rounded-full w-16 h-16 flex items-center justify-center mx-auto transform transition-transform group-hover:scale-110 group-hover:rotate-6">
455
  <i class="fas fa-cloud-upload-alt text-3xl text-blue-500"></i>
456
  </div>
457
  <p class="text-sm text-gray-600 font-medium">Glissez vos images ici ou cliquez
 
470
  </div>
471
  </button>
472
  </form>
473
+ <div id="etude-texte-output" class="mt-8 p-6 bg-blue-50 rounded-xl prose max-w-none shadow-inner">
474
  <!-- Le contenu analysé sera inséré ici -->
475
  </div>
476
  </div>
477
  </div>
478
  </div>
479
  <div class="mt-12">
480
+ <h2 class="text-2xl font-bold text-gray-800 mb-4 flex items-center">
481
+ <i class="fas fa-save mr-3 text-blue-500"></i>
482
+ Sauvegardes
483
+ </h2>
484
  <div id="backups-list" class="space-y-4">
485
  <!-- Les sauvegardes seront listées ici -->
486
  </div>
487
  </div>
488
  </main>
489
 
490
+ <footer class="bg-gray-50 border-t border-gray-200 py-6 mt-16">
491
+ <div class="container mx-auto px-6">
492
+ <div class="flex flex-col md:flex-row justify-between items-center">
493
+ <div class="flex items-center space-x-2 mb-4 md:mb-0">
494
+ <div class="bg-blue-600 rounded-lg p-1 shadow">
495
+ <i class="fas fa-robot text-white text-sm"></i>
496
+ </div>
497
+ <span class="text-gray-600 text-sm">Mariam AI</span>
498
+ </div>
499
+ <div class="flex space-x-6">
500
+ <a href="#" class="text-gray-500 hover:text-blue-600 transition-colors">
501
+ <i class="fas fa-question-circle"></i>
502
+ <span class="ml-1 text-sm">Aide</span>
503
+ </a>
504
+ <a href="#" class="text-gray-500 hover:text-blue-600 transition-colors">
505
+ <i class="fas fa-shield-alt"></i>
506
+ <span class="ml-1 text-sm">Confidentialité</span>
507
+ </a>
508
+ </div>
509
+ </div>
510
+ </div>
511
+ </footer>
512
+
513
  <script>
514
  function initializeFileUpload() {
515
  const dropZone = document.getElementById('drop-zone');
 
552
  const reader = new FileReader();
553
  reader.onload = (e) => {
554
  const previewItem = document.createElement('div');
555
+ previewItem.classList.add('image-preview-item', 'scale-in');
556
  previewItem.innerHTML = `
557
  <img src="${e.target.result}" alt="${file.name}">
558
+ <button class="remove-image" title="Supprimer"><i class="fas fa-times"></i></button>
559
  `;
560
  imagePreview.appendChild(previewItem);
561
 
562
  // Remove image event
563
  previewItem.querySelector('.remove-image').addEventListener('click', () => {
564
+ previewItem.style.opacity = '0';
565
+ previewItem.style.transform = 'scale(0.9)';
566
+ setTimeout(() => {
567
+ imagePreview.removeChild(previewItem);
568
+ }, 300);
569
  });
570
  };
571
  reader.readAsDataURL(file);
572
  }
573
  }
574
  }
575
+
576
  function sauvegarderReponse(titre, contenu) {
577
  const sauvegardes = JSON.parse(localStorage.getItem('mariam_ai_sauvegardes') || '[]');
578
  const dateSauvegarde = new Date().toISOString();
 
582
  date: dateSauvegarde
583
  });
584
  localStorage.setItem('mariam_ai_sauvegardes', JSON.stringify(sauvegardes));
585
+
586
+ // Animation de notification
587
+ const notification = document.createElement('div');
588
+ notification.className = 'fixed bottom-6 right-6 bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded-lg shadow-lg z-50 flex items-center scale-in';
589
+ notification.innerHTML = `
590
+ <i class="fas fa-check-circle text-green-500 mr-2"></i>
591
+ <span class="text-sm font-medium">Sauvegardé avec succès</span>
592
+ `;
593
+ document.body.appendChild(notification);
594
+
595
+ setTimeout(() => {
596
+ notification.style.opacity = '0';
597
+ notification.style.transform = 'translateY(10px)';
598
+ setTimeout(() => {
599
+ document.body.removeChild(notification);
600
+ }, 300);
601
+ }, 3000);
602
+
603
  afficherSauvegardes();
604
  }
605
 
 
615
  const backupsList = document.getElementById('backups-list');
616
  backupsList.innerHTML = '';
617
  if (sauvegardes.length === 0) {
618
+ backupsList.innerHTML = `
619
+ <div class="bg-blue-50 rounded-lg p-8 text-center">
620
+ <div class="bg-white rounded-full w-16 h-16 flex items-center justify-center mx-auto mb-4 shadow-sm">
621
+ <i class="fas fa-folder-open text-blue-300 text-2xl"></i>
622
+ </div>
623
+ <p class="text-gray-600">Aucune sauvegarde pour le moment.</p>
624
+ <p class="text-sm text-gray-500 mt-2">Vos réponses générées apparaîtront ici.</p>
625
+ </div>
626
+ `;
627
  return;
628
  }
629
 
630
  sauvegardes.forEach((sauvegarde, index) => {
631
+ const date = new Date(sauvegarde.date);
632
+ const formattedDate = date.toLocaleDateString('fr-FR', {
633
+ day: 'numeric',
634
+ month: 'short',
635
+ year: 'numeric',
636
+ hour: '2-digit',
637
+ minute: '2-digit'
638
+ });
639
+
640
  const sauvegardeDiv = document.createElement('div');
641
+ sauvegardeDiv.className = 'bg-white rounded-lg shadow-md p-4 relative backup-item hover:bg-blue-50 transition-all duration-200';
642
  sauvegardeDiv.innerHTML = `
643
+ <div class="flex items-start">
644
+ <div class="bg-blue-100 rounded-lg p-2 mr-3">
645
+ <i class="fas fa-file-alt text-blue-600"></i>
646
+ </div>
647
+ <div class="flex-grow">
648
+ <h3 class="text-lg font-semibold text-gray-800">${sauvegarde.titre}</h3>
649
+ <p class="text-sm text-gray-600 mb-2 flex items-center">
650
+ <i class="fas fa-clock text-xs mr-1 text-gray-400"></i>
651
+ ${formattedDate}
652
+ </p>
653
+ </div>
654
+ <div class="flex space-x-2">
655
+ <button class="text-gray-400 hover:text-blue-600 focus:outline-none copy-btn" data-index="${index}">
656
+ <i class="fas fa-copy"></i>
657
+ </button>
658
+ <button class="text-gray-400 hover:text-red-600 focus:outline-none delete-btn" data-index="${index}">
659
+ <i class="fas fa-trash-alt"></i>
660
+ </button>
661
+ </div>
662
+ </div>
663
+ <div class="text-sm text-gray-700 backup-content prose max-w-none mt-3">${marked.parse(sauvegarde.contenu)}</div>
664
  `;
665
  backupsList.appendChild(sauvegardeDiv);
666
 
667
  // Gestion de l'expansion/contraction du contenu
668
  const backupContentDiv = sauvegardeDiv.querySelector('.backup-content');
669
+ sauvegardeDiv.addEventListener('click', (e) => {
670
+ // Ignorer les clics sur les boutons
671
+ if (e.target.tagName === "BUTTON" || e.target.closest('button')) return;
672
+
673
+ const allContents = document.querySelectorAll('.backup-content');
674
+ allContents.forEach(content => {
675
+ if (content !== backupContentDiv) {
676
+ content.classList.remove('backup-content-expanded');
677
+ }
678
+ });
679
+
680
  backupContentDiv.classList.toggle('backup-content-expanded');
681
+
682
+ if (backupContentDiv.classList.contains('backup-content-expanded')) {
683
+ setTimeout(() => {
684
+ MathJax.typesetPromise([backupContentDiv]);
685
+ }, 300);
686
+ }
687
+ });
688
+
689
+ // Bouton de copie
690
+ const copyButton = sauvegardeDiv.querySelector('.copy-btn');
691
+ copyButton.addEventListener('click', (e) => {
692
+ e.stopPropagation();
693
+ navigator.clipboard.writeText(sauvegarde.contenu).then(() => {
694
+ copyButton.querySelector('i').className = 'fas fa-check';
695
+ setTimeout(() => {
696
+ copyButton.querySelector('i').className = 'fas fa-copy';
697
+ }, 2000);
698
+ });
699
  });
700
 
701
+ // Bouton de suppression
702
+ const deleteButton = sauvegardeDiv.querySelector('.delete-btn');
703
+ deleteButton.addEventListener('click', (e) => {
704
+ e.stopPropagation();
705
+
706
+ const confirmationModal = document.createElement('div');
707
+ confirmationModal.className = 'fixed inset-0 flex items-center justify-center z-50 bg-black bg-opacity-30 scale-in';
708
+ confirmationModal.innerHTML = `
709
+ <div class="bg-white rounded-lg p-6 max-w-sm mx-4 shadow-xl">
710
+ <div class="flex items-center mb-4">
711
+ <div class="bg-red-100 rounded-full p-2 mr-3">
712
+ <i class="fas fa-exclamation-triangle text-red-500"></i>
713
+ </div>
714
+ <h3 class="text-lg font-semibold text-gray-800">Confirmation de suppression</h3>
715
+ </div>
716
+ <p class="text-gray-600 mb-6">Êtes-vous sûr de vouloir supprimer cette sauvegarde ? Cette action est irréversible.</p>
717
+ <div class="flex justify-end space-x-3">
718
+ <button class="px-4 py-2 border border-gray-300 rounded-lg text-gray-700 hover:bg-gray-50 cancel-btn">Annuler</button>
719
+ <button class="px-4 py-2 bg-red-600 text-white rounded-lg hover:bg-red-700 confirm-btn">Supprimer</button>
720
+ </div>
721
+ </div>
722
+ `;
723
+ document.body.appendChild(confirmationModal);
724
+
725
+ confirmationModal.querySelector('.cancel-btn').addEventListener('click', () => {
726
+ confirmationModal.style.opacity = '0';
727
+ setTimeout(() => {
728
+ document.body.removeChild(confirmationModal);
729
+ }, 300);
730
+ });
731
+
732
+ confirmationModal.querySelector('.confirm-btn').addEventListener('click', () => {
733
  supprimerSauvegarde(index);
734
+ confirmationModal.style.opacity = '0';
735
+ setTimeout(() => {
736
+ document.body.removeChild(confirmationModal);
737
+ }, 300);
738
+ });
739
  });
740
  });
 
741
  }
742
 
743
  async function submitFrancaisForm() {
 
747
  form.addEventListener('submit', async (e) => {
748
  e.preventDefault();
749
  output.innerHTML = `
750
+ <div class="flex flex-col items-center justify-center py-8">
751
+ <div class="loader mb-4">
752
+ <div></div>
753
+ <div></div>
754
+ <div></div>
755
+ <div></div>
756
+ </div>
757
+ <p class="text-sm font-medium text-gray-600">Génération en cours, veuillez patienter...</p>
758
  </div>`;
759
 
760
  const formData = new FormData(form);
 
763
  method: 'POST',
764
  body: formData
765
  });
766
+
767
+ if (!response.ok) {
768
+ throw new Error('Erreur réseau');
769
+ }
770
+
771
  const result = await response.json();
772
+
773
+ output.style.opacity = '0';
774
+ setTimeout(() => {
775
+ output.innerHTML = marked.parse(result.output);
776
+ output.style.opacity = '1';
777
+
778
+ const sujet = formData.get('sujet');
779
+ sauvegarderReponse(sujet, result.output);
780
+ MathJax.typesetPromise([output]);
781
+ }, 300);
782
  } catch (error) {
783
  output.innerHTML = `
784
+ <div class="flex items-center space-x-3 text-red-500 bg-red-50 p-4 rounded-lg">
785
+ <i class="fas fa-exclamation-circle text-xl"></i>
786
+ <div>
787
+ <p class="font-medium">Une erreur est survenue</p>
788
+ <p class="text-sm text-red-400 mt-1">Veuillez réessayer ou vérifier votre connexion internet.</p>
789
+ </div>
790
  </div>`;
791
  }
792
  });
 
798
 
799
  form.addEventListener('submit', async (e) => {
800
  e.preventDefault();
801
+
802
+ const imagePreview = document.getElementById('image-preview');
803
+ if (imagePreview.children.length === 0) {
804
+ output.innerHTML = `
805
+ <div class="flex items-center space-x-3 text-amber-500 bg-amber-50 p-4 rounded-lg">
806
+ <i class="fas fa-exclamation-triangle text-xl"></i>
807
+ <div>
808
+ <p class="font-medium">Aucune image</p>
809
+ <p class="text-sm text-amber-400 mt-1">Veuillez ajouter au moins une image pour l'analyse.</p>
810
+ </div>
811
+ </div>`;
812
+ return;
813
+ }
814
+
815
  output.innerHTML = `
816
+ <div class="flex flex-col items-center justify-center py-8">
817
+ <div class="loader mb-4">
818
+ <div></div>
819
+ <div></div>
820
+ <div></div>
821
+ <div></div>
822
+ </div>
823
+ <p class="text-sm font-medium text-gray-600">Analyse en cours, veuillez patienter...</p>
824
+ <p class="text-xs text-gray-400 mt-2">Ce processus peut prendre quelques instants</p>
825
  </div>`;
826
 
827
  const formData = new FormData(form);
 
830
  method: 'POST',
831
  body: formData
832
  });
833
+
834
+ if (!response.ok) {
835
+ throw new Error('Erreur réseau');
836
+ }
837
+
838
  const result = await response.json();
839
+
840
+ output.style.opacity = '0';
841
+ setTimeout(() => {
842
+ output.innerHTML = marked.parse(result.output);
843
+ output.style.opacity = '1';
844
+
845
+ // Titre par défaut pour les analyses d'images
846
+ const titre = "Analyse d'image " + new Date().toLocaleString();
847
+ sauvegarderReponse(titre, result.output);
848
+ MathJax.typesetPromise([output]);
849
+ }, 300);
850
  } catch (error) {
851
  output.innerHTML = `
852
+ <div class="flex items-center space-x-3 text-red-500 bg-red-50 p-4 rounded-lg">
853
+ <i class="fas fa-exclamation-circle text-xl"></i>
854
+ <div>
855
+ <p class="font-medium">Une erreur est survenue</p>
856
+ <p class="text-sm text-red-400 mt-1">Veuillez réessayer ou vérifier votre connexion internet.</p>
857
+ </div>
858
  </div>`;
859
  }
860
  });
 
864
  function animateOnScroll() {
865
  const cards = document.querySelectorAll('.card-hover');
866
  const observer = new IntersectionObserver((entries) => {
867
+ entries.forEach((entry, index) => {
868
  if (entry.isIntersecting) {
869
+ setTimeout(() => {
870
+ entry.target.style.opacity = '1';
871
+ entry.target.style.transform = 'translateY(0)';
872
+ }, index * 100);
873
  }
874
  });
875
  }, {
 
878
 
879
  cards.forEach(card => {
880
  card.style.opacity = '0';
881
+ card.style.transform = 'translateY(30px)';
882
  card.style.transition = 'all 0.6s cubic-bezier(0.4, 0, 0.2, 1)';
883
  observer.observe(card);
884
  });
885
  }
886
 
887
+ // Effet de focus amélioré pour les zones de texte et compteur de caractères
888
  function enhanceTextareaFocus() {
889
+ const textarea = document.getElementById('sujet-francais');
890
+ const counter = document.getElementById('character-count');
891
+
892
+ textarea.addEventListener('input', () => {
893
+ const length = textarea.value.length;
894
+ counter.textContent = `${length} caractère${length !== 1 ? 's' : ''}`;
 
 
895
  });
896
  }
897
 
898
  // Effet de hover pour les boutons radio
899
  function enhanceRadioButtons() {
900
+ const radioLabels = document.querySelectorAll('input[type="radio"]:not(:disabled) + span');
901
  radioLabels.forEach(label => {
902
  label.addEventListener('mouseenter', () => {
903
  if (!label.previousElementSibling.checked) {
904
  label.style.borderColor = '#3182ce';
905
+ label.style.transform = 'translateY(-2px)';
906
+ label.style.boxShadow = '0 4px 6px -1px rgba(0, 0, 0, 0.1)';
907
  }
908
  });
909
+
910
  label.addEventListener('mouseleave', () => {
911
  if (!label.previousElementSibling.checked) {
912
+ label.style.borderColor = '#e5e7eb';
913
+ label.style.transform = 'translateY(0)';
914
+ label.style.boxShadow = 'none';
915
  }
916
  });
917
  });
 
926
  enhanceTextareaFocus();
927
  enhanceRadioButtons();
928
 
929
+ // Message de bienvenue avec animation
930
  const welcomeMessage = document.createElement('div');
931
  welcomeMessage.innerHTML = `
932
+ <div class="fixed bottom-6 right-6 bg-white rounded-xl shadow-lg p-5 transform transition-all duration-500 opacity-0 translate-y-4 max-w-xs z-50">
933
+ <div class="flex items-center space-x-4">
934
+ <div class="bg-gradient-to-r from-blue-500 to-blue-700 rounded-full p-3">
935
+ <i class="fas fa-robot text-white text-xl"></i>
936
+ </div>
937
+ <div>
938
+ <p class="text-sm font-semibold text-gray-800">Bienvenue sur Mariam AI</p>
939
+ <p class="text-xs text-gray-500 mt-1">Votre assistant français intelligent est prêt à vous accompagner.</p>
940
+ </div>
941
+ </div>
942
+ <button class="absolute top-2 right-2 text-gray-400 hover:text-gray-600 focus:outline-none close-welcome">
943
+ <i class="fas fa-times"></i>
944
+ </button>
945
+ </div>
946
+ `;
947
  document.body.appendChild(welcomeMessage);
948
 
949
  setTimeout(() => {
950
  welcomeMessage.firstElementChild.classList.remove('opacity-0', 'translate-y-4');
951
  }, 1000);
952
 
953
+ // Bouton de fermeture pour le message de bienvenue
954
+ welcomeMessage.querySelector('.close-welcome').addEventListener('click', () => {
955
  welcomeMessage.firstElementChild.classList.add('opacity-0', 'translate-y-4');
956
  setTimeout(() => welcomeMessage.remove(), 500);
957
+ });
958
+
959
+ setTimeout(() => {
960
+ if (document.body.contains(welcomeMessage)) {
961
+ welcomeMessage.firstElementChild.classList.add('opacity-0', 'translate-y-4');
962
+ setTimeout(() => welcomeMessage.remove(), 500);
963
+ }
964
+ }, 7000);
965
 
966
  afficherSauvegardes(); // Appel de la fonction pour afficher les sauvegardes
967
  });
968
  </script>
 
969
  </body>
970
+ </html>