Folder.svelte 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <script>
  2. import { getContext, createEventDispatcher, onMount, onDestroy } from 'svelte';
  3. const i18n = getContext('i18n');
  4. const dispatch = createEventDispatcher();
  5. import ChevronDown from '../icons/ChevronDown.svelte';
  6. import ChevronRight from '../icons/ChevronRight.svelte';
  7. import Collapsible from './Collapsible.svelte';
  8. export let open = true;
  9. export let id = '';
  10. export let name = '';
  11. export let collapsible = true;
  12. export let className = '';
  13. let folderElement;
  14. let draggedOver = false;
  15. const onDragOver = (e) => {
  16. e.preventDefault();
  17. e.stopPropagation();
  18. draggedOver = true;
  19. };
  20. const onDrop = (e) => {
  21. e.preventDefault();
  22. e.stopPropagation();
  23. if (folderElement.contains(e.target)) {
  24. console.log('Dropped on the Button');
  25. if (e.dataTransfer.items && e.dataTransfer.items.length > 0) {
  26. // Iterate over all items in the DataTransferItemList use functional programming
  27. for (const item of Array.from(e.dataTransfer.items)) {
  28. // If dropped items aren't files, reject them
  29. if (item.kind === 'file') {
  30. const file = item.getAsFile();
  31. if (file && file.type === 'application/json') {
  32. console.log('Dropped file is a JSON file!');
  33. // Read the JSON file with FileReader
  34. const reader = new FileReader();
  35. reader.onload = async function (event) {
  36. try {
  37. const fileContent = JSON.parse(event.target.result);
  38. console.log('Parsed JSON Content: ', fileContent);
  39. open = true;
  40. dispatch('import', fileContent);
  41. } catch (error) {
  42. console.error('Error parsing JSON file:', error);
  43. }
  44. };
  45. // Start reading the file
  46. reader.readAsText(file);
  47. } else {
  48. console.error('Only JSON file types are supported.');
  49. }
  50. } else {
  51. open = true;
  52. const dataTransfer = e.dataTransfer.getData('text/plain');
  53. const data = JSON.parse(dataTransfer);
  54. console.log(data);
  55. dispatch('drop', data);
  56. }
  57. }
  58. }
  59. draggedOver = false;
  60. }
  61. };
  62. const onDragLeave = (e) => {
  63. e.preventDefault();
  64. e.stopPropagation();
  65. draggedOver = false;
  66. };
  67. onMount(() => {
  68. folderElement.addEventListener('dragover', onDragOver);
  69. folderElement.addEventListener('drop', onDrop);
  70. folderElement.addEventListener('dragleave', onDragLeave);
  71. });
  72. onDestroy(() => {
  73. folderElement.addEventListener('dragover', onDragOver);
  74. folderElement.removeEventListener('drop', onDrop);
  75. folderElement.removeEventListener('dragleave', onDragLeave);
  76. });
  77. </script>
  78. <div bind:this={folderElement} class="relative {className}">
  79. {#if draggedOver}
  80. <div
  81. class="absolute top-0 left-0 w-full h-full rounded-sm bg-[hsla(260,85%,65%,0.1)] bg-opacity-50 dark:bg-opacity-10 z-50 pointer-events-none touch-none"
  82. ></div>
  83. {/if}
  84. {#if collapsible}
  85. <Collapsible
  86. bind:open
  87. className="w-full "
  88. buttonClassName="w-full"
  89. on:change={(e) => {
  90. dispatch('change', e.detail);
  91. }}
  92. >
  93. <!-- svelte-ignore a11y-no-static-element-interactions -->
  94. <div class="w-full">
  95. <button
  96. class="w-full py-1.5 px-2 rounded-md flex items-center gap-1.5 text-xs text-gray-500 dark:text-gray-500 font-medium hover:bg-gray-100 dark:hover:bg-gray-900 transition"
  97. >
  98. <div class="text-gray-300 dark:text-gray-600">
  99. {#if open}
  100. <ChevronDown className=" size-3" strokeWidth="2.5" />
  101. {:else}
  102. <ChevronRight className=" size-3" strokeWidth="2.5" />
  103. {/if}
  104. </div>
  105. <div class="translate-y-[0.5px]">
  106. {name}
  107. </div>
  108. </button>
  109. </div>
  110. <div slot="content" class="w-full">
  111. <slot></slot>
  112. </div>
  113. </Collapsible>
  114. {:else}
  115. <slot></slot>
  116. {/if}
  117. </div>