Add option for fullscreen covers
This commit is contained in:
parent
9efe5d18b1
commit
ed9cb97ba6
|
@ -1,7 +1,7 @@
|
|||
<script setup lang="ts">
|
||||
import type { QueueItemSource } from '~/types'
|
||||
|
||||
import { whenever, watchDebounced, useCurrentElement, useScrollLock } from '@vueuse/core'
|
||||
import { whenever, watchDebounced, useCurrentElement, useScrollLock, useFullscreen, useIdle, refAutoReset } from '@vueuse/core'
|
||||
import { nextTick, ref, computed, watchEffect, onMounted } from 'vue'
|
||||
import { useFocusTrap } from '@vueuse/integrations/useFocusTrap'
|
||||
import { useGettext } from 'vue3-gettext'
|
||||
|
@ -148,6 +148,18 @@ const hideArtist = () => {
|
|||
}
|
||||
}
|
||||
|
||||
const cover = ref()
|
||||
const { isFullscreen: fullscreen, enter, exit } = useFullscreen(cover)
|
||||
const { idle } = useIdle(2000)
|
||||
|
||||
const showTrackInfo = refAutoReset(false, 5000)
|
||||
whenever(currentTrack, () => (showTrackInfo.value = true))
|
||||
|
||||
const milkdrop = ref()
|
||||
const loadRandomPreset = () => {
|
||||
milkdrop.value?.loadRandomPreset()
|
||||
}
|
||||
|
||||
enum CoverType {
|
||||
COVER_ART,
|
||||
MILK_DROP
|
||||
|
@ -170,15 +182,27 @@ const coverType = ref(CoverType.COVER_ART)
|
|||
class="ui basic segment"
|
||||
>
|
||||
<template v-if="currentTrack">
|
||||
<div class="cover-container">
|
||||
<div
|
||||
ref="cover"
|
||||
:class="['cover-container', { idle, fullscreen }]"
|
||||
>
|
||||
<div class="cover">
|
||||
<img
|
||||
v-if="coverType === CoverType.COVER_ART"
|
||||
ref="cover"
|
||||
alt=""
|
||||
:src="$store.getters['instance/absoluteUrl'](currentTrack.coverUrl)"
|
||||
>
|
||||
<milk-drop v-else-if="coverType === CoverType.MILK_DROP" />
|
||||
<template v-if="coverType === CoverType.COVER_ART">
|
||||
<img
|
||||
v-if="fullscreen"
|
||||
class="cover-shadow"
|
||||
:src="$store.getters['instance/absoluteUrl'](currentTrack.coverUrl)"
|
||||
>
|
||||
<img
|
||||
ref="cover"
|
||||
alt=""
|
||||
:src="$store.getters['instance/absoluteUrl'](currentTrack.coverUrl)"
|
||||
>
|
||||
</template>
|
||||
<milk-drop
|
||||
v-else-if="coverType === CoverType.MILK_DROP"
|
||||
ref="milkdrop"
|
||||
/>
|
||||
|
||||
<div class="cover-buttons">
|
||||
<button
|
||||
|
@ -195,8 +219,26 @@ const coverType = ref(CoverType.COVER_ART)
|
|||
>
|
||||
<i class="icon image outline" />
|
||||
</button>
|
||||
<button
|
||||
v-if="!fullscreen"
|
||||
class="ui secondary button"
|
||||
@click="enter"
|
||||
>
|
||||
<i class="icon expand arrows alternate" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Transition name="queue">
|
||||
<div
|
||||
v-if="fullscreen && (!idle || showTrackInfo)"
|
||||
class="track-info"
|
||||
@click="loadRandomPreset()"
|
||||
>
|
||||
<h1>{{ currentTrack.title }}</h1>
|
||||
<h2>{{ currentTrack.artistName }} — {{ currentTrack.albumTitle }}</h2>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
<h1 class="ui header">
|
||||
<div class="content ellipsis">
|
||||
|
|
|
@ -2,100 +2,35 @@
|
|||
import { useMilkDrop } from '~/composables/audio/visualizer'
|
||||
|
||||
import { onScopeDispose, ref } from 'vue'
|
||||
import { refAutoReset, useFullscreen, useIdle, useRafFn, whenever } from '@vueuse/core'
|
||||
import { useQueue } from '~/composables/audio/queue'
|
||||
import { useRafFn } from '@vueuse/core'
|
||||
|
||||
const milkdrop = ref()
|
||||
const canvas = ref()
|
||||
|
||||
const { isFullscreen: fullscreen, enter, exit } = useFullscreen(milkdrop)
|
||||
const { visualizer, loadRandomPreset, render } = useMilkDrop(canvas)
|
||||
const { currentTrack } = useQueue()
|
||||
const { idle } = useIdle(2000)
|
||||
|
||||
const showTrackInfo = refAutoReset(false, 5000)
|
||||
whenever(currentTrack, () => (showTrackInfo.value = true))
|
||||
|
||||
const { pause } = useRafFn(render)
|
||||
|
||||
onScopeDispose(() => {
|
||||
exit()
|
||||
pause()
|
||||
if (visualizer.value) {
|
||||
visualizer.value.loseGLContext()
|
||||
}
|
||||
})
|
||||
|
||||
defineExpose({
|
||||
loadRandomPreset
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div
|
||||
ref="milkdrop"
|
||||
:class="['visualizer', { idle, fullscreen }]"
|
||||
class="visualizer"
|
||||
>
|
||||
<canvas
|
||||
ref="canvas"
|
||||
@click="loadRandomPreset()"
|
||||
/>
|
||||
|
||||
<Teleport to=".cover > .cover-buttons">
|
||||
<button
|
||||
v-if="!fullscreen"
|
||||
class="ui secondary button"
|
||||
@click="enter"
|
||||
>
|
||||
<i class="icon expand arrows alternate" />
|
||||
</button>
|
||||
</Teleport>
|
||||
|
||||
<Transition name="slide-down">
|
||||
<div
|
||||
v-if="fullscreen && (!idle || showTrackInfo)"
|
||||
class="track-info"
|
||||
@click="loadRandomPreset()"
|
||||
>
|
||||
<h1>{{ currentTrack.title }}</h1>
|
||||
<h2>{{ currentTrack.artistName }} — {{ currentTrack.albumTitle }}</h2>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.visualizer {
|
||||
&.idle {
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
&.fullscreen {
|
||||
.slide-down-enter-active,
|
||||
.slide-down-leave-active {
|
||||
transition: all 0.2s ease;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
.slide-down-enter-from,
|
||||
.slide-down-leave-to {
|
||||
opacity: 0;
|
||||
transform: translateY(5vh);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.track-info {
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: linear-gradient(to bottom, #0000, #000);
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
padding: 3em 1em 1em;
|
||||
|
||||
h1, h2 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -249,6 +249,10 @@
|
|||
|
||||
|
||||
// Wvffle's styles
|
||||
.theme-light .cover-container.fullscreen {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.component-queue {
|
||||
#queue-grid {
|
||||
display: grid;
|
||||
|
@ -289,6 +293,10 @@
|
|||
width: 50vh;
|
||||
max-width: 90%;
|
||||
|
||||
&.idle {
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
.cover {
|
||||
height: 0;
|
||||
width: 100%;
|
||||
|
@ -302,10 +310,15 @@
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 1;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
canvas {
|
||||
z-index: 1;
|
||||
img {
|
||||
max-width: 100vh;
|
||||
max-height: 100vh;
|
||||
}
|
||||
|
||||
&:hover .cover-buttons {
|
||||
|
@ -313,6 +326,12 @@
|
|||
transform: translateY(0);
|
||||
}
|
||||
|
||||
.cover-shadow {
|
||||
transform: scale(1.2);
|
||||
filter: blur(15vh);
|
||||
border-radius: 22vh;
|
||||
}
|
||||
|
||||
.cover-buttons {
|
||||
position: absolute;
|
||||
bottom: 1em;
|
||||
|
@ -347,6 +366,26 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.track-info {
|
||||
position: absolute;
|
||||
z-index: 3;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
background: linear-gradient(to bottom, #0000, #000);
|
||||
color: #fff;
|
||||
text-align: left;
|
||||
padding: 3em 1em 1em;
|
||||
|
||||
h1, h2 {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.fullscreen) .track-info {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-wrapper {
|
||||
|
|
Loading…
Reference in New Issue