<script lang="ts">
import FileTreeNode from './FileTreeNode.svelte';
import { filesStore } from '$lib/stores/files.svelte.js';
import { appStore } from '$lib/store.svelte.js';
import type { FileEntry } from '$lib/api.js';
let { entry, depth = 0 }: { entry: FileEntry; depth?: number } = $props();
let isExpanded = $derived(filesStore.isExpanded(entry.path));
let children = $derived(filesStore.getChildren(entry.path));
function handleClick() {
if (entry.is_dir) {
filesStore.toggleDir(entry.path, appStore.authToken ?? undefined);
}
}
function formatSize(bytes: number): string {
if (bytes < 1024) return `${bytes}B`;
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}K`;
return `${(bytes / (1024 * 1024)).toFixed(1)}M`;
}
</script>
<button
class="node"
class:dir={entry.is_dir}
style:padding-left="{depth * 1}rem"
onclick={handleClick}
>
{#if entry.is_dir}
<span class="arrow">{isExpanded ? '▼' : '▶'}</span>
{:else}
<span class="icon">·</span>
{/if}
<span class="name">{entry.name}</span>
{#if !entry.is_dir && entry.size > 0}
<span class="size">{formatSize(entry.size)}</span>
{/if}
</button>
{#if entry.is_dir && isExpanded}
{#each children as child (child.path)}
<FileTreeNode entry={child} depth={depth + 1} />
{/each}
{/if}
<style>
.node {
all: unset;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.3rem;
padding: 0.15rem 0.4rem;
font-family: monospace;
font-size: 0.75rem;
color: var(--fg);
width: 100%;
box-sizing: border-box;
white-space: nowrap;
transition: background 0.1s;
}
.node:hover {
background: var(--bg-surface);
}
.arrow {
color: var(--accent);
font-size: 0.6rem;
width: 0.7rem;
flex-shrink: 0;
}
.icon {
color: var(--fg-dim);
width: 0.7rem;
flex-shrink: 0;
text-align: center;
}
.name {
overflow: hidden;
text-overflow: ellipsis;
}
.dir .name {
color: var(--cyan);
}
.size {
margin-left: auto;
color: var(--fg-dim);
font-size: 0.65rem;
flex-shrink: 0;
}
</style>