mm.site/src/views/audio.js

182 lines
4.3 KiB
JavaScript

import { LitElement, css, html } from 'lit'
import { Task } from '@lit-labs/task'
// components
import '../components/Loading.js'
import '../components/AudioCard.js'
import '../components/ModularPlayer.js'
import Router from '../api/Router.js'
class AudioView extends LitElement {
static properties = {
tracks: { type: Array },
selected: { state: true }
}
constructor() {
super()
this.tracks = []
this.selected = null
}
firstUpdated() {
this.addEventListener('select-audio', ({ detail }) => {
const div = this.shadowRoot.querySelector('mm-audio-player')
div.addEventListener('transitionend', () => {
this.selected = {
...detail
}
div.classList.remove('unloading')
})
div.classList.add('unloading')
})
this.addEventListener('next-track', () => {
this._skipTrack(1)
})
this.addEventListener('prev-track', () => {
this._skipTrack(-1)
})
}
_getAudio = new Task(
this,
async () => {
const res = await fetch(`/data${Router.route.path}.json`)
const json = await res.json()
this.tracks = json.map(i => {
i.media = `/media${Router.route.path}/${i.media}`
i.image = i.image ? `/media${Router.route.path}/${i.image}` : ''
return i
})
if (this.tracks.length > 0) {
const idx = 0
this.selected = {
...this.tracks[idx], idx,
}
}
},
() => []
)
_skipTrack(direction) {
const idx = (this.selected.idx + direction) % this.tracks.length
const detail = { ...this.tracks[idx], idx }
this.selected = { ...detail, media: `${Router.route.path}/${detail.media}` }
}
render() {
return html`
<nav class="tracks">
<div class="scroll-items">
${this._getAudio.render({
pending: () => html`<mm-loading style="--fill-color: grey"></mm-loading>`,
complete: () => html`${this.tracks.length > 0 ? this.tracks.map((t, i) => html`
<mm-acard
idx=${i}
icon=${t.album ? 'album' : 'play-circle'}
?selected=${t.title == this.selected.title && t.details == this.selected.details}
.details=${t}
></mm-acard>`) : 'No tracks added for this category' }`,
error: (err) => html`Error: ${err}`
})}
</div>
</nav>
<div class="player ${this.selected.tracks ? '' : 'single'}">
<div>
<mm-audio-player .details=${this.selected}></mm-audio-player>
</div>
</div>
`
}
static styles = css`
:host {
flex-grow: 1;
display: grid;
grid-template-columns: 0.7fr 1fr;
gap: 0.5em;
height: 100%;
}
.tracks {
--border-radius: 0.75em;
--padding: 0.5em;
position: relative;
background: var(--neutral-400, lightgrey);
border-radius: 0 var(--border-radius) 0 0;
}
.scroll-items {
position: absolute;
inset: 0;
padding-block: 0.75em;
padding-inline-start: 0.5em;
padding-inline-end: 0.75em;
border-radius: 0 calc(var(--border-radius) * 0.5) 0 0;
display: grid;
grid-auto-flow: rows;
align-content: start;
gap: 0.75em;
overflow-x: hidden;
overflow-y: auto;
}
.player {
position: relative;
&.single > div {
background-image: url('/images/Meredith Monk (1974) Photo Lauretta Harris.jpg'), var(--green-gradient-400);
background-position: center;
background-size: 110%, 110%, cover;
background-blend-mode: soft-light, screen;
}
> div {
position: absolute;
inset: 0;
border-radius: 0.75em 0 0 0.75em;
background: var(--green-gradient-400, lightgrey);
margin-block-end: 1em;
overflow: hidden;
.bg-img {
position: absolute;
inset: 0;
object-fit: cover;
object-position: center 25%;
opacity: 0.2;
scale: 1.1;
width: 100%;
height: 100%;
}
}
}
mm-audio-player {
transition: opacity 0.125s 0.125s ease-in-out;
}
.unloading {
opacity: 0;
transition: opacity 0.125s ease-in-out;
}
mm-footer {
z-index: 1;
}
`
}
customElements.define('mm-audio', AudioView)