From 5c9164b185b3c63689a4bf46f30a258fd40c96b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81dric=20Andrietti?= Date: Fri, 2 Oct 2026 11:45:43 +0200 Subject: [PATCH 1/2] feat(scroll): add horizontal scroll snap mixin for responsive layouts --- .../02-tools/_m-horizontal-scroll-snap.scss | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/scss/02-tools/_m-horizontal-scroll-snap.scss diff --git a/src/scss/02-tools/_m-horizontal-scroll-snap.scss b/src/scss/02-tools/_m-horizontal-scroll-snap.scss new file mode 100644 index 00000000..bdba5e08 --- /dev/null +++ b/src/scss/02-tools/_m-horizontal-scroll-snap.scss @@ -0,0 +1,47 @@ +@use "../01-abstract/theme-json" as *; +@use "m-scrollbar" as *; + +/** + * Horizontal scroll track with mandatory snap (no Swiper). + * Full-bleed track via responsive gutters; next slide peeks on the right. + * + * @author Cédric Andrietti + * + * @param $item-selector - slide items (default: direct li children) + * + * Custom properties (optional overrides on the scroll container): + * --horizontal-scroll-gap - flex gap (falls back to --column-gap) + * --horizontal-scroll-peek - visible part of the next slide + * + * Example: + * + * .my-track { + * @include breakpoints(sm, max) { + * @include horizontal-scroll-snap; + * } + * } + */ +@mixin horizontal-scroll-snap($item-selector: "> li") { + --horizontal-scroll-gap: #{$settings-spacing-xs}; + --horizontal-scroll-peek: calc(var(--horizontal-scroll-gap) + #{$settings-spacing-xs}); + + display: flex; + flex-wrap: nowrap; + gap: var(--horizontal-scroll-gap); + width: calc(100% + var(--responsive--gutter-left) + var(--responsive--gutter-right)); + padding-inline: var(--responsive--gutter-left) var(--responsive--gutter-right); + margin-inline: calc(-1 * var(--responsive--gutter-left)) calc(-1 * var(--responsive--gutter-right)); + overflow-x: auto; + overscroll-behavior-x: contain; + scroll-snap-type: x mandatory; + scroll-padding-inline: var(--responsive--gutter-left) var(--responsive--gutter-right); + -webkit-overflow-scrolling: touch; + + @include scrollbar-invisible; + + #{$item-selector} { + flex: 0 0 calc(100% - var(--horizontal-scroll-peek)); + min-width: 0; + scroll-snap-align: start; + } +} From dd2ed26c590594ce32cc272a0e92b1a466a4fd3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ce=CC=81dric=20Andrietti?= Date: Fri, 2 Oct 2026 12:18:42 +0200 Subject: [PATCH 2/2] fix bugbot : enhance horizontal scroll snap mixin with improved custom property handling --- src/scss/02-tools/_m-horizontal-scroll-snap.scss | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/scss/02-tools/_m-horizontal-scroll-snap.scss b/src/scss/02-tools/_m-horizontal-scroll-snap.scss index bdba5e08..b3e2fe2e 100644 --- a/src/scss/02-tools/_m-horizontal-scroll-snap.scss +++ b/src/scss/02-tools/_m-horizontal-scroll-snap.scss @@ -9,25 +9,26 @@ * * @param $item-selector - slide items (default: direct li children) * - * Custom properties (optional overrides on the scroll container): - * --horizontal-scroll-gap - flex gap (falls back to --column-gap) - * --horizontal-scroll-peek - visible part of the next slide + * Custom properties (optional overrides on the scroll container, set before the include): + * --horizontal-scroll-gap - flex gap (falls back to --column-gap, then theme spacing) + * --horizontal-scroll-peek - visible part of the next slide (defaults to gap + xs spacing) * * Example: * * .my-track { * @include breakpoints(sm, max) { + * --horizontal-scroll-gap: var(--column-gap); * @include horizontal-scroll-snap; * } * } */ @mixin horizontal-scroll-snap($item-selector: "> li") { - --horizontal-scroll-gap: #{$settings-spacing-xs}; - --horizontal-scroll-peek: calc(var(--horizontal-scroll-gap) + #{$settings-spacing-xs}); + $_horizontal-scroll-gap: var(--horizontal-scroll-gap, var(--column-gap, #{$settings-spacing-xs})); + $_horizontal-scroll-peek: var(--horizontal-scroll-peek, calc(#{$_horizontal-scroll-gap} + #{$settings-spacing-xs})); display: flex; flex-wrap: nowrap; - gap: var(--horizontal-scroll-gap); + gap: #{$_horizontal-scroll-gap}; width: calc(100% + var(--responsive--gutter-left) + var(--responsive--gutter-right)); padding-inline: var(--responsive--gutter-left) var(--responsive--gutter-right); margin-inline: calc(-1 * var(--responsive--gutter-left)) calc(-1 * var(--responsive--gutter-right)); @@ -40,7 +41,7 @@ @include scrollbar-invisible; #{$item-selector} { - flex: 0 0 calc(100% - var(--horizontal-scroll-peek)); + flex: 0 0 calc(100% - #{$_horizontal-scroll-peek}); min-width: 0; scroll-snap-align: start; }