<section class="relative" x-data="initSlider" x-init="calcPageSize(); $nextTick( function() { calcActive() })" @resize.window.debounce="calcPageSize(); $nextTick(() => calcActive())" role="group" aria-roledescription="Carousel" aria-label="Hero Product Slider">
    <div class="relative">
        <div class="relative w-full overflow-x-hidden">
            <div class="relative flex flex-nowrap w-full overflow-auto js_slides snap" @scroll.debounce="calcActive" aria-label="Slides">

                <div class="js_slide flex-shrink-0 w-full" aria-roledescription="slide" id="slide-0" aria-labelledby="tab-0" role="tabpanel" tabindex="0" :aria-label="'Slide ' + (1) + ' of ' + 3" :aria-hidden="active !== 0">
                    <div class="relative h-full pt-20 md:pt-72 lg:pt-60 3xl:pt-80" style="background: url('/img/sliders/img_2.png') center/cover no-repeat;">

                        <div class="container mx-auto h-full pb-72 md:pb-56 lg:pb-40 3xl:pb-60">
                            <div class="flex h-full relative justify-start">

                                <div class="flex flex-col gap-6 lg:gap-8 3xl:gap-10
                                      w-full md:w-1/2 z-10
                                              pr-4 md:pr-8
                                                    ">
                                    <div class="flex flex-col gap-4">
                                        <h2 class="h2 [&>span]:font-normal">Titre avec <span>une longueur</span> réaliste pour un hero !</h2>

                                        <p class="h5-base">
                                            Sous-titre limité pour que tout aille bien.
                                        </p>
                                    </div>

                                    <a href="#" type="button" class="self-start  btn  btn-dark  btn-solid  btn-size-lg">
                                        Découvrir État Pur

                                    </a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="js_slide flex-shrink-0 w-full" aria-roledescription="slide" id="slide-1" aria-labelledby="tab-1" role="tabpanel" tabindex="0" :aria-label="'Slide ' + (2) + ' of ' + 3" :aria-hidden="active !== 1">
                    <div class="relative h-full pt-20 md:pt-72 lg:pt-60 3xl:pt-80" style="background: url('/img/sliders/img_3.png') center/cover no-repeat;">
                        <div class="hidden md:block absolute inset-0 w-full h-full z-0 transition-opacity duration-300" style="background: url('/img/sliders/img_1.png') center/cover no-repeat;">
                        </div>

                        <div class="container mx-auto h-full pb-72 md:pb-56 lg:pb-40 3xl:pb-60">
                            <div class="flex h-full relative justify-start">

                                <div class="flex flex-col gap-6 lg:gap-8 3xl:gap-10
                                      w-full md:w-1/2 z-10
                                              pl-4 md:pl-8
                                                    md:ml-auto">
                                    <div class="flex flex-col gap-4">
                                        <h2 class="h2 [&>span]:font-normal">Titre avec <span>une longueur</span> réaliste pour un hero !</h2>

                                        <p class="h5-base">
                                            Sous-titre limité pour que tout aille bien.
                                        </p>
                                    </div>

                                    <a href="#" type="button" class="self-start  btn  btn-dark  btn-solid  btn-size-lg">
                                        Découvrir État Pur

                                    </a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <div class="js_slide flex-shrink-0 w-full" aria-roledescription="slide" id="slide-2" aria-labelledby="tab-2" role="tabpanel" tabindex="0" :aria-label="'Slide ' + (3) + ' of ' + 3" :aria-hidden="active !== 2">
                    <div class="relative h-full pt-20 md:pt-72 lg:pt-60 3xl:pt-80" style="background: url('/img/sliders/img.png') center/cover no-repeat;">

                        <div class="container mx-auto h-full pb-72 md:pb-56 lg:pb-40 3xl:pb-60">
                            <div class="flex h-full relative justify-center">

                                <div class="flex flex-col gap-6 lg:gap-8 3xl:gap-10
                                      w-full md:w-2/3 text-center z-10
                                ">
                                    <div class="flex flex-col gap-4">
                                        <h2 class="h2 [&>span]:font-normal">Titre avec <span>une longueur</span> réaliste pour un hero !</h2>

                                        <p class="h5-base">
                                            Sous-titre limité pour que tout aille bien.
                                        </p>
                                    </div>

                                    <a href="#" type="button" class="self-center  btn  btn-dark  btn-solid  btn-size-lg">
                                        Découvrir État Pur

                                    </a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>

                <div x-bind:class="{
                        'js_dummy_slide w-full': pageFillers > 0
                    }"></div>
            </div>
        </div>

        <div class="absolute bottom-12 lg:bottom-14 3xl:bottom-10 w-full z-10">
            <div class="container relative">
                <div class="absolute left-1/2 transform -translate-x-1/2 h-full flex justify-center items-center">
                    <div class="flex items-center ">
                        <div role="tablist" aria-label="Navigation du slider" class="flex flex-wrap justify-center gap-3">
                            <template x-for="(index, i) in Math.ceil(itemCount / pageSize)" :key="i">
                                <button class="shrink-0 block h-1 bg-black rounded-full shadow cursor-pointer transition-all duration-300 ease-in-out" role="tab" :id="'tab-' + (index-1)" :aria-controls="'slide-' + (index-1)" :aria-selected="Math.floor(active/pageSize) === index-1" :tabindex="Math.floor(active/pageSize) === index-1 ? 0 : -1" :class="{
                    'bg-opacity-100 w-22': Math.floor(active/pageSize) === index-1,
                    'bg-opacity-40 w-6': Math.floor(active/pageSize) !== index-1
                }" @click="scrollTo((index-1)*pageSize);">
                                    <span class="sr-only" x-text="'Aller au groupe de slides ' + index"></span>
                                </button>
                            </template>
                        </div>
                    </div>
                </div>

                <!-- Boutons de navigation -->
                <div class="hidden sm:flex justify-end">
                    <div class="flex flex-row gap-4">
                        <button type="button" :class="{ 'opacity-25 pointer-events-none' : active === 0 }" @click="scrollPrevious" :disabled="active === 0" aria-label="Voir le slide précédent" class=" btn  btn-dark  btn-subtle btn-border btn-size-sm btn-only-icon">
                            <svg class=" shrink-0" width="24" height="24" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                                <path d="M10.5 19.5L3 12M3 12L10.5 4.5M3 12H21" stroke="currentColor" stroke-width="1.5" fill="none" />

                            </svg>

                        </button>

                        <button type="button" :class="{ 'opacity-25 pointer-events-none' : active >= itemCount - pageSize }" @click="scrollNext" :disabled="active >= itemCount - pageSize" aria-label="Voir le slide suivant" class=" btn  btn-dark  btn-subtle btn-border btn-size-sm btn-only-icon">
                            <svg class=" shrink-0" width="24" height="24" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
                                <path d="M13.5 4.5 21 12m0 0-7.5 7.5M21 12H3" stroke="currentColor" stroke-width="1.5" fill="none" />

                            </svg>

                        </button>
                    </div>
                </div>
            </div>
        </div>
    </div>
</section>

<script>
    'use strict';

    function initSlider() {
        return {
            active: 0,
            itemCount: 0,
            getSlider() {
                return this.$root.querySelector('.js_slides');
            },
            pageSize: 4,
            pageFillers: 0,
            calcPageSize() {
                const slider = this.getSlider();
                if (slider) {
                    this.itemCount = slider.querySelectorAll('.js_slide').length;
                    this.pageSize = Math.round(slider.clientWidth / slider.querySelector('.js_slide').clientWidth);
                    this.pageFillers = (
                        this.pageSize * Math.ceil(this.itemCount / this.pageSize)
                    ) - this.itemCount;
                }
            },
            calcActive() {
                const slider = this.getSlider();
                if (slider) {
                    const sliderItems = this.itemCount + this.pageFillers;
                    const calculatedActiveSlide = slider.scrollLeft / (slider.scrollWidth / sliderItems);
                    this.active = Math.round(calculatedActiveSlide / this.pageSize) * this.pageSize;
                }
            },
            scrollPrevious() {
                this.scrollTo(this.active - this.pageSize);
            },
            scrollNext() {
                this.scrollTo(this.active + this.pageSize);
            },
            scrollTo(idx) {
                const slider = this.getSlider();
                if (slider) {
                    const slideWidth = slider.scrollWidth / (this.itemCount + this.pageFillers);
                    slider.scrollLeft = Math.floor(slideWidth) * idx;
                    this.active = idx;
                }
            },
        }
    }
</script>
{# SLIDER HYVA #}
<section class="relative"
         x-data="initSlider"
         x-init="calcPageSize(); $nextTick( function() { calcActive() })"
         @resize.window.debounce="calcPageSize(); $nextTick(() => calcActive())"
         role="group"
         aria-roledescription="Carousel"
         aria-label="{{ title }}"
>
    <div class="relative">
        <div class="relative w-full overflow-x-hidden">
            <div class="relative flex flex-nowrap w-full overflow-auto js_slides snap"
                 @scroll.debounce="calcActive"
                 aria-label="Slides"
            >
                {% for item in items %}
                    {% set contentPosition = item.contentPosition|default('left') %}

                    <div class="js_slide flex-shrink-0 w-full"
                         aria-roledescription="slide"
						 id="slide-{{ loop.index0 }}"
						 aria-labelledby="tab-{{ loop.index0 }}"
						 role="tabpanel"
                         tabindex="0"
                         :aria-label="'Slide ' + ({{ loop.index }}) + ' of ' + {{ items|length }}"
                         :aria-hidden="active !== {{ loop.index0 }}"
                    >
                        {% render "@card-product-full-width" with {
                            item: item,
                            contentPosition: contentPosition
                        } %}
                    </div>
                {% endfor %}

                {% for i in 0..(maxVisibleSlides - 1) %}
                    <div x-bind:class="{
                        'js_dummy_slide w-full': pageFillers > {{ i }}
                    }"></div>
                {% endfor %}
            </div>
        </div>

        {% if items|length > 1 %}
            <div class="absolute bottom-12 lg:bottom-14 3xl:bottom-10 w-full z-10">
                <div class="container relative">
                    <div class="absolute left-1/2 transform -translate-x-1/2 h-full flex justify-center items-center">
						{% render "@slider-pagination" %}
					</div>

                    <!-- Boutons de navigation -->
                    <div class="hidden sm:flex justify-end">
                        <div class="flex flex-row gap-4">
                            {% render "@template-button" with {
                                color: 'dark',
                                type: 'subtle',
                                icon_type: "only-icon",
                                size: 'sm',
                                border: true,
                                label: 'Voir le slide précédent',
                                icon: {
                                    name: "heroicons--arrow-left-outline",
                                },
                                button_attribute: (":class=\"{ 'opacity-25 pointer-events-none' : active === 0 }\" @click=\"scrollPrevious\" :disabled=\"active === 0\"")|replace({'\"': '"'})
                            } %}

                            {% render "@template-button" with {
                                color: 'dark',
                                type: 'subtle',
                                icon_type: "only-icon",
                                size: 'sm',
                                border: true,
                                label: 'Voir le slide suivant',
                                icon: {
                                    name: "heroicons--arrow-right-outline",
                                },
                                button_attribute: (":class=\"{ 'opacity-25 pointer-events-none' : active >= itemCount - pageSize }\" @click=\"scrollNext\" :disabled=\"active >= itemCount - pageSize\"")|replace({'\"': '"'})
                            } %}
                        </div>
                    </div>
                </div>
            </div>
        {% endif %}
    </div>
</section>

<script>
	'use strict';

	function initSlider() {
		return {
			active: 0,
			itemCount: 0,
			getSlider() {
				return this.$root.querySelector('.js_slides');
			},
			pageSize: 4,
			pageFillers: 0,
			calcPageSize() {
				const slider = this.getSlider();
				if (slider) {
					this.itemCount = slider.querySelectorAll('.js_slide').length;
					this.pageSize = Math.round(slider.clientWidth / slider.querySelector('.js_slide').clientWidth);
					this.pageFillers = (
						this.pageSize * Math.ceil(this.itemCount / this.pageSize)
					) - this.itemCount;
				}
			},
			calcActive() {
				const slider = this.getSlider();
				if (slider) {
					const sliderItems = this.itemCount + this.pageFillers;
					const calculatedActiveSlide = slider.scrollLeft / (slider.scrollWidth / sliderItems);
					this.active = Math.round(calculatedActiveSlide / this.pageSize) * this.pageSize;
				}
			},
			scrollPrevious() {
				this.scrollTo(this.active - this.pageSize);
			},
			scrollNext() {
				this.scrollTo(this.active + this.pageSize);
			},
			scrollTo(idx) {
				const slider = this.getSlider();
				if (slider) {
					const slideWidth = slider.scrollWidth / (this.itemCount + this.pageFillers);
					slider.scrollLeft = Math.floor(slideWidth) * idx;
					this.active = idx;
				}
			},
		}
	}
</script>
{
  "title": "Hero Product Slider",
  "maxVisibleSlides": 1,
  "showNavigation": true,
  "showPagination": true,
  "items": [
    {
      "contentPosition": "left",
      "title": "Titre avec <span>une longueur</span> réaliste pour un hero !",
      "subtitle": "Sous-titre limité pour que tout aille bien.",
      "cta": {
        "label": "Découvrir État Pur",
        "link": "#"
      },
      "background": {
        "mobile": "/img/sliders/img_2.png"
      }
    },
    {
      "contentPosition": "right",
      "title": "Titre avec <span>une longueur</span> réaliste pour un hero !",
      "subtitle": "Sous-titre limité pour que tout aille bien.",
      "cta": {
        "label": "Découvrir État Pur",
        "link": "#"
      },
      "background": {
        "desktop": "/img/sliders/img_1.png",
        "mobile": "/img/sliders/img_3.png"
      }
    },
    {
      "contentPosition": "center",
      "title": "Titre avec <span>une longueur</span> réaliste pour un hero !",
      "subtitle": "Sous-titre limité pour que tout aille bien.",
      "cta": {
        "label": "Découvrir État Pur",
        "link": "#"
      },
      "background": {
        "mobile": "/img/sliders/img.png"
      }
    }
  ]
}

No notes defined.