templates/theme/default/modele-widget/avis_block.html.twig line 1

Open in your IDE?
  1. <div class="avis-widget" {% if widget.bgcolor is defined and widget.bgcolor != null %} style="background-color: {{ widget.bgcolor }};" {% endif %}>
  2. <style>
  3. .avis-widget {
  4. margin: auto;
  5. }
  6. .avis-cards-container {
  7. display: flex;
  8. gap: 30px;
  9. justify-content: center;
  10. }
  11. .avis-author {
  12. font-size: 18px;
  13. font-weight: 700;
  14. color: #4a6c82;
  15. }
  16. .avis-ville,
  17. .avis-activite,
  18. .avis-date {
  19. font-size: 14px;
  20. margin-top: 4px;
  21. }
  22. .avis-rating {
  23. margin: 10px 0;
  24. }
  25. .star {
  26. color: #bbdefb;
  27. font-size: 18px;
  28. }
  29. .star.filled {
  30. color: #4a6c82;
  31. }
  32. .avis-comment {
  33. font-size: 15px;
  34. margin-top: 14px;
  35. line-height: 1.6;
  36. font-style: italic;
  37. }
  38. .avis-reponse {
  39. margin-top: 16px;
  40. padding: 14px;
  41. background: #e3f2fd;
  42. border-left: 4px solid #4a6c82;
  43. border-radius: 8px;
  44. }
  45. .avis-reponse-titre {
  46. font-weight: 600;
  47. font-size: 14px;
  48. margin-bottom: 6px;
  49. color: #4a6c82;
  50. }
  51. .carousel-item.active .avis-card {
  52. animation: bounceUpDown 0.7s ease forwards;
  53. }
  54. .carousel-item.active .avis-card:nth-child(2) {
  55. animation-delay: 0.2s;
  56. }
  57. .carousel-item.active .avis-card:nth-child(3) {
  58. animation-delay: 0.4s;
  59. }
  60. @keyframes bounceUpDown {
  61. 0% {
  62. opacity: 0;
  63. transform: translateY(30px);
  64. }
  65. 50% {
  66. opacity: 1;
  67. transform: translateY(-8px);
  68. }
  69. 100% {
  70. opacity: 1;
  71. transform: translateY(0);
  72. }
  73. }
  74. @media(max-width: 992px) {
  75. .avis-cards-container {
  76. flex-direction: column;
  77. align-items: center;
  78. }
  79. .avis-card {
  80. max-width: 100%;
  81. }
  82. }
  83. .carousel-control-prev,
  84. .carousel-control-next {
  85. position: absolute;
  86. right: 10px; /* les déplace complètement à droite */
  87. top: auto; /* désactive la position verticale par défaut */
  88. bottom: auto;
  89. transform: none; /* annule le centrage vertical par défaut */
  90. width: 40px;
  91. height: 40px;
  92. margin: 5px 0; /* espace entre les flèches */
  93. }
  94. .carousel-control-prev {
  95. top: 50px; /* flèche du haut */
  96. }
  97. .carousel-control-next {
  98. top: 110px; /* flèche du bas */
  99. }
  100. .carousel-control-prev-icon,
  101. .carousel-control-next-icon {
  102. border-radius: 100%
  103. }
  104. button {
  105. background: transparent !important;
  106. }
  107. .carousel-item {
  108. transition: none; /* on gère la transition via JS */
  109. display: flex;
  110. justify-content: start;
  111. }
  112. .avis-card {
  113. opacity: 0;
  114. transform: translateY(30px); /* carte initialement en bas */
  115. transition: transform 0.50s ease, opacity 0.50s ease;
  116. }
  117. .carousel-control-prev-icon {
  118. background-image: url("data:image/svg+xml;charset=utf-8, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3E%3Cpath d='M1 8a.5.5 0 0 1 .5-.5h10.793L9.146 4.354a.5.5 0 1 1 .708-.708l4 4a.5.5 0 0 1 0 0.708l-4 4a.5.5 0 1 1-.708-.708L12.293 8.5H1.5A.5.5 0 0 1 1 8z'/%3E%3C/svg%3E") !important;
  119. transform: rotate(-90deg);
  120. }
  121. .carousel-control-next-icon {
  122. background-image: url("data:image/svg+xml;charset=utf-8, %3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3E%3Cpath d='M1 8a.5.5 0 0 1 .5-.5h10.793L9.146 4.354a.5.5 0 1 1 .708-.708l4 4a.5.5 0 0 1 0 0.708l-4 4a.5.5 0 1 1-.708-.708L12.293 8.5H1.5A.5.5 0 0 1 1 8z'/%3E%3C/svg%3E") !important;
  123. transform: rotate(90deg);
  124. }
  125. .content-avis {
  126. min-height: 100%;
  127. justify-content: space-evenly;
  128. display: flex;
  129. flex-direction: column;
  130. }
  131. </style>
  132. <div class="container-fluid">
  133. <div class="row">
  134. {% if widget.bgimage %}
  135. <div class="col-lg-5 order-lg-1 order-2 d-flex justify-content-center align-items-center image-avis">
  136. <div class="avis-image">
  137. <img src="{{ asset(widget.bgimage) }}" alt="Image avis" loading="lazy">
  138. </div>
  139. {% endif %}
  140. </div>
  141. <div class="col-lg-7 order-lg-2 order-1 content-avis">
  142. <div class="avis-header">
  143. <h2>
  144. <span>{{ 'label.item_avis'|trans([],'textes') }}</span/>{{ 'label.avis_client'|trans([],'textes') }}</h3>
  145. </div>
  146. {% set avis_chunks = avis|batch(1) %}
  147. <div>
  148. <div id="avis-carousel-{{ widget.id|default('1') }}" class="carousel slide avis-carousel" data-bs-ride="carousel">
  149. <div class="carousel-inner">
  150. {% for chunk in avis_chunks %}
  151. <div class="carousel-item {% if loop.first %}active{% endif %}">
  152. <div class="avis-cards-container">
  153. {% for response in chunk %}
  154. <div class="avis-card">
  155. <strong class="avis-author">
  156. {{ response.data.nom|default('') }}
  157. {{ response.data.prenom|default('') }}
  158. </strong>
  159. {% if response.data.ville is defined and response.data.ville %}
  160. <div class="avis-ville">
  161. De :
  162. {{ response.data.ville }}
  163. </div>
  164. {% endif %}
  165. {% if response.data.activite is defined and response.data.activite %}
  166. <div class="avis-activite">
  167. {{ response.data.activite }}
  168. </div>
  169. {% endif %}
  170. {% if response.data.note is defined %}
  171. <div class="avis-rating">
  172. {% for i in 1..5 %}
  173. <span class="star {{ i <= response.data.note ? 'filled' : '' }}">★</span>
  174. {% endfor %}
  175. </div>
  176. {% endif %}
  177. {% if response.data.commentaire is defined and response.data.commentaire %}
  178. <p class="avis-comment">
  179. “{{ response.data.commentaire|nl2br }}”
  180. </p>
  181. {% endif %}
  182. {% if response.reponse is defined and response.reponse %}
  183. <div class="avis-reponse">
  184. <p class="avis-reponse-titre">
  185. Réponse de l'équipe :
  186. </p>
  187. <p>{{ response.reponse|nl2br }}</p>
  188. </div>
  189. {% endif %}
  190. </div>
  191. {% endfor %}
  192. </div>
  193. </div>
  194. {% endfor %}
  195. </div>
  196. <button class="carousel-control-prev" type="button" data-bs-target="#avis-carousel-{{ widget.id|default('1') }}" data-bs-slide="prev">
  197. <span class="carousel-control-prev-icon"></span>
  198. </button>
  199. <button class="carousel-control-next" type="button" data-bs-target="#avis-carousel-{{ widget.id|default('1') }}" data-bs-slide="next">
  200. <span class="carousel-control-next-icon"></span>
  201. </button>
  202. </div>
  203. </div>
  204. </div>
  205. </div>
  206. </div>
  207. </div>
  208. <script>
  209. (function () {
  210. const carousel = document.getElementById('avis-carousel- {{ widget.id|default('1') }}');
  211. if (! carousel)
  212. return;
  213. carousel.addEventListener('slide.bs.carousel', function () {
  214. carousel.querySelectorAll('.avis-card').forEach(card => {
  215. card.style.opacity = '0';
  216. card.style.transform = 'translateY(25px)';
  217. });
  218. });
  219. })();
  220. </script>