fix: layout jump, feat: image preview

This commit is contained in:
not-nullptr 2024-11-12 00:23:51 +00:00
parent cda3825f6a
commit db5d5414db
7 changed files with 195 additions and 63 deletions

View File

@ -21,5 +21,5 @@
body {
@apply text-foreground bg-background font-body overflow-x-hidden;
padding-left: calc(100vw - 100%);
width: 100vw;
}

View File

@ -55,6 +55,7 @@
if (!event.dataTransfer) return;
if (!files) files = Array.from(event.dataTransfer.files);
else files.push(...Array.from(event.dataTransfer.files));
onupload?.();
return true;
}

View File

@ -0,0 +1,68 @@
<script lang="ts">
type Props = {
iterations: number;
endIntensity: number;
direction: "top" | "left" | "bottom" | "right";
fadeTo?: string;
};
let {
iterations,
endIntensity,
direction,
fadeTo = "transparent",
}: Props = $props();
const getGradientDirection = () => {
switch (direction) {
case "top":
return "to top";
case "left":
return "to left";
case "bottom":
return "to bottom";
case "right":
return "to right";
}
};
const blurSteps = $derived(
Array.from({ length: iterations }, (_, i) => {
const blurIntensity =
(endIntensity / 2 ** (iterations - 1)) * 2 ** i;
const gradientStart = (i / iterations) * 100;
const gradientEnd = ((i + 1) / iterations) * 100;
return {
blurIntensity,
mask: `linear-gradient(${getGradientDirection()}, rgba(0, 0, 0, 0) ${gradientStart}%, rgba(0, 0, 0, 1) ${gradientEnd}%)`,
};
}),
);
</script>
<div class="w-full h-full relative">
{#each blurSteps as { blurIntensity, mask }, index}
<div
class="absolute w-full h-full"
style="
z-index: {index + 2};
backdrop-filter: blur({blurIntensity}px);
mask: {mask};
"
></div>
{/each}
<div
style="
z-index: {iterations + 2};
backdrop-filter: blur({endIntensity}px);
mask: linear-gradient({getGradientDirection()}, rgba(0, 0, 0, 0) ${(iterations /
(iterations + 1)) *
100}%, rgba(0, 0, 0, 1) 100%);
"
></div>
<div
class="absolute top-0 left-0 w-full h-full z-50"
style="background: linear-gradient({getGradientDirection()}, transparent 0%, {fadeTo} 100%);"
></div>
</div>

View File

@ -1,7 +1,12 @@
class Files {
public files = $state<File[]>([]);
public files = $state<
{
file: File;
to: string;
blobUrl: string;
}[]
>([]);
public conversionTypes = $state<string[]>([]);
public downloadFns = $state<(() => void)[]>([]);
public beenToConverterPage = $state(false);
public shouldShowAlert = $derived(
!this.beenToConverterPage && this.files.length > 0,

View File

@ -25,18 +25,30 @@
const linkIndex = $derived(
Object.keys(links).findIndex((link) => links[link] === data.pathname),
);
const maybeNavToHome = (e: DragEvent) => {
if (e.dataTransfer?.types.includes("Files")) {
e.preventDefault();
goto("/");
}
};
</script>
<div class="w-full h-full flex items-center pt-48 flex-col gap-10">
<div
role="main"
class="w-full h-full flex items-center p-8 flex-col gap-8"
ondragenter={maybeNavToHome}
>
<div
class="w-full max-w-screen-lg p-1 border-solid border-2 rounded-2xl border-foreground-muted-alt grid"
style="grid-template-columns: auto 1fr"
class="w-full max-w-screen-lg p-1 border-solid border-2 rounded-2xl border-foreground-muted-alt flex"
>
<div
class="px-4 m-1 mr-3 flex items-center bg-accent-background fill-accent-foreground rounded-xl"
>
<div class="h-6">
<Logo />
<div class="p-1">
<div
class="px-4 relative w-full h-full mr-3 justify-center items-center bg-accent-background fill-accent-foreground rounded-xl md:flex hidden"
>
<div class="h-6 items-center flex justify-center">
<Logo />
</div>
</div>
</div>
@ -53,7 +65,7 @@
></div>
{#each Object.entries(links) as [name, link] (link)}
<button
class="w-1/2 h-full flex items-center justify-center rounded-xl relative font-display overflow-hidden"
class="w-1/2 px-2 h-full flex items-center justify-center rounded-xl relative font-display overflow-hidden"
onclick={() => {
const keys = Object.keys(links);
const currentIndex = keys.findIndex(
@ -90,9 +102,11 @@
{/each}
</div>
</div>
<div class="w-full max-w-screen-lg grid grid-cols-1 grid-rows-1 relative">
<div
class="w-full max-w-screen-lg h-full grid grid-cols-1 grid-rows-1 relative"
>
{#key data.pathname}
<div class="w-full">
<div class="w-full h-full">
<div
class="absolute top-0 left-0 w-full h-full flex justify-center"
in:blur={{

View File

@ -4,39 +4,58 @@
import { converters } from "$lib/converters";
import { files } from "$lib/store/index.svelte";
const convertAllFiles = async () => {
const promises = files.files?.map(async (file, i) => {
let conversionType = files.conversionTypes[i];
const converter = converters[0];
const convertedFile = await converter.convert(
{
name: file.name,
buffer: await file.arrayBuffer(),
},
conversionType,
);
files.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);
};
});
if (promises) await Promise.all(promises);
let ourFiles = $state<File[]>();
const runUpload = () => {
files.files = [
...files.files,
...(ourFiles || []).map((f) => ({
file: f,
to: converters[0].supportedFormats[0],
blobUrl: URL.createObjectURL(f),
})),
];
ourFiles = [];
if (files.files.length > 0 && !files.beenToConverterPage)
goto("/convert");
};
// const convertAllFiles = async () => {
// const promises = files.files?.map(async (file, i) => {
// let conversionType = files.conversionTypes[i];
// const converter = converters[0];
// const convertedFile = await converter.convert(
// {
// name: file.name,
// buffer: await file.arrayBuffer(),
// },
// conversionType,
// );
// files.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);
// };
// });
// if (promises) await Promise.all(promises);
// };
</script>
<Uploader
bind:files={files.files}
onupload={() => files.files.length > 0 && goto("/convert")}
/>
<div
class="flex w-full h-full items-center justify-center pb-32 [@media(max-height:768px)]:block"
>
<Uploader bind:files={ourFiles} onupload={runUpload} />
</div>
<style>
/* for this page specifically */

View File

@ -1,4 +1,5 @@
<script>
import ProgressiveBlur from "$lib/components/visual/effects/ProgressiveBlur.svelte";
import { converters } from "$lib/converters";
import { files } from "$lib/store/index.svelte";
@ -11,28 +12,52 @@
No files uploaded. Head to the Upload tab to begin!
</p>
{/if}
{#each files.files as file, i}
{#each files.files.reverse() as file, i}
<div
class="flex items-center w-full border-2 border-solid border-foreground-muted-alt rounded-xl pl-4 pr-2 py-2"
class="flex relative items-center w-full border-2 border-solid border-foreground-muted-alt rounded-xl pl-4 pr-2 py-2"
>
<div class="flex items-center flex-grow">
{file.name}
<div class="flex items-center w-full z-50 relative">
<div
class="flex items-center flex-grow"
style="text-shadow: 0px 0px 6px white, 0px 0px 12px white"
>
{file.file.name}
</div>
<div class="flex items-center gap-2 flex-shrink-0">
<span>from</span>
<span
class="py-2 px-3 font-display bg-foreground text-background rounded-xl"
>.{file.file.name.split(".").slice(-1)}</span
>
<span>to</span>
<select
class="font-display border-2 border-solid border-foreground-muted-alt rounded-xl p-2 focus:!outline-none"
bind:value={files.conversionTypes[i]}
>
{#each converters[0].supportedFormats as conversionType}
<option value={conversionType}
>{conversionType}</option
>
{/each}
</select>
</div>
</div>
<div class="flex items-center gap-2 flex-shrink-0">
<span>from</span>
<span
class="py-2 px-3 font-display bg-foreground text-background rounded-xl"
>.{file.name.split(".").slice(-1)}</span
>
<span>to</span>
<select
class="font-display border-2 border-solid border-foreground-muted-alt rounded-xl p-2 focus:!outline-none"
bind:value={files.conversionTypes[i]}
>
{#each converters[0].supportedFormats as conversionType}
<option value={conversionType}>{conversionType}</option>
{/each}
</select>
<!-- god knows why, but setting opacity > 0.98 causes a z-ordering issue in firefox ??? -->
<div
class="absolute top-0 -z-50 left-0 w-full h-full rounded-[10px] overflow-hidden opacity-[0.98]"
>
<div
class="bg-cover bg-center w-full h-full"
style="background-image: url({file.blobUrl});"
></div>
<div class="absolute top-0 right-0 w-5/6 h-full">
<ProgressiveBlur
direction="right"
endIntensity={64}
iterations={6}
fadeTo="rgba(255, 255, 255, 0.8)"
/>
</div>
</div>
</div>
{/each}