add cards & tracks
This commit is contained in:
@@ -130,7 +130,7 @@ onMounted(() => {
|
||||
const down = (ev: PointerEvent) => {
|
||||
ev.preventDefault()
|
||||
dragging = true
|
||||
scene.value?.setPointerCapture(ev.pointerId)
|
||||
box.value?.setPointerCapture(ev.pointerId)
|
||||
lastPointer = { x: ev.clientX, y: ev.clientY, time: performance.now() }
|
||||
velocity = { x: 0, y: 0 }
|
||||
if (raf) { cancelAnimationFrame(raf); raf = null }
|
||||
@@ -158,17 +158,17 @@ onMounted(() => {
|
||||
const end = (ev: PointerEvent) => {
|
||||
if (!dragging) return
|
||||
dragging = false
|
||||
try { scene.value?.releasePointerCapture(ev.pointerId) } catch { }
|
||||
try { box.value?.releasePointerCapture(ev.pointerId) } catch { }
|
||||
if (enableInertia && (Math.abs(velocity.x) > minVelocity || Math.abs(velocity.y) > minVelocity)) {
|
||||
if (!raf) raf = requestAnimationFrame(tickInertia)
|
||||
}
|
||||
}
|
||||
|
||||
scene.value?.addEventListener('pointerdown', down)
|
||||
scene.value?.addEventListener('pointermove', move)
|
||||
scene.value?.addEventListener('pointerup', end)
|
||||
scene.value?.addEventListener('pointercancel', end)
|
||||
scene.value?.addEventListener('pointerleave', end)
|
||||
box.value?.addEventListener('pointerdown', down)
|
||||
box.value?.addEventListener('pointermove', move)
|
||||
box.value?.addEventListener('pointerup', end)
|
||||
box.value?.addEventListener('pointercancel', end)
|
||||
box.value?.addEventListener('pointerleave', end)
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
cancelAnimationFrame(raf!)
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
<template>
|
||||
<article class="relative">
|
||||
<main
|
||||
class="absolute top-0 backdrop-blur-sm z-40 -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-10 bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
||||
class="backdrop-blur-sm border-2 -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-40 hover:bg-opacity-80 hover:shadow-xl transition-all bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
||||
<!-- Cover -->
|
||||
<figure class="flex-1 overflow-hidden rounded-t-xl">
|
||||
<figure @click="playerStore.playTrack(props.track)" class="flex-1 overflow-hidden rounded-t-xl cursor-pointer">
|
||||
<img :src="coverUrl" alt="Pochette de l'album" class="w-full h-full object-cover object-center" />
|
||||
</figure>
|
||||
|
||||
<!-- Body -->
|
||||
<div class="p-3 text-center bg-white rounded-b-xl">
|
||||
<div class="label">
|
||||
{{ props.track.order }}
|
||||
</div>
|
||||
<h2 class="text-base text-neutral-800 font-bold truncate">{{ props.track.title }}</h2>
|
||||
<p class="text-sm text-neutral-500 truncate">
|
||||
{{ props.track.artist.name }}
|
||||
@@ -17,11 +20,14 @@
|
||||
</main>
|
||||
|
||||
<footer
|
||||
class="absolute top-0 ml-32 backdrop-blur-sm -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-10 bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
||||
class="ml-32 backdrop-blur-sm -mt-12 z-10 card w-56 h-80 p-3 bg-opacity-10 bg-white rounded-2xl shadow-lg flex flex-col overflow-hidden">
|
||||
<!-- Back -->
|
||||
<div class="h-full flex p-16 text-center bg-slate-800 rounded-xl">
|
||||
<img src="/favicon.svg" />
|
||||
</div>
|
||||
<div class="label">
|
||||
{{ props.track.id }}
|
||||
</div>
|
||||
</footer>
|
||||
</article>
|
||||
|
||||
@@ -29,7 +35,19 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { Track } from '~~/types/types'
|
||||
import { usePlayerStore } from '~/store/player'
|
||||
|
||||
const props = defineProps<{ track: Track }>()
|
||||
const coverUrl = `https://f4.bcbits.com/img/${props.track.artist.coverId}_4.jpg`
|
||||
</script>
|
||||
const playerStore = usePlayerStore()
|
||||
const coverUrl = props.track.coverId.startsWith('http')
|
||||
? props.track.coverId
|
||||
: `https://f4.bcbits.com/img/${props.track.coverId}_4.jpg`;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.label {
|
||||
@apply rounded-full size-7 p-2 bg-esyellow leading-3 -mt-6;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
38
app/components/molecule/player.vue
Normal file
38
app/components/molecule/player.vue
Normal file
@@ -0,0 +1,38 @@
|
||||
<template>
|
||||
<audio ref="audioRef" class="fixed z-50 bottom-0 left-1/2 -translate-x-1/2 w-1/2"
|
||||
:src="playerStore.currentTrack ? playerStore.getCompilationUrlFromTrack(playerStore.currentTrack) : ''" controls
|
||||
@timeupdate="updatePosition" @ended="onEnded" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, onMounted, watch } from 'vue'
|
||||
import { usePlayerStore } from '~/store/player'
|
||||
|
||||
const playerStore = usePlayerStore()
|
||||
const audioRef = ref<HTMLAudioElement | null>(null)
|
||||
|
||||
onMounted(() => {
|
||||
if (audioRef.value) playerStore.audio = audioRef.value
|
||||
})
|
||||
|
||||
// Mettre à jour la position
|
||||
function updatePosition() {
|
||||
if (audioRef.value) playerStore.position = audioRef.value.currentTime
|
||||
}
|
||||
|
||||
function onEnded() {
|
||||
playerStore.isPlaying = false
|
||||
}
|
||||
|
||||
// Si la track change, mettre à jour le src et le start
|
||||
watch(
|
||||
() => playerStore.currentTrack,
|
||||
(newTrack) => {
|
||||
if (newTrack && audioRef.value) {
|
||||
audioRef.value.src = newTrack.url
|
||||
audioRef.value.currentTime = newTrack.start || 0
|
||||
if (playerStore.isPlaying) audioRef.value.play()
|
||||
}
|
||||
}
|
||||
)
|
||||
</script>
|
||||
@@ -12,7 +12,6 @@ import type { BoxState } from '~~/types/types'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const router = useRouter()
|
||||
const boxStates = ref<Record<string, BoxState>>({})
|
||||
|
||||
function openCompilation(id: string) {
|
||||
@@ -20,7 +19,6 @@ function openCompilation(id: string) {
|
||||
for (const key in boxStates.value) {
|
||||
boxStates.value[key] = (key === id) ? 'selected' : 'hide'
|
||||
}
|
||||
window.history.pushState({}, '', '/compilation/' + id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +28,6 @@ function closeCompilation(e: KeyboardEvent) {
|
||||
boxStates.value[key] = 'list'
|
||||
}
|
||||
}
|
||||
window.history.pushState({}, '', '/')
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="mt-8 p-8 w-96">
|
||||
<div class="mt-8 p-8 w-96 flex flex-wrap">
|
||||
<MoleculeCard v-for="track in dataStore.getTracksByCompilationId(compilation.id)" :key="track.id" :track="track" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -13,5 +13,4 @@ const props = defineProps<{
|
||||
}>()
|
||||
|
||||
const dataStore = useDataStore()
|
||||
|
||||
</script>
|
||||
Reference in New Issue
Block a user