wip(app): file tree mode

This commit is contained in:
adamelmore
2026-01-25 21:57:30 -06:00
parent d9eed4c6ca
commit ebeed03115
5 changed files with 907 additions and 658 deletions

View File

@@ -2,7 +2,16 @@ import { useFile } from "@/context/file"
import { Collapsible } from "@opencode-ai/ui/collapsible"
import { FileIcon } from "@opencode-ai/ui/file-icon"
import { Tooltip } from "@opencode-ai/ui/tooltip"
import { createEffect, For, Match, splitProps, Switch, type ComponentProps, type ParentProps } from "solid-js"
import {
createEffect,
createMemo,
For,
Match,
splitProps,
Switch,
type ComponentProps,
type ParentProps,
} from "solid-js"
import { Dynamic } from "solid-js/web"
import type { FileNode } from "@opencode-ai/sdk/v2"
@@ -11,15 +20,45 @@ export default function FileTree(props: {
class?: string
nodeClass?: string
level?: number
allowed?: readonly string[]
onFileClick?: (file: FileNode) => void
}) {
const file = useFile()
const level = props.level ?? 0
const filter = createMemo(() => {
const allowed = props.allowed
if (!allowed) return
const files = new Set(allowed)
const dirs = new Set<string>()
for (const item of allowed) {
const parts = item.split("/")
const parents = parts.slice(0, -1)
for (const [idx] of parents.entries()) {
const dir = parents.slice(0, idx + 1).join("/")
if (dir) dirs.add(dir)
}
}
return { files, dirs }
})
createEffect(() => {
void file.tree.list(props.path)
})
const nodes = createMemo(() => {
const nodes = file.tree.children(props.path)
const current = filter()
if (!current) return nodes
return nodes.filter((node) => {
if (node.type === "file") return current.files.has(node.path)
return current.dirs.has(node.path)
})
})
const Node = (
p: ParentProps &
ComponentProps<"div"> &
@@ -81,7 +120,7 @@ export default function FileTree(props: {
return (
<div class={`flex flex-col ${props.class ?? ""}`}>
<For each={file.tree.children(props.path)}>
<For each={nodes()}>
{(node) => {
const expanded = () => file.tree.state(node.path)?.expanded ?? false
return (
@@ -102,7 +141,12 @@ export default function FileTree(props: {
</Node>
</Collapsible.Trigger>
<Collapsible.Content>
<FileTree path={node.path} level={level + 1} onFileClick={props.onFileClick} />
<FileTree
path={node.path}
level={level + 1}
allowed={props.allowed}
onFileClick={props.onFileClick}
/>
</Collapsible.Content>
</Collapsible>
</Match>