SplitPane
splitpane-1779379671390.tsx
'use client'
import { useState, useRef, useCallback, useEffect } from 'react'
export default function SplitPane() {
const [split, setSplit] = useState(50)
const [dragging, setDragging] = useState(false)
const [collapsed, setCollapsed] = useState<'left' | 'right' | null>(null)
const containerRef = useRef<HTMLDivElement>(null)
const startDrag = useCallback((e: React.MouseEvent) => {
e.preventDefault()
setDragging(true)
setCollapsed(null)
}, [])
useEffect(() => {
if (!dragging) return
function onMove(e: MouseEvent) {
if (!containerRef.current) return
const rect = containerRef.current.getBoundingClientRect()
const pct = ((e.clientX - rect.left) / rect.width) * 100
setSplit(Math.max(15, Math.min(85, pct)))
}
function onUp() { setDragging(false) }
window.addEventListener('mousemove', onMove)
window.addEventListener('mouseup', onUp)
return () => { window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp) }
}, [dragging])
const leftW = collapsed === 'left' ? 0 : collapsed === 'right' ? 100 : split
const rightW = 100 - leftW
return (
<div style={{ background: '#0A0A0A', padding: 24, display: 'flex', flexDirection: 'column', gap: 16 }}>
<div style={{ display: 'flex', gap: 8 }}>
{(['left', 'right'] as const).map(side => (
<button key={side} onClick={() => setCollapsed(c => c === side ? null : side)}
style={{ background: 'rgba(255,255,255,0.06)', border: '1px solid rgba(255,255,255,0.1)', color: '#F5F5F0', borderRadius: 6, padding: '5px 12px', cursor: 'pointer', fontSize: 12 }}>
{collapsed === side ? 'Expand' : 'Collapse'} {side}
</button>
))}
</div>
<div ref={containerRef} style={{ position: 'relative', display: 'flex', height: 300, background: '#111', border: '1px solid rgba(255,255,255,0.06)', borderRadius: 12, overflow: 'hidden', cursor: dragging ? 'col-resize' : 'default', userSelect: 'none' }}>
{/* Left panel */}
<div style={{ width: `${leftW}%`, background: '#111', overflow: 'hidden', transition: dragging ? 'none' : 'width 0.25s ease', borderRight: leftW > 0 && rightW > 0 ? '1px solid rgba(255,255,255,0.06)' : 'none' }}>
<div style={{ padding: 20, height: '100%' }}>
<div style={{ color: '#C9A84C', fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 12 }}>File Explorer</div>
{['src/', 'components/', 'GlowButton.tsx', 'HoverCard.tsx', 'public/', 'package.json'].map(f => (
<div key={f} style={{ color: f.endsWith('/') ? '#6366f1' : 'rgba(255,255,255,0.6)', fontSize: 13, padding: '4px 0', paddingLeft: f.endsWith('/') || f === 'package.json' ? 0 : 16 }}>{f}</div>
))}
</div>
</div>
{/* Divider */}
{leftW > 0 && rightW > 0 && (
<div onMouseDown={startDrag} style={{ width: 4, background: dragging ? '#C9A84C' : 'transparent', cursor: 'col-resize', flexShrink: 0, position: 'relative', zIndex: 10, transition: 'background 0.15s' }}>
<div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', width: 16, height: 32, display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'rgba(255,255,255,0.2)', fontSize: 10 }}>⋮⋮</div>
</div>
)}
{/* Right panel */}
<div style={{ flex: 1, overflow: 'hidden', transition: dragging ? 'none' : 'flex 0.25s ease' }}>
<div style={{ padding: 20 }}>
<div style={{ color: '#C9A84C', fontSize: 11, textTransform: 'uppercase', letterSpacing: '0.1em', marginBottom: 12 }}>GlowButton.tsx</div>
<pre style={{ color: 'rgba(255,255,255,0.6)', fontSize: 12, margin: 0, fontFamily: 'monospace', lineHeight: 1.7 }}>{"'use client'
import { useState } from 'react'
export default function GlowButton() {
const [h, setH] = useState(false)
return (
<button
onMouseEnter={() => setH(true)}
onMouseLeave={() => setH(false)}
style={{ boxShadow: h
? '0 0 20px #C9A84C'
: 'none' }}
>
Click me
</button>
)
}"}</pre>
</div>
</div>
</div>
<div style={{ color: 'rgba(255,255,255,0.3)', fontSize: 12, textAlign: 'center' }}>Drag divider to resize · {Math.round(leftW)}% / {Math.round(rightW)}%</div>
</div>
)
}Component info
CategoryLayouts
Frameworkreact
TierFREE
Views0
Copies0
About
Resizable split pane layout with drag divider, min/max constraints, and collapse support