This gist was generated by the Svelte REPL. Visit https://svelte.technology/repl?gist=this_gist_id to see it.
Created
September 9, 2017 10:59
-
-
Save anonymous/e61d375b7bd84ad62c73d5246f60f4e7 to your computer and use it in GitHub Desktop.
Svelte component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="player"> | |
<audio ref:audio :src preload="none" | |
bind:currentTime bind:duration bind:paused | |
bind:buffered bind:played bind:seekable | |
/> | |
<div class="progress-bar"> | |
<ProgressBar :currentTime :duration :buffered | |
:played :seekable on:seek="seek(event.position)" | |
/> | |
</div> | |
<img on:click="playpause()" src="{{icon}}/EEEEEE"> | |
<span class="time elapsed">{{format(currentTime)}}</span> | |
<span class="time duration">{{format(duration)}}</span> | |
</div> | |
<style> | |
.player { | |
position: relative; | |
margin: 50px auto; | |
max-width: 600px; | |
min-width: 200px; | |
height: 100px; | |
background: #333; | |
} | |
.progress-bar { | |
padding: 20px; | |
height: 20px; | |
} | |
img, .time { | |
position: absolute; | |
bottom: 10px; | |
height: 40px; | |
} | |
img { | |
left: calc(50% - 20px); | |
cursor: pointer; | |
} | |
.time { | |
display: inline-block; | |
width: calc(50% - 30px); | |
line-height: 40px; | |
color: #ccc; | |
} | |
.elapsed { | |
left: 0; | |
text-align: right; | |
} | |
.duration { | |
right: 0; | |
} | |
</style> | |
<script> | |
import ProgressBar from './ProgressBar.html'; | |
export default { | |
components: { | |
ProgressBar, | |
}, | |
data() { | |
return { | |
paused: true, | |
}; | |
}, | |
computed: { | |
icon(paused) { | |
return `https://icon.now.sh/${paused ? 'play' : 'pause'}_circle_filled`; | |
}, | |
}, | |
methods: { | |
playpause() { | |
if (this.get('paused')) { | |
this.refs.audio.play(); | |
} else { | |
this.refs.audio.pause(); | |
} | |
}, | |
seek(position) { | |
this.set({ currentTime: position }); | |
}, | |
}, | |
helpers: { | |
format(time) { | |
if (isNaN(time)) return '--:--.-'; | |
const minutes = Math.floor(time / 60); | |
const seconds = (time % 60).toFixed(1); | |
return minutes + ':' + pad(seconds); | |
} | |
}, | |
}; | |
function pad(num) { | |
return num < 10 ? '0' + num : num; | |
} | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"src": "https://api.soundcloud.com/tracks/314855600/stream?client_id=2t9loNQH90kzJcsFCODdigxfp325aq4z" | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div :style on:dragover="event.preventDefault()"> | |
<TimeRanges :duration list={{buffered}} color="{{bufferedColor}}" /> | |
<TimeRanges :duration list={{played}} color="{{playedColor}}" /> | |
<TimeHandle :duration :currentTime color="{{handleColor}}" /> | |
<TimeRanges :duration list={{seekable}} color="{{seekableColor}}" on:seek="onseek(event)" cursor="pointer" /> | |
</div> | |
<style> | |
div { | |
position: relative; | |
width: 100%; | |
height: 100%; | |
} | |
</style> | |
<script> | |
import TimeRanges from './TimeRanges.html'; | |
import TimeHandle from './TimeHandle.html'; | |
export default { | |
components: { | |
TimeRanges, | |
TimeHandle, | |
}, | |
data() { | |
return { | |
backgroundColor: 'rgba(255, 255, 255, 0.1)', | |
bufferedColor: 'rgba(255, 255, 255, 0.15)', | |
playedColor: '#DD0000', | |
seekableColor: 'rgba(0, 0, 0, 0)', // transparent | |
handleColor: '#EEEEEE', | |
}; | |
}, | |
computed: { | |
style(backgroundColor) { | |
return `background: ${backgroundColor};`; | |
}, | |
}, | |
methods: { | |
onseek(data) { | |
this.fire('seek', data); | |
}, | |
} | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div ref:node :style><span /></div> | |
<style> | |
div { | |
position: absolute; | |
top: 0; | |
width: 14px; | |
height: 100%; | |
transform: translateX(-7px); | |
} | |
span { | |
display: block; | |
position: absolute; | |
top: 0; | |
left: 50%; | |
width: 2px; | |
height: calc(100% + 2px); | |
background: white; | |
border-radius: 1px; | |
transform: translateX(-1px) translateY(-1px); | |
} | |
</style> | |
<script> | |
export default { | |
computed: { | |
style(currentTime, duration, color) { | |
if (!duration || isNaN(duration) || !currentTime || isNaN(currentTime)) { | |
return 'display: none'; | |
} | |
return `left: ${currentTime * 100 / duration}%`; | |
}, | |
}, | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div ref:node :style on:click="onclick(event)" /> | |
<style> | |
div { | |
position: absolute; | |
top: 0; | |
height: 100%; | |
} | |
</style> | |
<script> | |
export default { | |
data() { | |
return { | |
start: 0, | |
end: 0, | |
duration: NaN, | |
color: 'black', | |
cursor: 'auto', | |
}; | |
}, | |
computed: { | |
style(start, end, duration, color, cursor) { | |
if (!duration || isNaN(duration)) { | |
return 'left: 0; width: 0'; | |
} | |
const left = start * 100 / duration; | |
const width = end * 100 / duration - left; | |
return `left: ${left}%; width: ${width}%; background: ${color}; cursor: ${cursor}`; | |
}, | |
}, | |
methods: { | |
onclick(e) { | |
const rect = this.refs.node.parentElement.getBoundingClientRect(); | |
const width = Math.floor(rect.right - rect.left); | |
const offset = event.clientX - rect.left; | |
const position = offset / width * this.get('duration'); | |
this.fire('seek', { position }); | |
}, | |
}, | |
}; | |
</script> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div ref:node /> | |
<style> | |
div { | |
position: absolute; | |
left: 0; | |
top: 0; | |
width: 100%; | |
height: 100%; | |
} | |
</style> | |
<script> | |
import TimeRange from './TimeRange.html'; | |
export default { | |
components: { | |
TimeRange, | |
}, | |
data() { | |
return { | |
duration: NaN, | |
list: [], | |
cursor: 'auto', | |
}; | |
}, | |
oncreate() { | |
this.ranges = []; | |
this.colorObserver = this.observe('color', this.updateColor.bind(this)); | |
this.durationObserver = this.observe('duration', this.updateDuration.bind(this)); | |
this.cursorObserver = this.observe('cursor', this.updateCursor.bind(this)); | |
this.listObserver = this.observe('list', this.updateList.bind(this)); | |
}, | |
ondestroy() { | |
this.listObserver.cancel(); | |
this.cursorObserver.cancel(); | |
this.durationObserver.cancel(); | |
this.colorObserver.cancel(); | |
this.clear(); | |
}, | |
methods: { | |
updateColor(color) { | |
this.ranges.forEach((range) => range.set({ color })); | |
}, | |
updateDuration(duration) { | |
this.ranges.forEach((range) => range.set({ duration })); | |
}, | |
updateCursor(cursor) { | |
this.ranges.forEach((range) => range.set({ cursor })); | |
}, | |
updateList(items) { | |
const diff = items.length - this.ranges.length; | |
// re-use existing ranges for performance | |
if (diff >= 0) { | |
for (let i = 0, range; i < items.length; i++) { | |
if (i < this.ranges.length) { | |
this.ranges[i].set({ | |
start: items.start(i), | |
end: items.end(i), | |
}); | |
} else { | |
range = new TimeRange({ | |
target: this.refs.node, | |
data: { | |
duration: this.get('duration'), | |
start: items.start(i), | |
end: items.end(i), | |
color: this.get('color'), | |
cursor: this.get('cursor'), | |
}, | |
}); | |
range.on('seek', (data) => this.fire('seek', data)); | |
this.ranges.push(range); | |
} | |
} | |
} else { | |
for (let i = this.ranges.length - 1, range; i >= 0; i--) { | |
if (i >= items.length) { | |
range = this.ranges.pop(); | |
range.destroy(); | |
range = null; | |
} else { | |
this.ranges[i].set({ | |
start: items.start(i), | |
end: items.end(i), | |
}); | |
} | |
} | |
} | |
}, | |
clear() { | |
this.ranges.forEach((range) => { | |
range.destroy(); | |
range = null; | |
}); | |
this.ranges = []; | |
}, | |
} | |
}; | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment