返回 DeepSeek-Reasonix
WorkspaceTreeRow.tsx
根目录 / desktop / frontend / src / components / WorkspaceTreeRow.tsx
1 import type { DragEvent, MouseEvent } from "react";
2 import { ChevronRight, Folder } from "lucide-react";
3 import type { DirEntry } from "../lib/types";
4 import { workspaceBasename as basename, workspaceParentPath as parentPath } from "../lib/workspacePanelFormat";
5 import { WorkspaceFileIcon } from "./WorkspaceFileIcon";
6
7 export interface WorkspaceTreeRowData {
8 key: string;
9 path: string;
10 depth: number;
11 entry: DirEntry;
12 active: boolean;
13 isOpen?: boolean;
14 isSearch?: boolean;
15 compactPaths?: string[];
16 displayName?: string;
17 }
18
19 export function WorkspaceTreeRow({
20 row,
21 onActivate,
22 onDragStart,
23 onContextMenu,
24 }: {
25 row: WorkspaceTreeRowData;
26 onActivate: (row: WorkspaceTreeRowData) => void;
27 onDragStart: (event: DragEvent<HTMLElement>, path: string, isDir: boolean) => void;
28 onContextMenu: (event: MouseEvent<HTMLElement>, path: string, isDir: boolean) => void;
29 }) {
30 const { path, depth, entry, isOpen, active, displayName = entry.name } = row;
31 if (row.isSearch) {
32 const dir = parentPath(path);
33 return (
34 <button
35 className={`workspace-tree__row workspace-tree__row--search${active ? " workspace-tree__row--active" : ""}`}
36 data-workspace-path={path}
37 draggable
38 onDragStart={(event) => onDragStart(event, path, entry.isDir)}
39 onClick={() => onActivate(row)}
40 onContextMenu={(event) => onContextMenu(event, path, entry.isDir)}
41 >
42 {entry.isDir ? (
43 <Folder size={14} className="workspace-tree__icon workspace-tree__icon--dir" />
44 ) : (
45 <WorkspaceFileIcon fileName={entry.name} />
46 )}
47 <span className="workspace-tree__result">
48 <span className="workspace-tree__result-name">{basename(path)}</span>
49 {dir && <span className="workspace-tree__result-dir">{dir}</span>}
50 </span>
51 </button>
52 );
53 }
54
55 return (
56 <button
57 className={`workspace-tree__row${active ? " workspace-tree__row--active" : ""}`}
58 data-workspace-path={path}
59 draggable
60 onDragStart={(event) => onDragStart(event, path, entry.isDir)}
61 onClick={() => onActivate(row)}
62 onContextMenu={(event) => onContextMenu(event, path, entry.isDir)}
63 style={{ paddingLeft: 8 + depth * 14 }}
64 >
65 {depth > 0 && (
66 <span className="workspace-tree__guides" aria-hidden="true">
67 {Array.from({ length: depth }, (_, index) => (
68 <span
69 className="workspace-tree__guide"
70 key={index}
71 style={{ left: 14 + index * 14 }}
72 />
73 ))}
74 </span>
75 )}
76 {entry.isDir ? (
77 <ChevronRight
78 size={13}
79 className={`workspace-tree__chev ${isOpen ? "workspace-tree__chev--open" : ""}`}
80 style={{
81 transition: "transform 0.15s ease",
82 transform: isOpen ? "rotate(90deg)" : "rotate(0deg)",
83 }}
84 />
85 ) : (
86 <span className="workspace-tree__chev" />
87 )}
88 {entry.isDir ? (
89 <Folder size={14} className="workspace-tree__icon workspace-tree__icon--dir" />
90 ) : (
91 <WorkspaceFileIcon fileName={entry.name} />
92 )}
93 <span className="workspace-tree__name">{displayName}</span>
94 </button>
95 );
96 }
97
97 lines Plain Text