second day

This commit is contained in:
2021-03-10 01:20:22 +01:00
parent 7fc8feb0cc
commit 521e2a4eb1
36 changed files with 3187 additions and 111 deletions

View File

@ -0,0 +1,18 @@
<script lang="ts">
import { bufToImageUrl } from "helpers";
import { route as currentRoute, images as imageStore } from "stores";
import Editor from "components/Editor/Editor.svelte";
const imageId = parseInt($currentRoute.split("/")[1]);
const imagePromise = imageStore.get(imageId);
</script>
{#await imagePromise}
Loading image
{:then image}
<Editor {image} />
{:catch err}
<p>Error loading image</p>
{JSON.stringify(err)}
{/await}

View File

@ -0,0 +1,2 @@
<script>
</script>

View File

@ -1,24 +1,133 @@
<script lang="ts">
import { store as imageStore } from "../stores/images";
import { Cross } from "../icons";
import { fly, fade } from "svelte/transition";
import { images as imageData, route } from "stores";
import { bufToImageUrl } from "helpers";
import type { Writable } from "svelte/store";
let images = [];
const urlCreator = window.URL || window.webkitURL;
import Toast from "../components/Toast";
import Analyzer from "../components/Analyzer.svelte";
import { onMount } from "svelte";
$: if ($imageStore.length) {
images = $imageStore.map((img) => {
const blob = new Blob([img.data], { type: img.type });
const imageUrl = urlCreator.createObjectURL(blob);
return {
...img,
imageUrl,
};
});
const imageStore: Writable<Image[]> = imageData.store;
let showAnalyzerIndex;
function handleFileChange(ev, img: Image) {
if (ev.target.innerText.includes("\n")) {
const value = ev.target.innerText.replace("\n", "");
ev.target.innerText = value;
ev.target.blur();
img.name = value;
imageData.updateImage(img);
}
}
let startCheckingEmpty = false;
setTimeout(() => {
startCheckingEmpty = true;
}, 1000);
onMount(() =>
imageStore.subscribe((img) => {
if (img.length === 0 && startCheckingEmpty) {
route.set("main");
}
})
);
</script>
{#each images as img}
<p>{img.filename}</p>
<img src={img.imageUrl} />
{/each}
<main>
<h3>List</h3>
<h3>List</h3>
{#each $imageStore as img, i}
<div class="list-item" in:fly={{ duration: 500, x: -50, delay: i * 200 }}>
<img
alt={img.filename}
on:click={() => route.set("editor/" + img.id)}
src={bufToImageUrl(img.data, img.type)}
/>
<div class="content">
<h4 contenteditable on:input={(ev) => handleFileChange(ev, img)}>
{img.name}
</h4>
<button
on:click={() => {
if (img.overlayData && img.overlayData.byteLength) {
if (showAnalyzerIndex === i) {
showAnalyzerIndex = undefined;
} else {
showAnalyzerIndex = i;
}
} else {
showAnalyzerIndex = undefined;
Toast.warn("Image has no data; Paint some regions to analyze");
}
}}>analyze</button
>
<button on:click={() => route.set("editor/" + img.id)}>edit</button>
<button
on:click={() => {
imageData.deleteImage(img);
}}>delete</button
>
</div>
</div>
{#if i === showAnalyzerIndex}
<div transition:fly={{ x: -50 }}>
<Analyzer {img} />
</div>
{/if}
{/each}
<div id="cross-wrapper" on:click={() => route.set("main")}>
<Cross />
<p>Add more images</p>
</div>
</main>
<style>
#cross-wrapper {
margin-top: 40px;
display: flex;
align-items: center;
}
#cross-wrapper > p {
margin-left: 10px;
}
main {
height: 100%;
max-width: 640px;
margin: 0 auto;
}
@media (max-width: 640px) {
main {
max-width: none;
}
}
.list-item {
position: relative;
display: grid;
grid-template-columns: 80px auto;
column-gap: 10px;
margin-top: 10px;
outline: solid thin black;
}
.list-item > img {
width: 80px;
height: 100%;
object-fit: cover;
cursor: pointer;
background-color: black;
transition: opacity 0.3s ease;
}
.list-item > img:hover {
opacity: 0.7;
}
</style>

View File

@ -3,10 +3,13 @@
import AnimatedNumber from "../components/AnimatedNumber.svelte";
import Cross from "../icons/Cross.svelte";
import Toast from "../components/Toast";
import { route as currentRoute, images } from "../stores";
import { route as currentRoute, images, route } from "../stores";
import { fileToImage } from "../helpers";
let acceptedFiles: File[] = [];
let hovering = false;
const imageStore = images.store;
async function handleFilesSelect(e) {
if (e.detail.acceptedFiles) {
const addedFiles: File[] = e.detail.acceptedFiles;
@ -14,13 +17,15 @@
const newFiles: File[] = [];
const dupes: File[] = [];
const allImages = [...$imageStore, ...acceptedFiles];
addedFiles.forEach((f) => {
const isNew = !acceptedFiles.find((_f) => {
const isNew = !allImages.find((_f: Image) => {
return (
_f.lastModified === f.lastModified &&
_f.name === f.name &&
_f.type === f.type &&
_f.size === f.size
_f.data.byteLength === f.size
);
});
@ -35,9 +40,9 @@
if (dupes.length) {
const loadDupes = await Toast.confirm(
`Add <b> ${dupes.length}</b> duplicate file${
dupes.length > 1 ? "s" : ""
}?`
`Some images are already loaded. Add <b> ${
dupes.length
}</b> duplicate${dupes.length > 1 ? "s" : ""}?`
);
if (loadDupes) {
@ -53,17 +58,7 @@
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(),
};
})
);
const img = await Promise.all(acceptedFiles.map(fileToImage));
images.add(img);
@ -78,7 +73,7 @@
}
</script>
<div class="wrapper">
<div id="wrapper">
<DropZone
accept="image/*"
on:drop={handleFilesSelect}
@ -86,6 +81,12 @@
on:dragleave={() => (hovering = false)}
on:dragenter={() => (hovering = false)}
>
{#if $imageStore.length}
<button on:click|preventDefault|stopPropagation={() => route.set("list")}
>Exit</button
>
{/if}
<div class="inner-wrapper">
<div class="icon-wrapper" class:hovering>
<Cross />
@ -103,7 +104,8 @@
</div>
<style>
.wrapper {
#wrapper {
position: relative;
display: grid;
place-items: center;
height: 100%;
@ -114,6 +116,7 @@
display: flex;
align-items: center;
padding: 20px;
outline: solid thin black;
}
p {