Skip to main content

Éditeur de bannières homepage (slides)

backend/src/controllers/slides.controller.js + slide_elements.controller.js + frontend/src/views/backoffice/SlidesEditor.vue (édition) + frontend/src/views/public/HomeView.vue (consommation publique).

Dernière vérification contre le code

Vérifié le 2026-08-13.

1. Modèle : une slide, plusieurs éléments positionnables

slides (image de fond, couleur de fond, actif, ordre, opacité d'overlay) a une relation 1—N vers slide_elements (suppression en cascade). Chaque élément est un text ou button positionné en pourcentage (pos_x/pos_y/width), avec sa propre police, couleur, lien.

2. L'éditeur (SlidesEditor.vue)

Éditeur WYSIWYG plein écran : positionnement libre par glisser-déposer, redimensionnement, guides d'alignement magnétiques, annuler/refaire (historique 60 étapes, Ctrl+Z/Ctrl+Y), déplacement au clavier, aperçu responsive (mobile/tablette/desktop/large).

Pas de champ d'ordre d'empilement explicite — l'ordre visuel des éléments suit l'ordre du tableau, pas un z-index dédié.

Upload d'image : base64, pas de stockage serveur dédié

handleImageUpload/handleDrop convertissent le fichier choisi en data URL base64 côté client (limite 5 Mo) — l'image finit encodée en base64 directement dans image_url, pas de vrai upload vers un stockage fichier/S3. Alternative : coller une URL externe, ou choisir parmi 3 images statiques prédéfinies.

3. Sauvegarde : remplacement atomique (corrigé le 2026-08-13)

Corrigé le 2026-08-13

La sauvegarde faisait auparavant une séquence DELETE/POST multiples non transactionnelle depuis le frontend (un crash en cours de route pouvait laisser la base sans aucune slide active). Un nouvel endpoint PUT /api/slides (slidesService.replaceAll) enveloppe désormais tout le remplacement — suppression des anciennes slides/éléments et recréation des nouvelles, éléments imbriqués inclus (écriture Prisma imbriquée elements: { create: [...] }) — dans une seule transaction Prisma (prisma.$transaction). ContentView.vue::saveSlides() envoie maintenant le tableau complet en un seul appel au lieu d'orchestrer les créations une par une.

La fonction save() locale de SlidesEditor.vue reste du code mort (écrit dans localStorage, jamais appelée) — la vraie logique vit dans ContentView.vue/le nouvel endpoint backend, pas dans cette fonction.

Mapping camelCase (frontend : x/y/width/fontSize/isActive/bgColor/textColor/overlayOpacity) ↔ snake_case (API : pos_x/pos_y/width/font_size/is_active/bg_color/text_color/overlay_opacity) fait à la main dans ContentView.vue, à l'aller comme au retour — deux points de duplication non factorisés, à garder synchronisés si un champ est ajouté.

4. Consommation publique : HomeView.vue, pas HeroBanner.vue

Attention à ne pas confondre : HeroBanner.vue est un composant générique de bannière statique par page (Assurances, Contact, Mentions légales...), sans aucun lien avec slides/slide_elements. Le vrai carrousel de la page d'accueil est géré directement dans HomeView.vue (fetchSlides()) : récupère les slides actives, repli sur fallbackSlides codé en dur si vide/erreur, transition d'opacité CSS, positionnement des éléments identique à l'éditeur, rotation automatique pilotée par site-settings/banner_scroll_duration.

5. Pièges connus pour un futur développeur

  1. save() locale de SlidesEditor.vue est du code mort — ne pas perdre de temps à la déboguer si un problème de sauvegarde survient, la vraie logique est dans ContentView.vue et PUT /api/slides.
  2. Cache API 5 minutes sur GET /slides (apicache) — une modification backoffice peut mettre jusqu'à 5 min à apparaître publiquement si l'invalidation du cache (apicache.clear(), appelée dans les contrôleurs create/update/delete) échoue ou est contournée.
  3. GET /slide-elements (toutes) et GET /slide-elements/slide/:id ne sont pas protégées par verifyToken, contrairement aux routes d'écriture.
  4. L'ancien système banniere/page que slides avait remplacé a été supprimé le 2026-08-13 (contrôleur, service, routes) — voir Contenu vitrine.