File size: 3,037 Bytes
7aec436
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<script>

  import {_} from '../locales';

  import DropArea from './DropArea.svelte';



  const ACCEPT = [

    '.png',

    '.jpg',

    '.jpeg',

    '.bmp',

    '.svg',

    '.ico',

    '.gif'

  ];



  export let file;

  export let previewSizes;

  let dropping;

  let url;



  // This is a bit strange, there's probably a better way to do this

  // Seems to create and revoke an extra object URL for each file for some reason

  $: if (file) {

    if (url) {

      URL.revokeObjectURL(url);

    }

    url = URL.createObjectURL(file);

  } else if (url) {

    URL.revokeObjectURL(url);

    url = null;

  }



  const clear = (e) => {

    e.stopPropagation();

    file = null;

  };



  const handleClickBackground = () => {

    const input = document.createElement('input');

    input.type = 'file';

    input.accept = ACCEPT.join(',');

    input.addEventListener('change', (e) => {

      const files = e.target.files;

      if (files.length) {

        file = files[0];

      } else {

        file = null;

      }

    });

    document.body.appendChild(input);

    input.click();

    input.remove();

  };



  const handleDrop = ({detail: dataTransfer}) => {

    const droppedFile = dataTransfer.files[0];

    if (ACCEPT.some((ext) => droppedFile.name.endsWith(ext))) {

      file = droppedFile;

    }

  };

</script>

<style>

  .container {

    background: transparent;

    color: #555;

    width: 100%;

    box-sizing: border-box;

    border: 3px dashed currentColor;

    transition: .2s border-color, .2s color;

    border-radius: 20px;

    min-height: 90px;

    font: inherit;

    display: flex;

    align-items: center;

    justify-content: center;

    text-align: center;

    overflow: hidden;

    position: relative;

    cursor: pointer;

    padding: 4px;

  }

  :global([theme="dark"]) .container {

    color: #aaa;

  }

  .dropping,

  .container:focus-visible,

  .container:active {

    color: rgb(79, 123, 211);

  }

  :global([theme="dark"]) .dropping,

  :global([theme="dark"]) .container:focus-visible,

  :global([theme="dark"]) .container:active {

    color: rgb(178, 195, 228);

  }

  .placeholder {

    font-size: 1.5em;

  }

  .selected {

    display: flex;

    align-items: center;

    justify-content: center;

    flex-wrap: wrap;

  }

  .selected > *:not(:last-child) {

    margin-right: 12px;

  }

</style>

<DropArea bind:dropping={dropping} on:drop={handleDrop}>
  <button class="container" class:dropping on:click={handleClickBackground}>
    {#if file}
      <div class="selected">
        {#each previewSizes as size}
          <!-- svelte-ignore a11y-missing-attribute -->
          <img src={url} width={size[0]} height={size[1]}>
        {/each}
        <div>{$_('fileInput.selected').replace('{file}', file.name)}</div>
        <button on:click={clear}>{$_('fileInput.clear')}</button>
      </div>
    {:else}
      <div class="placeholder">{$_('fileInput.select')}</div>
    {/if}
  </button>
</DropArea>