Platine etape 1
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
<img v-if="isCompilation" class="cover absolute" :src="`/${box.id}/${box.activeSide}/cover.jpg`" alt="" />
|
||||
<div v-else class="size-full flex flex-col justify-center items-center text-7xl text-black"
|
||||
v-html="box.description" />
|
||||
<CinemaScreen />
|
||||
</div>
|
||||
<div class="face back flex flex-row flex-wrap items-start p-4 overflow-hidden"
|
||||
:class="{ 'overflow-y-scroll': !isCompilation }" ref="backFace">
|
||||
@@ -142,13 +143,6 @@ function rotateBox() {
|
||||
applyTransform(0.8)
|
||||
}
|
||||
|
||||
watch(
|
||||
() => props.box.activeSide,
|
||||
() => {
|
||||
rotateBox()
|
||||
}
|
||||
)
|
||||
|
||||
// --- Inertie ---
|
||||
function tickInertia() {
|
||||
if (!enableInertia) return
|
||||
@@ -246,6 +240,10 @@ onBeforeUnmount(() => {
|
||||
})
|
||||
|
||||
// --- Watchers ---
|
||||
watch(
|
||||
() => props.box.activeSide,
|
||||
() => rotateBox()
|
||||
)
|
||||
watch(
|
||||
() => props.box.state,
|
||||
() => applyBoxState()
|
||||
@@ -255,7 +253,10 @@ watch(
|
||||
() => applyColor(),
|
||||
{ deep: true }
|
||||
)
|
||||
watch(isDraggable, (enabled) => (enabled ? addListeners() : removeListeners()))
|
||||
watch(
|
||||
isDraggable,
|
||||
(enabled) => (enabled ? addListeners() : removeListeners())
|
||||
)
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
<div class="boxes" :class="{ 'box-selected': uiStore.isBoxSelected }">
|
||||
<box v-for="(box, i) in dataStore.boxes" :key="box.id" :tabindex="dataStore.boxes.length - i"
|
||||
:box="getBoxToDisplay(box)" @click="openBox(box)" class="text-center" :class="box.state" :id="box.id">
|
||||
<playButton @click.stop="playSelectedBox(box)" :objectToPlay="box" class="relative z-40 m-auto" />
|
||||
<template v-if="box.state === 'box-selected'">
|
||||
<deckCompilation :box="getBoxToDisplay(box)" class="box-page" v-if="box.type === 'compilation'"
|
||||
:key="`${box.id}-${box.activeSide}`" @click.stop />
|
||||
<deckPlaylist :box="box" class="box-page" v-if="box.type === 'playlist'" @click.stop />
|
||||
<template v-if="box.type === 'compilation'">
|
||||
<playButton @click.stop="playSelectedBox(box)" :objectToPlay="box" class="relative z-40 m-auto" />
|
||||
<deckCompilation :box="getBoxToDisplay(box)" class="box-page" :key="`${box.id}-${box.activeSide}`"
|
||||
@click.stop="" />
|
||||
</template>
|
||||
<deckPlaylist :box="box" class="box-page" v-if="box.type === 'playlist'" @click.stop="" />
|
||||
</template>
|
||||
</box>
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
<!-- Cover -->
|
||||
|
||||
<figure class="pochette flex-1 flex justify-center items-center overflow-hidden rounded-t-xl cursor-pointer"
|
||||
<figure class="pochette flex-1 flex justify-center items-center overflow-hidden rounded-xl cursor-pointer"
|
||||
@click="playerStore.playTrack(track)">
|
||||
<playButton :objectToPlay="track" />
|
||||
<img v-if="isFaceUp" :src="coverUrl" alt="Pochette de l'album" loading="lazy"
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<!-- Body -->
|
||||
|
||||
<div class="p-3 text-center bg-white rounded-b-xl">
|
||||
<!-- <div class="p-3 text-center bg-white rounded-b-xl">
|
||||
<div v-if="isOrder" class="label">
|
||||
{{ props.track.order }}
|
||||
</div>
|
||||
@@ -48,7 +48,7 @@
|
||||
<p class="select-text">
|
||||
{{ props.track.url.split('/')[4]?.split('__')[0] }}
|
||||
</p>
|
||||
</div>
|
||||
</div> -->
|
||||
</main>
|
||||
|
||||
<!-- Face-Down -->
|
||||
@@ -154,7 +154,7 @@ const coverUrl = computed(() => {
|
||||
@apply z-50;
|
||||
|
||||
.face-up {
|
||||
@apply shadow-none;
|
||||
@apply shadow-2xl;
|
||||
transition:
|
||||
box-shadow 0.6s,
|
||||
transform 0.6s;
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<template>
|
||||
<video class="fixed h-full w-full object-cover" ref="video" muted autoplay src=""></video>
|
||||
<video class="h-full w-full object-cover" ref="video" muted autoplay src=""></video>
|
||||
</template>
|
||||
@@ -2,7 +2,7 @@
|
||||
<transition name="fade">
|
||||
<div v-if="data.isLoading" class="fixed inset-0 z-50 flex items-center justify-center">
|
||||
<div class="absolute inset-0 bg-black/60 backdrop-blur-md" />
|
||||
<img src="/loader.svg" alt="Loading" class="border-esyellow/30 border-2 relative h-40 w-40 p-6 rounded-full">
|
||||
<img src="/loader.svg" alt="Loading" class="border-esyellow/30 border-4 relative h-40 w-40 p-6 rounded-full">
|
||||
</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
206
app/components/Platine.vue
Normal file
206
app/components/Platine.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div class="layout player fixed z-40"
|
||||
:class="playerStore.currentTrack ? '-bottom-1/4 opacity-100' : '-bottom-1/2 opacity-0'">
|
||||
<div class="disc bg-slate-900" id="disc">
|
||||
<div class="disc__que">
|
||||
</div>
|
||||
<div class="disc__label rounded-full bg-cover bg-center" :style="{
|
||||
backgroundImage: playerStore.currentTrack?.coverId
|
||||
? `url(${playerStore.currentTrack.coverId})`
|
||||
: 'none'
|
||||
}">
|
||||
</div>
|
||||
<div class="disc__middle">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control fixed bottom-0 z-50">
|
||||
<button class="control button rewind" id="rewind"><<</button>
|
||||
<button class="control button toggle" id="playToggle">power</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import Disc from '@/platine-tools/disc';
|
||||
import Sampler from '@/platine-tools/sampler';
|
||||
import Controls from '@/platine-tools/controls';
|
||||
import { usePlayerStore } from '~/store/player'
|
||||
|
||||
const playerStore = usePlayerStore()
|
||||
|
||||
onMounted(async () => {
|
||||
const disc = new Disc(document.querySelector('#disc')!)
|
||||
const sampler = new Sampler()
|
||||
|
||||
const controls = new Controls({
|
||||
toggleButton: document.querySelector('#playToggle') as HTMLButtonElement,
|
||||
rewindButton: document.querySelector('#rewind') as HTMLButtonElement,
|
||||
})
|
||||
|
||||
await sampler.loadTrack('/jet.mp3')
|
||||
|
||||
controls.isDisabled = false
|
||||
|
||||
disc.setDuration(sampler.duration)
|
||||
|
||||
disc.start()
|
||||
|
||||
disc.callbacks.onStop = () => sampler.pause()
|
||||
|
||||
disc.callbacks.onDragEnded = () => {
|
||||
if (!controls.isPlaying) {
|
||||
return
|
||||
}
|
||||
|
||||
sampler.play(disc.secondsPlayed)
|
||||
}
|
||||
|
||||
disc.callbacks.onLoop = ({ playbackSpeed, isReversed, secondsPlayed }) => {
|
||||
sampler.updateSpeed(playbackSpeed, isReversed, secondsPlayed)
|
||||
}
|
||||
|
||||
controls.callbacks.onIsplayingChanged = (isPlaying) => {
|
||||
if (isPlaying) {
|
||||
disc.powerOn()
|
||||
sampler.play(disc.secondsPlayed)
|
||||
} else {
|
||||
disc.powerOff()
|
||||
}
|
||||
}
|
||||
|
||||
controls.callbacks.onRewind = () => {
|
||||
disc.rewind()
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.player {
|
||||
transition: all 1s ease-in-out;
|
||||
}
|
||||
|
||||
.layout {
|
||||
width: 100vw;
|
||||
height: 100vw;
|
||||
max-width: 500px;
|
||||
max-height: 500px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.disc-container {
|
||||
width: 100%;
|
||||
|
||||
aspect-ratio: 1;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
border-radius: 50%;
|
||||
border: 2px solid #000;
|
||||
background: linear-gradient(45deg, #f0f0f0, #424242);
|
||||
}
|
||||
|
||||
.disc {
|
||||
position: relative;
|
||||
|
||||
aspect-ratio: 1;
|
||||
width: 100%;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
border-radius: 50%;
|
||||
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.disc.is-scratching {
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.disc__que {
|
||||
--dim: 20px;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 50%;
|
||||
right: 30px;
|
||||
|
||||
width: var(--dim);
|
||||
height: var(--dim);
|
||||
|
||||
background: var(--color-theme);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.disc__label {
|
||||
position: absolute;
|
||||
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
background-size: cover;
|
||||
|
||||
width: 45%;
|
||||
aspect-ratio: 1/1;
|
||||
|
||||
/* background: no-repeat url(/logo.svg) center center; */
|
||||
background-size: cover;
|
||||
border-radius: 50%;
|
||||
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.disc__middle {
|
||||
--dim: 10px;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
width: var(--dim);
|
||||
height: var(--dim);
|
||||
|
||||
background: rgb(26, 26, 26);
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.button {
|
||||
border-radius: 0;
|
||||
border: none;
|
||||
background: rgb(69, 69, 69);
|
||||
font-size: 0.75rem;
|
||||
padding: 0.4rem;
|
||||
color: #fff;
|
||||
line-height: 1.3;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
box-shadow:
|
||||
1px 1px 0px 1px rgb(0 0 0),
|
||||
0px 0px 0px 0px var(--color-theme);
|
||||
|
||||
will-change: box-shadow;
|
||||
transition:
|
||||
box-shadow 0.2s ease-out,
|
||||
transform 0.05s ease-in;
|
||||
}
|
||||
|
||||
.button.is-active {
|
||||
transform: translate(1px, 2px);
|
||||
box-shadow: 0px 0px 5px 1px var(--color-theme);
|
||||
}
|
||||
|
||||
.button[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user