feat: basic functionality

This commit is contained in:
not-nullptr 2024-11-11 16:33:46 +00:00
parent 9952d1563a
commit b5ac70a015
3 changed files with 108 additions and 4 deletions

View File

@ -1,7 +1,18 @@
import type { IFile, OmitBetterStrict } from "$lib/types";
/**
* Base class for all converters.
*/
export class Converter {
/**
* List of supported formats.
*/
public supportedFormats: string[] = [];
/**
* Convert a file to a different format.
* @param input The input file.
* @param to The format to convert to. Includes the dot.
*/
public async convert(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
input: OmitBetterStrict<IFile, "extension">,

View File

@ -7,7 +7,20 @@ import type { VipsWorkerMessage, OmitBetterStrict } from "$lib/types";
export class VipsConverter extends Converter {
private worker: Worker = browser ? new VipsWorker() : null!;
private id = 0;
public supportedFormats = [""];
public supportedFormats = [
".jpg",
".jpeg",
".png",
".webp",
".tiff",
".tif",
".gif",
".svg",
".webp",
".jfif",
".ico",
".bmp",
];
constructor() {
super();

View File

@ -1,12 +1,92 @@
<script lang="ts">
import Uploader from "$lib/components/visual/Uploader.svelte";
import { converters } from "$lib/converters";
let conversionTypes = $state<string[]>([]);
let downloadFns = $state<(() => void)[]>([]);
let files = $state<FileList>();
let iterableFiles = $derived.by(() => {
if (!files) return [];
return Array.from(files);
});
const convertAllFiles = async () => {
const promises = iterableFiles.map(async (file, i) => {
let conversionType = conversionTypes[i];
const converter = converters[0];
const convertedFile = await converter.convert(
{
name: file.name,
buffer: await file.arrayBuffer(),
},
conversionType,
);
downloadFns[i] = () => {
const url = URL.createObjectURL(
new Blob([convertedFile.buffer]),
);
const a = document.createElement("a");
a.href = url;
if (conversionType.startsWith("."))
conversionType = conversionType.slice(1);
a.download = `${file.name}.${conversionType}`;
a.target = "_self";
a.click();
URL.revokeObjectURL(url);
};
});
await Promise.all(promises);
};
</script>
<div class="flex items-center justify-center h-full">
<div class="w-full max-w-screen-lg h-80">
<Uploader bind:files />
<div class="flex flex-col items-center">
<div class="max-w-screen-lg w-full">
<div class="h-80 justify-self-center mt-40">
<Uploader bind:files />
</div>
<div class="flex flex-col items-center">
{#each iterableFiles as file, i}
<div
class="flex items-center w-full max-w-screen-lg border-2 border-solid border-foreground rounded-xl px-4 py-2 mt-4"
>
<div class="flex items-center flex-grow">
{file.name}
</div>
<div class="flex gap-4 flex-shrink-0">
{#if downloadFns[i]}
<button
class="px-4 py-2 border-2 border-solid border-foreground rounded-xl"
onclick={downloadFns[i]}
>
Download
</button>
{/if}
<!-- <input
type="text"
class="border-2 border-solid border-foreground rounded-xl px-4 py-2 focus:!outline-none"
bind:value={conversionTypes[i]}
placeholder="jpeg"
/> -->
<select
class="border-2 border-solid border-foreground rounded-xl px-4 py-2 focus:!outline-none"
bind:value={conversionTypes[i]}
>
{#each converters[0].supportedFormats as conversionType}
<option value={conversionType}
>{conversionType}</option
>
{/each}
</select>
</div>
</div>
{/each}
<button
class="mt-4 px-4 py-2 border-2 border-solid border-foreground rounded-xl"
onclick={convertAllFiles}
>
Convert
</button>
</div>
</div>
</div>