68 lines
1.9 KiB
Vue
68 lines
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
|
import type { DirectoryEntry } from '#shared/types';
|
|
|
|
const {
|
|
entries,
|
|
parent,
|
|
isOverDropZone,
|
|
disableEntries = false,
|
|
entriesDraggable = true,
|
|
} = defineProps<{
|
|
entries: DirectoryEntry[];
|
|
parent: DirectoryEntry | null;
|
|
isOverDropZone?: boolean;
|
|
disableEntries?: boolean;
|
|
entriesDraggable?: boolean;
|
|
}>();
|
|
|
|
const emit = defineEmits<{
|
|
'entry-click': [entry: DirectoryEntry, event: MouseEvent];
|
|
'entry-download': [entry: DirectoryEntry];
|
|
back: [];
|
|
}>();
|
|
|
|
const { isLoading } = useLoadingIndicator();
|
|
|
|
const sortedEntries = computed(() =>
|
|
entries.toSorted((a, b) => a.name.localeCompare(b.name))
|
|
);
|
|
|
|
function onEntryClicked(entry: DirectoryEntry, event: MouseEvent) {
|
|
emit('entry-click', entry, event);
|
|
}
|
|
|
|
function onEntryDownload(entry: DirectoryEntry) {
|
|
emit('entry-download', entry);
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<ScrollArea class="flex h-full w-full flex-col overflow-hidden">
|
|
<div
|
|
v-if="isOverDropZone"
|
|
class="bg-background/50 pointer-events-none absolute flex h-full w-full items-center justify-center"
|
|
>
|
|
<Icon class="size-16 animate-pulse" name="lucide:upload" />
|
|
</div>
|
|
<div
|
|
class="flex w-full flex-col gap-2 overflow-hidden sm:flex-row sm:flex-wrap"
|
|
>
|
|
<DirectoryBackEntry
|
|
v-if="parent != null"
|
|
:entry="parent"
|
|
@back="() => emit('back')"
|
|
/>
|
|
<DirectoryEntry
|
|
v-for="entry in sortedEntries"
|
|
:key="entry.name"
|
|
:entry="entry"
|
|
:disabled="isLoading || disableEntries"
|
|
:draggable="entriesDraggable"
|
|
@entry-click="onEntryClicked"
|
|
@entry-download="onEntryDownload"
|
|
/>
|
|
</div>
|
|
</ScrollArea>
|
|
</template>
|