diff options
| author | adamelmore <[email protected]> | 2026-01-26 09:39:25 -0600 |
|---|---|---|
| committer | adamelmore <[email protected]> | 2026-01-26 11:07:52 -0600 |
| commit | 801eb5d2cb868d0a14c056439e3898b110f4cc21 (patch) | |
| tree | cf26ac655b9fef7e05e75982ee2aa51c13a5df4b /packages/app/src/components | |
| parent | ebeed03115b61f812c56c66785a09be61be35468 (diff) | |
| download | opencode-801eb5d2cb868d0a14c056439e3898b110f4cc21.tar.gz opencode-801eb5d2cb868d0a14c056439e3898b110f4cc21.zip | |
wip(app): file tree mode
Diffstat (limited to 'packages/app/src/components')
| -rw-r--r-- | packages/app/src/components/file-tree.tsx | 85 |
1 files changed, 58 insertions, 27 deletions
diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index ac435095d..a48f0039f 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -9,6 +9,7 @@ import { Match, splitProps, Switch, + untrack, type ComponentProps, type ParentProps, } from "solid-js" @@ -21,10 +22,14 @@ export default function FileTree(props: { nodeClass?: string level?: number allowed?: readonly string[] + draggable?: boolean + tooltip?: boolean onFileClick?: (file: FileNode) => void }) { const file = useFile() const level = props.level ?? 0 + const draggable = () => props.draggable ?? true + const tooltip = () => props.tooltip ?? true const filter = createMemo(() => { const allowed = props.allowed @@ -46,6 +51,18 @@ export default function FileTree(props: { }) createEffect(() => { + const current = filter() + if (!current) return + if (level !== 0) return + + for (const dir of current.dirs) { + const expanded = untrack(() => file.tree.state(dir)?.expanded) ?? false + if (expanded) continue + file.tree.expand(dir) + } + }) + + createEffect(() => { void file.tree.list(props.path) }) @@ -78,8 +95,9 @@ export default function FileTree(props: { [props.nodeClass ?? ""]: !!props.nodeClass, }} style={`padding-left: ${8 + level * 12}px`} - draggable={true} + draggable={draggable()} onDragStart={(e: DragEvent) => { + if (!draggable()) return e.dataTransfer?.setData("text/plain", `file:${local.node.path}`) e.dataTransfer?.setData("text/uri-list", `file://${local.node.path}`) if (e.dataTransfer) e.dataTransfer.effectAllowed = "copy" @@ -123,41 +141,54 @@ export default function FileTree(props: { <For each={nodes()}> {(node) => { const expanded = () => file.tree.state(node.path)?.expanded ?? false + const Wrapper = (p: ParentProps) => { + if (!tooltip()) return p.children + return ( + <Tooltip forceMount={false} openDelay={2000} value={node.path} placement="right" class="w-full"> + {p.children} + </Tooltip> + ) + } + return ( - <Tooltip forceMount={false} openDelay={2000} value={node.path} placement="right"> - <Switch> - <Match when={node.type === "directory"}> - <Collapsible - variant="ghost" - class="w-full" - forceMount={false} - open={expanded()} - onOpenChange={(open) => (open ? file.tree.expand(node.path) : file.tree.collapse(node.path))} - > - <Collapsible.Trigger> + <Switch> + <Match when={node.type === "directory"}> + <Collapsible + variant="ghost" + class="w-full" + forceMount={false} + open={expanded()} + onOpenChange={(open) => (open ? file.tree.expand(node.path) : file.tree.collapse(node.path))} + > + <Collapsible.Trigger> + <Wrapper> <Node node={node}> <Collapsible.Arrow class="text-icon-weak ml-1" /> <FileIcon node={node} expanded={expanded()} class="text-icon-weak -ml-1 size-4" /> </Node> - </Collapsible.Trigger> - <Collapsible.Content> - <FileTree - path={node.path} - level={level + 1} - allowed={props.allowed} - onFileClick={props.onFileClick} - /> - </Collapsible.Content> - </Collapsible> - </Match> - <Match when={node.type === "file"}> + </Wrapper> + </Collapsible.Trigger> + <Collapsible.Content> + <FileTree + path={node.path} + level={level + 1} + allowed={props.allowed} + draggable={props.draggable} + tooltip={props.tooltip} + onFileClick={props.onFileClick} + /> + </Collapsible.Content> + </Collapsible> + </Match> + <Match when={node.type === "file"}> + <Wrapper> <Node node={node} as="button" type="button" onClick={() => props.onFileClick?.(node)}> <div class="w-4 shrink-0" /> <FileIcon node={node} class="text-icon-weak size-4" /> </Node> - </Match> - </Switch> - </Tooltip> + </Wrapper> + </Match> + </Switch> ) }} </For> |
