'use client' import { useRef, useState, useEffect, useCallback } from 'react' import { cn } from '@/lib/utils' interface SplitPaneProps { left: React.ReactNode right: React.ReactNode storageKey: string defaultSplit?: number // percentage for left pane, default 40 minSize?: number // minimum px per pane, default 200 } export function SplitPane({ left, right, storageKey, defaultSplit = 40, minSize = 200, }: SplitPaneProps) { const containerRef = useRef(null) const [split, setSplit] = useState(defaultSplit) const [isDragging, setIsDragging] = useState(false) const [isMobile, setIsMobile] = useState(false) const [activeTab, setActiveTab] = useState<'left' | 'right'>('left') // Load stored split on mount useEffect(() => { const stored = localStorage.getItem(`split-pane:${storageKey}`) if (stored) { const val = parseFloat(stored) if (!isNaN(val) && val > 0 && val < 100) setSplit(val) } }, [storageKey]) // Detect mobile useEffect(() => { const check = () => setIsMobile(window.innerWidth < 1024) check() window.addEventListener('resize', check) return () => window.removeEventListener('resize', check) }, []) const onMouseMove = useCallback((e: MouseEvent) => { if (!isDragging || !containerRef.current) return const rect = containerRef.current.getBoundingClientRect() const containerWidth = rect.width const offsetX = e.clientX - rect.left const minPct = (minSize / containerWidth) * 100 const maxPct = 100 - minPct const newSplit = Math.min(maxPct, Math.max(minPct, (offsetX / containerWidth) * 100)) setSplit(newSplit) localStorage.setItem(`split-pane:${storageKey}`, String(newSplit)) }, [isDragging, minSize, storageKey]) const onMouseUp = useCallback(() => setIsDragging(false), []) useEffect(() => { if (isDragging) { window.addEventListener('mousemove', onMouseMove) window.addEventListener('mouseup', onMouseUp) } return () => { window.removeEventListener('mousemove', onMouseMove) window.removeEventListener('mouseup', onMouseUp) } }, [isDragging, onMouseMove, onMouseUp]) if (isMobile) { return (
{activeTab === 'left' ? left : right}
) } return (
{/* Left pane */}
{left}
{/* Divider */}
setIsDragging(true)} className={cn( 'w-1 shrink-0 bg-border hover:bg-primary transition-colors cursor-col-resize', isDragging && 'bg-primary' )} /> {/* Right pane */}
{right}
) }