Files
cog-socket/src/routes/experiment/[id]/FileBrowser.svelte
Shaheed Azaad 55401fd37b added menu
2025-07-15 15:23:54 +02:00

104 lines
4.5 KiB
Svelte

<script lang="ts">
import { Button } from '$lib/components/ui/button';
import FileIcon from '@lucide/svelte/icons/file';
import FolderIcon from '@lucide/svelte/icons/folder';
import FolderOpenIcon from '@lucide/svelte/icons/folder-open';
import TrashIcon from '@lucide/svelte/icons/trash';
import DownloadIcon from '@lucide/svelte/icons/download';
export let tree: any;
export let parentPath = '';
export let expanded: Set<string>;
export let onToggle: (path: string) => void;
export let onDelete: (key: string, isFolder: boolean) => void;
export let onDownload: (key: string) => void = () => {};
export let isRoot: boolean = false;
function handleToggle(path: string) {
onToggle(path);
}
function handleDelete(key: string, isFolder: boolean) {
onDelete(key, isFolder);
}
function handleDownload(key: string) {
onDownload(key);
}
function handleFolderClick(event: Event, path: string) {
event.stopPropagation();
handleToggle(path);
}
function handleFolderDelete(event: Event, path: string) {
event.stopPropagation();
handleDelete(path, true);
}
function formatSize(size: number) {
if (!size && size !== 0) return '';
if (size < 1024) return `${size} B`;
if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;
if (size < 1024 * 1024 * 1024) return `${(size / 1024 / 1024).toFixed(1)} MB`;
return `${(size / 1024 / 1024 / 1024).toFixed(1)} GB`;
}
function formatDate(date: string | Date) {
if (!date) return '';
const d = typeof date === 'string' ? new Date(date) : date;
return d.toLocaleString();
}
</script>
<ul class="ml-2">
{#if isRoot}
<li class="flex items-center gap-2 py-1 pl-2 text-xs font-semibold text-muted-foreground select-none border-b border-border mb-1">
<span class="flex-1 min-w-0">Name</span>
<span class="w-24 text-right">Size</span>
<span class="w-40 text-right">Last Uploaded</span>
<span class="w-16"></span>
</li>
{/if}
{#each Object.entries(tree) as [name, node] (parentPath + '/' + name)}
{#if (node as any).isFile}
<li class="flex items-center gap-2 py-1 pl-2 hover:bg-accent rounded group text-sm">
<span class="flex-1 min-w-0 flex items-center gap-1">
<FileIcon class="w-4 h-4 text-muted-foreground shrink-0" />
<span class="truncate" title={name || ''}>{name || ''}</span>
</span>
<span class="w-24 text-xs text-muted-foreground text-right ml-2 whitespace-nowrap">{formatSize((node as any).size)}</span>
<span class="w-40 text-xs text-muted-foreground text-right ml-2 whitespace-nowrap">{formatDate((node as any).lastModified)}</span>
<span class="w-16 flex items-center justify-end gap-1">
<button class="p-1 hover:text-primary" title="Download" on:click={() => handleDownload((node as any).key)}><DownloadIcon class="w-4 h-4" /></button>
<button class="p-1 hover:text-destructive" title="Delete" on:click={() => handleDelete((node as any).key, false)}><TrashIcon class="w-4 h-4" /></button>
</span>
</li>
{:else}
<li>
<div class="flex items-center gap-1 px-1 py-1 hover:bg-accent rounded cursor-pointer text-sm" >
<span class="flex-1 min-w-0 flex items-center gap-1" on:click={(e) => handleFolderClick(e, parentPath ? `${parentPath}/${name}` : name)}>
<span class="flex-shrink-0 w-5 h-5 flex items-center justify-center">
{#if expanded.has(parentPath ? `${parentPath}/${name}` : name)}
<FolderOpenIcon class="w-4 h-4 text-muted-foreground" />
{:else}
<FolderIcon class="w-4 h-4 text-muted-foreground" />
{/if}
</span>
<span class="font-semibold truncate" title={name || ''}>{name || ''}</span>
</span>
<span class="w-24"></span>
<span class="w-40"></span>
<span class="w-16 flex items-center justify-end">
<button class="p-1 hover:text-destructive" title="Delete folder" on:click={(e) => handleFolderDelete(e, (parentPath ? `${parentPath}/${name}` : name))}><TrashIcon class="w-4 h-4" /></button>
</span>
</div>
{#if expanded.has(parentPath ? `${parentPath}/${name}` : name)}
<svelte:self
tree={(node as any).children}
parentPath={parentPath ? `${parentPath}/${name}` : name}
{expanded}
{onToggle}
{onDelete}
{onDownload}
isRoot={false}
/>
{/if}
</li>
{/if}
{/each}
</ul>