Skip to content

Commit 11ddaad

Browse files
committed
fix: Hear what other users have to say... section on small devices
Signed-off-by: DANIEL KATOTO <katotodan@gmail.com>
1 parent ae9cf0a commit 11ddaad

1 file changed

Lines changed: 95 additions & 11 deletions

File tree

src/sections/Pricing/review-slider.js

Lines changed: 95 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11

2-
import React from "react";
2+
import React, { useRef, useState, useLayoutEffect } from "react";
3+
// NOTE: useLayoutEffect is used intentionally here (instead of useEffect) so
4+
// that we can compute the correct `slidesToShow` value before the browser
5+
// paints the component. This avoids a visual flash where the slider briefly
6+
// renders with the desktop slide count and then corrects itself on mount.
37
import styled from "styled-components";
48
import Customers from "../../reusecore/Blockquote/Blockquote-image";
59
import Slider from "react-slick";
@@ -33,28 +37,22 @@ const settings = {
3337
{
3438
breakpoint: 1300,
3539
settings: {
36-
slidesToShow: 2.5,
40+
slidesToShow: 2,
41+
slidesToScroll: 1,
3742
}
3843
},
3944
{
4045
breakpoint: 1024,
4146
settings: {
4247
slidesToShow: 2,
48+
slidesToScroll: 1,
4349
}
4450
},
4551
{
4652
breakpoint: 800,
47-
settings: {
48-
slidesToShow: 1.5,
49-
slidesToScroll: 0.5,
50-
}
51-
},
52-
{
53-
breakpoint: 600,
5453
settings: {
5554
slidesToShow: 1,
5655
slidesToScroll: 1,
57-
autoplaySpeed: 2000,
5856
}
5957
}
6058
]
@@ -81,15 +79,101 @@ max-width: 100%;
8179
opacity: 1;
8280
}
8381
82+
/* Prevent extreme shrinking on mobile */
83+
.slick-slide > div { min-width: 0; }
84+
.slider .type-one-wrapper { width: 100%; max-width: none; margin: 0 0.5rem; }
85+
86+
@media (max-width: 768px) {
87+
.type-one-wrapper.type-one-wrapper-boxed { max-width: none; padding: 0; }
88+
.type-one-quote .type-one-quote-base,
89+
.type-two-quote .type-two-quote-base { padding-left: 30px; padding-right: 30px; }
90+
}
91+
8492
`;
8593

8694

8795
const Reviews = () => {
96+
const [isClient, setIsClient] = useState(false);
97+
const [slidesToShowState, setSlidesToShowState] = useState(null);
98+
const sliderRef = useRef(null);
99+
100+
/* Merge runtime slidesToShow into settings and disable internal responsive handling.
101+
We disable the internal `responsive` array here because we compute the
102+
desired `slidesToShow` at runtime (based on window width) and pass it
103+
directly to the slider to avoid conflicting calculations and race
104+
conditions that can occur during initial mount. */
105+
const mergedSettings = {
106+
...settings,
107+
slidesToShow: slidesToShowState || 1,
108+
slidesToScroll: 1,
109+
responsive: []
110+
};
111+
112+
/* computeSlides: determine the appropriate slidesToShow based on the
113+
current window width. This centralises the breakpoint logic so we can
114+
compute the initial value synchronously and reuse it in resize handlers. */
115+
const computeSlides = () => {
116+
const w = typeof window !== "undefined" ? (window.innerWidth || document.documentElement.clientWidth) : 1200;
117+
if (w <= 800) return 1;
118+
if (w <= 1024) return 2;
119+
return 3;
120+
};
121+
122+
useLayoutEffect(() => {
123+
/* Initialise slider state synchronously before paint to avoid a flash of
124+
incorrect layout. We set slidesToShowState here so the Slider mounts with
125+
the right number of slides on initial render.
126+
127+
onResizeDebounced: debounced handler that recomputes slides and asks
128+
the react-slick instance to remeasure (via onWindowResized). Debounce
129+
helps avoid rapid repeated calls during a resize gesture.
130+
131+
onLoad: we also listen for the window "load" event and each slide image
132+
"load" event because images can change the layout width; when an image
133+
finishes loading we rerun the debounced handler to ensure the slider
134+
recalculates correctly.
135+
*/
136+
setIsClient(true);
137+
setSlidesToShowState(computeSlides());
138+
139+
let resizeTimeout = null;
140+
const onResizeDebounced = () => {
141+
clearTimeout(resizeTimeout);
142+
resizeTimeout = setTimeout(() => {
143+
const slides = computeSlides();
144+
setSlidesToShowState((prev) => {
145+
if (prev !== slides) return slides;
146+
return prev;
147+
});
148+
if (sliderRef.current && sliderRef.current.innerSlider && typeof sliderRef.current.innerSlider.onWindowResized === "function") {
149+
sliderRef.current.innerSlider.onWindowResized();
150+
}
151+
}, 100);
152+
};
153+
154+
const onLoad = () => onResizeDebounced();
155+
156+
window.addEventListener("resize", onResizeDebounced);
157+
window.addEventListener("load", onLoad);
158+
const imgs = document.querySelectorAll(".slider img");
159+
imgs.forEach((img) => img.addEventListener("load", onLoad));
160+
161+
return () => {
162+
window.removeEventListener("resize", onResizeDebounced);
163+
window.removeEventListener("load", onLoad);
164+
imgs.forEach((img) => img.removeEventListener("load", onLoad));
165+
clearTimeout(resizeTimeout);
166+
};
167+
}, []);
168+
169+
if (!isClient || slidesToShowState === null) return null;
170+
88171
return (
89172
<ReviewsWrapper>
90173
<div className="slider">
91174
<h2>Hear what other users have to say...</h2>
92-
<Slider {...settings}>
175+
{/* key property will force React to remount the Slider when slidesToShowState changes. */}
176+
<Slider key={`review-slider-${slidesToShowState}`} ref={sliderRef} {...mergedSettings}>
93177
{/* <Customers
94178
type="1"
95179
quote="The Meshery Extension transforms Docker Desktop into a powerful load generation utility, conveniently enabling me to deploy and configure any service mesh with a click of the button and invoke and control load-based performance tests from my desktop."

0 commit comments

Comments
 (0)