156 lines
3.7 KiB
Svelte
156 lines
3.7 KiB
Svelte
<script lang="ts">
|
|
import { fileOrder, selectedFiles, selectFiles } from '$lib/stores';
|
|
|
|
import { ScrollArea } from '$lib/components/ui/scroll-area/index';
|
|
import Sortable from 'sortablejs/Sortable';
|
|
|
|
import { afterUpdate, onMount } from 'svelte';
|
|
import { get } from 'svelte/store';
|
|
import FileListItem from './FileListItem.svelte';
|
|
import { fileObservers } from '$lib/db';
|
|
|
|
let container: HTMLDivElement;
|
|
let buttons: { [id: string]: HTMLElement } = {};
|
|
let sortable: Sortable;
|
|
|
|
function selectFile(fileId: string) {
|
|
selectedFiles.update((selectedFiles) => {
|
|
selectedFiles.clear();
|
|
selectedFiles.add(fileId);
|
|
return selectedFiles;
|
|
});
|
|
}
|
|
|
|
function addSelectFile(fileId: string) {
|
|
selectedFiles.update((selectedFiles) => {
|
|
selectedFiles.add(fileId);
|
|
return selectedFiles;
|
|
});
|
|
}
|
|
|
|
function selectAllFiles() {
|
|
selectedFiles.update((selectedFiles) => {
|
|
get(fileObservers).forEach((_, id) => {
|
|
selectedFiles.add(id);
|
|
});
|
|
return selectedFiles;
|
|
});
|
|
}
|
|
|
|
function deselectFile(fileId: string) {
|
|
selectedFiles.update((selectedFiles) => {
|
|
selectedFiles.delete(fileId);
|
|
return selectedFiles;
|
|
});
|
|
}
|
|
|
|
function updateFileOrder() {
|
|
let newFileOrder = sortable.toArray();
|
|
if (newFileOrder.length !== get(fileOrder).length) {
|
|
fileOrder.set(newFileOrder);
|
|
return;
|
|
}
|
|
|
|
for (let i = 0; i < newFileOrder.length; i++) {
|
|
if (newFileOrder[i] !== get(fileOrder)[i]) {
|
|
fileOrder.set(newFileOrder);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
onMount(() => {
|
|
sortable = Sortable.create(container, {
|
|
forceAutoScrollFallback: true,
|
|
multiDrag: true,
|
|
multiDragKey: 'Meta',
|
|
selectedClass: 'sortable-selected',
|
|
avoidImplicitDeselect: true,
|
|
onSelect: (e) => {
|
|
let selectedId = e.item.getAttribute('data-id');
|
|
addSelectFile(selectedId);
|
|
if (
|
|
!(e.originalEvent.shiftKey || e.originalEvent.ctrlKey || e.originalEvent.metaKey) &&
|
|
$selectedFiles.size > 1
|
|
) {
|
|
$selectedFiles.forEach((fileId) => {
|
|
if (fileId !== selectedId) {
|
|
deselectFile(fileId);
|
|
Sortable.utils.deselect(buttons[fileId]);
|
|
}
|
|
});
|
|
}
|
|
},
|
|
onDeselect: (e) => {
|
|
deselectFile(e.item.getAttribute('data-id'));
|
|
},
|
|
onSort: () => {
|
|
updateFileOrder();
|
|
}
|
|
});
|
|
});
|
|
|
|
selectFiles.update(() => {
|
|
return {
|
|
select: (fileId: string) => {
|
|
Object.values(buttons).forEach((button) => {
|
|
Sortable.utils.deselect(button);
|
|
});
|
|
Sortable.utils.select(buttons[fileId]);
|
|
selectFile(fileId);
|
|
},
|
|
addSelect: (fileId: string) => {
|
|
Sortable.utils.select(buttons[fileId]);
|
|
addSelectFile(fileId);
|
|
},
|
|
selectAllFiles: () => {
|
|
Object.values(buttons).forEach((button) => {
|
|
Sortable.utils.select(button);
|
|
});
|
|
selectAllFiles();
|
|
},
|
|
removeSelect: (fileId: string) => {
|
|
Sortable.utils.deselect(buttons[fileId]);
|
|
deselectFile(fileId);
|
|
}
|
|
};
|
|
});
|
|
|
|
afterUpdate(() => {
|
|
updateFileOrder();
|
|
Object.keys(buttons).forEach((fileId) => {
|
|
if (!get(fileObservers).has(fileId)) {
|
|
delete buttons[fileId];
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<div class="h-10 -translate-y-10 w-full pointer-events-none absolute z-30">
|
|
<ScrollArea orientation="horizontal" class="w-full h-full" scrollbarXClasses="h-2">
|
|
<div bind:this={container} class="flex flex-row gap-1">
|
|
{#if $fileObservers}
|
|
{#each $fileObservers.entries() as [fileId, file]}
|
|
<div
|
|
bind:this={buttons[fileId]}
|
|
data-id={fileId}
|
|
class="pointer-events-auto first:ml-1 last:mr-1 mb-1 bg-transparent"
|
|
>
|
|
<FileListItem {file} />
|
|
</div>
|
|
{/each}
|
|
{/if}
|
|
</div>
|
|
</ScrollArea>
|
|
</div>
|
|
|
|
<style lang="postcss">
|
|
div :global(button) {
|
|
@apply bg-accent;
|
|
@apply hover:bg-background;
|
|
}
|
|
|
|
div :global(.sortable-selected button) {
|
|
@apply bg-background;
|
|
}
|
|
</style>
|