templates/entreprise/nos_services.html.twig line 1

Open in your IDE?
  1. {% extends 'base.html.twig' %}
  2. {% block title  %}
  3. {{ parent() }} | Nos services
  4. {% endblock title  %}
  5. {% block stylesheets  %}
  6. {{ parent() }}
  7. <style>
  8.     .element-services{
  9.         margin: 20px;
  10.     }
  11.      .slider-container {
  12.             width: 100%;
  13.             /*max-width: 900px;*/
  14.             position: relative;
  15.             overflow: hidden;
  16.             border-radius: 12px;
  17.             box-shadow: 0 4px 20px rgba(0,0,0,0.1);
  18.         }
  19.         .slider {
  20.             display: flex;
  21.             transition: transform 0.3s ease-out;
  22.             cursor: grab;
  23.             padding: 20px 0;
  24.         }
  25.         .slider.grabbing {
  26.             cursor: grabbing;
  27.             transition: none;
  28.         }
  29.         .slide {
  30.             flex: 0 0 calc(33.333% - 20px);
  31.             margin: 0 10px;
  32.             background: white;
  33.             border-radius: 8px;
  34.             overflow: hidden;
  35.             box-shadow: 0 2px 10px rgba(0,0,0,0.1);
  36.             user-select: none;
  37.         }
  38.         .slide img {
  39.             width: 100%;
  40.             height: 200px;
  41.             object-fit: cover;
  42.             display: block;
  43.         }
  44.         .slide-content {
  45.             padding: 20px;
  46.         }
  47.         .slide-content h3 {
  48.             margin-bottom: 10px;
  49.             color: #333;
  50.         }
  51.         .slide-content p {
  52.             color: #666;
  53.             line-height: 1.5;
  54.         }
  55.         /* Navigation dots */
  56.         .dots {
  57.             display: flex;
  58.             justify-content: center;
  59.             gap: 10px;
  60.             margin-top: 20px;
  61.             padding-bottom: 20px;
  62.         }
  63.         .dot {
  64.             width: 10px;
  65.             height: 10px;
  66.             border-radius: 50%;
  67.             background: #ccc;
  68.             cursor: pointer;
  69.             transition: background 0.3s;
  70.         }
  71.         .dot.active {
  72.             background: #333;
  73.         }
  74.         /* Navigation arrows */
  75.         .nav-arrow {
  76.             position: absolute;
  77.             top: 50%;
  78.             transform: translateY(-50%);
  79.             width: 40px;
  80.             height: 40px;
  81.             background: white;
  82.             border-radius: 50%;
  83.             display: flex;
  84.             justify-content: center;
  85.             align-items: center;
  86.             cursor: pointer;
  87.             box-shadow: 0 2px 10px rgba(0,0,0,0.2);
  88.             z-index: 10;
  89.             opacity: 0.8;
  90.             transition: opacity 0.3s;
  91.             font-size: 20px;
  92.         }
  93.         .nav-arrow:hover {
  94.             opacity: 1;
  95.         }
  96.         .nav-arrow.prev {
  97.             left: 10px;
  98.         }
  99.         .nav-arrow.next {
  100.             right: 10px;
  101.         }
  102.         @media (max-width: 768px) {
  103.             .slide {
  104.                 flex: 0 0 calc(50% - 20px);
  105.             }
  106.             
  107.             .nav-arrow {
  108.                 width: 35px;
  109.                 height: 35px;
  110.                 font-size: 18px;
  111.             }
  112.         }
  113.         @media (max-width: 480px) {
  114.             .slide {
  115.                 flex: 0 0 calc(100% - 20px);
  116.             }
  117.         }
  118. </style>
  119. {% endblock stylesheets  %}
  120. {% block body  %}
  121.     <br/><br/><br/>
  122.     <h3 class="text-center">Nos services</h3>
  123.     <hr/>
  124.     <h4 class="text-center">Des experts pour tous vos besoins !</h4>
  125.     <p class="text-center">
  126.         Une large gamme de services professionnels à domicile pour simplifier votre quotidien
  127.     </p>
  128.     
  129.      <br/>
  130. <div class="container">
  131.     <div class="row">
  132.         <div class="col-md-12">
  133.             <div class="slider-container">
  134.                 <div class="nav-arrow prev">←</div>
  135.                 <div class="nav-arrow next">→</div>
  136.                 
  137.                 <div class="slider" id="slider">
  138.                     
  139.                 </div>
  140.                 
  141.                 <div class="dots" id="dots"></div>
  142.             </div>
  143.         </div>
  144.     </div>
  145.     <div class="row">
  146.         <div class="col-md-12">
  147.         <br/>
  148.             <h3 class="text-center">les raisons de nous choisir</h3>
  149.             <p class="text-center">HelpPlace votre partenaire de confiance pour tous vos besoins à domicile.</p>
  150.         </div>
  151.     </div>
  152.     <div class="row">
  153.         <div class="col-md-3">
  154.             <div class="assie-card">
  155.                 <div class="assie-card-body">
  156.                     <h3 class="text-center"><i class="bi bi-cash"></i></h3>
  157.                     <p class="text-center"><strong>Inscription gratuite</strong></p>
  158.                     <p class="text-center">
  159.                         Créez votre compte gratuitement, sans engagement et accédez à tous nos services.
  160.                         <br/><br/>
  161.                     </p>
  162.                 </div>
  163.             </div>
  164.         </div>
  165.         
  166.          <div class="col-md-3">
  167.             <div class="assie-card">
  168.                 <div class="assie-card-body">
  169.                     <h3 class="text-center"><i class="bi bi-clock"></i></h3>
  170.                     <p class="text-center"><strong>Service simple, rapide et sécurisé</strong></p>
  171.                     <p class="text-center">
  172.                         Trouvez un prestataire en 2 minutes et réservez directement en ligne en toute sécurité.
  173.                     </p>
  174.                 </div>
  175.             </div>
  176.         </div>
  177.         <div class="col-md-3">
  178.             <div class="assie-card">
  179.                 <div class="assie-card-body">
  180.                     <h3 class="text-center"><i class="bi bi-shield-lock"></i></h3>
  181.                     <p class="text-center"><strong>Prestataire vérifié et fiable</strong></p>
  182.                     <p class="text-center">
  183.                         Tous nos professionnels sont soigneusement sélectionnés et vérifiés avec document à l'appui.
  184.                         <br/><br/>
  185.                     </p>
  186.                 </div>
  187.             </div>
  188.         </div>
  189.         <div class="col-md-3">
  190.             <div class="assie-card">
  191.                 <div class="assie-card-body">
  192.                     <h3 class="text-center"><i class="bi bi-journal-bookmark"></i></h3>
  193.                     <p class="text-center"><strong>Qualité garantie</strong></p>
  194.                     <p class="text-center">
  195.                         Satisfaction client garantie avec notre système d'évaluation et de notation.
  196.                         <br/><br/>
  197.                     </p>
  198.                 </div>
  199.             </div>
  200.         </div>
  201.     </div>
  202.     <hr/>
  203.     <br/>
  204.     <div class="row">
  205.         <div class="col-md-12">
  206.            <h3 class="text-center"> Comment ça marche ?</h3>
  207.            <p class="text-center">
  208.             Trouvez votre prestataire en 2 minutes
  209.             Simplement, rapidement et en toute sécurité
  210.             </p>
  211.         </div>
  212.     </div>
  213.     <div class="row">
  214.         <div class="col-md-3">
  215.             <div class="assie-card">
  216.                 <div class="assie-card-body">
  217.                     <h3 class="text-center"><i class="bi bi-1-circle-fill"></i></h3>
  218.                     <h3 class="text-center"><i class="bi bi-search"></i></h3>
  219.                     <p class="text-center"><strong>Recherche</strong></p>
  220.                     <p class="text-center">
  221.                         Décrivez votre besoin et votre localisation en quelques clics.
  222.                          <br/> <br/>
  223.                     </p>
  224.                 </div>
  225.             </div>
  226.         </div>
  227.         
  228.         <div class="col-md-3">
  229.             <div class="assie-card">
  230.                 <div class="assie-card-body">
  231.                     <h3 class="text-center"><i class="bi bi-2-circle-fill"></i></h3>
  232.                     <h3 class="text-center"><i class="bi bi-person-check"></i></h3>
  233.                     <p class="text-center"><strong>Choisissez</strong></p>
  234.                     <p class="text-center">
  235.                         Comparez les profils, avis et tarifs des prestataires disponibles.
  236.                     </p>
  237.                 </div>
  238.             </div>
  239.         </div>
  240.         <div class="col-md-3">
  241.             <div class="assie-card">
  242.                 <div class="assie-card-body">
  243.                     <h3 class="text-center"><i class="bi bi-3-circle-fill"></i></h3>
  244.                     <h3 class="text-center"><i class="bi bi-calendar-check"></i></h3>
  245.                     <p class="text-center"><strong>Reservez</strong></p>
  246.                     <p class="text-center">
  247.                         Planifiez votre intervention au moment qui vous convient.
  248.                          <br/> <br/>
  249.                     </p>
  250.                 </div>
  251.             </div>
  252.         </div>
  253.          <div class="col-md-3">
  254.             <div class="assie-card">
  255.                 <div class="assie-card-body">
  256.                     <h3 class="text-center"><i class="bi bi-4-circle-fill"></i></h3>
  257.                     <h3 class="text-center"><i class="bi bi-star"></i></h3>
  258.                     <p class="text-center"><strong>Evaluez</strong></p>
  259.                     <p class="text-center">
  260.                         Partagez votre expérience et aidez la communauté.
  261.                         <br/> <br/>
  262.                     </p>
  263.                 </div>
  264.             </div>
  265.             <br/> <br/>
  266.         </div>
  267.         <br/> <br/>
  268.     </div>
  269.     </div>
  270.     <span hidden id="slidesData">{{ slidesData }}</span>
  271. {% endblock body  %}
  272. {% block javascripts  %}
  273. {{ parent() }}
  274.   <script type="text/javascript">
  275.        class SwipeSlider {
  276.             constructor() {
  277.                 
  278.                 this.slider = document.getElementById('slider');
  279.                 this.dotsContainer = document.getElementById('dots');
  280.                 this.prevBtn = document.querySelector('.prev');
  281.                 this.nextBtn = document.querySelector('.next');
  282.                 this.listeCategorie = document.getElementById('slidesData');
  283.                 this.slidesData = JSON.parse(this.listeCategorie.innerText);
  284.                 
  285.                 this.currentIndex = 0;
  286.                 this.startX = 0;
  287.                 this.currentX = 0;
  288.                 this.isDragging = false;
  289.                 this.visibleSlides = this.getVisibleSlidesCount();
  290.                 
  291.                 this.init();
  292.             }
  293.             
  294.             getVisibleSlidesCount() {
  295.                 if (window.innerWidth <= 480) return 1;
  296.                 if (window.innerWidth <= 768) return 2;
  297.                 return 3;
  298.             }
  299.             
  300.             init() {
  301.                 this.createSlides();
  302.                 this.createDots();
  303.                 this.updateSliderPosition();
  304.                 this.setupEventListeners();
  305.                 window.addEventListener('resize', () => this.handleResize());
  306.             }
  307.             
  308.             createSlides() {
  309.                 this.slider.innerHTML = this.slidesData.map(slide => `
  310.                     <div class="slide">
  311.                         <img src="${slide.img}" alt="${slide.title}">
  312.                         <div class="slide-content">
  313.                             <h3>${slide.title}</h3>
  314.                         </div>
  315.                     </div>
  316.                 `).join('');
  317.             }
  318.             
  319.             createDots() {
  320.                 const maxIndex = Math.max(0, this.slidesData.length - this.visibleSlides);
  321.                 const dots = [];
  322.                 for (let i = 0; i <= maxIndex; i++) {
  323.                     dots.push(`<div class="dot${i === this.currentIndex ? ' active' : ''}" data-index="${i}"></div>`);
  324.                 }
  325.                 this.dotsContainer.innerHTML = dots.join('');
  326.                 
  327.                 document.querySelectorAll('.dot').forEach(dot => {
  328.                     dot.addEventListener('click', (e) => {
  329.                         const index = parseInt(e.target.dataset.index);
  330.                         this.goToSlide(index);
  331.                     });
  332.                 });
  333.             }
  334.             
  335.             setupEventListeners() {
  336.                 // Mouse events
  337.                 this.slider.addEventListener('mousedown', (e) => this.startDrag(e));
  338.                 window.addEventListener('mousemove', (e) => this.drag(e));
  339.                 window.addEventListener('mouseup', () => this.endDrag());
  340.                 
  341.                 // Touch events
  342.                 this.slider.addEventListener('touchstart', (e) => this.startDrag(e));
  343.                 window.addEventListener('touchmove', (e) => this.drag(e), { passive: false });
  344.                 window.addEventListener('touchend', () => this.endDrag());
  345.                 
  346.                 // Navigation buttons
  347.                 this.prevBtn.addEventListener('click', () => this.prev());
  348.                 this.nextBtn.addEventListener('click', () => this.next());
  349.                 
  350.                 // Prevent context menu on slider
  351.                 this.slider.addEventListener('contextmenu', (e) => e.preventDefault());
  352.             }
  353.             
  354.             startDrag(e) {
  355.                 e.preventDefault();
  356.                 this.isDragging = true;
  357.                 this.startX = e.type === 'mousedown' ? e.pageX : e.touches[0].pageX;
  358.                 this.currentX = this.startX;
  359.                 this.slider.classList.add('grabbing');
  360.             }
  361.             
  362.             drag(e) {
  363.                 if (!this.isDragging) return;
  364.                 e.preventDefault();
  365.                 
  366.                 const currentX = e.type === 'mousemove' ? e.pageX : e.touches[0].pageX;
  367.                 const diff = currentX - this.startX;
  368.                 
  369.                 // Limiter le dépassement
  370.                 const maxDrag = 50; // pixels
  371.                 const boundedDiff = Math.max(-maxDrag, Math.min(maxDrag, diff));
  372.                 
  373.                 this.slider.style.transform = `translateX(calc(-${this.currentIndex * (100 / this.visibleSlides)}% + ${boundedDiff}px))`;
  374.             }
  375.             
  376.             endDrag() {
  377.                 if (!this.isDragging) return;
  378.                 
  379.                 this.slider.classList.remove('grabbing');
  380.                 
  381.                 const diff = this.currentX - this.startX;
  382.                 
  383.                 if (Math.abs(diff) > 50) {
  384.                     if (diff > 0 && this.currentIndex > 0) {
  385.                         this.prev();
  386.                     } else if (diff < 0 && this.currentIndex < this.slidesData.length - this.visibleSlides) {
  387.                         this.next();
  388.                     } else {
  389.                         this.updateSliderPosition();
  390.                     }
  391.                 } else {
  392.                     this.updateSliderPosition();
  393.                 }
  394.                 
  395.                 this.isDragging = false;
  396.             }
  397.             
  398.             updateSliderPosition() {
  399.                 const percentage = -(this.currentIndex * (100 / this.visibleSlides));
  400.                 this.slider.style.transform = `translateX(${percentage}%)`;
  401.                 
  402.                 // Update dots
  403.                 document.querySelectorAll('.dot').forEach((dot, index) => {
  404.                     dot.classList.toggle('active', index === this.currentIndex);
  405.                 });
  406.             }
  407.             
  408.             goToSlide(index) {
  409.                 this.currentIndex = Math.max(0, Math.min(index, this.slidesData.length - this.visibleSlides));
  410.                 this.updateSliderPosition();
  411.             }
  412.             
  413.             prev() {
  414.                 this.goToSlide(this.currentIndex - 1);
  415.             }
  416.             
  417.             next() {
  418.                 this.goToSlide(this.currentIndex + 1);
  419.             }
  420.             
  421.             handleResize() {
  422.                 const newVisibleSlides = this.getVisibleSlidesCount();
  423.                 if (newVisibleSlides !== this.visibleSlides) {
  424.                     this.visibleSlides = newVisibleSlides;
  425.                     this.currentIndex = Math.min(this.currentIndex, this.slidesData.length - this.visibleSlides);
  426.                     this.createDots();
  427.                     this.updateSliderPosition();
  428.                 }
  429.             }
  430.         }
  431.         
  432.         // Initialiser le slider
  433.         document.addEventListener('DOMContentLoaded', () => {
  434.             new SwipeSlider();
  435.         });
  436.     </script>
  437. {% endblock javascripts  %}