11import { useFile } from "@/context/file"
22import { encodeFilePath } from "@/context/file/path"
3+ import { useLanguage } from "@/context/language"
34import { Collapsible } from "@opencode-ai/ui/collapsible"
5+ import { ContextMenu } from "@opencode-ai/ui/context-menu"
46import { FileIcon } from "@opencode-ai/ui/file-icon"
57import { Icon } from "@opencode-ai/ui/icon"
68import {
@@ -13,10 +15,8 @@ import {
1315 splitProps ,
1416 Switch ,
1517 untrack ,
16- type ComponentProps ,
1718 type ParentProps ,
1819} from "solid-js"
19- import { Dynamic } from "solid-js/web"
2020import type { FileNode } from "@opencode-ai/sdk/v2"
2121
2222const MAX_DEPTH = 128
@@ -108,9 +108,7 @@ const withFileDragImage = (event: DragEvent) => {
108108}
109109
110110const FileTreeNode = (
111- p : ParentProps &
112- ComponentProps < "div" > &
113- ComponentProps < "button" > & {
111+ p : ParentProps & {
114112 node : FileNode
115113 level : number
116114 active ?: string
@@ -119,8 +117,13 @@ const FileTreeNode = (
119117 kinds ?: ReadonlyMap < string , Kind >
120118 marks ?: Set < string >
121119 as ?: "div" | "button"
120+ type ?: "button"
121+ onClick ?: ( e : MouseEvent ) => void
122+ class ?: string
123+ classList ?: { [ k : string ] : boolean | undefined }
122124 } ,
123125) => {
126+ const language = useLanguage ( )
124127 const [ local , rest ] = splitProps ( p , [
125128 "node" ,
126129 "level" ,
@@ -142,9 +145,18 @@ const FileTreeNode = (
142145 return kindTextColor ( value )
143146 }
144147
148+ const handleCopyAbsolutePath = ( ) => {
149+ navigator . clipboard . writeText ( local . node . absolute ) . catch ( ( ) => { } )
150+ }
151+
152+ const handleCopyRelativePath = ( ) => {
153+ navigator . clipboard . writeText ( local . node . path ) . catch ( ( ) => { } )
154+ }
155+
145156 return (
146- < Dynamic
147- component = { local . as ?? "div" }
157+ < ContextMenu modal = { false } preventScroll = { true } >
158+ < ContextMenu . Trigger
159+ as = { local . as ?? "div" }
148160 classList = { {
149161 "w-full min-w-0 h-6 flex items-center justify-start gap-x-1.5 rounded-md px-1.5 py-0 text-left hover:bg-surface-raised-base-hover active:bg-surface-base-active transition-colors cursor-pointer" : true ,
150162 "bg-surface-base-active" : local . node . path === local . active ,
@@ -186,7 +198,18 @@ const FileTreeNode = (
186198 }
187199 return < div class = "shrink-0 size-1.5 mr-1.5 rounded-full" style = { kindDotColor ( value ) } />
188200 } ) ( ) }
189- </ Dynamic >
201+ </ ContextMenu . Trigger >
202+ < ContextMenu . Portal >
203+ < ContextMenu . Content >
204+ < ContextMenu . Item onSelect = { handleCopyAbsolutePath } >
205+ < ContextMenu . ItemLabel > { language . t ( "filetree.contextMenu.copyPath" ) } </ ContextMenu . ItemLabel >
206+ </ ContextMenu . Item >
207+ < ContextMenu . Item onSelect = { handleCopyRelativePath } >
208+ < ContextMenu . ItemLabel > { language . t ( "filetree.contextMenu.copyRelativePath" ) } </ ContextMenu . ItemLabel >
209+ </ ContextMenu . Item >
210+ </ ContextMenu . Content >
211+ </ ContextMenu . Portal >
212+ </ ContextMenu >
190213 )
191214}
192215
0 commit comments