deemix-web-frontend/app/src/lib/Album.svelte

275 lines
6.9 KiB
Svelte

<script>
export let id;
export let title;
export let artist;
export let subtitle;
export let cover;
export let short;
export let hideDownload;
export let log;
export let butShowThisDownloadLinkInstead;
import { Icon } from 'svelte-fontawesome';
import { faDownload } from '@fortawesome/free-solid-svg-icons/faDownload';
import { inview } from 'svelte-inview';
import Loading from './Loading.svelte';
import Track from './Track.svelte';
import { startDownload } from './download';
import { dev } from './dev';
const options = {};
let album;
let loadingTracks = false;
async function loadTracks() {
if (loadingTracks || album || short) return;
loadingTracks = true;
try {
let url = dev ? (new URL('http://localhost:4500/api/album')) : (new URL('/api/album', window.location.origin));
url.searchParams.set('id', id);
const response = await fetch(url);
album = await response.json();
loadingTracks = false;
} catch(err) {
loadingTracks = false;
console.error(err);
}
}
</script>
<div class="album" class:short={short} id="album-{id}"
use:inview={options}
on:enter={loadTracks}
>
<div class="album-inner-top">
<div class="album-metadata">
<span class="metadata">
<div class="big">
{title}
{#if subtitle}
<span class="small">{subtitle}</span>
{/if}
</div>
<div class="small">{artist.name}</div>
</span>
<div class="album-inner-inner-bottom">
{#if !hideDownload || $butShowThisDownloadLinkInstead}
{#if $butShowThisDownloadLinkInstead}
<a href={$butShowThisDownloadLinkInstead} target="_blank" rel="noopener" download="{$butShowThisDownloadLinkInstead.split('/').slice(-1)}">
<div class="album-download" title="Download">
<Icon icon={faDownload}/>
</div>
</a>
{:else}
<div class="album-download" title="Download" on:click={() => startDownload(id, {title, artist, cover}, true)}>
<Icon icon={faDownload}/>
</div>
{/if}
{/if}
</div>
</div>
<div class="album-image-wrapper">
<img class="album-image" class:explicit={album && album.explicitCover === 1} width="128" height="128" src="https://e-cdns-images.dzcdn.net/images/cover/{cover}/128x128-000000-80-0-0.jpg" alt="Cover for '{title}'">
</div>
</div>
<div class="album-inner-bottom">
{#if log}
<div class="progress-state">
{#each $log as line, i}
<span style="order: {-i}">{line}</span>
{/each}
</div>
{/if}
</div>
</div>
<div class="album-bottom" id="album-bottom-{id}">
{#if loadingTracks}
<Loading/>
{/if}
{#if album && !short}
{#each album.tracks as track}
<Track id={track.id} title={track.title} duration={track.duration} artist={track.contributors.map(a => a && a.name).join(', ')} cover={cover} album={title} albumArtist={artist.name} explicit={track.explicit === 1}/>
{/each}
{/if}
</div>
<style>
.album {
padding: 15px;
margin: 2px;
font-size: large;
border-radius: 10px 10px 0px 0px;
transition: 0.1s border-left ease-out, 0.1s background-color ease-in-out;
min-height: 96px;
margin-top: 0.5em;
min-width: 330px;
display: flex;
flex-direction: column;
align-items: stretch;
gap: 0.5em;
}
.album-inner-top {
display: flex;
justify-content: space-between;
gap: 1em;
}
.album-inner-bottom {
display: flex;
flex-direction: column;
align-items: stretch;
}
.album-inner-inner-bottom {
display: flex;
flex-direction: row;
justify-content: space-between;
width: 100%;
align-items: flex-end;
}
.album.short {
border-radius: 10px 10px 10px 10px;
}
.album-image {
width: auto;
height: 100%;
border-radius: 10px;
transition: 0.1s border ease-out, 0.1s box-shadow ease-out;
width: 96px;
height: 96px;
}
.album-image-wrapper {
flex: 0 0 auto;
transition: 0.1s border ease-out;
}
.album-metadata {
display: flex;
flex-direction: column;
flex: 1 1 0px;
align-items: flex-start;
gap: 0.5em;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
.album-download {
cursor: pointer;
transition: 0.1s filter ease-out, 0.1s color ease-out;
}
.album-download {
font-size: 1.5em;
}
.album-bottom {
padding: 0px;
margin-left: 2px;
margin-right: 2px;
border-radius: 0px 0px 10px 10px;
transition: 0.1s border-left ease-out;
margin-bottom: 1em;
}
.metadata {
flex: 1 1 0px;
display: flex;
flex-direction: column;
align-items: stretch;
}
.progress-state {
font-family: monospace;
font-size: 12px;
border-radius: 10px;
padding: 6px;
height: 5.5em;
overflow: hidden;
overflow-y: auto;
display: flex;
flex-direction: column-reverse;
align-self: stretch;
}
.explicit {
transition: 0.2s filter ease-out;
filter: blur(8px);
}
.explicit:hover {
filter: blur(0px);
}
@media (prefers-color-scheme: dark) {
.album-download {
color: #fff;
filter: none;
}
.album-download:hover {
color: rgb(131, 131, 243);
filter: drop-shadow( 0px 0px 6px #8383F3);
}
.album {
background-color: #161627;
box-shadow: 0px 0px 12px #000;
border-left: 0rem solid rgb(131, 131, 243);
}
.album:hover {
border-left: 0.25rem solid rgb(131, 131, 243);
background-color: #181829;
}
.album-image {
border: 0px solid rgb(131, 131, 243);
box-shadow: 0px 0px 15px #000;
}
.album:hover .album-image {
border: 2px solid rgb(131, 131, 243);
box-shadow: 0px 0px 30px #000;
}
.album-image-wrapper {
border: 2px solid rgba(0, 0, 0, 0);
}
.album:hover .album-image-wrapper {
border: 0px solid rgba(0, 0, 0, 0);
}
.progress-state {
background-color: #0a0a0f;
}
}
@media (prefers-color-scheme: light) {
.album-download {
color: #1e1e2d;
filter: none;
}
.album-download:hover {
color: #ea74ac;
filter: drop-shadow( 0px 0px 6px #f484b6);
}
.album {
background-color: #ffffff;
box-shadow: 0px 0px 12px rgba(0, 0, 0, 0.2);
border-left: 0rem solid #ea74ac;
}
.album:hover {
border-left: 0.25rem solid #ea74ac;
background-color: #fafafa;
}
.album-image {
border: 0px solid #ea74ac;
box-shadow: 0px 0px 15px rgba(0, 0, 0, 0.2);
}
.album:hover .album-image {
border: 2px solid #ea74ac;
box-shadow: 0px 0px 30px rgba(0, 0, 0, 0.2);
}
.album-image-wrapper {
border: 2px solid rgba(0, 0, 0, 0);
}
.album:hover .album-image-wrapper {
border: 0px solid rgba(0, 0, 0, 0);
}
.progress-state {
background-color: #fafafa;
}
}
</style>