76 lines
1.6 KiB
Svelte
76 lines
1.6 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>
|