实现文件管理器面包屑可编辑路径输入功能

- 添加双模式设计:查看模式显示面包屑,编辑模式显示输入框
- 支持点击编辑图标切换到路径编辑模式
- 实现键盘快捷键:Enter确认,Escape取消
- 添加路径验证和自动规范化处理
- 保持与现有UI风格一致的视觉设计

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ZacharyZcR
2025-09-17 09:07:45 +08:00
parent 54d3668093
commit 7fc474b9e4

View File

@@ -19,7 +19,8 @@ import {
ArrowUp, ArrowUp,
FileSymlink, FileSymlink,
Move, Move,
GitCompare GitCompare,
Edit
} from "lucide-react"; } from "lucide-react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import type { FileItem } from "../../../types/index.js"; import type { FileItem } from "../../../types/index.js";
@@ -350,6 +351,10 @@ export function FileManagerGrid({
const [navigationHistory, setNavigationHistory] = useState<string[]>([currentPath]); const [navigationHistory, setNavigationHistory] = useState<string[]>([currentPath]);
const [historyIndex, setHistoryIndex] = useState(0); const [historyIndex, setHistoryIndex] = useState(0);
// 路径编辑状态
const [isEditingPath, setIsEditingPath] = useState(false);
const [editPathValue, setEditPathValue] = useState(currentPath);
// 更新导航历史 // 更新导航历史
useEffect(() => { useEffect(() => {
const lastPath = navigationHistory[historyIndex]; const lastPath = navigationHistory[historyIndex];
@@ -400,6 +405,44 @@ export function FileManagerGrid({
} }
}; };
// 路径编辑功能
const startEditingPath = () => {
setEditPathValue(currentPath);
setIsEditingPath(true);
};
const cancelEditingPath = () => {
setIsEditingPath(false);
setEditPathValue(currentPath);
};
const confirmEditingPath = () => {
const trimmedPath = editPathValue.trim();
if (trimmedPath) {
// 确保路径以 / 开头
const normalizedPath = trimmedPath.startsWith('/') ? trimmedPath : '/' + trimmedPath;
onPathChange(normalizedPath);
}
setIsEditingPath(false);
};
const handlePathInputKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
e.preventDefault();
confirmEditingPath();
} else if (e.key === 'Escape') {
e.preventDefault();
cancelEditingPath();
}
};
// 同步editPathValue与currentPath
useEffect(() => {
if (!isEditingPath) {
setEditPathValue(currentPath);
}
}, [currentPath, isEditingPath]);
// 拖放处理 - 区分内部文件拖拽和外部文件上传 // 拖放处理 - 区分内部文件拖拽和外部文件上传
const handleDragEnter = useCallback((e: React.DragEvent) => { const handleDragEnter = useCallback((e: React.DragEvent) => {
e.preventDefault(); e.preventDefault();
@@ -846,6 +889,40 @@ export function FileManagerGrid({
{/* 面包屑导航 */} {/* 面包屑导航 */}
<div className="flex items-center px-3 py-2 text-sm"> <div className="flex items-center px-3 py-2 text-sm">
{isEditingPath ? (
// 编辑模式:路径输入框
<div className="flex-1 flex items-center gap-2">
<input
type="text"
value={editPathValue}
onChange={(e) => setEditPathValue(e.target.value)}
onKeyDown={(e) => {
if (e.key === 'Enter') {
confirmEditingPath();
} else if (e.key === 'Escape') {
cancelEditingPath();
}
}}
className="flex-1 px-2 py-1 bg-dark-hover border border-dark-border rounded text-sm focus:outline-none focus:ring-1 focus:ring-primary"
placeholder="输入路径..."
autoFocus
/>
<button
onClick={confirmEditingPath}
className="px-2 py-1 bg-primary text-primary-foreground rounded text-xs hover:bg-primary/80"
>
</button>
<button
onClick={cancelEditingPath}
className="px-2 py-1 bg-secondary text-secondary-foreground rounded text-xs hover:bg-secondary/80"
>
</button>
</div>
) : (
// 查看模式:面包屑导航
<>
<button <button
onClick={() => navigateToPath(-1)} onClick={() => navigateToPath(-1)}
className="hover:text-primary hover:underline mr-1" className="hover:text-primary hover:underline mr-1"
@@ -865,6 +942,15 @@ export function FileManagerGrid({
)} )}
</React.Fragment> </React.Fragment>
))} ))}
<button
onClick={startEditingPath}
className="ml-2 p-1 rounded hover:bg-dark-hover opacity-60 hover:opacity-100"
title="编辑路径"
>
<Edit className="w-3 h-3" />
</button>
</>
)}
</div> </div>
</div> </div>