{# Reusable image gallery slider - horizontal swipe/drag, full-bleed width, alternating portrait/landscape image formats (even index = portrait/tall, odd index = landscape/wide) vertically centered so the shorter landscape tiles sit nested within the taller portrait row height - see assets/styles/components/_gallery-slider.scss. Scrollbar is hidden by design, so the viewport carries `data-drag-scroll="true"`: assets/components/gallery-slider.ts mounts a click-and-drag handler on it (desktop mouse only - touch/trackpad swipe is native `overflow-x: auto` and needs no JS). The page entrypoint must import and call `initGallerySliders()` for this to work (see assets/project-detail.ts). "Infinite": the image list is rendered twice in the DOM so swiping past the end continues into a visually identical repeat instead of visibly stopping. A true endless loop (silently resetting scroll position once the duplicate is reached) would need extra JS on top of that and isn't implemented here. Parameters: - images (array): list of { path: string, darkPath?: string, frame?: array, darkFrame?: array, alt: string }, in display order (`frame`/`darkFrame` = Été / Hiver cadrage, see ImageFrameExtension; tile format stays imposed by its position, so no ratio here). Renders nothing for an empty list; renders a single static image (no slider chrome) for exactly one image. #} {% macro frame(image) %}{{ image_frame_attrs({image: image.path, imageDark: image.darkPath|default(''), imageFrame: image.frame|default(null), imageDarkFrame: image.darkFrame|default(null)}, 'image', false, false) }}{% endmacro %} {% if images is defined and images|length > 1 %}
{% elseif images is defined and images|length == 1 %} {% endif %}