207 lines
3.8 KiB
Vue
207 lines
3.8 KiB
Vue
<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>
|