templates/front/home.html.twig line 1

Open in your IDE?
  1. {% extends 'front/base.html.twig' %}
  2. {% set company = Globals.getCompany() %}
  3. {% block meta_description %}
  4.     {{ websiteSettingService.get('description', '')|striptags|trim }}
  5. {% endblock %}
  6. {% block stylesheets %}
  7.     {{ parent() }}
  8.     <link rel="stylesheet" href="{{ asset('front/assets/css/product-card.css') }}">
  9.     <link rel="stylesheet" href="{{ asset('front/assets/css/home.css') }}">
  10. {% endblock %}
  11. {% block body %}
  12.     {% set heroSlides = sliders|default([])|slice(0,3) %}
  13.     {% set showHomepageHero = websiteSettingService.get('showHomepageHero', true) %}
  14.     <main class="main pt-4 pb-5" style="background-color: #fff; color: #222121;">
  15.         {% if showHomepageHero and heroSlides|length %}
  16.             <section class="hero-slider-section hero-slider--bleed" aria-label="Slider principal">
  17.                     <div class="hero-slider">
  18.                         <div class="hero-slider-track d-flex" style="transition:transform .5s ease;" aria-live="polite">
  19.                             {% for slider in heroSlides %}
  20.                                 {% set mode = slider.displayMode|default('full') %}
  21.                                 <article
  22.                                     class="hero-slide hero-slide--{{ mode }} flex-shrink-0"
  23.                                     style="{% if mode == 'full' %}background-image:url('{{ asset(slider.image) }}');{% endif %}"
  24.                                 >
  25.                                     <div class="hero-slide-gradient" aria-hidden="true"></div>
  26.                                     {% if mode == 'full' %}
  27.                                         <div class="hero-slide-inner">
  28.                                             <div class="hero-slide-content">
  29.                                                 <span class="hero-slide-kicker">{{ company.name|default('Collection') }}</span>
  30.                                                 {% if slider.title %}
  31.                                                     <h2 class="hero-slide-title">{{ slider.title }}</h2>
  32.                                                 {% endif %}
  33.                                                 {% if slider.description %}
  34.                                                     <p class="hero-slide-subtitle">{{ slider.description|striptags }}</p>
  35.                                                 {% endif %}
  36.                                                 {% if slider.url %}
  37.                                                     <a class="btn hero-slide-cta btn-light btn-lg mt-3" href="{{ slider.url }}">
  38.                                                         {{ slider.ctaLabel ?: 'Découvrir' }}
  39.                                                     </a>
  40.                                                 {% endif %}
  41.                                             </div>
  42.                                         </div>
  43.                                     {% else %}
  44.                                         <div class="hero-asset-layout">
  45.                                             <div class="hero-asset-media">
  46.                                                 <img src="{{ asset(slider.image) }}" alt="{{ slider.title ?: 'Slide' }}">
  47.                                             </div>
  48.                                             <div class="hero-asset-content">
  49.                                                 <span class="hero-slide-kicker">{{ company.name|default('Collection') }}</span>
  50.                                                 {% if slider.title %}
  51.                                                     <h2 class="hero-slide-title">{{ slider.title }}</h2>
  52.                                                 {% endif %}
  53.                                                 {% if slider.description %}
  54.                                                     <p class="hero-slide-subtitle">{{ slider.description|striptags }}</p>
  55.                                                 {% endif %}
  56.                                                 {% if slider.url %}
  57.                                                     <a class="btn hero-slide-cta btn-light btn-lg mt-3" href="{{ slider.url }}">
  58.                                                         {{ slider.ctaLabel ?: 'Découvrir' }}
  59.                                                     </a>
  60.                                                 {% endif %}
  61.                                             </div>
  62.                                         </div>
  63.                                     {% endif %}
  64.                                 </article>
  65.                             {% endfor %}
  66.                         </div>
  67.                         <button type="button" class="hero-slider-arrow hero-slider-arrow--prev" aria-label="Slide precedente">
  68.                             <span aria-hidden="true">&#8249;</span>
  69.                         </button>
  70.                         <button type="button" class="hero-slider-arrow hero-slider-arrow--next" aria-label="Slide suivante">
  71.                             <span aria-hidden="true">&#8250;</span>
  72.                         </button>
  73.                         <div class="hero-slider-dots" role="tablist" aria-label="Indicateurs du slider"></div>
  74.                     </div>
  75.             </section>
  76.         {% endif %}
  77.         {# Barre descriptive supprimée : le slider gère tout #}
  78.         {% set homepageMode = websiteSettingService.get('homepageMode')|default('category') %}
  79.         {% set homepageColumns = websiteSettingService.get('homepageColumns')|default(2) %}
  80.         {% set homepageOrder = websiteSettingService.get('homepageOrder')|default(6) %}
  81.         {% set homepageProductsPerTab = websiteSettingService.get('homepageProductsPerTab')|default(12) %}
  82.         {% set showHomepageTopRated = websiteSettingService.get('showHomepageTopRated', true) %}
  83.         {% set showHomepagePacks = websiteSettingService.get('showHomepagePacks', true) %}
  84.         {% set catalogListMode = websiteSettingService.get('catalogListMode')|default('product') %}
  85.         <script>
  86.         var HOME_DEFAULT_MODE = '{{ homepageMode }}';
  87.         var HOME_DEFAULT_COLUMNS = {{ homepageColumns }};
  88.         var HOME_DEFAULT_ORDER = {{ homepageOrder }};
  89.         var HOME_PRODUCTS_PER_TAB = {{ homepageProductsPerTab }};
  90.         var HOME_CATALOG_LIST_MODE = '{{ catalogListMode }}';
  91.         var HOME_SHOW_TOP_RATED = {{ showHomepageTopRated ? 'true' : 'false' }};
  92.         var HOME_SHOW_PACKS = {{ showHomepagePacks ? 'true' : 'false' }};
  93.         var HOME_MODE_LABELS = {{ { all: 'Tous',
  94.             category: websiteSettingService.get('homepageLabelCategory', 'Catégories'),
  95.             new: websiteSettingService.get('homepageLabelNew', 'Nouveautés'),
  96.             promo: websiteSettingService.get('homepageLabelPromo', 'Promos'),
  97.             top: websiteSettingService.get('homepageLabelTop', 'Top ventes'),
  98.             topRated: websiteSettingService.get('homepageLabelTopRated', 'Top classé'),
  99.             packs: websiteSettingService.get('homepageLabelPacks', 'Nos Packs')
  100.         }|json_encode|raw }};
  101.         var HOMEPAGE_FALLBACK_PRODUCTS = {{ products|json_encode|raw }};
  102.         var HOME_SHOW_OUT_OF_STOCK = {{ websiteSettingService.get('showOutOfStock')|default(false)|json_encode|raw }};
  103.     </script>
  104.         <div id="app">
  105.             <section id="mode-display" class="container">
  106.                 <div class="mode-controls">
  107.                     <div class="mode-toggle" role="tablist" aria-label="Modes d'affichage accueil">
  108.                         {# Mode tous #}
  109.                         <button class="mode-item"
  110.                                 :class="{ active: activeMode === 'all' }"
  111.                                 @click="setMode('all')">
  112.                             ${ getModeLabel('all') }
  113.                         </button>
  114.                         {# Mode catégorie #}
  115.                         <button class="mode-item"
  116.                                 :class="{ active: activeMode === 'category' }"
  117.                                 @click="setMode('category')">
  118.                             ${ getModeLabel('category') }
  119.                         </button>
  120.                         {# Mode nouveautés #}
  121.                         <button class="mode-item"
  122.                                 :class="{ active: activeMode === 'new' }"
  123.                                 @click="setMode('new')">
  124.                             ${ getModeLabel('new') }
  125.                         </button>
  126.                         {# Mode promos #}
  127.                         <button class="mode-item"
  128.                                 :class="{ active: activeMode === 'promo' }"
  129.                                 @click="setMode('promo')">
  130.                             ${ getModeLabel('promo') }
  131.                         </button>
  132.                         {# Mode top ventes #}
  133.                         <button class="mode-item"
  134.                                 :class="{ active: activeMode === 'top' }"
  135.                                 @click="setMode('top')">
  136.                             ${ getModeLabel('top') }
  137.                         </button>
  138.                         {# Mode top classé #}
  139.                         <button class="mode-item"
  140.                                 v-if="isHomeModeEnabled('topRated')"
  141.                                 :class="{ active: activeMode === 'topRated' }"
  142.                                 @click="setMode('topRated')">
  143.                             ${ getModeLabel('topRated') }
  144.                         </button>
  145.                         {# Mode packs #}
  146.                         <button class="mode-item"
  147.                                 v-if="isHomeModeEnabled('packs')"
  148.                                 :class="{ active: activeMode === 'packs' }"
  149.                                 @click="setMode('packs')">
  150.                             ${ getModeLabel('packs') }
  151.                         </button>
  152.                     </div>
  153.                     <div class="view-controls" aria-label="Options d'affichage">
  154.                         {# Filtre — icône + texte #}
  155.                         <button class="filter-trigger"
  156.                                 type="button"
  157.                                 data-bs-toggle="modal"
  158.                                 data-bs-target="#filterModal"
  159.                                 data-filter-source="home">
  160.                             <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
  161.                                 <path d="M3 5h18M6 12h12M10 19h4"
  162.                                     fill="none"
  163.                                     stroke="currentColor"
  164.                                     stroke-width="2"
  165.                                     stroke-linecap="round"/>
  166.                             </svg>
  167.                             <span>Filtre</span>
  168.                         </button>
  169.                         {# Séparateur #}
  170.                         <span class="view-separator" aria-hidden="true"></span>
  171.                         <div class="view-density" aria-label="Nombre de colonnes">
  172.                             {# Vue 1 colonne #}
  173.                             <button class="view-btn"
  174.                                     type="button"
  175.                                     :class="{ active: homeColumns === 1 }"
  176.                                     @click="setColumns(1)"
  177.                                     title="1 colonne"
  178.                                     aria-label="1 colonne">
  179.                                 <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
  180.                                     <rect x="5" y="3" width="14" height="18" rx="2"
  181.                                         fill="currentColor"/>
  182.                                 </svg>
  183.                             </button>
  184.                             {# Vue 2 colonnes #}
  185.                             <button class="view-btn"
  186.                                     type="button"
  187.                                     :class="{ active: homeColumns === 2 }"
  188.                                     @click="setColumns(2)"
  189.                                     title="2 colonnes"
  190.                                     aria-label="2 colonnes">
  191.                                 <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
  192.                                     <rect x="3" y="3" width="8" height="18" rx="2"
  193.                                         fill="currentColor"/>
  194.                                     <rect x="13" y="3" width="8" height="18" rx="2"
  195.                                         fill="currentColor"/>
  196.                                 </svg>
  197.                             </button>
  198.                             {# Vue 3 colonnes #}
  199.                             <button class="view-btn"
  200.                                     type="button"
  201.                                     :class="{ active: homeColumns === 3 }"
  202.                                     @click="setColumns(3)"
  203.                                     title="3 colonnes"
  204.                                     aria-label="3 colonnes">
  205.                                 <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
  206.                                     <rect x="2" y="3" width="6" height="18" rx="2"
  207.                                         fill="currentColor"/>
  208.                                     <rect x="9" y="3" width="6" height="18" rx="2"
  209.                                         fill="currentColor"/>
  210.                                     <rect x="16" y="3" width="6" height="18" rx="2"
  211.                                         fill="currentColor"/>
  212.                                 </svg>
  213.                             </button>
  214.                             {# Vue 4 colonnes #}
  215.                             <button class="view-btn"
  216.                                     type="button"
  217.                                     :class="{ active: homeColumns === 4 }"
  218.                                     @click="setColumns(4)"
  219.                                     title="4 colonnes"
  220.                                     aria-label="4 colonnes">
  221.                                 <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
  222.                                     <rect x="2" y="3" width="4" height="18" rx="1.5"
  223.                                         fill="currentColor"/>
  224.                                     <rect x="7" y="3" width="4" height="18" rx="1.5"
  225.                                         fill="currentColor"/>
  226.                                     <rect x="12" y="3" width="4" height="18" rx="1.5"
  227.                                         fill="currentColor"/>
  228.                                     <rect x="17" y="3" width="4" height="18" rx="1.5"
  229.                                         fill="currentColor"/>
  230.                                 </svg>
  231.                             </button>
  232.                         </div>
  233.                     </div>
  234.                 </div>
  235.                 <div class="active-filters-row" v-if="hasActiveFilters">
  236.                     <span class="active-filter-chip" v-for="badge in activeFilterBadges" :key="badge.type + '-' + badge.value">
  237.                         ${ badge.label }
  238.                         <button type="button" @click="clearHomeFilterBadge(badge)" aria-label="Supprimer ce filtre">&times;</button>
  239.                     </span>
  240.                 </div>
  241.                 <div class="active-filters-meta" v-if="hasActiveFilters && ['new', 'promo', 'top', 'topRated'].indexOf(activeMode) !== -1">
  242.                     ${ currentResultsCount } résultats correspondent aux filtres actifs.
  243.                 </div>
  244.               <div class="home-empty" v-if="homeEmptyMessage">
  245.                     {# Icône information #}
  246.                     <span class="home-empty-icon" aria-hidden="true">
  247.                         <i class="fa fa-archive"></i>
  248.                     </span>
  249.                     {# Texte #}
  250.                     <span class="home-empty-text"  v-text="homeEmptyMessage"></span>
  251.                 </div>
  252.             </section>
  253.             <section v-if="activeMode==='all'" class="container home-section">
  254.                 <div v-if="loadingMode==='all' && !homeAllProducts.length" class="row g-3">
  255.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-all-'+n">
  256.                         {% include 'front/_product_skeleton.html.twig' %}
  257.                     </div>
  258.                 </div>
  259.                 <div v-if="loadingMode==='all' && !homeAllProducts.length" class="text-center text-muted my-4">
  260.                     Chargement des produits...
  261.                 </div>
  262.                 <div v-else class="row g-3">
  263.                     <div :class="getColClass()" v-for="prod in homeAllProducts" :key="prod.id">
  264.                         {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  265.                     </div>
  266.                     <div :class="getColClass()" v-if="loadingMoreAll" v-for="n in 2" :key="'sk-all-more-'+n">
  267.                         {% include 'front/_product_skeleton.html.twig' %}
  268.                     </div>
  269.                 </div>
  270.                 <div class="d-flex justify-content-center mt-3">
  271.                     <button class="btn btn-sm btn-dark"
  272.                             v-if="homeAllHasMore"
  273.                             :disabled="loadingMoreAll"
  274.                             @click="loadMoreAll">
  275.                         ${ loadingMoreAll ? 'Chargement...' : 'Voir plus' }
  276.                     </button>
  277.                 </div>
  278.             </section>
  279.             <section v-else-if="activeMode==='category'" class="container home-section">
  280.                 <template v-if="loadingMode==='category' || !homeCategoryRenderReady">
  281.                     <div class="row g-3">
  282.                         <div :class="getColClass()" v-for="n in 4" :key="'sk-cat-'+n">
  283.                             {% include 'front/_product_skeleton.html.twig' %}
  284.                         </div>
  285.                     </div>
  286.                     <div class="text-center text-muted my-4">
  287.                         Chargement des visuels en cours...
  288.                     </div>
  289.                 </template>
  290.                 <template v-else>
  291.                     <div v-for="entry in homeCategories" :key="entry.category.id">
  292.                         <div class="section-header">
  293.                             <h2 class="section-title" v-text="entry.category.name"></h2>
  294.                         </div>
  295.                         <div v-if="entry.loaded" class="row g-3">
  296.                             <div :class="getColClass()" v-for="prod in entry.products.slice(0, getHomeProductsLimit())" :key="prod.id">
  297.                                 {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  298.                             </div>
  299.                         </div>
  300.                         <div v-else class="row g-3">
  301.                             <div :class="getColClass()" v-for="n in Math.min(getHomeProductsLimit(), 4)" :key="'sk-cat-entry-' + entry.category.id + '-' + n">
  302.                                 {% include 'front/_product_skeleton.html.twig' %}
  303.                             </div>
  304.                         </div>
  305.                         <div class="d-flex justify-content-center mt-3 mb-2">
  306.                             <button class="btn btn-dark px-4 py-2" style="min-width: 180px;" @click="openCategory(entry.category.id, entry.category.name)">Voir plus</button>
  307.                         </div>
  308.                     </div>
  309.                 </template>
  310.             </section>
  311.             <section v-else-if="activeMode==='new'" class="container home-section">
  312.                 <div v-if="loadingMode==='new' && !homeNewProducts.length" class="row g-3">
  313.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-new-'+n">
  314.                         {% include 'front/_product_skeleton.html.twig' %}
  315.                     </div>
  316.                 </div>
  317.                 <div v-if="loadingMode==='new' && !homeNewProducts.length" class="text-center text-muted my-4">
  318.                     Chargement des nouveautés...
  319.                 </div>
  320.                     <div v-else class="row g-3">
  321.                         <div :class="getColClass()" v-for="prod in homeNewProducts" :key="prod.id">
  322.                             {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  323.                         </div>
  324.                         <div :class="getColClass()" v-if="loadingMoreNew" v-for="n in 2" :key="'sk-new-more-'+n">
  325.                             {% include 'front/_product_skeleton.html.twig' %}
  326.                         </div>
  327.                     </div>
  328.                     <div class="d-flex justify-content-center mt-3">
  329.                         <button class="btn btn-sm btn-dark"
  330.                                 v-if="homeNewHasMore"
  331.                                 :disabled="loadingMoreNew"
  332.                                 @click="loadMoreNew">
  333.                             ${ loadingMoreNew ? 'Chargement...' : 'Voir plus' }
  334.                         </button>
  335.                     </div>
  336.             </section>
  337.             <section v-else-if="activeMode==='promo'" class="container home-section">
  338.                 <div v-if="loadingMode==='promo' && !homePromoProducts.length" class="row g-3">
  339.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-promo-'+n">
  340.                         {% include 'front/_product_skeleton.html.twig' %}
  341.                     </div>
  342.                 </div>
  343.                 <div v-if="loadingMode==='promo' && !homePromoProducts.length" class="text-center text-muted my-4">
  344.                     Chargement des promotions...
  345.                 </div>
  346.                 <div v-else class="row g-3">
  347.                     <div :class="getColClass()" v-for="prod in homePromoProducts" :key="prod.id">
  348.                         {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  349.                     </div>
  350.                     <div :class="getColClass()" v-if="loadingMorePromo" v-for="n in 2" :key="'sk-promo-more-'+n">
  351.                         {% include 'front/_product_skeleton.html.twig' %}
  352.                     </div>
  353.                 </div>
  354.                 <div class="d-flex justify-content-center mt-3">
  355.                     <button class="btn btn-sm btn-dark"
  356.                             v-if="homePromoHasMore"
  357.                             :disabled="loadingMorePromo"
  358.                             @click="loadMorePromo">
  359.                         ${ loadingMorePromo ? 'Chargement...' : 'Voir plus' }
  360.                     </button>
  361.                 </div>
  362.             </section>
  363.             <section v-else-if="activeMode==='top'" class="container home-section">
  364.                 <div v-if="loadingMode==='top' && !homeTopProducts.length" class="row g-3">
  365.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-top-'+n">
  366.                         {% include 'front/_product_skeleton.html.twig' %}
  367.                     </div>
  368.                 </div>
  369.                 <div v-if="loadingMode==='top' && !homeTopProducts.length" class="text-center text-muted my-4">
  370.                     Chargement des best-sellers...
  371.                 </div>
  372.                 <div v-else class="row g-3">
  373.                     <div :class="getColClass()" v-for="prod in homeTopProducts" :key="prod.id">
  374.                         {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  375.                     </div>
  376.                     <div :class="getColClass()" v-if="loadingMoreTop" v-for="n in 2" :key="'sk-top-more-'+n">
  377.                         {% include 'front/_product_skeleton.html.twig' %}
  378.                     </div>
  379.                 </div>
  380.                 <div class="d-flex justify-content-center mt-3">
  381.                     <button class="btn btn-sm btn-dark"
  382.                             v-if="homeTopHasMore"
  383.                             :disabled="loadingMoreTop"
  384.                             @click="loadMoreTop">
  385.                         ${ loadingMoreTop ? 'Chargement...' : 'Voir plus' }
  386.                     </button>
  387.                 </div>
  388.             </section>
  389.             <section v-else-if="activeMode==='topRated'" class="container home-section">
  390.                 <div v-if="loadingMode==='topRated' && !homeTopRatedProducts.length" class="row g-3">
  391.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-top-rated-'+n">
  392.                         <div class="card-product skeleton-card">
  393.                             <div class="skeleton-image"></div>
  394.                             <div class="card-product-body">
  395.                                 <div class="skeleton-line w-80"></div>
  396.                                 <div class="skeleton-line w-60"></div>
  397.                                 <div class="skeleton-line w-40"></div>
  398.                             </div>
  399.                         </div>
  400.                     </div>
  401.                 </div>
  402.                 <div v-else class="row g-3">
  403.                     <div :class="getColClass()" v-for="prod in homeTopRatedProducts.slice(0, getHomeProductsLimit())" :key="prod.id">
  404.                         {% include 'front/_product_card.html.twig' with { var: 'prod' } %}
  405.                     </div>
  406.                 </div>
  407.             </section>
  408.             <section v-else-if="activeMode==='packs'" class="container home-section">
  409.                 <div v-if="loadingMode==='packs' && !homePacks.length" class="row g-3">
  410.                     <div :class="getColClass()" v-for="n in 4" :key="'sk-pack-'+n">
  411.                         {% include 'front/_product_skeleton.html.twig' %}
  412.                     </div>
  413.                 </div>
  414.                 <div v-if="loadingMode==='packs' && !homePacks.length" class="text-center text-muted my-4">
  415.                     Chargement des packs...
  416.                 </div>
  417.                 <div v-else class="row g-3">
  418.                     <div :class="getColClass()" v-for="p in homePacks.slice(0, getHomeProductsLimit())" :key="p.id">
  419.                         <div class="card-product">
  420.                             <div class="card-product-media" style="--img-aspect: 0.8;">
  421.                                 <img class="is-loaded"
  422.                                     :src="packImgUrl(p.picture)"
  423.                                     :alt="p.name"
  424.                                     @click="goToPackConfig(p)"
  425.                                     style="cursor:pointer;">
  426.                                 <h3 class="home-card-title product-name">${ p.name }</h3>
  427.                             </div>
  428.                             <div class="card-product-body">
  429.                                 <div class="small text-muted mb-1">${ p.reference || '' }</div>
  430.                                 <div class="product-price">
  431.                                     <div class="price-current">
  432.                                         <span class="price-value">${ formatPrice(p.final_price_ttc) } TND</span>
  433.                                         <span class="price-meta" v-if="Number(p.remise||0) > 0">
  434.                                             <span class="original-price">${ formatPrice(p.price_ttc) } TND</span>
  435.                                             <span class="discount-flag">-${ Number(p.remise||0).toFixed(2) }%</span>
  436.                                         </div>
  437.                                     </div>
  438.                                 </div>
  439.                                 <button class="btn btn-dark btn-sm mt-2" @click="goToPackConfig(p)">
  440.                                     Configurer ce pack
  441.                                 </button>
  442.                             </div>
  443.                         </div>
  444.                     </div>
  445.                 </div>
  446.             </section>
  447.         </div>
  448.     </main>
  449.     <section class="info-icons-wrapper container" aria-label="Services et garanties">
  450.         <header class="info-icons-header text-center">
  451.             <h2 class="info-icons-title">Nos services</h2>
  452.             <p class="info-icons-subtitle">Tout ce qu’il faut pour une expérience d’achat simple et sereine.</p>
  453.         </header>
  454.         <div class="info-icons-separator" aria-hidden="true"></div>
  455.         <div class="info-icons">
  456.             <a href="{{ path('delivery_information') }}" class="info-item">
  457.                 <img src="{{ asset('images/icons/livraison.png') }}" alt="Livraison rapide">
  458.                 <span>Livraison rapide</span>
  459.             </a>
  460.             <a href="{{ path('return_and_exchange') }}" class="info-item">
  461.                 <img src="{{ asset('images/icons/retour.png') }}" alt="Retours faciles">
  462.                 <span>Retours faciles</span>
  463.             </a>
  464.             <a href="{{ path('terms_of_sales') }}" class="info-item">
  465.                 <img src="{{ asset('images/icons/paiement.png') }}" alt="Paiement sécurisé">
  466.                 <span>Paiement sécurisé</span>
  467.             </a>
  468.             <a href="{{ path('contact') }}" class="info-item">
  469.                 <img src="{{ asset('images/icons/contact.png') }}" alt="Support client">
  470.                 <span>Support client</span>
  471.             </a>
  472.         </div>
  473.     </section>
  474.     {% include 'front/product/_filter_modal.html.twig' %}
  475. {% endblock %}
  476. {% block javascripts %}
  477.     {{ parent() }}
  478.     <script>
  479.         document.addEventListener('DOMContentLoaded', function () {
  480.             var slider = document.querySelector('.hero-slider');
  481.             if (!slider) {
  482.                 return;
  483.             }
  484.             var wrapper = slider.querySelector('.hero-slider-track');
  485.             var slides = slider.querySelectorAll('.hero-slide');
  486.             if (!slides.length) {
  487.                 return;
  488.             }
  489.             var currentIndex = 0;
  490.             var leftArrow = slider.querySelector('.hero-slider-arrow--prev');
  491.             var rightArrow = slider.querySelector('.hero-slider-arrow--next');
  492.             var dotsWrapper = slider.querySelector('.hero-slider-dots');
  493.             var prefersReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
  494.             var dots = [];
  495.             var setSlide = (index) => {
  496.                 currentIndex = (index + slides.length) % slides.length;
  497.                 wrapper.style.transform = `translate3d(-${currentIndex * 100}%, 0, 0)`;
  498.                 updateDots();
  499.             };
  500.             var updateDots = () => {
  501.                 dots.forEach((dot, idx) => {
  502.                     dot.classList.toggle('active', idx === currentIndex);
  503.                     dot.setAttribute('aria-selected', idx === currentIndex);
  504.                 });
  505.             };
  506.             if (dotsWrapper) {
  507.                 slides.forEach((_, idx) => {
  508.                     var dot = document.createElement('button');
  509.                     dot.type = 'button';
  510.                     dot.className = 'hero-slider-dot';
  511.                     dot.setAttribute('role', 'tab');
  512.                     dot.setAttribute('aria-label', `Slide ${idx + 1}`);
  513.                     dot.addEventListener('click', () => {
  514.                         setSlide(idx);
  515.                         resetAutoplay();
  516.                     });
  517.                     dotsWrapper.appendChild(dot);
  518.                     dots.push(dot);
  519.                 });
  520.             }
  521.             var goToPrevious = () => {
  522.                 setSlide(currentIndex - 1);
  523.                 resetAutoplay();
  524.             };
  525.             var goToNext = () => {
  526.                 setSlide(currentIndex + 1);
  527.                 resetAutoplay();
  528.             };
  529.             if (leftArrow) {
  530.                 leftArrow.addEventListener('click', goToPrevious);
  531.             }
  532.             if (rightArrow) {
  533.                 rightArrow.addEventListener('click', goToNext);
  534.             }
  535.             setSlide(currentIndex);
  536.             var autoplayId = null;
  537.             var startAutoplay = () => {
  538.                 if (slides.length <= 1) {
  539.                     return;
  540.                 }
  541.                 if (prefersReduced) {
  542.                     return;
  543.                 }
  544.                 autoplayId = setInterval(goToNext, 5000);
  545.             };
  546.             var resetAutoplay = () => {
  547.                 if (autoplayId) {
  548.                     clearInterval(autoplayId);
  549.                     autoplayId = null;
  550.                 }
  551.                 startAutoplay();
  552.             };
  553.             slider.addEventListener('mouseenter', function () {
  554.                 if (autoplayId) {
  555.                     clearInterval(autoplayId);
  556.                     autoplayId = null;
  557.                 }
  558.             });
  559.             slider.addEventListener('mouseleave', function () {
  560.                 startAutoplay();
  561.             });
  562.             startAutoplay();
  563.         });
  564.     </script>
  565.     <script src="{{ asset('front/assets/scripts/home/home.js') }}"></script>
  566. {% endblock %}