Docfile commited on
Commit
1083672
·
verified ·
1 Parent(s): f3b3c3c

Delete templates/philosophie.html

Browse files
Files changed (1) hide show
  1. templates/philosophie.html +0 -865
templates/philosophie.html DELETED
@@ -1,865 +0,0 @@
1
-
2
- <!DOCTYPE html>
3
- <html lang="fr">
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Mariam AI - Assistant Philosophique</title>
8
- <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
9
- <script src="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.all.min.js"></script>
10
- <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/4.3.0/marked.min.js"></script>
11
- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
12
- <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/locale/fr.js"></script>
13
- <link href="https://cdnjs.cloudflare.com/ajax/libs/sweetalert2/11.7.3/sweetalert2.min.css" rel="stylesheet">
14
- <script src="https://cdn.tailwindcss.com"></script>
15
- <style>
16
- /* Styles existants */
17
- .collapsible {
18
- cursor: pointer;
19
- padding: 18px;
20
- width: 100%;
21
- border: none;
22
- text-align: left;
23
- outline: none;
24
- font-size: 15px;
25
- background-color: #f1f1f1;
26
- display: flex;
27
- justify-content: space-between;
28
- align-items: center;
29
- }
30
-
31
- /* Nouveaux styles pour le Markdown responsive */
32
- .prose {
33
- max-width: 100% !important;
34
- }
35
-
36
- .prose p {
37
- margin-top: 1.25em;
38
- margin-bottom: 1.25em;
39
- line-height: 1.75;
40
- }
41
-
42
- .prose ul {
43
- margin-top: 1.25em;
44
- margin-bottom: 1.25em;
45
- padding-left: 1.625em;
46
- }
47
-
48
- .prose li {
49
- margin-top: 0.5em;
50
- margin-bottom: 0.5em;
51
- padding-left: 0.375em;
52
- }
53
-
54
- .prose h1, .prose h2, .prose h3 {
55
- margin-top: 2em;
56
- margin-bottom: 1em;
57
- line-height: 1.3;
58
- }
59
-
60
- /* Styles spécifiques pour mobile */
61
- @media (max-width: 640px) {
62
- .prose {
63
- font-size: 0.95rem;
64
- }
65
-
66
- .prose p {
67
- margin-top: 1em;
68
- margin-bottom: 1em;
69
- }
70
-
71
- .prose ul {
72
- padding-left: 1.25em;
73
- }
74
-
75
- .prose li {
76
- margin-top: 0.375em;
77
- margin-bottom: 0.375em;
78
- }
79
-
80
- .prose h1, .prose h2, .prose h3 {
81
- margin-top: 1.5em;
82
- margin-bottom: 0.75em;
83
- }
84
- }
85
-
86
- /* Styles pour améliorer la lisibilité du texte */
87
- #response .prose {
88
- color: #374151;
89
- word-wrap: break-word;
90
- overflow-wrap: break-word;
91
- hyphens: auto;
92
- }
93
-
94
- #response .prose > * + * {
95
- margin-top: 1em;
96
- }
97
-
98
- #response .prose blockquote {
99
- margin: 1.5em 0;
100
- padding-left: 1em;
101
- border-left: 4px solid #e5e7eb;
102
- font-style: italic;
103
- }
104
-
105
- #response .prose code {
106
- background-color: #f3f4f6;
107
- padding: 0.2em 0.4em;
108
- border-radius: 0.25em;
109
- font-size: 0.875em;
110
- }
111
-
112
-
113
-
114
- .active, .collapsible:hover {
115
- background-color: #ddd;
116
- }
117
-
118
- .content {
119
- padding: 0 18px;
120
- display: none;
121
- overflow: hidden;
122
- background-color: white;
123
- }
124
- .animate-fadeIn {
125
- animation: fadeIn 0.5s ease-out forwards;
126
- }
127
- .animate-slideUp {
128
- animation: slideUp 0.5s ease-out forwards;
129
- }
130
- .animate-shake {
131
- animation: shake 0.5s ease-in-out;
132
- }
133
- @keyframes fadeIn {
134
- from { opacity: 0; transform: translateY(10px); }
135
- to { opacity: 1; transform: translateY(0); }
136
- }
137
- @keyframes slideUp {
138
- from { opacity: 0; transform: translateY(20px); }
139
- to { opacity: 1; transform: translateY(0); }
140
- }
141
- @keyframes shake {
142
- 0%, 100% { transform: translateX(0); }
143
- 25% { transform: translateX(-5px); }
144
- 75% { transform: translateX(5px); }
145
- }
146
-
147
- /* Styles pour la liste déroulante améliorée */
148
- .custom-select-wrapper {
149
- position: relative;
150
- user-select: none;
151
- }
152
-
153
- .custom-select {
154
- position: relative;
155
- display: flex;
156
- flex-direction: column;
157
- border-width: 2px;
158
- border-color: #a78bfa; /* Violet */
159
- border-radius: 0.5rem;
160
- background-color: #f3f4f6; /* Gris clair */
161
- }
162
-
163
- .custom-select-trigger {
164
- position: relative;
165
- display: flex;
166
- align-items: center;
167
- justify-content: space-between;
168
- padding: 0 1rem;
169
- font-size: 1rem;
170
- font-weight: 600;
171
- color: #4b5563; /* Gris foncé */
172
- height: 3rem;
173
- line-height: 3rem;
174
- background-color: #ffffff; /* Blanc */
175
- border-bottom: 2px solid #a78bfa; /* Violet */
176
- cursor: pointer;
177
- }
178
-
179
- .custom-options {
180
- position: absolute;
181
- display: block;
182
- top: 100%;
183
- left: 0;
184
- right: 0;
185
- border: 2px solid #a78bfa; /* Violet */
186
- border-top: 0;
187
- background-color: #ffffff; /* Blanc */
188
- transition: opacity 0.2s ease-in-out;
189
- z-index: 10;
190
- max-height: 20rem; /* Hauteur maximale */
191
- overflow-y: auto; /* Barre de défilement */
192
- border-bottom-left-radius: 0.5rem;
193
- border-bottom-right-radius: 0.5rem;
194
- }
195
-
196
- .custom-select.open .custom-options {
197
- opacity: 1;
198
- pointer-events: auto;
199
- }
200
-
201
- .custom-options .custom-option {
202
- position: relative;
203
- display: block;
204
- padding: 0.5rem 1rem;
205
- font-size: 1rem;
206
- color: #4b5563; /* Gris foncé */
207
- cursor: pointer;
208
- transition: background-color 0.2s ease-in-out;
209
- border-bottom: 1px solid #e5e7eb; /* Gris clair */
210
- }
211
-
212
- .custom-options .custom-option:last-child {
213
- border-bottom: none;
214
- }
215
-
216
- .custom-options .custom-option:hover {
217
- background-color: #ede9fe; /* Violet clair */
218
- }
219
-
220
- .custom-options .custom-option.selected {
221
- background-color: #ddd6fe; /* Violet clair */
222
- color: #6b21a8; /* Violet foncé */
223
- }
224
-
225
- .custom-options .custom-option .option-badge {
226
- display: flex;
227
- align-items: center;
228
- justify-content: space-between;
229
- width: 100%;
230
- }
231
-
232
- .custom-options .custom-option .option-badge .option-title {
233
- font-weight: 600;
234
- color: #4b5563; /* Gris foncé */
235
- }
236
-
237
- .custom-options .custom-option .option-badge .option-meta {
238
- font-size: 0.875rem;
239
- color: #6b7280; /* Gris moyen */
240
- }
241
-
242
- .custom-options .custom-option .option-badge .option-meta span {
243
- margin-left: 0.5rem;
244
- color: #a78bfa; /* Violet */
245
- }
246
-
247
- .arrow {
248
- position: relative;
249
- height: 1.5rem;
250
- width: 1.5rem;
251
- }
252
-
253
- .arrow::before,
254
- .arrow::after {
255
- content: "";
256
- position: absolute;
257
- bottom: 0px;
258
- width: 0.15rem;
259
- height: 100%;
260
- transition: all 0.5s ease;
261
- }
262
-
263
- .arrow::before {
264
- left: -5px;
265
- transform: rotate(45deg);
266
- background-color: #a78bfa; /* Violet */
267
- }
268
-
269
- .arrow::after {
270
- left: 5px;
271
- transform: rotate(-45deg);
272
- background-color: #a78bfa; /* Violet */
273
- }
274
-
275
- .open .arrow::before {
276
- transform: rotate(-45deg);
277
- }
278
-
279
- .open .arrow::after {
280
- transform: rotate(45deg);
281
- }
282
- </style>
283
- </head>
284
-
285
- <body class="bg-gradient-to-br from-violet-50 to-indigo-50 min-h-screen">
286
- <!-- Navbar -->
287
- <nav class="bg-white/80 backdrop-blur-md border-b border-gray-200 fixed w-full z-50">
288
- <div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
289
- <div class="flex justify-between items-center h-16">
290
- <div class="flex items-center">
291
- <div class="text-2xl font-bold bg-gradient-to-r from-violet-600 to-indigo-600 text-transparent bg-clip-text">
292
- Mariam AI
293
- </div>
294
- </div>
295
- <div class="flex items-center space-x-4">
296
- <span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium bg-violet-100 text-violet-800">
297
- <span class="w-2 h-2 bg-violet-400 rounded-full animate-pulse mr-2"></span>
298
- Assistant Philosophique
299
- </span>
300
- </div>
301
- </div>
302
- </div>
303
- </nav>
304
-
305
- <!-- Main Content -->
306
- <div class="pt-24 pb-12 px-4 sm:px-6 lg:px-8">
307
- <div class="max-w-4xl mx-auto">
308
- <!-- Main Card -->
309
- <div class="bg-white/80 backdrop-blur-md rounded-2xl shadow-xl border border-gray-100 overflow-hidden">
310
- <!-- Header Section -->
311
- <div class="bg-gradient-to-r from-violet-600 to-indigo-600 p-6 text-white">
312
- <h2 class="text-2xl font-bold">Gen'Dissertation</h2>
313
- <p class="mt-2 opacity-90">Créez des dissertations philosophiques pertinentes et structurées</p>
314
- </div>
315
-
316
- <!-- Content Section -->
317
- <div class="p-8 space-y-8">
318
- <!-- Type Selection -->
319
- <div class="space-y-3">
320
- <label class="block text-sm font-medium text-gray-700">Type de dissertation</label>
321
- <div class="relative">
322
- <select id="type-select" class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 appearance-none bg-white py-3 px-4 pr-10">
323
- <option value="1">Type 1 -</option>
324
- <option value="2">Type 2 -</option>
325
- <option value="3">Synthèse -</option>
326
- </select>
327
- <div class="absolute inset-y-0 right-0 flex items-center px-4 pointer-events-none">
328
- <svg class="h-5 w-5 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
329
- <path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
330
- </svg>
331
- </div>
332
- </div>
333
- <div id="current-type-label" class="inline-flex px-4 py-2 rounded-xl text-sm font-medium bg-gradient-to-r from-violet-50 to-indigo-50 text-violet-700 border border-violet-200">
334
- Sujet de type 1
335
- </div>
336
- </div>
337
-
338
- <!-- Course Selection -->
339
- <div class="space-y-3">
340
- <label class="block text-sm font-medium text-gray-700">Sélection du cours</label>
341
- <div class="custom-select-wrapper">
342
- <div id="custom-select" class="custom-select">
343
- <div class="custom-select-trigger">
344
- <span>Choisir un cours...</span>
345
- <div class="arrow"></div>
346
- </div>
347
- <div class="custom-options">
348
- <!-- Les options seront ajoutées ici par JavaScript -->
349
- </div>
350
- </div>
351
- </div>
352
- <div class="course-meta hidden mt-4">
353
- <div class="bg-gradient-to-r from-gray-50 to-white rounded-xl p-4 border border-gray-100">
354
- <div class="flex justify-between items-center">
355
- <span id="course-author" class="flex items-center space-x-2">
356
- <svg class="h-5 w-5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
357
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" />
358
- </svg>
359
- <span class="text-gray-600"></span>
360
- </span>
361
- <span id="course-date" class="flex items-center space-x-2">
362
- <svg class="h-5 w-5 text-violet-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
363
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
364
- </svg>
365
- <span class="text-gray-600"></span>
366
- </span>
367
- </div>
368
- </div>
369
- </div>
370
- </div>
371
-
372
- <!-- Question Input -->
373
- <div class="space-y-3">
374
- <label class="block text-sm font-medium text-gray-700">Sujet de dissertation</label>
375
- <div class="relative">
376
- <textarea id="question" rows="4"
377
- class="w-full rounded-xl border-gray-200 shadow-sm focus:border-violet-500 focus:ring-violet-500 resize-none bg-white py-3 px-4"
378
- placeholder="Saisissez votre sujet de dissertation..."></textarea>
379
- <div class="absolute bottom-3 right-3 flex items-center space-x-2 text-gray-400">
380
- <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
381
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.232 5.232l3.536 3.536m-2.036-5.036a2.5 2.5 0 113.536 3.536L6.5 21.036H3v-3.572L16.732 3.732z" />
382
- </svg>
383
- </div>
384
- </div>
385
- </div>
386
-
387
- <!-- Submit Button -->
388
- <button id="submit-btn" class="w-full py-4 px-6 rounded-xl bg-gradient-to-r from-violet-600 to-indigo-600 text-white font-medium shadow-lg shadow-violet-200 hover:shadow-xl hover:shadow-violet-300 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-violet-500 focus:ring-offset-2">
389
- <span class="flex items-center justify-center space-x-2">
390
- <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
391
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
392
- </svg>
393
- <span>Générer la dissertation</span>
394
- </span>
395
- </button>
396
-
397
- <!-- Response Section -->
398
- <div id="response" class="hidden mt-8 prose prose-violet max-w-none">
399
- <div class="bg-gradient-to-r from-gray-50 to-white rounded-xl p-6 border border-gray-100">
400
- <!-- La réponse sera insérée ici -->
401
- </div>
402
- </div>
403
-
404
- <!-- Copy Button -->
405
- <button id="copy-btn" class="hidden w-full py-3 px-6 rounded-xl bg-gray-50 text-gray-700 font-medium border border-gray-200 hover:bg-gray-100 transform hover:-translate-y-0.5 transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-gray-500 focus:ring-offset-2">
406
- <span class="flex items-center justify-center space-x-2">
407
- <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
408
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
409
- </svg>
410
- <span>Copier la dissertation</span>
411
- </span>
412
- </button>
413
-
414
- <!-- Saved Dissertations Section -->
415
- <div id="saved-dissertations" class="mt-8">
416
- <h3 class="text-lg font-medium text-gray-700 mb-4">Dissertations Sauvegardées</h3>
417
- <div id="dissertations-list" class="space-y-4">
418
- <!-- Les dissertations sauvegardées seront insérées ici -->
419
- </div>
420
- </div>
421
-
422
- </div>
423
- </div>
424
- </div>
425
- </div>
426
-
427
- <script>
428
- $(document).ready(function() {
429
- // Configuration de marked
430
- marked.setOptions({
431
- breaks: true,
432
- gfm: true,
433
- headerIds: true,
434
- langPrefix: 'language-',
435
- smartLists: true,
436
- smartypants: true
437
- });
438
-
439
- moment.locale('fr'); // Configuration de moment.js en français
440
-
441
- // Configuration des notifications
442
- const Toast = Swal.mixin({
443
- toast: true,
444
- position: 'top-end',
445
- showConfirmButton: false,
446
- timer: 3000,
447
- timerProgressBar: true,
448
- customClass: {
449
- popup: 'rounded-lg shadow-xl border border-gray-100'
450
- }
451
- });
452
-
453
-
454
-
455
- // Animation des boutons
456
- function addButtonAnimation(buttonId) {
457
- $(`#${buttonId}`).on('mousedown', function() {
458
- $(this).addClass('scale-95');
459
- }).on('mouseup mouseleave', function() {
460
- $(this).removeClass('scale-95');
461
- });
462
- }
463
- addButtonAnimation('submit-btn');
464
- addButtonAnimation('copy-btn');
465
-
466
- // Gestion du changement de type
467
- $('#type-select').change(function() {
468
- const type = $(this).val();
469
- const labels = {
470
- '1': 'Type1',
471
- '2': 'Type2',
472
- '3': 'Synthèse'
473
- };
474
- $('#current-type-label').text(`Type ${type} - ${labels[type]}`);
475
- });
476
-
477
- // Gestion de la liste déroulante personnalisée
478
- function setupCustomSelect() {
479
- const customSelect = $('#custom-select');
480
- const customOptionsContainer = customSelect.find('.custom-options');
481
- const trigger = customSelect.find('.custom-select-trigger');
482
-
483
- function toggleOptions() {
484
- customSelect.toggleClass('open');
485
- }
486
-
487
- trigger.click(toggleOptions);
488
-
489
- // Chargement et ajout des options
490
- loadCourses().done(function(courses) {
491
- courses.forEach(course => {
492
- const option = $(`
493
- <div class="custom-option" data-value="${course.id}">
494
- <div class="option-badge">
495
- <span class="option-title">${course.title}</span>
496
- <span class="option-meta">par <span>${course.author}</span></span>
497
- </div>
498
- </div>
499
- `);
500
-
501
- option.click(function() {
502
- customOptionsContainer.find('.custom-option').removeClass('selected');
503
- $(this).addClass('selected');
504
- trigger.find('span').text($(this).find('.option-title').text());
505
- customSelect.removeClass('open');
506
- // Déclencher l'événement de changement de cours
507
- $('.course-meta').removeClass('hidden animate-pulse').addClass('animate-fadeIn');
508
- $('#course-author span').text(`Pr. ${course.author}`);
509
- $('#course-date span').text(moment(course.updated_at).format('Do MMMM YYYY'));
510
- Toast.fire({
511
- icon: 'success',
512
- title: 'Cours chargé avec succès'
513
- });
514
- // ... (votre logique de chargement de cours ici)
515
- });
516
-
517
- customOptionsContainer.append(option);
518
- });
519
- }).fail(function() {
520
- Toast.fire({
521
- icon: 'error',
522
- title: 'Erreur de chargement des cours',
523
- text: 'Veuillez réessayer ultérieurement'
524
- });
525
- });
526
- }
527
-
528
- // Initialiser la liste déroulante personnalisée
529
- setupCustomSelect();
530
-
531
- // Chargement des cours avec animation
532
- function loadCourses() {
533
- return $.ajax({
534
- url: '/api/philosophy/courses',
535
- method: 'GET',
536
- beforeSend: function() {
537
- $('#custom-select').addClass('animate-pulse');
538
- },
539
- complete: function() {
540
- $('#custom-select').removeClass('animate-pulse');
541
- }
542
- });
543
- }
544
-
545
- // Gestion du changement de cours avec animations et nouvelle structure
546
- $('#course-select').change(function() {
547
- const courseId = $(this).val();
548
- if (courseId) {
549
- $.ajax({
550
- url: `/api/philosophy/courses/${courseId}`,
551
- method: 'GET',
552
- beforeSend: function() {
553
- $('.course-meta').addClass('animate-pulse');
554
- },
555
- success: function(course) {
556
- $('.course-meta').removeClass('hidden animate-pulse')
557
- .addClass('animate-fadeIn');
558
- $('#course-author span').text(`Pr. ${course.author}`);
559
- $('#course-date span').text(new Date(course.updated_at).toLocaleDateString('fr-FR', {
560
- day: 'numeric',
561
- month: 'long',
562
- year: 'numeric'
563
- }));
564
-
565
- // Afficher une notification de succès
566
- Toast.fire({
567
- icon: 'success',
568
- title: 'Cours chargé avec succès'
569
- });
570
- },
571
- error: function() {
572
- Toast.fire({
573
- icon: 'error',
574
- title: 'Erreur',
575
- text: 'Impossible de charger les détails du cours'
576
- });
577
- }
578
- });
579
- } else {
580
- $('.course-meta').addClass('animate-fadeOut').on('animationend', function() {
581
- $(this).addClass('hidden').removeClass('animate-fadeOut');
582
- });
583
- }
584
- });
585
-
586
- // Gestion de la soumission avec conversion en Markdown et sauvegarde
587
- $('#submit-btn').click(function() {
588
- const question = $('#question').val().trim();
589
-
590
- if (!question) {
591
- // Gestion de l'erreur si la question est vide (inchangée)
592
- return;
593
- }
594
-
595
- // Animation de chargement sophistiquée
596
- Swal.fire({
597
- title: 'Génération en cours',
598
- html: `
599
- <div class="space-y-4">
600
- <div class="flex justify-center">
601
- <div class="w-16 h-16 relative">
602
- <div class="absolute inset-0 rounded-full border-4 border-violet-200 animate-ping"></div>
603
- <div class="absolute inset-0 rounded-full border-4 border-violet-500 animate-pulse"></div>
604
- </div>
605
- </div>
606
- <div class="text-gray-600">
607
- <p class="animate-pulse">Analyse philosophique en cours...</p>
608
- <p class="text-sm mt-2 text-gray-500">Veuillez patienter quelques instants</p>
609
- </div>
610
- </div>
611
- `,
612
- allowOutsideClick: false,
613
- showConfirmButton: false,
614
- customClass: {
615
- popup: 'rounded-2xl'
616
- }
617
- });
618
-
619
- const data = {
620
- question: question,
621
- type: $('#type-select').val(),
622
- courseId: $('#course-select').val() || null
623
- };
624
-
625
- $.ajax({
626
- url: '/submit_philo',
627
- method: 'POST',
628
- contentType: 'application/json',
629
- data: JSON.stringify(data),
630
- success: function(data) {
631
- Swal.close();
632
-
633
- const htmlContent = marked.parse(data.response);
634
- // Afficher la dissertation
635
- $('#response > div').html(htmlContent);
636
- $('#response').removeClass('hidden').addClass('animate-fadeIn');
637
- $('#copy-btn').removeClass('hidden').addClass('animate-slideUp');
638
-
639
- // Sauvegarder la dissertation
640
- saveDissertation(question, data.response);
641
-
642
- Toast.fire({
643
- icon: 'success',
644
- title: 'Dissertation générée et sauvegardée avec succès',
645
- timer: 2000
646
- });
647
- },
648
- error: function() {
649
- Swal.fire({
650
- icon: 'error',
651
- title: 'Erreur de génération',
652
- text: 'Une erreur est survenue lors de la génération de votre dissertation.',
653
- customClass: {
654
- popup: 'rounded-2xl',
655
- confirmButton: 'bg-violet-600 hover:bg-violet-700 text-white font-medium py-2 px-4 rounded-lg transition-colors duration-200'
656
- }
657
- });
658
- }
659
- });
660
- });
661
-
662
- // Fonction pour sauvegarder la dissertation (localStorage ou autre)
663
- function saveDissertation(title, content) {
664
- let savedDissertations = JSON.parse(localStorage.getItem('dissertations')) || [];
665
- savedDissertations.push({ title, content, timestamp: Date.now() });
666
- localStorage.setItem('dissertations', JSON.stringify(savedDissertations));
667
- updateSavedDissertationsList();
668
-
669
- }
670
-
671
-
672
-
673
- // Fonction pour supprimer une dissertation sauvegardée
674
- function deleteDissertation(index) {
675
- let savedDissertations = JSON.parse(localStorage.getItem('dissertations')) || [];
676
- savedDissertations.splice(index, 1);
677
- localStorage.setItem('dissertations', JSON.stringify(savedDissertations));
678
- updateSavedDissertationsList();
679
- Toast.fire({
680
- icon: 'success',
681
- title: 'Dissertation supprimée avec succès'
682
- });
683
-
684
- }
685
-
686
- // Fonction pour afficher les dissertations sauvegardées (avec sections repliables et suppression)
687
- function updateSavedDissertationsList() {
688
- const dissertationsList = $('#dissertations-list');
689
- dissertationsList.empty(); // Vider la liste actuelle
690
-
691
- let savedDissertations = JSON.parse(localStorage.getItem('dissertations')) || [];
692
-
693
- if (savedDissertations.length === 0) {
694
- dissertationsList.append('<p class="text-gray-500">Aucune dissertation sauvegardée.</p>');
695
- return;
696
- }
697
-
698
-
699
-
700
- savedDissertations.forEach((diss, index) => {
701
- const date = moment(diss.timestamp).format('LLL');
702
-
703
- const collapsible = $(`<button class="collapsible rounded-xl border border-gray-100 flex justify-between w-full"><span>${diss.title}</span><span class="text-gray-500 text-sm">${date}</span></button>`);
704
- const deleteButton = $('<button class="text-red-500 hover:text-red-700 ml-2">Supprimer</button>');
705
- const content = $('<div class="content prose prose-violet max-w-none p-4"></div>').html(marked.parse(diss.content)); // Convertir en HTML
706
-
707
- collapsible.append(deleteButton); // Ajouter le bouton supprimer
708
- dissertationsList.append(collapsible, content);
709
-
710
- // Gestionnaire d'événement pour chaque section repliable
711
- collapsible.click(function(event) {
712
- // Empêcher la propagation de l'événement click sur le bouton "Supprimer"
713
- if (event.target === deleteButton[0]) {
714
- return;
715
- }
716
-
717
- content.slideToggle("fast");
718
- collapsible.toggleClass("active");
719
- });
720
-
721
- deleteButton.click(function() {
722
- // Supprimer la dissertation correspondante
723
- deleteDissertation(index);
724
-
725
- });
726
- });
727
- }
728
-
729
- // Appeler la fonction pour afficher les dissertations au chargement de la page
730
- updateSavedDissertationsList();
731
-
732
- // Nouvelle gestion de la copie
733
- $('#copy-btn').click(function() {
734
- // Sélectionner le contenu de la réponse en utilisant innerHTML pour obtenir le HTML formaté
735
- const responseDiv = document.querySelector('#response > div');
736
- let textToCopy = '';
737
-
738
- // Créer un élément temporaire pour convertir le HTML en texte brut tout en préservant le formatage
739
- const temp = document.createElement('div');
740
- temp.innerHTML = responseDiv.innerHTML;
741
-
742
- // Fonction récursive pour extraire le texte en préservant les sauts de ligne
743
- function extractText(node) {
744
- let text = '';
745
- node.childNodes.forEach(child => {
746
- if (child.nodeType === 3) { // Nœud texte
747
- text += child.textContent;
748
- } else if (child.nodeType === 1) { // Élément
749
- // Ajouter des sauts de ligne pour les éléments de bloc
750
- if (window.getComputedStyle(child).display === 'block') {
751
- text += '\n';
752
- }
753
- text += extractText(child);
754
- if (window.getComputedStyle(child).display === 'block') {
755
- text += '\n';
756
- }
757
- }
758
- });
759
- return text;
760
- }
761
-
762
- textToCopy = extractText(temp).trim();
763
-
764
- // Animation et copie
765
- $(this).addClass('scale-95 bg-violet-100');
766
-
767
- // Utiliser l'API Clipboard avec gestion des erreurs
768
- navigator.clipboard.writeText(textToCopy)
769
- .then(() => {
770
- $(this).removeClass('scale-95 bg-violet-100')
771
- .addClass('bg-green-50 text-green-700');
772
-
773
- setTimeout(() => {
774
- $(this).removeClass('bg-green-50 text-green-700');
775
- }, 1000);
776
-
777
- Toast.fire({
778
- icon: 'success',
779
- title: 'Copié avec succès',
780
- text: 'Le contenu a été copié dans votre presse-papiers',
781
- timer: 2000
782
- });
783
- })
784
- .catch((err) => {
785
- // Fallback pour les appareils mobiles qui ne supportent pas l'API Clipboard
786
- try {
787
- // Créer un élément textarea temporaire
788
- const textarea = document.createElement('textarea');
789
- textarea.value = textToCopy;
790
- textarea.style.position = 'fixed'; // Évite le défilement
791
- textarea.style.opacity = '0';
792
- document.body.appendChild(textarea);
793
-
794
- // Sélectionner et copier le texte
795
- textarea.select();
796
- document.execCommand('copy');
797
-
798
- // Nettoyer
799
- document.body.removeChild(textarea);
800
-
801
- // Feedback positif
802
- $(this).removeClass('scale-95 bg-violet-100')
803
- .addClass('bg-green-50 text-green-700');
804
-
805
- setTimeout(() => {
806
- $(this).removeClass('bg-green-50 text-green-700');
807
- }, 1000);
808
-
809
- Toast.fire({
810
- icon: 'success',
811
- title: 'Copié avec succès',
812
- timer: 2000
813
- });
814
- } catch (fallbackErr) {
815
- // Si même le fallback échoue
816
- $(this).removeClass('scale-95 bg-violet-100')
817
- .addClass('bg-red-50 text-red-700');
818
-
819
- setTimeout(() => {
820
- $(this).removeClass('bg-red-50 text-red-700');
821
- }, 1000);
822
-
823
- Toast.fire({
824
- icon: 'error',
825
- title: 'Erreur de copie',
826
- text: 'Impossible de copier le contenu',
827
- timer: 3000
828
- });
829
- }
830
- });
831
- });
832
-
833
-
834
- // Ajout des styles d'animation personnalisés
835
- const style = document.createElement('style');
836
- style.textContent = `
837
- @keyframes fadeIn {
838
- from { opacity: 0; transform: translateY(10px); }
839
- to { opacity: 1; transform: translateY(0); }
840
- }
841
- @keyframes slideUp {
842
- from { opacity: 0; transform: translateY(20px); }
843
- to { opacity: 1; transform: translateY(0); }
844
- }
845
- @keyframes shake {
846
- 0%, 100% { transform: translateX(0); }
847
- 25% { transform: translateX(-5px); }
848
- 75% { transform: translateX(5px); }
849
- }
850
- .animate-fadeIn {
851
- animation: fadeIn 0.5s ease-out forwards;
852
- }
853
- .animate-slideUp {
854
- animation: slideUp 0.5s ease-out forwards;
855
- }
856
- .animate-shake {
857
- animation: shake 0.5s ease-in-out;
858
- }
859
- `;
860
- document.head.appendChild(style);
861
- });
862
- </script>
863
-
864
- </body>
865
- </html>