Add FileUpload component

This commit is contained in:
venashial
2022-06-20 15:34:45 -07:00
parent b8b36b6248
commit 252c812125
7 changed files with 159 additions and 4 deletions

View File

@@ -3,14 +3,14 @@
import IconMoon from 'virtual:icons/heroicons-outline/moon'
import IconSun from 'virtual:icons/heroicons-outline/sun'
export let meta: { raised: boolean }
export let meta: { raised: boolean; column: boolean }
let theme = 'light'
let background = meta.raised ? 'var(--color-raised-bg)' : 'var(--color-bg)'
</script>
<div class="example">
<div class="example__preview theme-{theme} base" style:background>
<div class="example__preview theme-{theme} base" class:column={meta.column} style:background>
<slot name="example" />
</div>
<div class="example__source">
@@ -44,6 +44,10 @@
justify-content: flex-start;
z-index: 1;
padding: 1rem;
&.column {
flex-direction: column;
}
}
&__source {

View File

@@ -0,0 +1,31 @@
### Single constrained example
```svelte example raised column
<script lang="ts">
import { Field, FileUpload } from 'omorphia'
let file: File
</script>
<Field label="Upload image">
<FileUpload accept="image/*" constrained bind:file />
</Field>
File name: {file?.name}
```
### Multiple example
```svelte example raised column
<script lang="ts">
import { Field, FileUpload } from 'omorphia'
let files: File[] = []
</script>
<Field label="Upload file">
<FileUpload accept="*" multiple bind:files />
</Field>
Count: {files.length}
```

View File

@@ -68,7 +68,7 @@
align-items: center;
justify-content: center;
padding: 0.5rem 1rem;
min-width: 2rem;
min-width: min-content;
gap: 0.5rem;
cursor: pointer;
position: relative;

View File

@@ -23,6 +23,7 @@
display: flex;
flex-direction: column;
gap: 0.5rem;
min-width: 0;
&__label {
display: flex;

View File

@@ -0,0 +1,118 @@
<script lang="ts">
import IconTrash from 'virtual:icons/heroicons-outline/trash'
import IconUpload from 'virtual:icons/heroicons-outline/upload'
import IconFile from 'virtual:icons/lucide/file'
import { t } from 'svelte-intl-precompile'
import Button from 'omorphia/components/Button.svelte'
import { classCombine } from 'omorphia/utils/classCombine'
export let multiple = false
export let accept: string
/** Prevents width from expanding due to large file names or images */
export let constrained = false
export let files: File[] = []
export let file: File | undefined
$: if (files) file = files[0] || undefined
let inputElement: HTMLInputElement
function addFiles(fileList: FileList) {
for (const file of Array.from(fileList)) {
// Check for duplicate files
if (!files.map((file) => file.name).includes(file.name)) {
files = [...files, file]
}
}
}
</script>
<div class={classCombine(['file-dropzone', constrained && 'file-dropzone--constrained'])}>
{#if !file || multiple}
<div
class="file-dropzone__input"
on:drop|preventDefault={(event) => addFiles(event.dataTransfer.files)}
on:dragover|preventDefault
on:click={() => {
if (inputElement) inputElement.click()
}}>
<IconUpload />
{$t('images.how_to')}
<input
type="file"
{multiple}
{accept}
style:display="none"
bind:this={inputElement}
on:change={() => addFiles(inputElement.files)} />
</div>
{/if}
{#each files as file (file.name)}
<div class="file">
<div class="file__tab">
<IconFile />
<div class="file__tab__name"><b>{file.name}</b></div>
<Button
color="tertiary"
on:click={() => {
files = files.filter((it) => it.name !== file.name)
}}><IconTrash /> Remove</Button>
</div>
{#if file.type.startsWith('image/')}
<img class="file__preview" src={URL.createObjectURL(file)} alt="Uploaded file preview" />
{/if}
</div>
{/each}
</div>
<style lang="postcss">
.file-dropzone {
display: flex;
flex-direction: column;
gap: 1rem;
&--constrained {
width: 27rem;
}
&__input {
display: flex;
padding: 1.5rem 2rem;
justify-content: center;
align-items: center;
gap: 0.5rem;
background-color: var(--color-button-bg);
border-radius: var(--rounded-sm);
border: dashed 0.3rem var(--color-text-lightest);
cursor: pointer;
color: var(--color-text-light);
}
.file {
box-shadow: var(--shadow-inset);
border-radius: var(--rounded);
background-color: var(--color-button-bg);
&__tab {
display: flex;
align-items: center;
padding: 0.75rem 1rem;
gap: 1rem;
&__name {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
margin-right: auto;
}
}
&__preview {
width: 100%;
border-radius: var(--rounded-bottom);
}
}
}
</style>

View File

@@ -14,6 +14,8 @@ export { default as Chips } from './components/Chips.svelte'
export { default as Field } from './components/Field.svelte'
export { default as FileUpload } from './components/FileUpload.svelte'
export { default as Modal } from './components/Modal.svelte'
export { default as ModalDeletion } from './components/ModalDeletion.svelte'

View File

@@ -18,7 +18,6 @@
.link {
color: var(--color-text);
margin-right: 1rem;
&:hover {
color: var(--color-link);