This commit is contained in:
2021-03-09 01:13:42 +01:00
commit 7fc8feb0cc
32 changed files with 3700 additions and 0 deletions

2
view/src/routes/index.ts Executable file
View File

@ -0,0 +1,2 @@
export { default as main } from "./main.svelte"
export { default as list } from "./list.svelte"

View File

@ -0,0 +1,24 @@
<script lang="ts">
import { store as imageStore } from "../stores/images";
let images = [];
const urlCreator = window.URL || window.webkitURL;
$: if ($imageStore.length) {
images = $imageStore.map((img) => {
const blob = new Blob([img.data], { type: img.type });
const imageUrl = urlCreator.createObjectURL(blob);
return {
...img,
imageUrl,
};
});
}
</script>
{#each images as img}
<p>{img.filename}</p>
<img src={img.imageUrl} />
{/each}
<h3>List</h3>

168
view/src/routes/main.svelte Executable file
View File

@ -0,0 +1,168 @@
<script lang="ts">
import DropZone from "../components/DropZone/index.svelte";
import AnimatedNumber from "../components/AnimatedNumber.svelte";
import Cross from "../icons/Cross.svelte";
import Toast from "../components/Toast";
import { route as currentRoute, images } from "../stores";
let acceptedFiles: File[] = [];
let hovering = false;
async function handleFilesSelect(e) {
if (e.detail.acceptedFiles) {
const addedFiles: File[] = e.detail.acceptedFiles;
const newFiles: File[] = [];
const dupes: File[] = [];
addedFiles.forEach((f) => {
const isNew = !acceptedFiles.find((_f) => {
return (
_f.lastModified === f.lastModified &&
_f.name === f.name &&
_f.type === f.type &&
_f.size === f.size
);
});
if (isNew) {
newFiles.push(f);
} else {
dupes.push(f);
}
});
acceptedFiles = [...acceptedFiles, ...newFiles];
if (dupes.length) {
const loadDupes = await Toast.confirm(
`Add <b> ${dupes.length}</b> duplicate file${
dupes.length > 1 ? "s" : ""
}?`
);
if (loadDupes) {
acceptedFiles = [...acceptedFiles, ...dupes];
}
}
}
hovering = false;
}
async function handleLoadingImages(e) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
const img = await Promise.all(
acceptedFiles.map(async (f) => {
return {
name: f.name,
filename: f.name,
type: f.type,
lastModified: f.lastModified,
data: await f.arrayBuffer(),
};
})
);
images.add(img);
await currentRoute.set("list");
}
function handleClearingImages(e) {
e.preventDefault();
e.stopImmediatePropagation();
e.stopPropagation();
acceptedFiles = [];
}
</script>
<div class="wrapper">
<DropZone
accept="image/*"
on:drop={handleFilesSelect}
on:dragenter={() => (hovering = true)}
on:dragleave={() => (hovering = false)}
on:dragenter={() => (hovering = false)}
>
<div class="inner-wrapper">
<div class="icon-wrapper" class:hovering>
<Cross />
</div>
<p>Drop an image here to get started</p>
<div class="button-wrapper" class:visible={acceptedFiles.length > 0}>
<button on:click={handleLoadingImages}>
load <b><AnimatedNumber num={acceptedFiles.length} /></b>
</button>
<button on:click={handleClearingImages}> clear </button>
</div>
</div>
</DropZone>
</div>
<style>
.wrapper {
display: grid;
place-items: center;
height: 100%;
}
.inner-wrapper {
position: relative;
display: flex;
align-items: center;
padding: 20px;
}
p {
font-family: Roboto;
margin-left: 20px;
font-weight: 500;
text-align: left;
}
.button-wrapper > button {
border-radius: 0px;
background: none;
height: 100%;
border: none;
color: black;
outline: solid thin black;
}
.button-wrapper > button:first-child {
background-color: rgb(131, 255, 131);
}
.button-wrapper > button:last-child {
background-color: rgb(255, 126, 126);
}
.button-wrapper {
position: absolute;
bottom: -1px;
left: 0px;
width: 100%;
display: grid;
transform: translateY(100%);
pointer-events: none;
opacity: 0;
transition: opacity 0.3s cubic-bezier(0.57, 0.21, 0.69, 1.25);
grid-template-columns: 1fr 1fr;
}
.icon-wrapper {
transform: rotate(0deg);
transition: transform 0.3s ease;
}
.icon-wrapper.hovering {
transform: rotate(45deg);
}
.button-wrapper.visible {
opacity: 1;
pointer-events: all;
}
</style>