koel/resources/assets/js/components/layout/app-footer/index.vue

157 lines
4 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
2022-12-23 15:44:34 +00:00
<footer id="mainFooter" ref="root" @contextmenu.prevent="requestContextMenu">
<AudioPlayer v-show="song" />
<div class="fullscreen-backdrop" :style="styles" />
2022-04-15 14:24:30 +00:00
2022-10-13 15:18:47 +00:00
<div class="wrapper">
2022-12-02 16:17:37 +00:00
<SongInfo />
<PlaybackControls />
<ExtraControls />
2022-04-15 14:24:30 +00:00
</div>
</footer>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
2022-12-23 15:44:34 +00:00
import { computed, nextTick, ref, watch } from 'vue'
import { eventBus, isAudioContextSupported, requireInjection } from '@/utils'
2022-10-13 15:18:47 +00:00
import { CurrentSongKey } from '@/symbols'
2022-12-23 15:44:34 +00:00
import { artistStore, preferenceStore } from '@/stores'
import { audioService, playbackService, volumeManager } from '@/services'
2022-04-15 17:00:08 +00:00
2022-10-13 15:18:47 +00:00
import AudioPlayer from '@/components/layout/app-footer/AudioPlayer.vue'
import SongInfo from '@/components/layout/app-footer/FooterSongInfo.vue'
2022-04-20 15:57:53 +00:00
import ExtraControls from '@/components/layout/app-footer/FooterExtraControls.vue'
2022-10-13 15:18:47 +00:00
import PlaybackControls from '@/components/layout/app-footer/FooterPlaybackControls.vue'
2022-04-15 14:24:30 +00:00
2022-12-23 15:44:34 +00:00
const song = requireInjection(CurrentSongKey, ref())
const root = ref<HTMLElement>()
const artist = ref<Artist>()
2022-04-15 14:24:30 +00:00
2022-04-15 17:00:08 +00:00
const requestContextMenu = (event: MouseEvent) => {
2022-10-13 15:18:47 +00:00
song.value && eventBus.emit('SONG_CONTEXT_MENU_REQUESTED', event, song.value)
2022-04-15 17:00:08 +00:00
}
2022-12-23 15:44:34 +00:00
watch(song, async () => {
if (!song.value) return
artist.value = await artistStore.resolve(song.value.artist_id)
})
const styles = computed(() => {
const src = artist.value?.image ?? song.value?.album_cover
return {
backgroundImage: src ? `url(${src})` : 'none'
}
})
const initPlaybackRelatedServices = async () => {
const plyrWrapper = document.querySelector<HTMLElement>('.plyr')
const volumeInput = document.querySelector<HTMLInputElement>('#volumeInput')
if (!plyrWrapper || !volumeInput) {
await nextTick()
await initPlaybackRelatedServices()
return
}
playbackService.init(plyrWrapper)
volumeManager.init(volumeInput)
isAudioContextSupported && audioService.init(playbackService.player.media)
}
watch(preferenceStore.initialized, async initialized => {
if (!initialized) return
await initPlaybackRelatedServices()
}, { immediate: true })
2022-12-23 15:44:34 +00:00
eventBus.on('FULLSCREEN_TOGGLE', () => {
if (document.fullscreenElement) {
document.exitFullscreen()
} else {
root.value?.requestFullscreen()
}
})
2022-04-15 14:24:30 +00:00
</script>
<style lang="scss" scoped>
footer {
2022-12-23 15:44:34 +00:00
background-color: var(--color-bg-secondary);
background-size: 0;
2022-04-15 14:24:30 +00:00
height: var(--footer-height);
display: flex;
2022-10-13 15:18:47 +00:00
box-shadow: 0 0 30px 20px rgba(0, 0, 0, .2);
flex-direction: column;
2022-04-15 14:24:30 +00:00
position: relative;
2022-11-27 17:39:50 +00:00
z-index: 3;
2022-04-15 14:24:30 +00:00
2022-10-13 15:18:47 +00:00
.wrapper {
2022-12-23 15:44:34 +00:00
position: relative;
2022-04-15 14:24:30 +00:00
display: flex;
2022-10-13 15:18:47 +00:00
flex: 1;
2022-04-15 14:24:30 +00:00
}
2022-12-23 15:44:34 +00:00
.fullscreen-backdrop {
display: none;
}
&:fullscreen {
padding: calc(100vh - 9rem) 5vw 0;
background: none;
.wrapper {
z-index: 3;
}
&::before {
background-color: #000;
background-image: linear-gradient(135deg, #111 25%, transparent 25%),
linear-gradient(225deg, #111 25%, transparent 25%),
linear-gradient(45deg, #111 25%, transparent 25%),
linear-gradient(315deg, #111 25%, rgba(255, 255, 255, 0) 25%);
background-position: 6px 0, 6px 0, 0 0, 0 0;
background-size: 6px 6px;
background-repeat: repeat;
content: '';
position: absolute;
width: calc(100% + 40rem);
height: calc(100% + 40rem);
top: 0;
left: 0;
opacity: .5;
z-index: 1;
pointer-events: none;
margin: -20rem;
transform: rotate(10deg);
}
&::after {
background-image: linear-gradient(0deg, rgba(0, 0, 0, 1) 0%, rgba(255, 255, 255, 0) 30vh);
content: '';
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
z-index: 1;
pointer-events: none;
}
.fullscreen-backdrop {
filter: saturate(.2);
display: block;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 0;
background-size: cover;
background-repeat: no-repeat;
background-position: top center;
}
}
2022-04-15 14:24:30 +00:00
}
</style>