FileExplorerAndEditorRow.tsx136 lines · main
1import { IS_PLATFORM } from 'common'
2import { Edit, File, Trash } from 'lucide-react'
3import {
4 cn,
5 ContextMenu,
6 ContextMenuContent,
7 ContextMenuItem,
8 ContextMenuSeparator,
9 ContextMenuTrigger,
10 Tooltip,
11 TooltipContent,
12 TooltipTrigger,
13 TreeViewItem,
14 type INodeRendererProps,
15} from 'ui'
16
17import { FileData } from './FileExplorerAndEditor.types'
18
19type FileExplorerAndEditorRowProps = INodeRendererProps & {
20 files: FileData[]
21 selectedFileId: number
22 setSelectedFileId: (id: number) => void
23 handleFileNameChange: (id: number, newName: string) => void
24 handleStartRename: (id: number) => void
25 handleFileDelete: (id: number) => void
26}
27
28export const FileExplorerAndEditorRow = ({
29 element,
30 isBranch,
31 isExpanded,
32 getNodeProps,
33 level,
34 files,
35 selectedFileId,
36 setSelectedFileId,
37 handleFileNameChange,
38 handleStartRename,
39 handleFileDelete,
40}: FileExplorerAndEditorRowProps) => {
41 const nodeProps = getNodeProps()
42 const originalId =
43 typeof element.metadata?.originalId === 'number' ? element.metadata.originalId : null
44 const state = element.metadata?.state as FileData['state']
45 const isEditing = Boolean(element.metadata?.isEditing)
46
47 return (
48 <ContextMenu modal={false}>
49 <ContextMenuTrigger asChild>
50 <div>
51 <TreeViewItem
52 {...nodeProps}
53 isExpanded={isExpanded}
54 isBranch={isBranch}
55 isSelected={files.find((f) => f.id === originalId)?.id === selectedFileId}
56 level={level}
57 xPadding={16}
58 name={element.name}
59 className={cn(
60 isEditing
61 ? ''
62 : state === 'new'
63 ? 'text-brand-600'
64 : state === 'modified'
65 ? 'text-code_block-2'
66 : ''
67 )}
68 icon={<File size={14} className="text-foreground-light shrink-0" />}
69 isEditing={isEditing}
70 onEditSubmit={(value) => {
71 if (IS_PLATFORM && originalId !== null) {
72 handleFileNameChange(originalId, value)
73 }
74 }}
75 onClick={() => {
76 if (originalId !== null && !isEditing) {
77 setSelectedFileId(originalId)
78 }
79 }}
80 onDoubleClick={() => {
81 if (IS_PLATFORM && originalId !== null) {
82 handleStartRename(originalId)
83 }
84 }}
85 actions={
86 state !== 'unchanged' && (
87 <div className="flex items-center justify-center w-3">
88 <Tooltip>
89 <TooltipTrigger className="text-xs">
90 {state === 'new' ? 'U' : 'M'}
91 </TooltipTrigger>
92 <TooltipContent side="bottom">
93 {state === 'new' ? 'Unsaved' : 'Modified'}
94 </TooltipContent>
95 </Tooltip>
96 </div>
97 )
98 }
99 />
100 </div>
101 </ContextMenuTrigger>
102 {IS_PLATFORM && (
103 <ContextMenuContent onCloseAutoFocus={(e) => e.stopPropagation()}>
104 <ContextMenuItem
105 className="gap-x-2"
106 onSelect={() => {
107 if (originalId !== null) handleStartRename(originalId)
108 }}
109 onFocusCapture={(e) => e.stopPropagation()}
110 >
111 <Edit size={14} />
112 Rename file
113 </ContextMenuItem>
114
115 {files.length > 1 && (
116 <>
117 <ContextMenuSeparator />
118 <ContextMenuItem
119 className="gap-x-2"
120 onSelect={() => {
121 if (originalId !== null) {
122 handleFileDelete(originalId)
123 }
124 }}
125 onFocusCapture={(e) => e.stopPropagation()}
126 >
127 <Trash size={14} />
128 Delete file
129 </ContextMenuItem>
130 </>
131 )}
132 </ContextMenuContent>
133 )}
134 </ContextMenu>
135 )
136}