163 lines
3.9 KiB
JavaScript
163 lines
3.9 KiB
JavaScript
import { LitElement, css, html } from 'lit'
|
|
import { Task } from '@lit-labs/task'
|
|
|
|
// components
|
|
import '../components/Header.js'
|
|
import '../components/Footer.js'
|
|
import '../components/Loading.js'
|
|
import '../components/AudioCard.js'
|
|
import '../components/ModularPlayer.js'
|
|
|
|
import Router from '../api/Router.js'
|
|
|
|
class AudioView extends LitElement {
|
|
static properties = {
|
|
path: { type: String },
|
|
tracks: { type: Array },
|
|
selected: { state: true }
|
|
}
|
|
|
|
constructor() {
|
|
super()
|
|
this.path = ''
|
|
this.tracks = []
|
|
this.selected = null
|
|
}
|
|
|
|
firstUpdated() {
|
|
this.addEventListener('select-audio', ({ detail }) => {
|
|
this.selected = { ...detail, media: `${Router.route.path}/${detail.media}` }
|
|
console.log(this.selected)
|
|
this._selectAudio.run()
|
|
})
|
|
|
|
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
|
|
// start track (0 is not currently available)
|
|
const idx = 1
|
|
this.selected = { ...this.tracks[idx], idx, media: `${Router.route.path}/${this.tracks[idx].media}` }
|
|
},
|
|
() => [ this.path ]
|
|
)
|
|
|
|
_selectAudio = new Task(
|
|
this,
|
|
{
|
|
task: async ([ selected ]) => {
|
|
const res = await fetch(`/media${selected.media}.json`)
|
|
return { ...selected, ...await res.json() }
|
|
},
|
|
args: () => [ this.selected ]
|
|
}
|
|
)
|
|
|
|
_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}` }
|
|
this._selectAudio.run()
|
|
}
|
|
|
|
render() {
|
|
return html`
|
|
<mm-header></mm-header>
|
|
|
|
<main>
|
|
<nav class="tracks">
|
|
<div class="scroll-items">
|
|
${this._getAudio.render({
|
|
pending: () => html`<mm-loading style="--fill-color: grey"></mm-loading>`,
|
|
complete: () => html`${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>`)}`,
|
|
error: (err) => html`Error: ${err}`
|
|
})}
|
|
</div>
|
|
</nav>
|
|
|
|
<div class="player">
|
|
<div>
|
|
${this._selectAudio.render({
|
|
pending: () => html`<mm-loading style="--fill-color: grey"></mm-loading>`,
|
|
complete: (selected) => html`<mm-audio-player .details=${selected}></mm-audio-player>`
|
|
})}
|
|
</div>
|
|
</div>
|
|
</main>
|
|
|
|
<mm-footer></mm-footer>
|
|
`
|
|
}
|
|
|
|
static styles = css`
|
|
:host {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
|
|
}
|
|
|
|
main {
|
|
flex-grow: 1;
|
|
display: grid;
|
|
grid-template-columns: 0.7fr 1fr;
|
|
gap: 0.5em;
|
|
}
|
|
|
|
.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;
|
|
}
|
|
|
|
.player > div {
|
|
position: absolute;
|
|
inset: 0;
|
|
border-radius: 0.75em 0 0 0.75em;
|
|
background: var(--green-gradient-400, lightgrey);
|
|
margin-block-end: 1em;
|
|
}
|
|
|
|
mm-footer {
|
|
z-index: 1;
|
|
}
|
|
`
|
|
}
|
|
|
|
|
|
customElements.define('mm-audio', AudioView)
|