From c3b4707f8595ae647ca565f6a069dca988bdd63c Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Mon, 18 May 2026 19:51:43 +0200 Subject: [PATCH] feat: pro: drop top/bottom split, keep side-by-side only --- app/[locale]/pro/page.tsx | 124 +++++++------------------------------- stores/pro-tab-store.ts | 7 ++- 2 files changed, 29 insertions(+), 102 deletions(-) diff --git a/app/[locale]/pro/page.tsx b/app/[locale]/pro/page.tsx index eebb7288..cab5a8fe 100644 --- a/app/[locale]/pro/page.tsx +++ b/app/[locale]/pro/page.tsx @@ -31,7 +31,7 @@ const APP_TAB_COMPONENTS: Partial> = { settings: SettingsPage, }; -type DropTarget = 'left' | 'right' | 'top' | 'bottom' | null; +type DropTarget = 'left' | 'right' | null; function renderTabBody(tab: ProTab): React.ReactNode { if (tab.kind === 'compose' && tab.composeData) { @@ -172,44 +172,15 @@ export default function ProHome() { const computeDropTarget = (e: DragEvent): DropTarget => { const rect = e.currentTarget.getBoundingClientRect(); - const x = e.clientX - rect.left; - const y = e.clientY - rect.top; - const xFrac = x / rect.width; - const yFrac = y / rect.height; - - if (isSplit) { - // When split: each pane gets half the body as its drop zone. - if (splitOrientation === 'vertical') { - return xFrac < 0.5 ? 'left' : 'right'; - } - return yFrac < 0.5 ? 'top' : 'bottom'; - } - // No split: only the outer 22% of each edge creates a split. - const fromLeft = xFrac; - const fromRight = 1 - xFrac; - const fromTop = yFrac; - const fromBottom = 1 - yFrac; - const min = Math.min(fromLeft, fromRight, fromTop, fromBottom); - if (min > 0.22) return null; - if (min === fromRight) return 'right'; - if (min === fromLeft) return 'left'; - if (min === fromBottom) return 'bottom'; - return 'top'; + const xFrac = (e.clientX - rect.left) / rect.width; + return xFrac < 0.5 ? 'left' : 'right'; }; const targetPaneFromDrop = (target: DropTarget): ProPaneId | null => { if (!target || !isSplit) return null; - if (splitOrientation === 'vertical') { - const leftIsSplit = splitLeading; - if (target === 'left') return leftIsSplit ? 'split' : 'main'; - if (target === 'right') return leftIsSplit ? 'main' : 'split'; - } - if (splitOrientation === 'horizontal') { - const topIsSplit = splitLeading; - if (target === 'top') return topIsSplit ? 'split' : 'main'; - if (target === 'bottom') return topIsSplit ? 'main' : 'split'; - } - return null; + const leftIsSplit = splitLeading; + if (target === 'left') return leftIsSplit ? 'split' : 'main'; + return leftIsSplit ? 'main' : 'split'; }; const handleBodyDragOver = (e: DragEvent) => { @@ -242,10 +213,10 @@ export default function ProHome() { if (destPane) moveTabToPane(draggedId, destPane); return; } - // Create a new split. - const orientation = (target === 'left' || target === 'right') ? 'vertical' : 'horizontal'; - moveTabToPane(draggedId, 'split', orientation); - setSplitLeading(target === 'left' || target === 'top'); + // Create a new side-by-side split. `splitLeading` controls which side + // visually hosts the split pane. + moveTabToPane(draggedId, 'split', 'vertical'); + setSplitLeading(target === 'left'); }; // Loading state (matches standard page exactly) @@ -287,42 +258,16 @@ export default function ProHome() { const splitDivider = isSplit ? ( )} @@ -404,34 +346,14 @@ export default function ProHome() { ); } -function DropZone({ active, side }: { active: boolean; side: 'left' | 'right' | 'top' | 'bottom' }) { - const isVertical = side === 'left' || side === 'right'; +function DropZone({ side }: { side: 'left' | 'right' }) { return (