mirror of
https://github.com/gpxstudio/gpx.studio.git
synced 2026-02-06 08:23:09 +00:00
140 lines
4.1 KiB
Svelte
140 lines
4.1 KiB
Svelte
<script lang="ts">
|
|
import { GPXFile, Track, Waypoint, type AnyGPXTreeElement, type GPXTreeElement } from 'gpx';
|
|
import { getContext, onDestroy, onMount } from 'svelte';
|
|
import { type Readable } from 'svelte/store';
|
|
import FileListNodeStore from './FileListNodeStore.svelte';
|
|
import FileListNode from './FileListNode.svelte';
|
|
import FileListNodeContent from './FileListNodeContent.svelte';
|
|
import { ListFileItem, ListLevel, ListWaypointsItem, type ListItem } from './file-list';
|
|
import type { GPXFileWithStatistics } from '$lib/logic/statistics-tree';
|
|
import { allowedMoves, dragging, SortableFileList } from './sortable-file-list';
|
|
|
|
let {
|
|
node,
|
|
item,
|
|
waypointRoot = false,
|
|
}: {
|
|
node:
|
|
| Map<string, Readable<GPXFileWithStatistics | undefined>>
|
|
| GPXTreeElement<AnyGPXTreeElement>
|
|
| Waypoint[]
|
|
| Waypoint;
|
|
item: ListItem;
|
|
waypointRoot?: boolean;
|
|
} = $props();
|
|
|
|
let container: HTMLElement;
|
|
let sortableLevel: ListLevel =
|
|
node instanceof Map
|
|
? ListLevel.FILE
|
|
: node instanceof GPXFile
|
|
? waypointRoot
|
|
? ListLevel.WAYPOINTS
|
|
: item instanceof ListWaypointsItem
|
|
? ListLevel.WAYPOINT
|
|
: ListLevel.TRACK
|
|
: node instanceof Track
|
|
? ListLevel.SEGMENT
|
|
: ListLevel.WAYPOINT;
|
|
let orientation = getContext<'vertical' | 'horizontal'>('orientation');
|
|
|
|
let canDrop = $derived($dragging !== null && allowedMoves[$dragging].includes(sortableLevel));
|
|
|
|
let sortable: SortableFileList;
|
|
|
|
onMount(() => {
|
|
sortable = new SortableFileList(
|
|
container,
|
|
node,
|
|
item,
|
|
waypointRoot,
|
|
sortableLevel,
|
|
orientation
|
|
);
|
|
});
|
|
|
|
$effect(() => {
|
|
if (sortable && node) {
|
|
sortable.updateElements();
|
|
}
|
|
});
|
|
|
|
onDestroy(() => {
|
|
sortable.destroy();
|
|
});
|
|
</script>
|
|
|
|
<div
|
|
bind:this={container}
|
|
class="sortable {orientation} flex {orientation === 'vertical'
|
|
? 'flex-col'
|
|
: 'flex-row gap-1'} {canDrop ? 'min-h-5' : ''}"
|
|
>
|
|
{#if node instanceof Map}
|
|
{#each node as [fileId, file] (fileId)}
|
|
<div data-id={fileId}>
|
|
<FileListNodeStore {file} />
|
|
</div>
|
|
{/each}
|
|
{:else if node instanceof GPXFile}
|
|
{#if item instanceof ListWaypointsItem}
|
|
{#each node.wpt as wpt, i (wpt)}
|
|
<div data-id={i} class="ml-1">
|
|
<FileListNode node={wpt} item={item.extend(i)} />
|
|
</div>
|
|
{/each}
|
|
{:else if waypointRoot}
|
|
{#if node.wpt.length > 0}
|
|
<div data-id="waypoints">
|
|
<FileListNode {node} item={item.extend('waypoints')} />
|
|
</div>
|
|
{/if}
|
|
{:else}
|
|
{#each node.children as child, i (child)}
|
|
<div data-id={i}>
|
|
<FileListNode node={child} item={item.extend(i)} />
|
|
</div>
|
|
{/each}
|
|
{/if}
|
|
{:else if node instanceof Track}
|
|
{#each node.children as child, i (child)}
|
|
<div data-id={i} class="ml-1">
|
|
<FileListNode node={child} item={item.extend(i)} />
|
|
</div>
|
|
{/each}
|
|
{/if}
|
|
</div>
|
|
|
|
{#if node instanceof GPXFile && item instanceof ListFileItem}
|
|
{#if !waypointRoot}
|
|
<FileListNodeContent {node} {item} waypointRoot={true} />
|
|
{/if}
|
|
{/if}
|
|
|
|
<style lang="postcss">
|
|
@reference "../../../app.css";
|
|
|
|
.sortable > div {
|
|
@apply rounded-md;
|
|
@apply h-fit;
|
|
@apply leading-none;
|
|
}
|
|
|
|
.vertical :global(button) {
|
|
@apply hover:bg-[var(--selection)];
|
|
}
|
|
|
|
.vertical :global(.sortable-selected) {
|
|
@apply bg-[var(--selection)];
|
|
}
|
|
|
|
.horizontal :global(button) {
|
|
@apply bg-[var(--selection)];
|
|
@apply hover:bg-background;
|
|
}
|
|
|
|
.horizontal :global(.sortable-selected button) {
|
|
@apply bg-background;
|
|
}
|
|
</style>
|