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

Create philosophie.html

Browse files
Files changed (1) hide show
  1. templates/philosophie.html +865 -0
templates/philosophie.html ADDED
@@ -0,0 +1,865 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>