feat(ui): 添加可拖拽的面板分割线

- 新增 Resizer 组件,支持拖拽调整面板宽度
- IDE 和聊天区域宽度可通过拖拽分割线调整
- 宽度范围限制在 30%-80%,防止面板过小或过大
- 调整后的宽度保存到 localStorage,下次打开时保持
This commit is contained in:
2025-12-17 17:08:08 +08:00
parent a3ddc39771
commit fc75fcfc90
3 changed files with 112 additions and 1 deletions
+79
View File
@@ -0,0 +1,79 @@
/**
* Resizer Component
*
* 可拖拽的分割线,用于调整面板宽度
*/
import { useState, useCallback, useEffect, useRef } from 'react';
import { cn } from '../utils/cn.js';
interface ResizerProps {
/** 拖拽时的回调,返回拖拽的像素偏移量 */
onResize: (delta: number) => void;
/** 拖拽结束的回调 */
onResizeEnd?: () => void;
/** 方向:vertical(左右拖拽)或 horizontal(上下拖拽) */
direction?: 'vertical' | 'horizontal';
className?: string;
}
export function Resizer({
onResize,
onResizeEnd,
direction = 'vertical',
className,
}: ResizerProps) {
const [isDragging, setIsDragging] = useState(false);
const startPosRef = useRef(0);
const handleMouseDown = useCallback((e: React.MouseEvent) => {
e.preventDefault();
setIsDragging(true);
startPosRef.current = direction === 'vertical' ? e.clientX : e.clientY;
}, [direction]);
const handleMouseMove = useCallback((e: MouseEvent) => {
if (!isDragging) return;
const currentPos = direction === 'vertical' ? e.clientX : e.clientY;
const delta = currentPos - startPosRef.current;
startPosRef.current = currentPos;
onResize(delta);
}, [isDragging, direction, onResize]);
const handleMouseUp = useCallback(() => {
if (isDragging) {
setIsDragging(false);
onResizeEnd?.();
}
}, [isDragging, onResizeEnd]);
useEffect(() => {
if (isDragging) {
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
// 拖拽时禁止选中文本
document.body.style.userSelect = 'none';
document.body.style.cursor = direction === 'vertical' ? 'col-resize' : 'row-resize';
}
return () => {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
document.body.style.userSelect = '';
document.body.style.cursor = '';
};
}, [isDragging, handleMouseMove, handleMouseUp, direction]);
return (
<div
onMouseDown={handleMouseDown}
className={cn(
'flex-shrink-0 bg-line hover:bg-primary-500 transition-colors',
direction === 'vertical' ? 'w-1 cursor-col-resize' : 'h-1 cursor-row-resize',
isDragging && 'bg-primary-500',
className
)}
/>
);
}
+1
View File
@@ -254,6 +254,7 @@ export { FileExplorer } from './components/FileExplorer.js';
export { CodeEditor, getLanguageFromFilename, type EditorTab } from './components/CodeEditor.js';
export { IDE } from './components/IDE.js';
export { StatusBar } from './components/StatusBar.js';
export { Resizer } from './components/Resizer.js';
// Toast function (re-export from sonner)
export { toast } from 'sonner';