templates/frontView/product/index.html.twig line 1

Open in your IDE?
  1. {% extends 'base.html.twig' %}
  2. {% block stylesheets %}
  3.     {{ parent() }}
  4.     <style>
  5.         .image-wrapper {
  6.             width: 206px;
  7.             height: 208px;
  8.             position: relative;
  9.             overflow: hidden;
  10.         }
  11.         .product-thumb {
  12.             width: 100%;
  13.             height: 100%;
  14.             object-fit: cover; /* fill without distortion */
  15.             display: block;
  16.         }
  17.         .custom-separator {
  18.     position: relative;
  19.     margin: 30px 0;
  20. }
  21. /* La ligne horizontale */
  22. .custom-separator::after {
  23.     content: "";
  24.     position: absolute;
  25.     left: 0;
  26.     right: 0;
  27.     bottom: 0;
  28.     height: 2px;
  29.     background: linear-gradient(
  30.         to right,
  31.         transparent,
  32.         #003B7E,
  33.         #003B7E,
  34.         #003B7E
  35.     );
  36. }
  37. /* Le titre */
  38. .custom-separator h3 {
  39.     display: inline-block;
  40.     background-color: #003B7E;
  41.     color: #fff;
  42.     padding: 8px 25px;
  43.     border-radius: 0 25px 0 25px;
  44.     margin-bottom: 0;
  45.     font-size: 1.2rem;
  46.     font-weight: bold;
  47.     position: relative;
  48.     z-index: 1; /* reste au-dessus de la ligne */
  49. }
  50.         /* État de base masqué */
  51.     .product-card-animated {
  52.         opacity: 0;
  53.         transition: all 0.7s cubic-bezier(0.2, 0.8, 0.2, 1);
  54.         will-change: transform, opacity;
  55.     }
  56.     /* Départ à gauche */
  57.     .fade-left {
  58.         transform: translateX(-80px);
  59.     }
  60.     /* Départ à droite */
  61.     .fade-right {
  62.         transform: translateX(80px);
  63.     }
  64.     /* État quand la carte est dans l'écran (FADE IN) */
  65.     .product-card-animated.is-visible {
  66.         opacity: 1;
  67.         transform: translateX(0);
  68.     }
  69.     </style>
  70. {% endblock %}
  71. {% block title %}Liste produit{% endblock %}
  72. {% block body %}
  73. <header>
  74. {{ include('@FrontView/menus.html.twig') }} {##}
  75. </header>
  76. <main class="front-office-page front-office-catalog">
  77.     <div class="container"> <!--  <div class="py-3 px-5"> -->
  78.         <div class="row py-1">
  79.             <div class="col-md-2">
  80.                 {{ include('@FrontView/menusgeneral.html.twig') }}
  81.             </div>
  82.             <div class="col-md-10">
  83.                 {# <h1>liste de tous les produits </h1>
  84.                 {% if is_granted('ROLE_ADMIN') %}
  85.                     vous êtes administrateur
  86.                 {% endif %} #}
  87.                 {# <div class="row">
  88.                     {% for product in products %}
  89.                     <div class="col-xxl-2 col-xl-3 col-lg-4 col-md-4 col-sm-6 col-12 mt-2">
  90.                         <div class="card bg-custom-product" >
  91.                               <div class="image-content">
  92.                                 <div class="image-wrapper">
  93.                                 <img src="{{ asset('img/logo-rapeto-img.png') }}" class="logo">
  94.                                     <a href="{{ path('app_product_show', {'id': product.id}) }}" ><img src="{{ asset('uploads/products/'~product.picture) }}" class="imgproduct" alt="..."></a>
  95.                                 </div>
  96.                               </div>
  97.                             
  98.                              <div class="card-body">
  99.                                 <div class="row"><a href="#" class="title-product ">  <a href="{{ path('app_product_show', {'id': product.id}) }}" >{{ product.title }} ({{ product.statetypeLabels|join(' / ') }}) </a>
  100.                                 
  101.                                 <span class="fw-light description-product">{{ product.desctription|slice(0,50) }}...</span></div>
  102.                                 
  103.                                 <div class="row mt-2">
  104.                                   <div class="col-md-10 col-6 col-sm-12">
  105.                                 
  106.                                     {% if is_granted('ROLE_COM') %}
  107.                                             <span class="marge-price">{{ product.priceProducts[0].priceCustomer|number_format(2, '.', ' ') }}</span>
  108.                                     {% elseif is_granted('ROLE_CUSTOMER')%}
  109.                                             <span class="marge-price">{{ product.priceProducts[0].priceCustomer|number_format(2, '.', ' ') }} </span>
  110.                                     {% else %}
  111.                                             <span class="marge-price">{{ product.priceProducts[0].priceCustomer|number_format(2, '.', ' ') }}</span> 
  112.                                     {% endif %}
  113.                                     <sup class="exposant"> {{ product.fkdevise.title }}</sup>
  114.                                     
  115.                                   </div>
  116.                                   <div class="col-md-2 product-price-position  col-6 col-sm-12">
  117.                                       <a href="{{ path('app_product_panier', {'product': product.id}) }}" class="btn btn-warning">
  118.                                             <i class="bi bi-cart-plus-fill px-1 icon-color-nav"></i> 
  119.                                         </a>
  120.                                    </div>
  121.                                 </div>                                    
  122.                                 <span class="per-tarif text-info">{{ product.fkcategorie.title }} |
  123.                                 {{ product.statetypeLabels|join(' / ') }}
  124.                                 </span>
  125.                                 {% if temoin is defined and product.id == temoin %}
  126.                                     <p>
  127.                                         <span class="per-tarif text-danger">{{ message }} </span>
  128.                                     </p>
  129.                                 {% endif %}
  130.                             </div>
  131.                         </div>
  132.                     </div>
  133.                     {% else %}
  134.                         Aucun produit.
  135.                     {% endfor %}
  136.                 </div> #}
  137.                 {# New design #}
  138.                 {# <div class="row g-3">
  139.                     {% for product in products %}
  140.                         {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  141.                     {% else %}
  142.                         <p class="text-center">Aucun produit.</p>
  143.                     {% endfor %}
  144.                 </div> #}
  145.                 {# ================= Featured ================= 🔥 #}
  146.                 {% if featuredProducts|default([]) is not empty %}
  147.                     <div class="custom-separator">
  148.                             <h3>Produits phares</h3>
  149.                     </div>
  150.                     <div class="row g-3 mb-5 product-card-animated">
  151.                         {% for product in featuredProducts %}
  152.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  153.                         {% endfor %}
  154.                     </div>
  155.                 {% endif %}
  156.                 
  157.                 {# ================= Interest ================= 🎯 #}
  158.                 {% if interestProducts|default([]) is not empty %}
  159.                     <div class="custom-separator">
  160.                             <h3>Produits qui peuvent vous intéresser</h3>
  161.                     </div>
  162.                     
  163.                     <div class="row g-3 mb-5 product-card-animated">
  164.                         {% for product in interestProducts %}
  165.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  166.                         {% endfor %}
  167.                     </div>
  168.                 {% endif %}
  169.                 {# ================= Cheapest ================= 💰 #}
  170.                 {% if cheapestProducts|default([]) is not empty %}
  171.                     <div class="custom-separator">
  172.                             <h3>Produits les moins chers</h3>
  173.                     </div>
  174.                     
  175.                     <div class="row g-3 mb-5 product-card-animated">
  176.                         {% for product in cheapestProducts %}
  177.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  178.                         {% endfor %}
  179.                     </div>
  180.                 {% endif %}
  181.                 {# ================= Top Ranked ================= ⭐ #}
  182.                 {% if recentProducts|default([]) is not empty %}
  183.                     <div class="custom-separator">
  184.                         <h3>Les nouveaux produits</h3>
  185.                     </div>
  186.                     <div class="row g-3 mb-5 product-card-animated">
  187.                         {% for product in recentProducts %}
  188.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  189.                         {% endfor %}
  190.                     </div>
  191.                 {% endif %}
  192.                 {% if topOrderedProducts|default([]) is not empty %}
  193.                     <div class="custom-separator">
  194.                             <h3>Les mieux notés</h3>
  195.                     </div>
  196.                     <div class="row g-3 mb-5 product-card-animated">
  197.                         {% for product in topOrderedProducts %}
  198.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  199.                         {% endfor %}
  200.                     </div>
  201.                 {% endif %}
  202.                 {# ================= Rental ================= 🏠 #}
  203.                 {% if false %}
  204.                     <div class="custom-separator">
  205.                             <h3>Produits à louer</h3>
  206.                     </div>
  207.                     <div class="row g-3 mb-5 product-card-animated">
  208.                         {% for product in recentProducts %}
  209.                             {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  210.                         {% endfor %}
  211.                     </div>
  212.                 {% endif %}
  213.                 {# ================= Searching products ================= #}
  214.                 {% if products is defined %}
  215.                     {% if products is not empty %}
  216.                         <div class="row g-3 mb-5">
  217.                             {% for product in products %}
  218.                                 {{ include('@FrontView/product/partials/_product_card.html.twig', { product: product }) }}
  219.                             {% endfor %}
  220.                         </div>
  221.                     {% else %}
  222.                         <div class="text-center my-5">
  223.                             <i class="bi bi-box-seam fs-1 text-muted"></i>
  224.                             <p class="mt-3 fs-5 fw-semibold">
  225.                                 Aucun produit ne correspond à votre recherche
  226.                             </p>
  227.                         </div>
  228.                     {% endif %}
  229.                 {% endif %}
  230.             </div>
  231.         </div>
  232.     </div> 
  233. </main>
  234. {{ include('@FrontView/footer.html.twig') }}
  235. {% block javascripts %}
  236.     {{ parent() }}
  237.     <script>
  238.         document.addEventListener('DOMContentLoaded', function() {
  239.             const cards = document.querySelectorAll('.product-card-animated');
  240.             // Attribution des directions (alternance)
  241.             cards.forEach((card, index) => {
  242.                 if (index % 2 === 0) {
  243.                     card.classList.add('fade-left');
  244.                 } else {
  245.                     card.classList.add('fade-right');
  246.                 }
  247.             });
  248.             const observerOptions = {
  249.                 threshold: 0.1, // Déclenche dès que 10% est visible
  250.                 rootMargin: "-20px 0px -20px 0px" // Petit buffer pour éviter les clignotements
  251.             };
  252.             const observer = new IntersectionObserver((entries) => {
  253.                 entries.forEach(entry => {
  254.                     if (entry.isIntersecting) {
  255.                         // Entre dans l'écran : FADE IN
  256.                         entry.target.classList.add('is-visible');
  257.                     } else {
  258.                         // Sort de l'écran : FADE OUT (permet de rejouer au prochain passage)
  259.                         entry.target.classList.remove('is-visible');
  260.                     }
  261.                 });
  262.             }, observerOptions);
  263.             cards.forEach(card => observer.observe(card));
  264.         });
  265.     </script>
  266. {% endblock %}
  267. {% endblock %}