Something went wrong. Try again.
a simple but full-featured web player for OpenSubsonic music servers (Navidrome, Gonic, Ampache, etc) devins.page/tinysub
svelte typescript javascript subsonic gonic navidrome
Something went wrong. Try again.
Svelte
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109<script lang="ts">import { retryImageWithoutCors } from "./image.js";import { fadeImage } from "./motion.js";import { settings } from "./settings.svelte.js";
let blurModulePromise: Promise<typeof import("./blur.js")> | undefined;
const attachCoverImage = ( image: HTMLImageElement, src: string, radius: number, fadeIfComplete: boolean,) => { if (radius <= 0) return fadeImage(image, fadeIfComplete);
let isCancelled = false; let cleanupBlur: (() => void) | undefined; let cleanupFade: (() => void) | undefined; blurModulePromise ??= import("./blur.js"); void blurModulePromise .then(({ blurImage }) => { if (isCancelled) return; cleanupBlur = blurImage(image, src, radius, () => { cleanupFade = fadeImage(image, fadeIfComplete); }); }) .catch(() => { if (isCancelled) return; image.classList.remove("blur-loading"); cleanupFade = fadeImage(image, fadeIfComplete); });
return () => { isCancelled = true; cleanupFade?.(); cleanupBlur?.(); };};
let { src, className, fadeIfComplete = false,}: { src: string; className: string; fadeIfComplete?: boolean;} = $props();</script>
{#if settings.coverBackground !== "off"} {@const blurEnabled = settings.coverBackgroundBlur > 0} <div class={className} style:opacity={settings.coverBackgroundOpacity}> {#key src} {#key blurEnabled} <img alt="" class:blur-loading={blurEnabled} crossorigin={blurEnabled && !src.startsWith("blob:") ? "anonymous" : undefined} {src} decoding="async" loading="lazy" fetchpriority="low" {@attach retryImageWithoutCors} {@attach (image) => attachCoverImage(image, src, settings.coverBackgroundBlur, fadeIfComplete)} > {/key} {/key} </div>{/if}
<style>div { pointer-events: none;
> img { display: block; inline-size: 100%; block-size: 100%; object-fit: cover;
&.blur-loading { visibility: hidden; } }}
.app-background { position: fixed; inset-inline-start: 0; inset-block-start: 0; z-index: -1; inline-size: 100dvw; block-size: 100dvh; mask-image: linear-gradient( to bottom, transparent max(10%, var(--viewport-inset-top)), black );
> img { object-position: center bottom; }}</style>