koel/resources/assets/js/components/layout/main-wrapper/ExtraPanel.vue

204 lines
5.3 KiB
Vue
Raw Normal View History

2022-04-15 14:24:30 +00:00
<template>
<section id="extra" :class="{ showing }" class="text-secondary" data-testid="extra-panel">
2022-04-15 14:24:30 +00:00
<div class="tabs">
<div class="clear" role="tablist">
<button
id="extraTabLyrics"
2022-04-15 14:24:30 +00:00
:aria-selected="currentTab === 'Lyrics'"
aria-controls="extraPanelLyrics"
data-testid="extra-tab-lyrics"
2022-04-15 14:24:30 +00:00
role="tab"
type="button"
@click.prevent="currentTab = 'Lyrics'"
2022-04-15 14:24:30 +00:00
>
Lyrics
</button>
<button
id="extraTabArtist"
2022-04-15 14:24:30 +00:00
:aria-selected="currentTab === 'Artist'"
aria-controls="extraPanelArtist"
data-testid="extra-tab-artist"
2022-04-15 14:24:30 +00:00
role="tab"
type="button"
@click.prevent="currentTab = 'Artist'"
2022-04-15 14:24:30 +00:00
>
Artist
</button>
<button
id="extraTabAlbum"
2022-04-15 14:24:30 +00:00
:aria-selected="currentTab === 'Album'"
aria-controls="extraPanelAlbum"
data-testid="extra-tab-album"
2022-04-15 14:24:30 +00:00
role="tab"
type="button"
@click.prevent="currentTab = 'Album'"
2022-04-15 14:24:30 +00:00
>
Album
</button>
<button
v-if="useYouTube"
id="extraTabYouTube"
2022-04-15 14:24:30 +00:00
:aria-selected="currentTab === 'YouTube'"
aria-controls="extraPanelYouTube"
data-testid="extra-tab-youtube"
2022-04-15 14:24:30 +00:00
role="tab"
title="YouTube"
type="button"
@click.prevent="currentTab = 'YouTube'"
2022-04-15 14:24:30 +00:00
>
2022-07-15 07:23:55 +00:00
<icon :icon="faYoutube"/>
2022-04-15 14:24:30 +00:00
</button>
</div>
<div class="panes">
<div
v-show="currentTab === 'Lyrics'"
2022-04-15 14:24:30 +00:00
id="extraPanelLyrics"
aria-labelledby="extraTabLyrics"
2022-04-15 14:24:30 +00:00
role="tabpanel"
tabindex="0"
>
<LyricsPane :song="song"/>
2022-04-15 14:24:30 +00:00
</div>
<div
v-show="currentTab === 'Artist'"
2022-04-15 14:24:30 +00:00
id="extraPanelArtist"
aria-labelledby="extraTabArtist"
2022-04-15 14:24:30 +00:00
role="tabpanel"
tabindex="0"
>
<ArtistInfo v-if="artist" :artist="artist" mode="aside"/>
2022-04-15 14:24:30 +00:00
</div>
<div
v-show="currentTab === 'Album'"
2022-04-15 14:24:30 +00:00
id="extraPanelAlbum"
aria-labelledby="extraTabAlbum"
2022-04-15 14:24:30 +00:00
role="tabpanel"
tabindex="0"
>
<AlbumInfo v-if="album" :album="album" mode="aside"/>
2022-04-15 14:24:30 +00:00
</div>
<div
v-show="currentTab === 'YouTube'"
2022-04-15 14:24:30 +00:00
id="extraPanelYouTube"
aria-labelledby="extraTabYouTube"
2022-04-15 14:24:30 +00:00
role="tabpanel"
tabindex="0"
>
<YouTubeVideoList v-if="useYouTube && song" :song="song"/>
2022-04-15 14:24:30 +00:00
</div>
</div>
</div>
</section>
</template>
2022-04-15 17:00:08 +00:00
<script lang="ts" setup>
2022-04-15 14:24:30 +00:00
import isMobile from 'ismobilejs'
2022-07-15 07:23:55 +00:00
import { faYoutube } from '@fortawesome/free-brands-svg-icons'
import { ref, toRef, watch } from 'vue'
2022-07-25 12:57:58 +00:00
import { eventBus } from '@/utils'
2022-06-10 10:47:46 +00:00
import { albumStore, artistStore, preferenceStore as preferences } from '@/stores'
import { useThirdPartyServices } from '@/composables'
2022-04-15 14:24:30 +00:00
import LyricsPane from '@/components/ui/LyricsPane.vue'
import ArtistInfo from '@/components/artist/ArtistInfo.vue'
import AlbumInfo from '@/components/album/AlbumInfo.vue'
import YouTubeVideoList from '@/components/ui/YouTubeVideoList.vue'
2022-04-15 14:24:30 +00:00
type Tab = 'Lyrics' | 'Artist' | 'Album' | 'YouTube'
const defaultTab: Tab = 'Lyrics'
2022-04-15 17:00:08 +00:00
const song = ref<Song | null>(null)
const showing = toRef(preferences.state, 'showExtraPanel')
2022-04-29 13:32:12 +00:00
const currentTab = ref<Tab>(defaultTab)
2022-04-15 17:00:08 +00:00
const { useYouTube } = useThirdPartyServices()
2022-06-10 10:47:46 +00:00
const artist = ref<Artist>()
const album = ref<Album>()
2022-04-15 17:00:08 +00:00
watch(showing, (showingExtraPanel) => {
2022-04-15 17:00:08 +00:00
if (showingExtraPanel && !isMobile.any) {
2022-07-25 12:57:58 +00:00
document.documentElement.classList.add('with-extra-panel')
2022-04-15 17:00:08 +00:00
} else {
2022-07-25 12:57:58 +00:00
document.documentElement.classList.remove('with-extra-panel')
2022-04-15 17:00:08 +00:00
}
})
const fetchSongInfo = async (_song: Song) => {
2022-04-15 17:00:08 +00:00
try {
song.value = _song
2022-06-10 10:47:46 +00:00
artist.value = await artistStore.resolve(_song.artist_id)
album.value = await albumStore.resolve(_song.album_id)
} catch (err) {
2022-04-15 17:00:08 +00:00
throw err
}
}
eventBus.on({
2022-04-29 13:32:12 +00:00
'SONG_STARTED': async (song: Song) => await fetchSongInfo(song),
2022-04-15 17:00:08 +00:00
'LOAD_MAIN_CONTENT': (): void => {
// On ready, add 'with-extra-panel' class.
2022-07-25 12:57:58 +00:00
isMobile.any || document.documentElement.classList.add('with-extra-panel')
2022-04-15 17:00:08 +00:00
// Hide the extra panel if on mobile
isMobile.phone && (showing.value = false)
2022-04-15 14:24:30 +00:00
}
})
</script>
<style lang="scss">
#extra {
flex: 0 0 var(--extra-panel-width);
padding-top: 2.3rem;
background: var(--color-bg-secondary);
display: none;
overflow: auto;
-ms-overflow-style: -ms-autohiding-scrollbar;
@media (hover: none) {
// Enable scroll with momentum on touch devices
overflow-y: scroll;
-webkit-overflow-scrolling: touch;
}
&.showing {
display: block;
}
h1 {
font-weight: var(--font-weight-thin);
font-size: 2.2rem;
margin-bottom: 1.25rem;
line-height: 2.8rem;
}
2022-04-15 17:00:08 +00:00
@media only screen and (max-width: 1024px) {
2022-04-15 14:24:30 +00:00
position: fixed;
height: calc(100vh - var(--header-height));
width: var(--extra-panel-width);
2022-07-29 12:12:55 +00:00
z-index: 9;
2022-04-15 14:24:30 +00:00
top: var(--header-height);
right: -100%;
transition: right .3s ease-in;
&.showing {
right: 0;
}
}
2022-04-15 17:00:08 +00:00
@media only screen and (max-width: 667px) {
2022-04-15 14:24:30 +00:00
@include themed-background();
width: 100%;
[role=tabpanel] {
padding-bottom: calc(var(--footer-height-mobile) + 1rem)
}
}
}
</style>