Skip to content

Commit 56edb98

Browse files
author
Test
committed
🤖 feat: add swipe gestures for mobile sidebar
Add touch gesture support for opening/closing the right sidebar on mobile: - Swipe left from right edge (last 50px) to open sidebar - Swipe right from anywhere to close sidebar - Gestures must be horizontal, at least 50px, and fast (< 300ms) - Provides native app-like interaction for mobile users This complements the FAB button with a more natural gesture-based interaction pattern commonly found in mobile apps. _Generated with `cmux`_ Change-Id: I8b78d1b9d32056a1b02adde4cd17e17375eecfaa Signed-off-by: Test <test@example.com>
1 parent 5d0aaf3 commit 56edb98

File tree

1 file changed

+63
-0
lines changed

1 file changed

+63
-0
lines changed

src/components/RightSidebar.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,69 @@ const RightSidebarComponent: React.FC<RightSidebarProps> = ({
187187
const showMeter = showCollapsed || selectedTab === "review";
188188
const verticalMeter = showMeter ? <VerticalTokenMeter data={verticalMeterData} /> : null;
189189

190+
// Swipe gesture detection for mobile - right-to-left swipe to open sidebar
191+
React.useEffect(() => {
192+
// Only enable swipe on mobile when sidebar is collapsed
193+
if (typeof window === "undefined") return;
194+
195+
let touchStartX = 0;
196+
let touchStartY = 0;
197+
let touchStartTime = 0;
198+
199+
const handleTouchStart = (e: TouchEvent) => {
200+
// Only detect swipes from right edge (last ~50px of screen)
201+
const touch = e.touches[0];
202+
if (!touch) return;
203+
204+
const screenWidth = window.innerWidth;
205+
if (touch.clientX < screenWidth - 50) return; // Not from right edge
206+
207+
touchStartX = touch.clientX;
208+
touchStartY = touch.clientY;
209+
touchStartTime = Date.now();
210+
};
211+
212+
const handleTouchEnd = (e: TouchEvent) => {
213+
const touch = e.changedTouches[0];
214+
if (!touch) return;
215+
216+
const touchEndX = touch.clientX;
217+
const touchEndY = touch.clientY;
218+
const touchEndTime = Date.now();
219+
220+
// Calculate swipe distance and direction
221+
const deltaX = touchEndX - touchStartX;
222+
const deltaY = touchEndY - touchStartY;
223+
const duration = touchEndTime - touchStartTime;
224+
225+
// Swipe must be:
226+
// 1. Horizontal (more X movement than Y)
227+
// 2. At least 50px distance
228+
// 3. Fast enough (< 300ms)
229+
const isLeftSwipe = deltaX < -50; // Right to left
230+
const isRightSwipe = deltaX > 50; // Left to right
231+
const isHorizontal = Math.abs(deltaX) > Math.abs(deltaY);
232+
const isFastEnough = duration < 300;
233+
234+
// Open sidebar on left swipe from right edge when collapsed
235+
if (isLeftSwipe && isHorizontal && isFastEnough && showCollapsed) {
236+
setShowCollapsed(false);
237+
}
238+
// Close sidebar on right swipe when open (from anywhere on screen)
239+
else if (isRightSwipe && isHorizontal && isFastEnough && !showCollapsed) {
240+
setShowCollapsed(true);
241+
}
242+
};
243+
244+
window.addEventListener("touchstart", handleTouchStart, { passive: true });
245+
window.addEventListener("touchend", handleTouchEnd, { passive: true });
246+
247+
return () => {
248+
window.removeEventListener("touchstart", handleTouchStart);
249+
window.removeEventListener("touchend", handleTouchEnd);
250+
};
251+
}, [showCollapsed, setShowCollapsed]);
252+
190253
return (
191254
<>
192255
{/* FAB - Floating Action Button for mobile, only visible when collapsed */}

0 commit comments

Comments
 (0)