@setoelkahfi / svara / commits / 326fff7

added file drag and drop

mellbacon committed May 7, 2023 at 16:43 UTC 326fff7c339ffaa4b543779e2f3fb0308855a625
4 files changed +78 -11
src-tauri/tauri.conf.json
+2 -1
@@ -119,7 +119,8 @@
119 "width": 800,
120 "minWidth": 680,
121 "minHeight": 430,
122 - "decorations": false
122 + "decorations": false,
123 + "fileDropEnabled": false
124 }
125 ]
126 }
src/lib/FileTree.svelte
+8 -4
@@ -1,7 +1,13 @@
1 <script lang="ts">
2 import FileTreeView from "./FileTree/FileTreeView.svelte";
3 + export let tree = $filetree;
4
4 - let data = [{
5 +</script>
6 +
7 +<script lang="ts" context="module">
8 + import { writable } from "svelte/store";
9 +
10 + export let filetree = writable([{
11 id: 0, label: "FakeDir", path:"FakeDir/", children: [
12 {id: 1, label: "src", path:"FakeDir/src", children: [
13 {id: 2, label: "dist", path:"FakeDir/src/dist/", children: [
@@ -18,9 +24,7 @@
24 {id: 11, label: "misc3.nucleus", path:"FakeDir/Misc/misc3.nucleus",},
25 ]},
26 ],
21 - }]
22 - export let tree = data;
23 -
27 + }]);
28 </script>
29
30 {#if tree.length === 0}
src/lib/FileTree/FileTreeList.svelte
+57 -3
@@ -8,6 +8,9 @@
8
9 import FileTreeNode, { computeTreeLeafDepth } from "./FileTreeNode.svelte";
10 import Directory from "../../util/icons/Directory.svelte";
11 + import Sortable from 'sortablejs';
12 + import { afterUpdate, onMount } from "svelte";
13 + import {filetree} from "../FileTree.svelte";
14
15 export let root = false;
16 export let isroot = false;
@@ -20,10 +23,61 @@
23 let expanded = _expansionState[label] || false;
24 let ref = null;
25 let refLabel = null;
26 + let refChildren = null;
27 let selected = false;
28
29 let icon = Directory;
30
31 + onMount(() => {
32 +
33 + })
34 +
35 + function findNode(nodeid, tree = null) {
36 + if (!tree) {
37 + tree = $filetree;
38 + if (nodeid === tree[0].id) {
39 + return tree[0];
40 + }
41 + }
42 + for (let node of tree) {
43 + if (nodeid === node.id) {
44 + return node;
45 + }
46 + else if (node.children) {
47 + let n = findNode(nodeid, node.children);
48 + if (n) {
49 + return n;
50 + }
51 + continue;
52 + }
53 + }
54 + }
55 +
56 + function dragstart(e) {
57 + let data = {element: `filetree-node-${id}`, id:id, type: "parent"};
58 + e.dataTransfer.setData("text/plain", JSON.stringify(data));
59 + }
60 +
61 + function drop(e) {
62 + let data = JSON.parse(e.dataTransfer.getData("text/plain"))
63 + let el = document.getElementById(data.element);
64 + let from = el.parentElement;
65 + let to = e.target.parentElement.parentElement;
66 +
67 + let fromid = from.getAttribute("data-id");
68 + let toid = to.getAttribute("data-id");
69 +
70 + const element = findNode(parseInt(data.id));
71 + const fromlist = findNode(parseInt(fromid));
72 + const tolist = findNode(parseInt(toid));
73 +
74 + fromlist.children.splice(fromlist.children.indexOf(element), 1);
75 + tolist.children = [...tolist.children, element];
76 +
77 + from.removeChild(el);
78 + to.appendChild(el);
79 + }
80 +
81 const toggleExpansion = (event) => {
82 for (let nodes of document.getElementsByClassName("tree-label")) {
83 nodes.classList.remove("selected")
@@ -60,9 +114,9 @@
114 {/if}
115 {/each}
116 {:else}
63 - <li id={id} bind:this={ref} class="treenode" class:root={isroot}>
117 + <li id={`filetree-node-${id}`} bind:this={ref} class="treenode" class:root={isroot}>
118 <!-- svelte-ignore a11y-click-events-have-key-events -->
65 - <div bind:this={refLabel} class:selected class="tree-label" on:click={toggleExpansion}>
119 + <div bind:this={refLabel} class:selected class="tree-label" on:click={toggleExpansion} draggable={true} on:dragstart={dragstart}>
120 <span class="arrow" class:arrowDown>&#x25b6</span>
121 {#if icon}
122 <svelte:component this={icon} />
@@ -70,7 +124,7 @@
124 <div class="item-label">{label}</div>
125 </div>
126 {#if expanded}
73 - <ul role="group" class="tree-children">
127 + <ul role="group" bind:this={refChildren} data-id={id} class="tree-children" on:dragover|preventDefault on:drop|stopPropagation={drop}>
128 {#each children as child (child.id) }
129 {#if Array.isArray(child.children)}
130 <svelte:self on:nodeselect {...child}></svelte:self>
src/lib/FileTree/FileTreeNode.svelte
+11 -3
@@ -18,7 +18,6 @@
18 import { createEventDispatcher } from "svelte";
19 import File from "../../util/icons/File.svelte";
20
21 -
21 export let id;
22 export let label;
23 export let path;
@@ -29,6 +28,15 @@
28 let refLabel = null;
29 let icon = File;
30
31 + function dragstart(e) {
32 + e.dataTransfer.setData(
33 + "text/html",
34 + e.target.parentElement.outerHTML
35 + );
36 + let data = {element: `filetree-node-${id}`, id:id, type: "node"};
37 + e.dataTransfer.setData("text/plain", JSON.stringify(data));
38 + }
39 +
40 const offset = () => computeTreeLeafDepth(refLabel) + (icon ? 2 : 1);
41
42 const dispatch = createEventDispatcher();
@@ -56,9 +64,9 @@
64 }
65 }}></svelte:window>
66
59 -<li id={id} bind:this={ref} class="treenode">
67 +<li id={`filetree-node-${id}`} bind:this={ref} class="treenode">
68 <!-- svelte-ignore a11y-click-events-have-key-events -->
61 - <div bind:this={refLabel} class="tree-label" class:selected on:click={(e) => {handleSelect(treenode, e)}}>
69 + <div bind:this={refLabel} class="tree-label" class:selected on:click={(e) => {handleSelect(treenode, e)}} draggable={true} on:dragstart={dragstart}>
70 <span class="no-arrow"></span>
71 {#if icon}
72 <svelte:component this={icon} />