307 lines
9.0 KiB
Vue
307 lines
9.0 KiB
Vue
<template>
|
|
<div class="col-span-7 md:col-span-5 lg:col-span-3 player-widget">
|
|
<div
|
|
@click="openFull"
|
|
ref="topbar"
|
|
class="
|
|
player-line
|
|
rounded-md
|
|
transition-colors
|
|
bg-transparent
|
|
hover:bg-orange-min
|
|
flex
|
|
items-center
|
|
space-x-3
|
|
p-2
|
|
cursor-pointer
|
|
"
|
|
>
|
|
<button @click.stop="skipTrack('prev')" class="focus:outline-none text-gray-600 hover:text-gray-800">
|
|
<svg
|
|
class="w-4 h-4"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<polygon points="19 20 9 12 19 4 19 20"></polygon>
|
|
<line x1="5" y1="19" x2="5" y2="5"></line>
|
|
</svg>
|
|
</button>
|
|
<button
|
|
@click.stop="toggleAudio"
|
|
class="
|
|
flex
|
|
h-8
|
|
items-center
|
|
justify-center
|
|
w-8
|
|
transition-colors
|
|
text-gray-600
|
|
hover:text-gray-800
|
|
"
|
|
>
|
|
<PlayIcon v-show="!playing" class="w-8 h-8" />
|
|
<StopIcon v-show="playing" class="w-8 h-8" />
|
|
</button>
|
|
<button @click.stop="skipTrack('next')" class="focus:outline-none text-gray-600 hover:text-gray-800">
|
|
<svg
|
|
class="w-4 h-4"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<polygon points="5 4 15 12 5 20 5 4"></polygon>
|
|
<line x1="19" y1="5" x2="19" y2="19"></line>
|
|
</svg>
|
|
</button>
|
|
<div v-show="count_playlist" class="text-base truncate select-none">
|
|
{{ currentSong.name }}
|
|
</div>
|
|
</div>
|
|
|
|
<teleport to="body">
|
|
<div v-if="open_drop">
|
|
<div
|
|
style="
|
|
position: fixed;
|
|
top: 0;
|
|
right: 0;
|
|
left: 0;
|
|
bottom: 0;
|
|
z-index: 9998;
|
|
background: black;
|
|
opacity: 0.2;
|
|
"
|
|
@click="open_drop = false"
|
|
/>
|
|
<div
|
|
ref="dropdown"
|
|
class="z-[9999] player-widget-list w-full lg:w-[48rem]"
|
|
>
|
|
<div class="shadow-classic rounded-md bg-indigo-200">
|
|
|
|
<div
|
|
v-show="count_playlist"
|
|
@click.prevent="updateSeek"
|
|
class="overflow-hidden bg-orange relative h-2 mt-2 mb-2"
|
|
>
|
|
<div
|
|
:style="{ transform: `translate3d(${playerProgress}, 0, 0)` }"
|
|
class="will-change-transform absolute transition-transform h-full bg-white flex items-center justify-end w-full"
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<div
|
|
class="
|
|
p-2
|
|
lg:p-4
|
|
rounded-md
|
|
items-center
|
|
grid grid-cols-1
|
|
md:grid-cols-10
|
|
cursor-pointer
|
|
"
|
|
>
|
|
<div class="col-span-7 flex items-center space-x-3">
|
|
<button @click.stop="skipTrack('prev')" class="focus:outline-none text-gray">
|
|
<svg
|
|
class="w-4 h-4"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<polygon points="19 20 9 12 19 4 19 20"></polygon>
|
|
<line x1="5" y1="19" x2="5" y2="5"></line>
|
|
</svg>
|
|
</button>
|
|
<button
|
|
@click.stop="toggleAudio"
|
|
class="
|
|
flex
|
|
h-8
|
|
items-center
|
|
justify-center
|
|
w-8
|
|
transition-colors
|
|
text-gray
|
|
"
|
|
>
|
|
<PlayIcon v-show="!playing" class="w-8 h-8" />
|
|
<StopIcon v-show="playing" class="w-8 h-8" />
|
|
</button>
|
|
<button @click.stop="skipTrack('next')" class="focus:outline-none text-gray">
|
|
<svg
|
|
class="w-4 h-4"
|
|
viewBox="0 0 24 24"
|
|
fill="none"
|
|
stroke="currentColor"
|
|
stroke-width="2"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
>
|
|
<polygon points="5 4 15 12 5 20 5 4"></polygon>
|
|
<line x1="19" y1="5" x2="19" y2="19"></line>
|
|
</svg>
|
|
</button>
|
|
<div class="text-gray-light text-base truncate select-none">
|
|
{{ currentSong.name }}
|
|
</div>
|
|
</div>
|
|
<div v-show="count_playlist" class="col-span-1 text-center text-gray-light text-xs select-none">
|
|
{{ seek }}
|
|
</div>
|
|
<div v-show="count_playlist" class="col-span-2 mt-2 md:mt-0 md:ml-auto flex items-center">
|
|
<input class="w-full custom-input-range" type="range" v-model="volume" @click.stop="" @input="updateVolume(volume)" max="1" step="0.1" />
|
|
<span class="text-gray-light ml-1.5 text-xs">{{ volume * 100 + "%" }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="choices-tabs">
|
|
<div class="border-b border-indigo-300">
|
|
<nav class="-mb-px flex" aria-label="Tabs">
|
|
<a v-for="tab in tabs" :key="tab.key" href="#" @click.prevent="changeTab(tab.key)"
|
|
:class="[
|
|
current_tab === tab.key ? 'border-orange text-white' : 'border-transparent text-gray-light hover:text-white',
|
|
'w-1/2 lg:w-1/4 py-3 lg:py-4 px-1 text-center text-sm border-b-2',
|
|
]"
|
|
>{{tab.name}}</a>
|
|
|
|
</nav>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<!-- <audio-tab /> -->
|
|
<keep-alive>
|
|
<component :is="currentTabComponent"></component>
|
|
</keep-alive>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</teleport>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import Popper from "popper.js";
|
|
import { PlayIcon } from "@heroicons/vue/solid";
|
|
import { StopIcon } from "@heroicons/vue/solid";
|
|
import AudioTabNow from "@/Shared/Tabs/AudioTabNow";
|
|
import AudioTabLoaded from "@/Shared/Tabs/AudioTabLoaded";
|
|
import { mapActions, mapGetters, mapState } from "vuex";
|
|
|
|
|
|
export default {
|
|
name: "Player",
|
|
components: {
|
|
AudioTabNow,
|
|
AudioTabLoaded,
|
|
PlayIcon,
|
|
StopIcon
|
|
},
|
|
data() {
|
|
return {
|
|
tabs: [
|
|
{key: 'now', name: 'Текущая'},
|
|
{key: 'loaded', name: 'Загруженная'},
|
|
{key: 'history', name: 'История'},
|
|
],
|
|
open_drop: false,
|
|
popper: null,
|
|
volume: 0.5,
|
|
};
|
|
},
|
|
|
|
created() {
|
|
this.loadExsitPlaylist();
|
|
this.changeVolume(this.volume_step);
|
|
this.volume = this.volume_step;
|
|
},
|
|
|
|
|
|
|
|
computed: {
|
|
currentTabComponent() {
|
|
return 'audio-tab-' + this.current_tab
|
|
},
|
|
...mapGetters(["playing", "count_playlist", "volume_step"]),
|
|
...mapState({
|
|
current_tab: (state) => state.player.tab,
|
|
seek: (state) => state.player.seek,
|
|
duration: (state) => state.player.duration,
|
|
playerProgress: (state) => state.player.playerProgress,
|
|
currentSong: (state) => state.player.currentSong,
|
|
}),
|
|
},
|
|
|
|
watch: {
|
|
|
|
open_drop(open_drop) {
|
|
if (open_drop) {
|
|
this.$nextTick(() => {
|
|
if (window.matchMedia("(min-width: 1024px)").matches) {
|
|
this.popper = new Popper(this.$refs.topbar, this.$refs.dropdown, {
|
|
placement: "bottom-start",
|
|
modifiers: {
|
|
preventOverflow: { boundariesElement: "scrollParent" },
|
|
},
|
|
});
|
|
}else {
|
|
this.popper = new Popper(this.$refs.topbar, this.$refs.dropdown, {
|
|
placement: 'bottom-end',
|
|
modifiers: {
|
|
preventOverflow: {
|
|
boundariesElement: 'scrollParent',
|
|
padding: 0,
|
|
},
|
|
offset: {
|
|
enabled: true,
|
|
offset: '0, 10'
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
});
|
|
} else if (this.popper) {
|
|
setTimeout(() => this.popper.destroy(), 100);
|
|
}
|
|
},
|
|
},
|
|
methods: {
|
|
|
|
...mapActions([
|
|
"toggleAudio",
|
|
"updateSeek",
|
|
"skipTrack",
|
|
"changeVolume",
|
|
"tabName",
|
|
"loadExsitPlaylist",
|
|
]),
|
|
|
|
openFull() {
|
|
this.open_drop = !this.open_drop;
|
|
},
|
|
|
|
updateVolume(volume) {
|
|
this.changeVolume(volume);
|
|
},
|
|
|
|
changeTab(name){
|
|
this.tabName(name);
|
|
},
|
|
|
|
},
|
|
};
|
|
</script>
|