Docfile commited on
Commit
ee7781a
·
verified ·
1 Parent(s): 7f01bad

Update api/templates/admin/edit_texte.html

Browse files
Files changed (1) hide show
  1. api/templates/admin/edit_texte.html +51 -238
api/templates/admin/edit_texte.html CHANGED
@@ -4,90 +4,44 @@
4
 
5
  {% block styles %}
6
  <style>
7
- /* Quill editor needs some height */
8
- .ql-container { min-height: 150px; }
9
-
10
  .block-editor {
11
  position: relative;
12
  transition: all 0.3s ease;
13
  }
14
-
15
  .block-ghost {
16
  opacity: 0.5;
17
  background: var(--primary-color);
18
  }
19
-
20
  .block-handle {
21
  cursor: move;
22
  color: var(--muted-color);
23
- padding-right: 10px; /* Add some space next to handle */
24
  }
25
-
26
  .image-position-example {
27
  padding: 10px;
28
  border: 1px dashed var(--border-color);
29
  margin-top: 10px;
30
  border-radius: 4px;
31
  }
32
-
33
  .block-image-container {
34
  margin-bottom: 15px;
35
  }
36
-
37
  .image-preview {
38
  max-height: 150px;
39
  object-fit: contain;
40
- border-radius: 4px;
41
- border: 1px solid var(--border-color);
42
- background-color: var(--background-color);
43
  }
44
-
45
  .gallery-image {
46
  transition: transform 0.2s;
47
  cursor: pointer;
48
- border: 1px solid var(--border-color);
49
- padding: 5px;
50
- border-radius: 4px;
51
  }
52
-
53
  .gallery-image:hover {
54
  transform: scale(1.05);
55
- border-color: var(--primary-color);
56
- }
57
-
58
- /* Style adjustments for Quill within the block */
59
- .block-content-editor {
60
- background-color: var(--input-bg); /* Match theme */
61
- border-radius: 4px; /* Match form controls */
62
- margin-bottom: 5px; /* Space between editor and hidden input if needed */
63
- }
64
-
65
- /* Style the block editor structure */
66
- .block-editor {
67
- background-color: var(--card-bg);
68
- padding: 20px;
69
- border: 1px solid var(--border-color);
70
- border-radius: 8px;
71
- box-shadow: var(--shadow);
72
- }
73
- .block-editor-header {
74
- display: flex;
75
- justify-content: space-between;
76
- align-items: center;
77
- margin-bottom: 15px;
78
- padding-bottom: 10px;
79
- border-bottom: 1px solid var(--border-color);
80
- }
81
- .block-editor-title {
82
- margin: 0;
83
- font-size: 1.2rem;
84
- font-weight: 600;
85
- }
86
- .delete-block-btn i {
87
- pointer-events: none; /* Ensure clicking icon triggers button */
88
- }
89
- .ml-2 { /* Simple margin helper */
90
- margin-left: 0.5rem !important;
91
  }
92
  </style>
93
  {% endblock %}
@@ -131,11 +85,11 @@
131
  </ul>
132
  </div>
133
  </div>
134
-
135
  <div class="col-md-9">
136
  <div class="admin-container">
137
  <h2 class="admin-title">Éditer la méthodologie : {{ texte.titre }}</h2>
138
-
139
  <div class="mb-4">
140
  <a href="{{ url_for('admin_bp.textes') }}" class="btn btn-secondary mb-3">
141
  <i class="fas fa-arrow-left"></i> Retour à la liste
@@ -144,7 +98,7 @@
144
  <i class="fas fa-history"></i> Voir l'historique
145
  </a>
146
  </div>
147
-
148
  <!-- Basic Information Form -->
149
  <div class="card mb-4">
150
  <div class="card-header">
@@ -152,14 +106,13 @@
152
  </div>
153
  <div class="card-body">
154
  <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
155
- <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
156
  <input type="hidden" name="action" value="update_basic">
157
-
158
  <div class="form-group mb-3">
159
  <label for="titre">Titre</label>
160
  <input type="text" class="form-control" id="titre" name="titre" value="{{ texte.titre }}" required>
161
  </div>
162
-
163
  <div class="form-group mb-3">
164
  <label for="sous_categorie_id">Sous-catégorie</label>
165
  <select class="form-control" id="sous_categorie_id" name="sous_categorie_id" required>
@@ -170,14 +123,14 @@
170
  {% endfor %}
171
  </select>
172
  </div>
173
-
174
  <button type="submit" class="btn btn-primary">
175
  <i class="fas fa-save"></i> Mettre à jour les informations
176
  </button>
177
  </form>
178
  </div>
179
  </div>
180
-
181
  <!-- Content Blocks Editor -->
182
  <div class="card mb-4">
183
  <div class="card-header d-flex justify-content-between align-items-center">
@@ -188,15 +141,14 @@
188
  </div>
189
  <div class="card-body">
190
  <p class="text-muted mb-4">
191
- Organisez votre contenu en blocs distincts. Chaque bloc peut contenir un titre, du texte riche et une image.
192
- Vous pouvez réorganiser les blocs en les faisant glisser (<i class="fas fa-grip-vertical"></i>).
193
  </p>
194
-
195
  <form id="blocks-form" method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
196
- <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
197
  <input type="hidden" name="action" value="update_blocks">
198
  <input type="hidden" id="blocks-data" name="blocks_data" value="">
199
-
200
  <div id="blocks-container">
201
  {% for block in blocks %}
202
  <div class="block-editor mb-4" data-block-id="{{ block.id }}">
@@ -206,7 +158,7 @@
206
  <h3 class="block-editor-title">Bloc #{{ loop.index }}</h3>
207
  </div>
208
  <div class="block-editor-actions">
209
- <button type="button" class="btn btn-danger btn-sm delete-block-btn" title="Supprimer ce bloc">
210
  <i class="fas fa-trash"></i>
211
  </button>
212
  </div>
@@ -216,16 +168,11 @@
216
  <input type="text" class="form-control block-title" id="block-{{ block.id }}-title" value="{{ block.title or '' }}">
217
  </div>
218
  <div class="form-group mb-3">
219
- <label for="quill-editor-{{ block.id }}">Contenu du bloc</label>
220
- <!-- Quill editor container -->
221
- <div id="quill-editor-{{ block.id }}" class="block-content-editor">
222
- {{ block.content|safe if block.content else '' }}
223
- </div>
224
- <!-- Hidden input to store Quill's HTML content -->
225
- <input type="hidden" class="block-content-hidden" id="block-{{ block.id }}-content" value="{{ block.content or '' }}">
226
  </div>
227
  <div class="form-group">
228
- <label>Image (optionnel)</label>
229
  <div class="d-flex align-items-center mb-2">
230
  <button type="button" class="btn btn-primary btn-sm select-image-btn" {% if block.image %}style="display:none;"{% endif %}>
231
  <i class="fas fa-image"></i> Sélectionner une image
@@ -235,16 +182,16 @@
235
  </button>
236
  </div>
237
  <input type="hidden" class="block-image-id" value="{{ block.image.id if block.image else '' }}">
238
-
 
239
  <div class="block-image-container">
240
- {% if block.image %}
241
- <img src="{{ block.image.src }}" alt="{{ block.image.alt or 'Prévisualisation' }}" class="image-preview">
242
- {% else %}
243
- <img src="" alt="Preview" class="image-preview" style="display:none;">
244
- {% endif %}
245
  </div>
246
-
247
- <div class="form-group mt-3 {% if not block.image %}d-none{% endif %} image-position-controls"> {# Hide position if no image #}
 
 
 
248
  <label for="block-{{ block.id }}-image-position">Position de l'image</label>
249
  <select class="form-control image-position-select" id="block-{{ block.id }}-image-position">
250
  <option value="left" {% if block.image_position == 'left' %}selected{% endif %}>Gauche</option>
@@ -256,51 +203,39 @@
256
  </div>
257
  {% endfor %}
258
  </div>
259
-
260
  <div class="mt-4 text-center">
261
  <button type="button" id="save-blocks-button" class="btn btn-primary btn-lg">
262
- <i class="fas fa-save"></i> Enregistrer les blocs
263
  </button>
264
  </div>
265
  </form>
266
  </div>
267
  </div>
268
-
269
  <!-- Image Upload Section -->
270
  <div class="card mb-4">
271
  <div class="card-header">
272
- <h4>Ajouter une nouvelle image (Galerie)</h4>
273
  </div>
274
  <div class="card-body">
275
- <form method="POST" action="{{ url_for('admin_bp.upload_image_action') }}" enctype="multipart/form-data" id="image-upload-form"> {# Action points to a dedicated route #}
276
- <input type="hidden" name="csrf_token" value="{{ csrf_token() }}"/> {# Add CSRF token if using Flask-WTF #}
277
- {# Removed 'action' hidden input, handled by route #}
278
- {# Removed texte_id hidden input, not needed for general upload #}
279
-
280
  <div class="form-group mb-3">
281
  <label for="image">Sélectionner une image</label>
282
- <input type="file" class="form-control" id="image-file" name="image" accept="image/*" required>
283
  </div>
284
-
285
  <div class="form-group mb-3">
286
  <label for="alt_text">Texte alternatif (pour l'accessibilité)</label>
287
- <input type="text" class="form-control" id="alt_text" name="alt_text" placeholder="Description de l'image" required>
288
  </div>
289
-
290
- <img id="upload-image-preview" src="#" alt="Image Preview" style="display: none; max-height: 100px; margin-bottom: 10px;"/>
291
-
292
-
293
  <button type="submit" class="btn btn-success">
294
- <i class="fas fa-upload"></i> Télécharger et ajouter à la galerie
295
  </button>
296
  </form>
297
- <div id="upload-status" class="mt-3"></div> {# For AJAX feedback #}
298
-
299
- <div class="mt-3">
300
- <a href="{{ url_for('admin_bp.images') }}" class="btn btn-info">
301
- <i class="fas fa-images"></i> Gérer la galerie d'images
302
- </a>
303
- </div>
304
  </div>
305
  </div>
306
  </div>
@@ -309,26 +244,24 @@
309
 
310
  <!-- Image Gallery Modal -->
311
  <div class="modal fade" id="image-gallery-modal" tabindex="-1" aria-labelledby="imageGalleryModalLabel" aria-hidden="true">
312
- <div class="modal-dialog modal-xl"> {# Larger modal for more images #}
313
  <div class="modal-content">
314
  <div class="modal-header">
315
- <h5 class="modal-title" id="imageGalleryModalLabel">Sélectionner une image de la galerie</h5>
316
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
317
  </div>
318
  <div class="modal-body">
319
- <div id="image-gallery-content" class="row">
320
- {# Images will be loaded here dynamically by JS or initially #}
321
  {% for image in images %}
322
- <div class="col-lg-2 col-md-3 col-sm-4 col-6 mb-3">
323
- <div class="gallery-item text-center" data-image-id="{{ image.id }}">
324
- <img src="{{ image.src }}" alt="{{ image.alt or 'Image galerie' }}" class="gallery-image img-fluid">
325
- <small class="d-block mt-1 text-muted" style="word-wrap: break-word;">{{ image.alt or '(Sans description)'}}</small>
326
  </div>
327
  </div>
328
  {% else %}
329
  <div class="col-12">
330
  <div class="alert alert-info">
331
- Aucune image disponible dans la galerie. Veuillez en télécharger une via la section ci-dessus ou la page "Images".
332
  </div>
333
  </div>
334
  {% endfor %}
@@ -344,126 +277,6 @@
344
 
345
  {% block scripts %}
346
  <!-- Include Sortable.js for drag and drop functionality -->
347
- <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.15.0/Sortable.min.js"></script>
348
-
349
- <!-- Include Quill.js -->
350
- <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.snow.css" rel="stylesheet">
351
- <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.js"></script>
352
-
353
- <!-- Your Custom Admin JS -->
354
  <script src="{{ url_for('static', filename='js/admin.js') }}"></script>
355
-
356
- <script>
357
- // Add specific JS for this page if needed,
358
- // for example, handling the image upload AJAX response.
359
-
360
- document.addEventListener('DOMContentLoaded', function() {
361
- // Show/Hide image position controls based on image presence
362
- function toggleImagePositionControls(blockEditor) {
363
- const imageIdInput = blockEditor.querySelector('.block-image-id');
364
- const positionControls = blockEditor.querySelector('.image-position-controls');
365
- if (positionControls) {
366
- if (imageIdInput && imageIdInput.value) {
367
- positionControls.classList.remove('d-none');
368
- } else {
369
- positionControls.classList.add('d-none');
370
- }
371
- }
372
- }
373
-
374
- // Initial check for all blocks
375
- document.querySelectorAll('.block-editor').forEach(toggleImagePositionControls);
376
-
377
- // Add event listeners to image selection/removal buttons to update controls
378
- document.querySelectorAll('.select-image-btn, .remove-image-btn').forEach(button => {
379
- button.addEventListener('click', function() {
380
- // Need a small delay for the image ID value to potentially update
381
- setTimeout(() => {
382
- toggleImagePositionControls(this.closest('.block-editor'));
383
- }, 50);
384
- });
385
- });
386
-
387
- // Update position controls when an image is selected from the gallery
388
- const galleryModal = document.getElementById('image-gallery-modal');
389
- if (galleryModal) {
390
- galleryModal.addEventListener('click', function(event) {
391
- const galleryItem = event.target.closest('.gallery-item');
392
- if (galleryItem) {
393
- const targetBlockId = galleryModal.getAttribute('data-target-block');
394
- const blockEditor = document.querySelector(`.block-editor[data-block-id="${targetBlockId}"]`);
395
- if(blockEditor) {
396
- // Delay necessary as the image selection logic in admin.js runs first
397
- setTimeout(() => {
398
- toggleImagePositionControls(blockEditor);
399
- }, 100);
400
- }
401
- }
402
- });
403
- }
404
-
405
- // Image Upload Preview
406
- const imageFileInput = document.getElementById('image-file');
407
- const imagePreview = document.getElementById('upload-image-preview');
408
-
409
- if(imageFileInput && imagePreview) {
410
- imageFileInput.addEventListener('change', function() {
411
- if (this.files && this.files[0]) {
412
- const reader = new FileReader();
413
- reader.onload = function(e) {
414
- imagePreview.src = e.target.result;
415
- imagePreview.style.display = 'block';
416
- }
417
- reader.readAsDataURL(this.files[0]);
418
- } else {
419
- imagePreview.src = '#';
420
- imagePreview.style.display = 'none';
421
- }
422
- });
423
- }
424
-
425
- // Optional: AJAX Image Upload Handling (Example)
426
- const imageUploadForm = document.getElementById('image-upload-form');
427
- const uploadStatusDiv = document.getElementById('upload-status');
428
-
429
- if (imageUploadForm && uploadStatusDiv) {
430
- imageUploadForm.addEventListener('submit', function(e) {
431
- e.preventDefault(); // Prevent default form submission
432
- uploadStatusDiv.innerHTML = '<div class="alert alert-info">Téléchargement en cours...</div>';
433
- const formData = new FormData(this);
434
-
435
- fetch(this.action, { // Use the form's action URL
436
- method: 'POST',
437
- body: formData,
438
- headers: {
439
- // No 'Content-Type': browser sets it correctly for FormData
440
- 'X-CSRFToken': this.querySelector('input[name="csrf_token"]').value // Send CSRF token if needed
441
- }
442
- })
443
- .then(response => response.json())
444
- .then(data => {
445
- if (data.success) {
446
- uploadStatusDiv.innerHTML = `<div class="alert alert-success">Image "${data.alt}" ajoutée avec succès !</div>`;
447
- // Optionally: Clear the form
448
- imageUploadForm.reset();
449
- if(imagePreview) imagePreview.style.display = 'none';
450
- // Optionally: Refresh the image gallery modal content (more complex)
451
- // You might need another fetch call to get updated gallery HTML
452
- // or just add the new image data to the modal dynamically.
453
- // For simplicity, we'll just notify the user.
454
- alert('Image ajoutée à la galerie. Vous pouvez maintenant la sélectionner pour un bloc.');
455
- } else {
456
- uploadStatusDiv.innerHTML = `<div class="alert alert-danger">Erreur: ${data.error || 'Impossible de télécharger l\'image.'}</div>`;
457
- }
458
- })
459
- .catch(error => {
460
- console.error('Upload error:', error);
461
- uploadStatusDiv.innerHTML = '<div class="alert alert-danger">Erreur lors du téléchargement. Vérifiez la console.</div>';
462
- });
463
- });
464
- }
465
-
466
-
467
- });
468
- </script>
469
- {% endblock %}
 
4
 
5
  {% block styles %}
6
  <style>
 
 
 
7
  .block-editor {
8
  position: relative;
9
  transition: all 0.3s ease;
10
  }
11
+
12
  .block-ghost {
13
  opacity: 0.5;
14
  background: var(--primary-color);
15
  }
16
+
17
  .block-handle {
18
  cursor: move;
19
  color: var(--muted-color);
 
20
  }
21
+
22
  .image-position-example {
23
  padding: 10px;
24
  border: 1px dashed var(--border-color);
25
  margin-top: 10px;
26
  border-radius: 4px;
27
  }
28
+
29
  .block-image-container {
30
  margin-bottom: 15px;
31
  }
32
+
33
  .image-preview {
34
  max-height: 150px;
35
  object-fit: contain;
 
 
 
36
  }
37
+
38
  .gallery-image {
39
  transition: transform 0.2s;
40
  cursor: pointer;
 
 
 
41
  }
42
+
43
  .gallery-image:hover {
44
  transform: scale(1.05);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  }
46
  </style>
47
  {% endblock %}
 
85
  </ul>
86
  </div>
87
  </div>
88
+
89
  <div class="col-md-9">
90
  <div class="admin-container">
91
  <h2 class="admin-title">Éditer la méthodologie : {{ texte.titre }}</h2>
92
+
93
  <div class="mb-4">
94
  <a href="{{ url_for('admin_bp.textes') }}" class="btn btn-secondary mb-3">
95
  <i class="fas fa-arrow-left"></i> Retour à la liste
 
98
  <i class="fas fa-history"></i> Voir l'historique
99
  </a>
100
  </div>
101
+
102
  <!-- Basic Information Form -->
103
  <div class="card mb-4">
104
  <div class="card-header">
 
106
  </div>
107
  <div class="card-body">
108
  <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
 
109
  <input type="hidden" name="action" value="update_basic">
110
+
111
  <div class="form-group mb-3">
112
  <label for="titre">Titre</label>
113
  <input type="text" class="form-control" id="titre" name="titre" value="{{ texte.titre }}" required>
114
  </div>
115
+
116
  <div class="form-group mb-3">
117
  <label for="sous_categorie_id">Sous-catégorie</label>
118
  <select class="form-control" id="sous_categorie_id" name="sous_categorie_id" required>
 
123
  {% endfor %}
124
  </select>
125
  </div>
126
+
127
  <button type="submit" class="btn btn-primary">
128
  <i class="fas fa-save"></i> Mettre à jour les informations
129
  </button>
130
  </form>
131
  </div>
132
  </div>
133
+
134
  <!-- Content Blocks Editor -->
135
  <div class="card mb-4">
136
  <div class="card-header d-flex justify-content-between align-items-center">
 
141
  </div>
142
  <div class="card-body">
143
  <p class="text-muted mb-4">
144
+ Organisez votre contenu en blocs distincts. Chaque bloc peut contenir un titre, du texte et une image.
145
+ Vous pouvez réorganiser les blocs en les faisant glisser.
146
  </p>
147
+
148
  <form id="blocks-form" method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}">
 
149
  <input type="hidden" name="action" value="update_blocks">
150
  <input type="hidden" id="blocks-data" name="blocks_data" value="">
151
+
152
  <div id="blocks-container">
153
  {% for block in blocks %}
154
  <div class="block-editor mb-4" data-block-id="{{ block.id }}">
 
158
  <h3 class="block-editor-title">Bloc #{{ loop.index }}</h3>
159
  </div>
160
  <div class="block-editor-actions">
161
+ <button type="button" class="btn btn-danger btn-sm delete-block-btn">
162
  <i class="fas fa-trash"></i>
163
  </button>
164
  </div>
 
168
  <input type="text" class="form-control block-title" id="block-{{ block.id }}-title" value="{{ block.title or '' }}">
169
  </div>
170
  <div class="form-group mb-3">
171
+ <label for="block-{{ block.id }}-content">Contenu du bloc</label>
172
+ <textarea class="form-control block-content" id="block-{{ block.id }}-content" rows="5">{{ block.content or '' }}</textarea>
 
 
 
 
 
173
  </div>
174
  <div class="form-group">
175
+ <label>Image</label>
176
  <div class="d-flex align-items-center mb-2">
177
  <button type="button" class="btn btn-primary btn-sm select-image-btn" {% if block.image %}style="display:none;"{% endif %}>
178
  <i class="fas fa-image"></i> Sélectionner une image
 
182
  </button>
183
  </div>
184
  <input type="hidden" class="block-image-id" value="{{ block.image.id if block.image else '' }}">
185
+
186
+ {% if block.image %}
187
  <div class="block-image-container">
188
+ <img src="{{ block.image.src }}" alt="{{ block.image.alt }}" class="image-preview">
 
 
 
 
189
  </div>
190
+ {% else %}
191
+ <img src="" alt="Preview" class="image-preview" style="display:none;">
192
+ {% endif %}
193
+
194
+ <div class="form-group mt-3">
195
  <label for="block-{{ block.id }}-image-position">Position de l'image</label>
196
  <select class="form-control image-position-select" id="block-{{ block.id }}-image-position">
197
  <option value="left" {% if block.image_position == 'left' %}selected{% endif %}>Gauche</option>
 
203
  </div>
204
  {% endfor %}
205
  </div>
206
+
207
  <div class="mt-4 text-center">
208
  <button type="button" id="save-blocks-button" class="btn btn-primary btn-lg">
209
+ <i class="fas fa-save"></i> Enregistrer les modifications
210
  </button>
211
  </div>
212
  </form>
213
  </div>
214
  </div>
215
+
216
  <!-- Image Upload Section -->
217
  <div class="card mb-4">
218
  <div class="card-header">
219
+ <h4>Ajouter une nouvelle image</h4>
220
  </div>
221
  <div class="card-body">
222
+ <form method="POST" action="{{ url_for('admin_bp.edit_texte', texte_id=texte.id) }}" enctype="multipart/form-data">
223
+ <input type="hidden" name="action" value="upload_image">
224
+
 
 
225
  <div class="form-group mb-3">
226
  <label for="image">Sélectionner une image</label>
227
+ <input type="file" class="form-control" id="image" name="image" accept="image/*" required>
228
  </div>
229
+
230
  <div class="form-group mb-3">
231
  <label for="alt_text">Texte alternatif (pour l'accessibilité)</label>
232
+ <input type="text" class="form-control" id="alt_text" name="alt_text" placeholder="Description de l'image">
233
  </div>
234
+
 
 
 
235
  <button type="submit" class="btn btn-success">
236
+ <i class="fas fa-upload"></i> Télécharger l'image
237
  </button>
238
  </form>
 
 
 
 
 
 
 
239
  </div>
240
  </div>
241
  </div>
 
244
 
245
  <!-- Image Gallery Modal -->
246
  <div class="modal fade" id="image-gallery-modal" tabindex="-1" aria-labelledby="imageGalleryModalLabel" aria-hidden="true">
247
+ <div class="modal-dialog modal-lg">
248
  <div class="modal-content">
249
  <div class="modal-header">
250
+ <h5 class="modal-title" id="imageGalleryModalLabel">Sélectionner une image</h5>
251
  <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
252
  </div>
253
  <div class="modal-body">
254
+ <div class="row">
 
255
  {% for image in images %}
256
+ <div class="col-md-3 col-sm-4 col-6 mb-3">
257
+ <div class="gallery-item" data-image-id="{{ image.id }}">
258
+ <img src="{{ image.src }}" alt="{{ image.alt }}" class="gallery-image img-fluid">
 
259
  </div>
260
  </div>
261
  {% else %}
262
  <div class="col-12">
263
  <div class="alert alert-info">
264
+ Aucune image disponible. Veuillez en télécharger une.
265
  </div>
266
  </div>
267
  {% endfor %}
 
277
 
278
  {% block scripts %}
279
  <!-- Include Sortable.js for drag and drop functionality -->
280
+ <script src="https://cdn.jsdelivr.net/npm/sortablejs@1.14.0/Sortable.min.js"></script>
 
 
 
 
 
 
281
  <script src="{{ url_for('static', filename='js/admin.js') }}"></script>
282
+ {% endblock %}