upend/webui/src/components/display/blobs/AudioPreview.svelte

76 lines
1.7 KiB
Svelte

<script lang="ts">
import { useEntity } from "../../../lib/entity";
import api from "../../../lib/api";
import { createEventDispatcher } from "svelte";
import { formatDuration } from "../../../util/fragments/time";
import { concurrentImage } from "../../imageQueue";
const dispatch = createEventDispatcher();
export let address: string;
$: ({ entity } = useEntity(address));
let loaded = null;
let handled = true;
$: dispatch("handled", handled);
$: dispatch("loaded", Boolean(loaded));
let clientHeight = 0;
let clientWidth = 0;
$: fontSize = Math.min(clientHeight, clientWidth) * 0.66;
let mediaDuration = "";
$: {
let duration = $entity?.get("MEDIA_DURATION") as number | undefined;
if (duration) {
mediaDuration = formatDuration(duration);
}
}
</script>
<div class="audiopreview" bind:clientWidth bind:clientHeight>
<img
class:loaded={loaded === address}
alt="Thumbnail for {address}"
use:concurrentImage={`${api.apiUrl}/thumb/${address}?mime=audio`}
on:load={() => (loaded = address)}
on:error
/>
{#if mediaDuration}
<div class="duration" style="--font-size: {fontSize}px">
{mediaDuration}
</div>
{/if}
</div>
<style lang="scss">
.audiopreview {
position: relative;
width: 100%;
}
img {
width: 100%;
height: 100%;
&:not(.loaded) {
flex-grow: 1;
height: 6rem;
max-height: 100%;
width: 100%;
min-width: 0;
}
}
.duration {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: var(--font-size);
font-weight: bold;
color: var(--foreground-lightest);
text-shadow: 0px 0px 0.2em var(--background-lighter);
}
</style>