mirror of
https://github.com/koel/koel
synced 2024-12-22 10:33:16 +00:00
99 lines
3 KiB
Vue
99 lines
3 KiB
Vue
<template>
|
|
<section id="vizContainer" ref="container" :class="{ fullscreen: isFullscreen }" @dblclick.prevent="toggleFullscreen">
|
|
<div
|
|
class="absolute z-[1] w-full h-full top-0 left-0 opacity-0 transition-opacity
|
|
duration-300 ease-in-out hover:opacity-100"
|
|
>
|
|
<div
|
|
v-if="selectedVisualizer"
|
|
class="absolute bottom-8 left-8 px-6 py-4 bg-black/30 rounded-md"
|
|
>
|
|
<h3 class="text-lg mb-2">{{ selectedVisualizer.name }}</h3>
|
|
<p v-if="selectedVisualizer.credits" class="text-k-text-secondary">
|
|
by {{ selectedVisualizer.credits.author }}
|
|
<a :href="selectedVisualizer.credits.url" class="ml-2" target="_blank">
|
|
<Icon :icon="faUpRightFromSquare" />
|
|
</a>
|
|
</p>
|
|
</div>
|
|
|
|
<div class="absolute bottom-8 right-8 border border-white/30 rounded-md">
|
|
<SelectBox v-model="selectedId" class="!bg-black/20 !text-white block">
|
|
<option disabled value="-1">Pick a visualizer</option>
|
|
<option v-for="v in visualizers" :key="v.id" :value="v.id">{{ v.name }}</option>
|
|
</SelectBox>
|
|
</div>
|
|
</div>
|
|
|
|
<div ref="el" class="viz h-full w-full absolute z-0" />
|
|
</section>
|
|
</template>
|
|
|
|
<script lang="ts" setup>
|
|
import { faUpRightFromSquare } from '@fortawesome/free-solid-svg-icons'
|
|
import { nextTick, onBeforeUnmount, onMounted, ref, watch } from 'vue'
|
|
import { useFullscreen } from '@vueuse/core'
|
|
import { logger } from '@/utils'
|
|
import { preferenceStore as preferences, visualizerStore } from '@/stores'
|
|
|
|
import SelectBox from '@/components/ui/form/SelectBox.vue'
|
|
|
|
const visualizers = visualizerStore.all
|
|
let destroyVisualizer: () => void
|
|
|
|
const el = ref<HTMLElement | null>(null)
|
|
const container = ref<HTMLElement | null>(null)
|
|
const selectedId = ref<Visualizer['id']>()
|
|
|
|
const { isFullscreen, toggle: toggleFullscreen } = useFullscreen(container)
|
|
|
|
const render = async (viz: Visualizer) => {
|
|
if (!el.value) {
|
|
await nextTick()
|
|
await render(viz)
|
|
}
|
|
|
|
freeUp()
|
|
|
|
try {
|
|
destroyVisualizer = await viz.init(el.value!)
|
|
} catch (error: unknown) {
|
|
// in e.g., DOM testing, the call will fail due to the lack of proper API support
|
|
logger.warn('Failed to initialize visualizer', error)
|
|
}
|
|
}
|
|
|
|
const selectedVisualizer = ref<Visualizer>()
|
|
|
|
watch(selectedId, id => {
|
|
preferences.visualizer = id
|
|
selectedVisualizer.value = visualizerStore.getVisualizerById(id || 'default')!
|
|
render(selectedVisualizer.value)
|
|
})
|
|
|
|
onMounted(() => {
|
|
selectedId.value = preferences.visualizer || 'default'
|
|
|
|
if (!visualizerStore.getVisualizerById(selectedId.value)) {
|
|
selectedId.value = 'default'
|
|
}
|
|
})
|
|
|
|
const freeUp = () => {
|
|
destroyVisualizer?.()
|
|
el.value && (el.value.innerHTML = '')
|
|
}
|
|
|
|
onBeforeUnmount(() => freeUp())
|
|
</script>
|
|
|
|
<style lang="postcss" scoped>
|
|
:deep(canvas) {
|
|
@apply transition-opacity duration-300 h-full w-full;
|
|
}
|
|
|
|
.fullscreen {
|
|
/* :fullscreen pseudo support is kind of buggy, so we use a class instead */
|
|
@apply bg-k-bg-primary;
|
|
}
|
|
</style>
|