mirror of https://github.com/VERT-sh/VERT.git
feat: asynchronous album covers
This commit is contained in:
parent
1328cdcb05
commit
aac176816b
|
@ -47,7 +47,7 @@
|
|||
class="absolute w-full h-full"
|
||||
style="
|
||||
z-index: {index + 2};
|
||||
backdrop-filter: blur({blurIntensity}px);
|
||||
backdrop-filter: blur( calc({blurIntensity}px * var(--blur-amount, 1)) );
|
||||
mask: {mask};
|
||||
"
|
||||
></div>
|
||||
|
@ -63,6 +63,6 @@
|
|||
></div>
|
||||
<div
|
||||
class="absolute top-0 left-0 w-full h-full z-50"
|
||||
style="background: linear-gradient({getGradientDirection()}, transparent 0%, {fadeTo} 100%);"
|
||||
style="background: linear-gradient({getGradientDirection()}, transparent 0%, {fadeTo} 100%); opacity: var(--blur-amount, 1);"
|
||||
></div>
|
||||
</div>
|
||||
|
|
|
@ -16,18 +16,21 @@ export class VertFile {
|
|||
|
||||
public to = $state("");
|
||||
|
||||
public blobUrl = $state<string>();
|
||||
|
||||
public converter: Converter | null = null;
|
||||
|
||||
constructor(
|
||||
public readonly file: File,
|
||||
to: string,
|
||||
converter?: Converter,
|
||||
public readonly blobUrl?: string,
|
||||
blobUrl?: string,
|
||||
) {
|
||||
this.to = to;
|
||||
this.converter = converter ?? null;
|
||||
this.convert = this.convert.bind(this);
|
||||
this.download = this.download.bind(this);
|
||||
this.blobUrl = blobUrl;
|
||||
}
|
||||
|
||||
public async convert() {
|
||||
|
|
|
@ -11,8 +11,10 @@ export const load = ({ url, request, cookies }) => {
|
|||
const { pathname } = url;
|
||||
const ua = request.headers.get("user-agent");
|
||||
const isMobile = /mobile/i.test(ua || "");
|
||||
const isFirefox = /firefox/i.test(ua || "");
|
||||
return {
|
||||
pathname,
|
||||
isMobile,
|
||||
isFirefox,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -63,49 +63,35 @@
|
|||
img.onerror = async () => {
|
||||
// resolve(new VertFile(f, to, converter));
|
||||
const reader = new FileReader();
|
||||
const file = new VertFile(f, to, converter);
|
||||
resolve(file);
|
||||
reader.onload = async (e) => {
|
||||
try {
|
||||
const tags = await new Promise<TagType>(
|
||||
(resolve, reject) => {
|
||||
jsmediatags.read(
|
||||
new Blob([
|
||||
new Uint8Array(
|
||||
e.target
|
||||
?.result as ArrayBuffer,
|
||||
),
|
||||
]),
|
||||
{
|
||||
onSuccess: (tag) =>
|
||||
resolve(tag),
|
||||
onError: (error) =>
|
||||
reject(error),
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
console.log(tags);
|
||||
const picture = tags.tags.picture;
|
||||
if (!picture) {
|
||||
resolve(new VertFile(f, to, converter));
|
||||
return;
|
||||
}
|
||||
const blob = new Blob(
|
||||
[new Uint8Array(picture.data)],
|
||||
{
|
||||
type: picture.format,
|
||||
},
|
||||
);
|
||||
resolve(
|
||||
new VertFile(
|
||||
f,
|
||||
to,
|
||||
converter,
|
||||
URL.createObjectURL(blob),
|
||||
),
|
||||
);
|
||||
} catch {
|
||||
resolve(new VertFile(f, to, converter));
|
||||
}
|
||||
const tags = await new Promise<TagType>(
|
||||
(resolve, reject) => {
|
||||
jsmediatags.read(
|
||||
new Blob([
|
||||
new Uint8Array(
|
||||
e.target?.result as ArrayBuffer,
|
||||
),
|
||||
]),
|
||||
{
|
||||
onSuccess: (tag) => resolve(tag),
|
||||
onError: (error) => reject(error),
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
const picture = tags.tags.picture;
|
||||
if (!picture) return;
|
||||
|
||||
const blob = new Blob(
|
||||
[new Uint8Array(picture.data)],
|
||||
{
|
||||
type: picture.format,
|
||||
},
|
||||
);
|
||||
const url = URL.createObjectURL(blob);
|
||||
file.blobUrl = url;
|
||||
};
|
||||
reader.readAsArrayBuffer(f);
|
||||
};
|
||||
|
|
|
@ -13,6 +13,13 @@
|
|||
import { ArrowRight, Disc2Icon, FileAudioIcon, XIcon } from "lucide-svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { quintOut } from "svelte/easing";
|
||||
import {
|
||||
fade,
|
||||
type EasingFunction,
|
||||
type TransitionConfig,
|
||||
} from "svelte/transition";
|
||||
|
||||
const { data } = $props();
|
||||
|
||||
const reversedFiles = $derived(files.files.slice().reverse());
|
||||
|
||||
|
@ -131,6 +138,33 @@
|
|||
files.files = [];
|
||||
goto("/");
|
||||
};
|
||||
|
||||
export const progBlur = (
|
||||
_: HTMLElement,
|
||||
config:
|
||||
| Partial<{
|
||||
duration: number;
|
||||
easing: EasingFunction;
|
||||
}>
|
||||
| undefined,
|
||||
dir: {
|
||||
direction: "in" | "out" | "both";
|
||||
},
|
||||
): TransitionConfig => {
|
||||
const prefersReducedMotion = window.matchMedia(
|
||||
"(prefers-reduced-motion: reduce)",
|
||||
).matches;
|
||||
if (!config) config = {};
|
||||
if (!config.duration) config.duration = 300;
|
||||
if (!config.easing) config.easing = quintOut;
|
||||
return {
|
||||
duration: prefersReducedMotion ? 0 : config?.duration || 300,
|
||||
css: (t) => {
|
||||
return "--blur-amount: " + (dir.direction !== "in" ? t : 1 - t);
|
||||
},
|
||||
easing: config?.easing,
|
||||
};
|
||||
};
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -279,7 +313,9 @@
|
|||
)}
|
||||
style="background-color: color-mix(in srgb, var(--{file.result
|
||||
? 'accent-bg'
|
||||
: 'bg'}), transparent var(--transparency)); backdrop-filter: blur(18px);"
|
||||
: 'bg'}), transparent var(--transparency)); backdrop-filter: blur({data.isFirefox
|
||||
? 0
|
||||
: 18}px);"
|
||||
>
|
||||
<div
|
||||
class="w-full grid grid-cols-1 grid-rows-1"
|
||||
|
@ -418,10 +454,23 @@
|
|||
{#if file.blobUrl}
|
||||
<div
|
||||
class="bg-cover bg-center w-full h-full"
|
||||
style="background-image: url({file.blobUrl});"
|
||||
style="background-image: url({file.blobUrl})"
|
||||
in:blur={{
|
||||
blurMultiplier: 24,
|
||||
scale: {
|
||||
start: 1.1,
|
||||
end: 1,
|
||||
},
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
></div>
|
||||
<div
|
||||
class="absolute left-0 top-0 pt-[50px] h-full w-full"
|
||||
transition:progBlur={{
|
||||
duration,
|
||||
easing: quintOut,
|
||||
}}
|
||||
>
|
||||
<ProgressiveBlur
|
||||
direction="bottom"
|
||||
|
|
Loading…
Reference in New Issue