Docfile commited on
Commit
564705b
·
verified ·
1 Parent(s): 64ff4b2

Update templates/philosophie.html

Browse files
Files changed (1) hide show
  1. templates/philosophie.html +242 -426
templates/philosophie.html CHANGED
@@ -3,453 +3,293 @@
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
- <title>Assistant de Philosophie (Vue.js)</title>
7
 
8
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
10
 
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@400;600&display=swap" rel="stylesheet">
 
14
 
15
  <style>
16
  :root {
17
- --primary: #1f2937;
18
- --secondary: #6366f1;
19
- --accent: #f59e0b;
20
- --text-primary: #111827;
21
- --text-secondary: #6b7280;
22
- --background: #fafafa;
23
- --surface: #ffffff;
24
- --border: #e5e7eb;
25
- --hover: #f3f4f6;
26
  }
27
 
 
28
  * {
29
- margin: 0;
30
- padding: 0;
31
  box-sizing: border-box;
32
  }
33
 
34
  body {
35
- font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
36
- background: var(--background);
37
- color: var(--text-primary);
38
- line-height: 1.6;
39
- font-weight: 400;
40
- }
41
-
42
- .main-container {
43
- min-height: 100vh;
44
- padding: 2rem;
45
- display: flex;
46
- align-items: flex-start;
47
- justify-content: center;
 
 
 
 
 
48
  }
49
 
50
- .app-wrapper {
51
- width: 100%;
52
- max-width: 900px;
53
- background: var(--surface);
54
- border-radius: 24px;
55
- overflow: hidden;
56
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02), 0 4px 25px rgba(0, 0, 0, 0.04);
57
  }
58
 
59
- .header {
60
- background: linear-gradient(135deg, var(--primary) 0%, #374151 100%);
61
- padding: 3rem 3rem 2rem;
62
  text-align: center;
 
 
 
 
 
 
 
 
63
  position: relative;
64
- overflow: hidden;
65
- }
66
-
67
- .header::before {
68
- content: '';
69
- position: absolute;
70
- top: 0;
71
- left: 0;
72
- right: 0;
73
- bottom: 0;
74
- background: url("data:image/svg+xml,%3Csvg width='40' height='40' viewBox='0 0 40 40' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='%23ffffff' fill-opacity='0.02'%3E%3Cpath d='M20 20c0 11.046-8.954 20-20 20v-2c9.94 0 18-8.06 18-18s-8.06-18-18-18V0c11.046 0 20 8.954 20 20zM0 2v2a18 18 0 1 1 18 18h2a20 20 0 1 0-20-20z'/%3E%3C/g%3E%3C/svg%3E") repeat;
75
- opacity: 0.5;
76
  }
77
 
78
- .header-title {
79
- font-family: 'Playfair Display', serif;
80
- font-size: 2.5rem;
81
- font-weight: 600;
82
- color: white;
83
  margin-bottom: 0.5rem;
84
- position: relative;
85
- z-index: 1;
86
- }
87
-
88
- .header-subtitle {
89
- color: rgba(255, 255, 255, 0.8);
90
- font-size: 1.1rem;
91
- font-weight: 300;
92
- position: relative;
93
- z-index: 1;
94
- }
95
-
96
- .content {
97
- padding: 3rem;
98
- }
99
-
100
- .form-section {
101
- margin-bottom: 2rem;
102
  }
103
-
 
104
  .form-group {
105
- margin-bottom: 1.5rem;
106
- }
107
-
108
- .form-label {
109
- display: block;
110
- font-weight: 500;
111
- color: var(--text-primary);
112
- margin-bottom: 0.75rem;
113
- font-size: 0.95rem;
114
  }
115
 
116
- .form-input, .form-select, .form-textarea {
117
  width: 100%;
118
- padding: 1rem 1.25rem;
119
- border: 1px solid var(--border);
120
- border-radius: 12px;
121
  font-size: 1rem;
122
- background: var(--surface);
123
- transition: all 0.2s ease;
124
- font-family: inherit;
125
- }
126
-
127
- .form-textarea {
128
- min-height: 120px;
129
- resize: vertical;
130
- line-height: 1.6;
131
  }
132
-
133
  .form-select {
134
- cursor: pointer;
135
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
136
- background-position: right 1rem center;
137
  background-repeat: no-repeat;
138
- background-size: 1.25rem;
139
- padding-right: 3rem;
140
- appearance: none;
 
 
 
 
141
  }
142
 
143
- .form-input:focus, .form-select:focus, .form-textarea:focus {
144
  outline: none;
145
- border-color: var(--secondary);
146
- box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.1);
147
- background: white;
148
  }
149
-
150
- .btn {
151
- display: inline-flex;
152
- align-items: center;
153
- justify-content: center;
154
- padding: 1rem 2rem;
 
 
155
  border: none;
156
- border-radius: 12px;
157
- font-size: 1rem;
158
  font-weight: 500;
159
  cursor: pointer;
160
- transition: all 0.2s ease;
161
- text-decoration: none;
162
- font-family: inherit;
163
- min-height: 52px;
164
- }
165
-
166
- .btn-primary {
167
- background: var(--secondary);
168
- color: white;
169
- width: 100%;
170
- }
171
-
172
- .btn-primary:hover:not(:disabled) {
173
- background: #5855eb;
174
- transform: translateY(-1px);
175
- box-shadow: 0 4px 20px rgba(99, 102, 241, 0.3);
176
- }
177
-
178
- .btn-secondary {
179
- background: var(--hover);
180
- color: var(--text-primary);
181
- border: 1px solid var(--border);
182
- width: 100%;
183
- margin-top: 1rem;
184
  }
185
 
186
- .btn-secondary:hover:not(:disabled) {
187
- background: #e5e7eb;
188
- border-color: #d1d5db;
189
  transform: translateY(-1px);
190
  }
191
 
192
- .btn:disabled {
193
- opacity: 0.6;
194
  cursor: not-allowed;
195
- transform: none !important;
196
  }
197
-
198
- /* Loader avec pourcentage */
199
- .loading-container {
200
- display: flex;
201
- flex-direction: column;
202
- align-items: center;
203
- padding: 3rem 0;
204
- gap: 1.5rem;
205
  }
206
-
207
- .progress-circle {
208
- position: relative;
209
- width: 120px;
210
- height: 120px;
211
  }
212
-
213
- .progress-ring {
214
- width: 120px;
215
- height: 120px;
216
- transform: rotate(-90deg);
217
  }
218
 
219
- .progress-ring-bg {
220
- fill: transparent;
221
- stroke: #f3f4f6;
222
- stroke-width: 8;
223
  }
224
-
225
- .progress-ring-fill {
226
- fill: transparent;
227
- stroke: var(--secondary);
228
- stroke-width: 8;
229
- stroke-linecap: round;
230
- stroke-dasharray: 314;
231
- stroke-dashoffset: 314;
232
- transition: stroke-dashoffset 0.5s ease;
233
  }
234
-
235
- .progress-text {
236
- position: absolute;
237
- top: 50%;
238
- left: 50%;
239
- transform: translate(-50%, -50%);
240
- font-size: 1.5rem;
241
- font-weight: 600;
242
- color: var(--secondary);
243
  }
244
-
245
- .loading-message {
246
- color: var(--text-secondary);
247
- font-size: 1.1rem;
248
  text-align: center;
 
 
249
  font-weight: 500;
250
  }
251
 
252
- .error-message {
253
- background: linear-gradient(135deg, #fef2f2 0%, #fee2e2 100%);
254
- color: #dc2626;
255
- padding: 1.25rem;
256
- border-radius: 12px;
257
  margin-top: 1.5rem;
258
- border-left: 4px solid #ef4444;
 
259
  font-weight: 500;
 
260
  }
261
 
262
- /* Styles pour la dissertation */
263
  .dissertation-paper {
264
- font-family: 'Inter', sans-serif;
265
- font-size: 18px;
266
- color: #1a202c;
267
- background: #fefefe;
268
- line-height: 1.8;
269
- padding: 3rem;
270
- margin: 2rem 0;
271
- border-radius: 16px;
272
- border: 1px solid #e2e8f0;
273
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.02);
274
- }
275
-
276
- .dissertation-paper h2 {
277
- font-family: 'Playfair Display', serif;
278
- font-size: 1.75rem;
279
- text-align: center;
280
- margin-bottom: 2rem;
281
- color: var(--primary);
282
- font-weight: 600;
283
- }
284
-
285
- .dissertation-paper h3 {
286
- font-size: 1.25rem;
287
- margin: 2.5rem 0 1.5rem;
288
- color: var(--primary);
289
- font-weight: 600;
290
- border-bottom: 2px solid var(--secondary);
291
- padding-bottom: 0.5rem;
292
- display: inline-block;
293
- }
294
-
295
- .dissertation-paper .prof {
296
- text-align: center;
297
- font-style: italic;
298
- margin-bottom: 2.5rem;
299
- color: var(--text-secondary);
300
- font-size: 1.1rem;
301
- }
302
-
303
- .dissertation-paper p {
304
- text-align: justify;
305
- margin-bottom: 1.5rem;
306
- }
307
-
308
- .dissertation-paper .indented {
309
- text-indent: 2rem;
310
- }
311
-
312
- .dissertation-paper .transition {
313
- font-style: italic;
314
- color: var(--secondary);
315
- border-left: 3px solid var(--secondary);
316
- padding-left: 1rem;
317
- margin: 2rem 0;
318
- background: rgba(99, 102, 241, 0.05);
319
- border-radius: 8px;
320
- padding: 1rem 1rem 1rem 2rem;
321
- }
322
-
323
- .development-block {
324
- margin: 2rem 0;
325
- }
326
-
327
- .avoid-page-break {
328
- page-break-inside: avoid;
329
- break-inside: avoid;
330
- }
331
-
332
- /* Responsive */
333
- @media (max-width: 768px) {
334
- .main-container {
335
- padding: 1rem;
336
- }
337
-
338
- .header {
339
- padding: 2rem 1.5rem;
340
- }
341
-
342
- .header-title {
343
- font-size: 2rem;
344
- }
345
-
346
- .content {
347
- padding: 2rem 1.5rem;
348
- }
349
-
350
- .dissertation-paper {
351
- padding: 2rem 1.5rem;
352
- }
353
- }
354
-
355
- /* Animation pour l'entrée */
356
- @keyframes fadeInUp {
357
- from {
358
- opacity: 0;
359
- transform: translateY(30px);
360
- }
361
- to {
362
- opacity: 1;
363
- transform: translateY(0);
364
- }
365
- }
366
-
367
- .app-wrapper {
368
- animation: fadeInUp 0.6s ease-out;
369
- }
370
  </style>
371
  </head>
372
  <body>
373
- <div class="main-container">
374
- <div id="app" class="app-wrapper">
375
- <div class="header">
376
- <h1 class="header-title">Assistant Philosophique</h1>
377
- <p class="header-subtitle">Méthodologie [[ dissertationTypeLabel ]] • Génération automatisée</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  </div>
379
 
380
- <div class="content">
381
- <form @submit.prevent="generateDissertation" class="form-section">
382
- <div class="form-group">
383
- <label for="dissertation-type" class="form-label">Méthodologie de dissertation</label>
384
- <select id="dissertation-type" v-model="dissertationType" class="form-select">
385
- <option value="type1">Type 1 Problématique en deux questions</option>
386
- <option value="type2">Type 2 — Introduction autour d'une citation</option>
387
- </select>
388
- </div>
389
-
390
- <div class="form-group">
391
- <label for="course-context" class="form-label">Contexte de cours (optionnel)</label>
392
- <select id="course-context" v-model="selectedCourse" class="form-select">
393
- <option value="">Aucun contexte spécifique</option>
394
- <option v-for="course in courses" :key="course.id" :value="course.id">
395
- [[ course.title ]]
396
- </option>
397
- </select>
398
- </div>
399
-
400
- <div class="form-group">
401
- <label for="question" class="form-label">Sujet de dissertation</label>
402
- <textarea id="question" v-model="question" class="form-textarea"
403
- placeholder="Saisissez ici votre sujet de dissertation ou la citation à analyser..."></textarea>
404
- </div>
405
-
406
- <button type="submit" :disabled="isLoading" class="btn btn-primary">
407
- [[ isLoading ? 'Génération en cours...' : 'Générer la dissertation' ]]
408
- </button>
409
- </form>
410
-
411
- <div v-if="dissertation" data-html2canvas-ignore="true">
412
- <button class="btn btn-secondary" @click="generatePDF">
413
- 📄 Télécharger en PDF
414
- </button>
415
- </div>
416
 
417
- <div v-if="isLoading" class="loading-container">
418
- <div class="progress-circle">
419
- <svg class="progress-ring">
420
- <circle class="progress-ring-bg" cx="60" cy="60" r="50"></circle>
421
- <circle class="progress-ring-fill" cx="60" cy="60" r="50"
422
- :style="{ strokeDashoffset: 314 - (314 * progress / 100) }"></circle>
423
- </svg>
424
- <div class="progress-text">[[ Math.round(progress) ]]%</div>
 
 
 
 
 
 
 
 
 
 
 
425
  </div>
426
- <div class="loading-message">[[ loadingMessage ]]</div>
427
- </div>
428
-
429
- <div v-if="errorMessage" class="error-message">
430
- ⚠️ [[ errorMessage ]]
431
  </div>
432
 
433
- <div v-if="dissertation" id="dissertation-content" class="dissertation-paper">
434
- <h2>Sujet : [[ dissertation.sujet ]]</h2>
435
- <p class="prof">Professeur : [[ dissertation.prof ]]</p>
436
-
437
- <h3>Introduction</h3>
438
- <p class="indented">[[ dissertation.introduction ]]</p>
439
-
440
- <div v-for="partie in dissertation.parties" :key="partie.chapeau" class="avoid-page-break">
441
- <div class="development-block">
442
- <p class="indented">[[ partie.chapeau ]]</p>
443
- <p v-for="(arg, idx) in partie.arguments" :key="idx" class="indented">
444
- [[ arg.paragraphe_argumentatif ]]
445
- </p>
446
- </div>
447
- <div v-if="partie.transition" class="transition">[[ partie.transition ]]</div>
448
- </div>
449
-
450
- <h3>Conclusion</h3>
451
- <p class="indented">[[ dissertation.conclusion ]]</p>
452
- </div>
453
  </div>
454
  </div>
455
  </div>
@@ -465,10 +305,10 @@
465
  courses: [],
466
  selectedCourse: '',
467
  isLoading: false,
 
 
468
  errorMessage: null,
469
- dissertation: null,
470
- progress: 0,
471
- loadingMessage: 'Initialisation...'
472
  }
473
  },
474
  computed: {
@@ -483,7 +323,7 @@
483
  async fetchCourses() {
484
  try {
485
  const response = await fetch('/api/philosophy/courses');
486
- if (!response.ok) throw new Error('Impossible de charger les cours. Vérifiez la connexion à la base de données.');
487
  const data = await response.json();
488
  if (data.error) throw new Error(data.error);
489
  this.courses = data;
@@ -492,36 +332,26 @@
492
  console.error("Erreur de chargement des cours:", error);
493
  }
494
  },
495
-
496
- simulateProgress() {
497
- const messages = [
498
- 'Initialisation...',
499
- 'Analyse du sujet...',
500
- 'Recherche de références...',
501
- 'Construction de la problématique...',
502
- 'Développement des arguments...',
503
- 'Rédaction de l\'introduction...',
504
- 'Élaboration du plan...',
505
- 'Rédaction du développement...',
506
- 'Formulation de la conclusion...',
507
- 'Finalisation...'
508
- ];
509
-
510
- const intervals = [10, 20, 35, 50, 65, 75, 85, 95, 99, 100];
511
- let step = 0;
512
-
513
- const updateProgress = () => {
514
- if (step < intervals.length && this.isLoading) {
515
- this.progress = intervals[step];
516
- this.loadingMessage = messages[step];
517
- step++;
518
-
519
- const delay = step < 3 ? 800 : step < 6 ? 1200 : 1000;
520
- setTimeout(updateProgress, delay);
521
- }
522
- };
523
-
524
- updateProgress();
525
  },
526
 
527
  async generateDissertation() {
@@ -529,14 +359,11 @@
529
  this.errorMessage = "Veuillez entrer un sujet de dissertation.";
530
  return;
531
  }
532
-
533
  this.isLoading = true;
534
  this.errorMessage = null;
535
  this.dissertation = null;
536
- this.progress = 0;
537
 
538
- this.simulateProgress();
539
-
540
  try {
541
  const response = await fetch('/api/generate_dissertation', {
542
  method: 'POST',
@@ -547,25 +374,15 @@
547
  courseId: this.selectedCourse
548
  })
549
  });
550
-
551
  const data = await response.json();
552
  if (!response.ok) {
553
  throw new Error(data.error || "Une erreur inconnue est survenue.");
554
  }
555
-
556
- this.progress = 100;
557
- this.loadingMessage = 'Terminé !';
558
-
559
- setTimeout(() => {
560
- this.dissertation = data;
561
- }, 500);
562
-
563
  } catch (error) {
564
  this.errorMessage = error.message;
565
  } finally {
566
- setTimeout(() => {
567
- this.isLoading = false;
568
- }, 800);
569
  }
570
  },
571
 
@@ -575,7 +392,6 @@
575
  this.errorMessage = "Contenu introuvable pour le PDF.";
576
  return;
577
  }
578
-
579
  try {
580
  if (document.fonts && document.fonts.ready) {
581
  await document.fonts.ready;
@@ -589,8 +405,8 @@
589
  html2canvas: {
590
  scale: 2,
591
  useCORS: true,
592
- logging: false,
593
- backgroundColor: '#ffffff',
594
  },
595
  jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
596
  };
 
3
  <head>
4
  <meta charset="UTF-8" />
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>Assistant de Philosophie</title>
7
 
8
  <script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
9
  <script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
10
 
11
  <link rel="preconnect" href="https://fonts.googleapis.com">
12
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
13
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;700&family=Kalam&display=swap" rel="stylesheet">
14
+
15
 
16
  <style>
17
  :root {
18
+ --primary-color: #3b82f6; /* Bleu doux */
19
+ --primary-hover: #2563eb;
20
+ --text-color-dark: #1f2937; /* Gris très foncé */
21
+ --text-color-light: #4b5563; /* Gris moyen */
22
+ --background-color: #f9fafb; /* Gris très clair */
23
+ --container-bg: #ffffff;
24
+ --border-color: #d1d5db;
25
+ --border-focus-color: var(--primary-color);
 
26
  }
27
 
28
+ /* === Reset et Base === */
29
  * {
 
 
30
  box-sizing: border-box;
31
  }
32
 
33
  body {
34
+ font-family: 'Inter', sans-serif;
35
+ background-color: var(--background-color);
36
+ margin: 0;
37
+ padding: 3rem 1.5rem;
38
+ color: var(--text-color-dark);
39
+ -webkit-font-smoothing: antialiased;
40
+ -moz-osx-font-smoothing: grayscale;
41
+ }
42
+
43
+ /* === Layout et Conteneur principal === */
44
+ #app {
45
+ max-width: 800px;
46
+ margin: 0 auto;
47
+ background: var(--container-bg);
48
+ padding: 2.5rem 3rem;
49
+ border-radius: 16px;
50
+ border: 1px solid var(--border-color);
51
+ box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.05), 0 2px 4px -2px rgb(0 0 0 / 0.05);
52
  }
53
 
54
+ /* === Typographie === */
55
+ h1 {
56
+ text-align: center;
57
+ color: var(--text-color-dark);
58
+ font-size: 2.25rem;
59
+ font-weight: 700;
60
+ margin-bottom: 0.25em;
61
  }
62
 
63
+ .type-indicator {
 
 
64
  text-align: center;
65
+ color: var(--text-color-light);
66
+ font-size: 1rem;
67
+ margin-bottom: 3rem;
68
+ font-weight: 500;
69
+ background-color: #f3f4f6;
70
+ display: inline-block;
71
+ padding: 0.25rem 0.75rem;
72
+ border-radius: 999px;
73
  position: relative;
74
+ left: 50%;
75
+ transform: translateX(-50%);
 
 
 
 
 
 
 
 
 
 
76
  }
77
 
78
+ label {
79
+ display: block;
 
 
 
80
  margin-bottom: 0.5rem;
81
+ font-weight: 500;
82
+ color: var(--text-color-dark);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
+
85
+ /* === Formulaires === */
86
  .form-group {
87
+ margin-bottom: 1.5rem;
 
 
 
 
 
 
 
 
88
  }
89
 
90
+ textarea, .form-select {
91
  width: 100%;
92
+ padding: 0.875rem 1rem;
93
+ border-radius: 8px;
94
+ border: 1px solid var(--border-color);
95
  font-size: 1rem;
96
+ line-height: 1.5;
97
+ transition: border-color 0.2s, box-shadow 0.2s;
98
+ background-color: #fff;
99
+ -webkit-appearance: none;
100
+ -moz-appearance: none;
101
+ appearance: none;
 
 
 
102
  }
103
+
104
  .form-select {
 
105
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
106
+ background-position: right 0.75rem center;
107
  background-repeat: no-repeat;
108
+ background-size: 1.5em 1.5em;
109
+ padding-right: 2.5rem;
110
+ }
111
+
112
+ textarea {
113
+ min-height: 120px;
114
+ resize: vertical;
115
  }
116
 
117
+ textarea:focus, .form-select:focus {
118
  outline: none;
119
+ border-color: var(--border-focus-color);
120
+ box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2);
 
121
  }
122
+
123
+ /* === Boutons === */
124
+ button {
125
+ display: block;
126
+ width: 100%;
127
+ padding: 1rem;
128
+ background-color: var(--primary-color);
129
+ color: white;
130
  border: none;
131
+ border-radius: 8px;
132
+ font-size: 1.125rem;
133
  font-weight: 500;
134
  cursor: pointer;
135
+ transition: background-color 0.2s, transform 0.1s;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
138
+ button:hover:not(:disabled) {
139
+ background-color: var(--primary-hover);
 
140
  transform: translateY(-1px);
141
  }
142
 
143
+ button:disabled {
144
+ background-color: #9ca3af;
145
  cursor: not-allowed;
 
146
  }
147
+
148
+ .download-container {
149
+ margin-top: 1.5rem;
 
 
 
 
 
150
  }
151
+ .secondary-button {
152
+ background-color: transparent;
153
+ color: var(--text-color-light);
154
+ border: 1px solid var(--border-color);
 
155
  }
156
+ .secondary-button:hover:not(:disabled) {
157
+ background-color: #f9fafb;
158
+ border-color: #9ca3af;
 
 
159
  }
160
 
161
+ /* === Loader avec Pourcentage === */
162
+ .loader-container {
163
+ width: 100%;
164
+ margin: 2.5rem 0;
165
  }
166
+ .progress-bar {
167
+ height: 12px;
168
+ background-color: #e5e7eb;
169
+ border-radius: 6px;
170
+ overflow: hidden;
 
 
 
 
171
  }
172
+ .progress-bar-inner {
173
+ height: 100%;
174
+ width: 0%;
175
+ background-color: var(--primary-color);
176
+ border-radius: 6px;
177
+ transition: width 0.4s ease-in-out;
 
 
 
178
  }
179
+ .progress-text {
 
 
 
180
  text-align: center;
181
+ margin-top: 0.5rem;
182
+ color: var(--text-color-light);
183
  font-weight: 500;
184
  }
185
 
186
+ /* === Message d'erreur === */
187
+ .error {
188
+ color: #b91c1c;
189
+ background-color: #fee2e2;
190
+ text-align: center;
191
  margin-top: 1.5rem;
192
+ padding: 1rem;
193
+ border-radius: 8px;
194
  font-weight: 500;
195
+ border: 1px solid #fecaca;
196
  }
197
 
198
+ /* === Styles de la feuille de dissertation (INCHANGÉS) === */
199
  .dissertation-paper {
200
+ font-family: 'Kalam', cursive;
201
+ font-size: 20px;
202
+ color: #1a2a4c;
203
+ background-color: #fdfaf4;
204
+ line-height: 2;
205
+ background-image: linear-gradient(transparent 97%, #d8e2ee 98%);
206
+ background-size: 100% 40px;
207
+ border-left: 3px solid #ffaaab;
208
+ padding-left: 4em;
209
+ margin: 40px -48px -40px -48px; /* Ajusté au nouveau padding */
210
+ padding-top: 30px;
211
+ padding-bottom: 40px;
212
+ padding-right: 30px;
213
+ -webkit-print-color-adjust: exact;
214
+ print-color-adjust: exact;
215
+ }
216
+ .dissertation-paper h2 { font-size: 1.5em; text-align: center; margin-bottom: 1.5em; }
217
+ .dissertation-paper h3 { font-size: 1.2em; margin-top: 3em; margin-bottom: 1.5em; text-transform: uppercase; text-decoration: underline; }
218
+ .dissertation-paper .development-block { margin-top: 3em; }
219
+ .dissertation-paper p { text-align: justify; margin: 0; padding: 0; }
220
+ .dissertation-paper .prof { text-align: center; font-style: italic; margin-bottom: 2em; }
221
+ .dissertation-paper .indented { text-indent: 3em; }
222
+ .dissertation-paper .transition { margin-top: 2em; margin-bottom: 2em; font-style: italic; color: #4a6a9c; }
223
+ .dissertation-paper, .dissertation-paper * { box-sizing: border-box; }
224
+
225
+ .avoid-page-break { page-break-inside: avoid; break-inside: avoid; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  </style>
227
  </head>
228
  <body>
229
+ <div id="app">
230
+ <h1>Assistant Philosophique</h1>
231
+ <p class="type-indicator">Méthode : [[ dissertationTypeLabel ]]</p>
232
+
233
+ <form @submit.prevent="generateDissertation" v-if="!dissertation">
234
+ <div class="form-group">
235
+ <label for="dissertation-type">Choisir la méthodologie</label>
236
+ <select id="dissertation-type" v-model="dissertationType" class="form-select">
237
+ <option value="type1">Type 1 (Problématique en deux questions)</option>
238
+ <option value="type2">Type 2 (Introduction autour d'une citation)</option>
239
+ </select>
240
+ </div>
241
+
242
+ <div class="form-group">
243
+ <label for="course-context">Contexte du cours (optionnel)</label>
244
+ <select id="course-context" v-model="selectedCourse" class="form-select">
245
+ <option value="">-- Aucun cours en contexte --</option>
246
+ <option v-for="course in courses" :key="course.id" :value="course.id">
247
+ [[ course.title ]]
248
+ </option>
249
+ </select>
250
  </div>
251
 
252
+ <div class="form-group">
253
+ <label for="question">Votre sujet de dissertation</label>
254
+ <textarea id="question" v-model="question" placeholder="Entrez votre sujet ou la citation à analyser ici..."></textarea>
255
+ </div>
256
+ <button type="submit" :disabled="isLoading">
257
+ [[ isLoading ? 'Génération en cours...' : 'Générer la dissertation' ]]
258
+ </button>
259
+ </form>
260
+
261
+ <div v-if="isLoading" class="loader-container">
262
+ <div class="progress-bar">
263
+ <div class="progress-bar-inner" :style="{ width: loadingProgress + '%' }"></div>
264
+ </div>
265
+ <p class="progress-text">Analyse du sujet... [[ Math.round(loadingProgress) ]]%</p>
266
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
267
 
268
+ <p v-if="errorMessage" class="error">[[ errorMessage ]]</p>
269
+
270
+ <div v-if="dissertation">
271
+ <div class="download-container" data-html2canvas-ignore="true">
272
+ <button class="secondary-button" @click="generatePDF">Télécharger la dissertation en PDF</button>
273
+ </div>
274
+ <div id="dissertation-content" class="dissertation-paper">
275
+ <h2>Sujet : [[ dissertation.sujet ]]</h2>
276
+ <p class="prof">Prof : [[ dissertation.prof ]]</p>
277
+
278
+ <h3>Introduction</h3>
279
+ <p class="indented">[[ dissertation.introduction ]]</p>
280
+
281
+ <div v-for="partie in dissertation.parties" :key="partie.chapeau" class="avoid-page-break">
282
+ <div class="development-block">
283
+ <p class="indented">[[ partie.chapeau ]]</p>
284
+ <p v-for="(arg, idx) in partie.arguments" :key="idx" class="indented">
285
+ [[ arg.paragraphe_argumentatif ]]
286
+ </p>
287
  </div>
288
+ <p v-if="partie.transition" class="indented transition">[[ partie.transition ]]</p>
 
 
 
 
289
  </div>
290
 
291
+ <h3>Conclusion</h3>
292
+ <p class="indented">[[ dissertation.conclusion ]]</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
  </div>
294
  </div>
295
  </div>
 
305
  courses: [],
306
  selectedCourse: '',
307
  isLoading: false,
308
+ loadingProgress: 0, // Pour le nouveau loader
309
+ progressInterval: null, // Pour stocker l'ID de l'intervalle
310
  errorMessage: null,
311
+ dissertation: null
 
 
312
  }
313
  },
314
  computed: {
 
323
  async fetchCourses() {
324
  try {
325
  const response = await fetch('/api/philosophy/courses');
326
+ if (!response.ok) throw new Error('Impossible de charger les cours.');
327
  const data = await response.json();
328
  if (data.error) throw new Error(data.error);
329
  this.courses = data;
 
332
  console.error("Erreur de chargement des cours:", error);
333
  }
334
  },
335
+
336
+ // Méthode pour simuler la progression
337
+ startProgressSimulation() {
338
+ this.loadingProgress = 0;
339
+ this.progressInterval = setInterval(() => {
340
+ // Fait progresser la barre, mais ralentit en approchant de 99%
341
+ if (this.loadingProgress < 99) {
342
+ const increment = Math.random() * (100 - this.loadingProgress) / 25;
343
+ this.loadingProgress = Math.min(99, this.loadingProgress + increment);
344
+ }
345
+ }, 200);
346
+ },
347
+
348
+ stopProgressSimulation() {
349
+ clearInterval(this.progressInterval);
350
+ this.loadingProgress = 100;
351
+ // On cache la barre après une courte temporisation
352
+ setTimeout(() => {
353
+ this.isLoading = false;
354
+ }, 500);
 
 
 
 
 
 
 
 
 
 
355
  },
356
 
357
  async generateDissertation() {
 
359
  this.errorMessage = "Veuillez entrer un sujet de dissertation.";
360
  return;
361
  }
 
362
  this.isLoading = true;
363
  this.errorMessage = null;
364
  this.dissertation = null;
365
+ this.startProgressSimulation(); // Démarrer la simulation
366
 
 
 
367
  try {
368
  const response = await fetch('/api/generate_dissertation', {
369
  method: 'POST',
 
374
  courseId: this.selectedCourse
375
  })
376
  });
 
377
  const data = await response.json();
378
  if (!response.ok) {
379
  throw new Error(data.error || "Une erreur inconnue est survenue.");
380
  }
381
+ this.dissertation = data;
 
 
 
 
 
 
 
382
  } catch (error) {
383
  this.errorMessage = error.message;
384
  } finally {
385
+ this.stopProgressSimulation(); // Terminer la simulation
 
 
386
  }
387
  },
388
 
 
392
  this.errorMessage = "Contenu introuvable pour le PDF.";
393
  return;
394
  }
 
395
  try {
396
  if (document.fonts && document.fonts.ready) {
397
  await document.fonts.ready;
 
405
  html2canvas: {
406
  scale: 2,
407
  useCORS: true,
408
+ logging: true,
409
+ backgroundColor: null,
410
  },
411
  jsPDF: { unit: 'mm', format: 'a4', orientation: 'portrait' }
412
  };