From 549c61a10822f5d1e1430d491b8d02b0a4841d39 Mon Sep 17 00:00:00 2001 From: not-nullptr Date: Thu, 14 Nov 2024 13:34:51 +0000 Subject: [PATCH] feat: conversion page redesign --- src/lib/components/visual/ProgressBar.svelte | 18 + src/lib/converters/vips.svelte.ts | 23 +- src/lib/types/conversion-worker.ts | 2 +- src/lib/types/file.svelte.ts | 34 +- src/lib/workers/vips.ts | 11 +- src/routes/+page.svelte | 7 +- src/routes/convert/+page.svelte | 407 ++++++++++++------- 7 files changed, 339 insertions(+), 163 deletions(-) create mode 100644 src/lib/components/visual/ProgressBar.svelte diff --git a/src/lib/components/visual/ProgressBar.svelte b/src/lib/components/visual/ProgressBar.svelte new file mode 100644 index 0000000..6145819 --- /dev/null +++ b/src/lib/components/visual/ProgressBar.svelte @@ -0,0 +1,18 @@ + + +
+
+
diff --git a/src/lib/converters/vips.svelte.ts b/src/lib/converters/vips.svelte.ts index a6a6072..4bd2871 100644 --- a/src/lib/converters/vips.svelte.ts +++ b/src/lib/converters/vips.svelte.ts @@ -41,15 +41,21 @@ export class VipsConverter extends Converter { public async convert(input: VertFile, to: string): Promise { log(["converters", this.name], `converting ${input.name} to ${to}`); - const res = await this.sendMessage({ + const msg = { type: "convert", - input, + input: { + file: input.file, + name: input.name, + to: input.to, + from: input.from, + }, to, - }); + } as WorkerMessage; + const res = await this.sendMessage(msg); if (res.type === "finished") { log(["converters", this.name], `converted ${input.name} to ${to}`); - return res.output; + return new VertFile(new File([res.output], input.name), to); } if (res.type === "error") { @@ -81,8 +87,13 @@ export class VipsConverter extends Converter { }, 60000); this.worker.addEventListener("message", onMessage); - - this.worker.postMessage({ ...message, id }); + const msg = { ...message, id, worker: null }; + log(["converters", this.name], `sending message`, msg); + try { + this.worker.postMessage(msg); + } catch (e) { + console.error(e); + } }); } } diff --git a/src/lib/types/conversion-worker.ts b/src/lib/types/conversion-worker.ts index c1b5bdc..daf287f 100644 --- a/src/lib/types/conversion-worker.ts +++ b/src/lib/types/conversion-worker.ts @@ -8,7 +8,7 @@ interface ConvertMessage { interface FinishedMessage { type: "finished"; - output: VertFile; + output: ArrayBufferLike; } interface LoadedMessage { diff --git a/src/lib/types/file.svelte.ts b/src/lib/types/file.svelte.ts index 157fa56..d6a59e4 100644 --- a/src/lib/types/file.svelte.ts +++ b/src/lib/types/file.svelte.ts @@ -1,3 +1,5 @@ +import type { Converter } from "$lib/converters/converter.svelte"; + export class VertFile { public id: string = Math.random().toString(36).slice(2, 8); @@ -10,16 +12,46 @@ export class VertFile { } public progress = $state(0); - // public result: VertFile | null = null; public result = $state(null); public to = $state(""); + public converter: Converter | null = null; + constructor( public readonly file: File, to: string, + converter?: Converter, public readonly blobUrl?: string, ) { this.to = to; + this.converter = converter ?? null; + this.convert = this.convert.bind(this); + this.download = this.download.bind(this); + } + + public async convert() { + console.log(this.converter); + if (!this.converter) throw new Error("No converter found"); + this.result = null; + this.progress = 0; + const res = await this.converter.convert(this, this.to); + this.result = res; + return res; + } + + public async download() { + if (!this.result) throw new Error("No result found"); + const blob = URL.createObjectURL( + new Blob([await this.result.file.arrayBuffer()], { + type: this.to.slice(1), + }), + ); + const a = document.createElement("a"); + a.href = blob; + a.download = `VERT-Converted_${new Date().toISOString()}${this.to}`; + a.click(); + URL.revokeObjectURL(blob); + a.remove(); } } diff --git a/src/lib/workers/vips.ts b/src/lib/workers/vips.ts index 30fcbee..058cb67 100644 --- a/src/lib/workers/vips.ts +++ b/src/lib/workers/vips.ts @@ -1,8 +1,4 @@ -import { - type WorkerMessage, - type OmitBetterStrict, - VertFile, -} from "$lib/types"; +import { type WorkerMessage, type OmitBetterStrict } from "$lib/types"; import Vips from "wasm-vips"; const vipsPromise = Vips({ @@ -32,10 +28,7 @@ const handleMessage = async ( image.delete(); return { type: "finished", - output: new VertFile( - new File([output.buffer], message.input.name), - message.to, - ), + output: output.buffer, }; } } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 346640c..5004409 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -2,9 +2,9 @@ import { goto } from "$app/navigation"; import Uploader from "$lib/components/functional/Uploader.svelte"; import { converters } from "$lib/converters"; - import { log } from "$lib/logger/index.js"; + import { log } from "$lib/logger"; import { files } from "$lib/store/index.svelte"; - import { VertFile } from "$lib/types/file.svelte.js"; + import { VertFile } from "$lib/types/file.svelte"; import { Check } from "lucide-svelte"; const { data } = $props(); @@ -48,6 +48,7 @@ new VertFile( f, to, + converter, URL.createObjectURL(blob!), ), ); @@ -58,7 +59,7 @@ }; img.onerror = async () => { - resolve(new VertFile(f, to)); + resolve(new VertFile(f, to, converter)); }; }, ); diff --git a/src/routes/convert/+page.svelte b/src/routes/convert/+page.svelte index d7cb7e0..70e5910 100644 --- a/src/routes/convert/+page.svelte +++ b/src/routes/convert/+page.svelte @@ -3,10 +3,12 @@ import { blur, duration, flip } from "$lib/animation"; import Dropdown from "$lib/components/functional/Dropdown.svelte"; import ProgressiveBlur from "$lib/components/visual/effects/ProgressiveBlur.svelte"; + import ProgressBar from "$lib/components/visual/ProgressBar.svelte"; import { converters } from "$lib/converters"; import type { Converter } from "$lib/converters/converter.svelte"; import { log } from "$lib/logger"; import { files } from "$lib/store/index.svelte"; + import type { VertFile } from "$lib/types"; import clsx from "clsx"; import { ArrowRight, XIcon } from "lucide-svelte"; import { onMount } from "svelte"; @@ -19,6 +21,7 @@ ); let isSm = $state(false); + let isLg = $state(false); let processings = $state([]); @@ -49,8 +52,10 @@ onMount(() => { isSm = window.innerWidth < 640; + isLg = window.innerWidth > 1024; window.addEventListener("resize", () => { isSm = window.innerWidth < 640; + isLg = window.innerWidth > 1024; }); }); @@ -71,20 +76,9 @@ const promises: Promise[] = []; for (let i = 0; i < files.files.length; i++) { promises.push( - (async () => { - const file = files.files[i]; - const converter = converters.find( - (c) => - c.supportedFormats.includes(file.from) && - c.supportedFormats.includes(file.to), - ); - if (!converter) throw new Error("No converter found"); - const to = file.to; - processings[i] = true; - const converted = await converter.convert(file, to); - file.result = converted; - processings[i] = false; - })(), + (async (i) => { + await convert(files.files[i]); + })(i), ); } @@ -94,6 +88,14 @@ log(["converter"], `converted all files in ${seconds}s`); }; + const convert = async (file: VertFile) => { + file.progress = 0; + const index = files.files.findIndex((f) => f === file); + processings[index] = true; + await file.convert(); + processings[index] = false; + }; + const downloadAll = async () => { const dlFiles: any[] = []; for (let i = 0; i < files.files.length; i++) { @@ -233,149 +235,249 @@ > - {#each reversedFiles as file, i (file.id)} - {@const converter = (() => { - return converters.find((c) => - c.supportedFormats.includes(file.from), - ); - })()} -
+
+ {#each reversedFiles as file, i (file.id)} + {@const converter = (() => { + return converters.find((c) => + c.supportedFormats.includes(file.from), + ); + })()}
- -
- {file.file.name} -
-
- {#if converter && converter.supportedFormats.includes(file.from)} - - - - -
-
- {file.from} -
-
+
- -
-
- { - file.result = null; +

+ {file.file.name} +

+
- {:else} - {file.from} +
+
+ {#if processings[i]} + + {/if} +
+ {#if converter && converter.supportedFormats.includes(file.from)} + + + + + +
+
+ {file.from} +
+
+
+ +
+
+ { + file.result = null; + }} + /> +
+ {:else} + {file.from} - - is not supported! - - {/if} - -
-
- {#if converter && converter.supportedFormats.includes(file.from)} - -
-
-
- + + is not supported! + + {/if} +
+ +
+
- {/if} + {#if converter && converter.supportedFormats.includes(file.from)} + +
+
+
+ +
+
+ {/if} +
-
- {/each} + {/each} +
{/if} @@ -406,9 +508,28 @@ opacity: 1 !important; } + @keyframes processing { + 0% { + transform: scale(1); + filter: blur(0px); + animation-timing-function: ease-in-out; + } + + 50% { + transform: scale(1.05); + filter: blur(4px); + animation-timing-function: ease-in-out; + } + + 100% { + transform: scale(1); + filter: blur(0px); + animation-timing-function: ease-in-out; + } + } + .processing { - transform: scale(1.05); - filter: blur(4px); + animation: processing 2000ms infinite; pointer-events: none; }