...
 
Commits (2)
<template>
<div class="progress" role="progressbar" @click="seek"
:aria-valuemin="min" :aria-valuemax="max"
:aria-valuenow="value" :aria-valuetext="label">
<div class="progress-track" ref="track" role="presentation">
<div class="progress-value" :style="barValue"></div>
</div>
<button type="button" class="progress-knob" :style="knobValue"></button>
</div>
</template>
<script>
// TODO implement knob drag & drop
export default {
props: {
min: {
type: Number,
default: 0
},
max: {
type: Number,
default: 100
},
value: {
type: Number,
required: true
},
label: String
},
computed: {
barValue () {
return {
transform: `translateX(${this.value / this.max * 100}%)`
}
},
knobValue () {
const { value, max } = this
const trackWidth = this.$refs.track
? this.$refs.track.getBoundingClientRect().width
: 0
return {
transform: `translateX(calc(${trackWidth * (value / max)}px + 50%))`
}
}
},
methods: {
seek (e) {
const rect = e.target.getBoundingClientRect()
const relativeValue = (e.clientX - rect.left) / rect.width
this.$emit('input', relativeValue * this.max)
}
}
}
</script>
<style>
.progress {
width: 100%;
padding: 6px 0;
position: relative;
overflow: visible;
}
.progress-track {
width: 100%;
height: 4px;
border-radius: 2px;
background-color: #404040;
overflow: hidden;
position: relative;
}
.progress-value {
width: 100%;
height: 100%;
position: absolute;
right: 100%;
transition: color .1s cubic-bezier(.3, 0, 0, 1);
transition-delay: .1s;
background-color: currentColor;
color: #b3b3b3;
z-index: 1;
}
.progress:hover .progress-value {
color: #ff9800;
}
.progress-knob {
border-radius: 50%;
background-color: #fff;
width: 12px;
height: 12px;
border: none;
opacity: 0;
pointer-events: none;
position: absolute;
right: 100%;
top: calc(50% - 6px);
transition: opacity .1s cubic-bezier(.3, 0, 0, 1);
transition-delay: .1s;
z-index: 2;
}
.progress:hover .progress-knob {
opacity: 1;
pointer-events: all;
}
</style>
......@@ -2,16 +2,16 @@
<div class="player-progress">
<span class="player-progress-label">{{ timeLabels.progress }}</span>
<div class="player-progress-bar">
<div class="player-progress-track" ref="track">
<div class="player-progress-value" :style="barValue"></div>
</div>
<button type="button" class="player-progress-knob" :style="knobValue"></button>
<SeekableProgress :min="progress.min" :max="progress.max" v-model="value"
:label="`${timeLabels.progress} / ${timeLabels.duration}`"/>
</div>
<span class="player-progress-label">{{ timeLabels.duration }}</span>
</div>
</template>
<script>
import SeekableProgress from '../SeekableProgress'
function secondsToDuration (seconds, max = null) {
max = max === null ? seconds : max
const start = max <= 599 ? 15 : max <= 3599 ? 14 : 11
......@@ -20,9 +20,17 @@
return date.toISOString().substring(start, 19)
}
// TODO implement knob drag & drop
export default {
components: { SeekableProgress },
computed: {
value: {
get () {
return this.progress.value
},
set (pos) {
this.$player.seek(pos)
}
},
progress () {
return this.$player.currentTrack
? { min: 0, max: this.$player.currentTrack.duration, value: this.$player.currentTrack.progress }
......@@ -34,20 +42,6 @@
duration: secondsToDuration(duration),
progress: secondsToDuration(progress, duration)
}
},
barValue () {
return {
transform: `translateX(${this.progress.value / this.progress.max * 100}%)`
}
},
knobValue () {
const { value, max } = this.progress
const trackWidth = this.$refs.track
? this.$refs.track.getBoundingClientRect().width
: 0
return {
transform: `translateX(calc(${trackWidth * (value / max)}px + 50%))`
}
}
}
}
......@@ -66,56 +60,7 @@
}
.player-progress-bar {
width: 100%;
margin: 0 16px;
padding: 6px 0;
position: relative;
overflow: visible;
}
.player-progress-track {
width: 100%;
height: 4px;
border-radius: 2px;
background-color: #404040;
overflow: hidden;
position: relative;
}
.player-progress-value {
width: 100%;
height: 100%;
position: absolute;
right: 100%;
transition: color .1s cubic-bezier(.3, 0, 0, 1);
transition-delay: .1s;
background-color: currentColor;
color: #b3b3b3;
z-index: 1;
}
.player-progress-bar:hover .player-progress-value {
color: #ff9800;
}
.player-progress-knob {
border-radius: 50%;
background-color: #fff;
width: 12px;
height: 12px;
border: none;
opacity: 0;
pointer-events: none;
position: absolute;
right: 100%;
top: calc(50% - 6px);
transition: opacity .1s cubic-bezier(.3, 0, 0, 1);
transition-delay: .1s;
z-index: 2;
}
.player-progress-bar:hover .player-progress-knob {
opacity: 1;
pointer-events: all;
}
</style>
......@@ -107,6 +107,12 @@ function createPlayer (Vue) {
}
return this
},
seek (pos) {
if (currentHowler) {
currentHowler.seek(pos)
}
return this
},
mute (state = null) {
const newState = state !== null ? Boolean(state) : !this.isMuted
this.isMuted = newState
......