8.0k New

File Tree

The files the agent changed, as a folder tree.

Epicenter

Local-first, open source apps

Special Sponsor
<script lang="ts">
  import FileTreeNode, {
    type FileNode
  } from "$lib/components/file-tree/file-tree-node.svelte";
 
  const files: FileNode[] = [
    {
      type: "folder",
      name: "app",
      path: "app",
      children: [
        { type: "file", name: "layout.tsx", path: "app/layout.tsx" },
        { type: "file", name: "page.tsx", path: "app/page.tsx" }
      ]
    },
    {
      type: "folder",
      name: "components",
      path: "components",
      children: [
        {
          type: "folder",
          name: "ui",
          path: "components/ui",
          children: [
            {
              type: "file",
              name: "button.tsx",
              path: "components/ui/button.tsx"
            }
          ]
        },
        {
          type: "file",
          name: "login-form.tsx",
          path: "components/login-form.tsx"
        }
      ]
    }
  ];
 
  let selected = $state("components/ui/button.tsx");
</script>
 
<div class="flex w-full max-w-xs flex-col py-6 text-sm">
  {#each files as node (node.path)}
    <FileTreeNode {node} {selected} onSelect={(path) => (selected = path)} />
  {/each}
</div>

File Tree is the files the agent changed, shown as folders you can open. A folder is a Collapsible. A file is a Button. For a single file the agent read or edited, use a Tool line instead.

Installation

File Tree is built with the Collapsible and Button components.

pnpm dlx shadcn-svelte@latest add collapsible button

Usage

Render nodes recursively. Nest each folder's children in its Collapsible.Content.

{#if node.type === "folder"}
  <Collapsible.Root open class="group/folder">
    <Collapsible.Trigger>
      {#snippet child({ props })}
        <Button
          {...props}
          variant="ghost"
          size="sm"
          class="w-full justify-start"
        >
          <ChevronRightIcon
            class="transition-transform group-data-[state=open]/folder:rotate-90"
          />
          <FolderIcon />
          {node.name}
        </Button>
      {/snippet}
    </Collapsible.Trigger>
    <Collapsible.Content>
      <div class="ml-4 flex flex-col">
        {#each node.children as child (child.path)}
          <FileTreeNode node={child} />
        {/each}
      </div>
    </Collapsible.Content>
  </Collapsible.Root>
{/if}
<Button
  variant="ghost"
  size="sm"
  class="w-full justify-start"
  onclick={() => onSelect(node.path)}
>
  <FileIcon />
  {node.name}
</Button>

See Collapsible.