upend/webui/src/components/AddModal.svelte

165 lines
3.1 KiB
Svelte

<script context="module" lang="ts">
import mitt from "mitt";
export type AddEvents = {
files: File[];
urls: string[];
};
export const addEmitter = mitt<AddEvents>();
</script>
<script lang="ts">
import { useNavigate } from "svelte-navigator";
import Icon from "./utils/Icon.svelte";
import IconButton from "./utils/IconButton.svelte";
import api from "../lib/api";
const navigate = useNavigate();
let files: File[] = [];
let URLs: string[] = [];
let uploading = false;
$: visible = files.length + URLs.length > 0;
addEmitter.on("files", (ev) => {
ev.forEach((file) => {
if (
!files
.map((f) => `${f.name}${f.size}`)
.includes(`${file.name}${file.size}`)
) {
files.push(file);
}
files = files;
});
});
async function upload() {
uploading = true;
try {
const addresses = await Promise.all(
files.map(async (file) => api.putBlob(file))
);
navigate(`/browse/${addresses.join(",")}`);
} catch (error) {
alert(error);
}
uploading = false;
reset();
}
function reset() {
if (!uploading) {
files = [];
URLs = [];
}
}
</script>
<div class="addmodal-container" class:visible class:uploading on:click={reset}>
<div class="addmodal" on:click|stopPropagation>
<div class="files">
{#each files as file}
<div class="file">
{#if file.type.startsWith("image")}
<img src={URL.createObjectURL(file)} alt="To be uploaded." />
{:else}
<div class="icon">
<Icon name="file" />
</div>
{/if}
<div class="label">{file.name}</div>
</div>
{/each}
</div>
<div class="controls">
<IconButton name="upload" on:click={upload} />
</div>
</div>
</div>
<style lang="scss">
.addmodal-container {
position: absolute;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.5);
color: var(--foreground);
display: none;
&.visible {
display: unset;
}
&.uploading {
cursor: progress;
.addmodal {
filter: brightness(0.5);
}
}
}
.addmodal {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
background: var(--background);
color: var(--foreground);
border: solid 2px var(--foreground);
border-radius: 8px;
padding: 1rem;
}
.files {
display: flex;
flex-direction: column;
gap: 1em;
padding: 0.5em;
overflow-y: auto;
max-height: 66vh;
}
.file {
display: flex;
align-items: center;
flex-direction: column;
border: 1px solid var(--foreground);
border-radius: 4px;
background: var(--background-lighter);
padding: 0.5em;
img {
max-height: 12em;
max-width: 12em;
}
.icon {
font-size: 24px;
}
.label {
flex-grow: 1;
text-align: center;
}
}
.controls {
display: flex;
justify-content: center;
font-size: 48px;
margin-top: 0.5rem;
}
</style>