From 4d901e16bd35c0da68f6868698c49db52156b373 Mon Sep 17 00:00:00 2001 From: Arnas Donauskas Date: Sun, 19 Apr 2026 11:53:10 +0300 Subject: [PATCH] feat(mobile): snap-scroll kanban board with viewport-sized columns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The pipelines board was already horizontally scrollable, but on a phone it felt imprecise — swipes landed mid-column, there was no visual hint that more columns existed past the viewport, and 260px columns felt cramped at 375px width. - Each StageColumn is now w-[85vw] min/max-clamped on mobile, so the next column's edge peeks in as a "more here" affordance. On lg+ the columns revert to flex-1 basis-[260px] (share the row). - Scroll container gets snap-x + snap-mandatory on mobile, snap-none on lg+. Each column has snap-start so swipes always land cleanly at the left edge of the next column. - shrink-0 on mobile prevents flex from compressing the columns when space is tight. No desktop visual change — all the mobile-specific classes are overridden back by their lg: counterparts, and the original flex-1 basis-[260px] behavior is preserved above lg. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/components/pipelines/pipeline-board.tsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/pipelines/pipeline-board.tsx b/src/components/pipelines/pipeline-board.tsx index ddfa1d9..135acb7 100644 --- a/src/components/pipelines/pipeline-board.tsx +++ b/src/components/pipelines/pipeline-board.tsx @@ -102,7 +102,11 @@ export function PipelineBoard({ onDragEnd={handleDragEnd} onDragCancel={handleDragCancel} > -
+ {/* snap-x + snap-mandatory on mobile so swipes land the next + stage cleanly at the viewport edge instead of mid-column. + Disabled on lg+ because the full board fits without scroll + there and snapping would interfere with the natural layout. */} +
{sortedStages.map((stage) => { const stageDeals = dealsByStage.get(stage.id) ?? []; const totalValue = stageDeals.reduce( @@ -176,7 +180,13 @@ function StageColumn({ const { setNodeRef, isOver } = useDroppable({ id: stage.id }); return ( -
+ // On mobile each column is `w-[85vw]` (with a reasonable min/max) + // so the next column's edge peeks in — a "there's more here" hint. + // snap-start lands each column cleanly when swiping. On lg+ we + // restore the flex-1 share-the-row behavior. The droppable ref is + // on the inner messages region below — intentionally NOT here, so + // a drag over the column header doesn't highlight the whole column. +
{/* 3px colored top border — sits above the column's padding */}