Creating themes for a custom audio player with css vars
Last active
August 5, 2017 15:17
-
-
Save Archangel212/a903fd41a413e1da175b0fde8241043e to your computer and use it in GitHub Desktop.
Using CSS Vars for Themes
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="hidden"> | |
<input id=audiofile type=file> | |
<div id="audio_box"></div> | |
</div> | |
<h2 class="title">Using CSS Vars for Themes</h2> | |
<div class="demo"> | |
<div id="player"> | |
<div class="visor"> | |
<div class="time"> | |
<span class="current">0:00</span> | |
<span class="duration">0:00</span> | |
</div> | |
<div class="info"> | |
<div class="track">Artist - Song Title</div> | |
<div class="status"> | |
<span></span> | |
<span>128 KBPS</span> | |
<span>44 KHZ</span> | |
<span><i class="zmdi zmdi-surround-sound"></i></span> | |
</div> | |
</div> | |
</div> | |
<div class="controls"> | |
<button class="open-button" alt="open"> | |
<i class="zmdi zmdi-eject"></i> | |
</button> | |
<button class="play-button" alt="play"> | |
<i class="zmdi zmdi-play"></i> | |
</button> | |
<button class="pause-button" alt="pause"> | |
<i class="zmdi zmdi-pause"></i> | |
</button> | |
<button class="repeat-button" alt="repeat" title="repeat"> | |
<i class="zmdi zmdi-repeat"></i> | |
</button> | |
</div> | |
<div class="analyser"> | |
<canvas id="analyser_render"></canvas> | |
</div> | |
</div> | |
<div class="themes"> | |
<div class="radio"> | |
<input id="radio-1" name="radio" type="radio" value="0" checked> | |
<label for="radio-1" class="radio-label">Night</label> | |
</div> | |
<div class="radio"> | |
<input id="radio-2" name="radio" type="radio" value="1"> | |
<label for="radio-2" class="radio-label">Fire</label> | |
</div> | |
<div class="radio"> | |
<input id="radio-3" name="radio" type="radio" value="2"> | |
<label for="radio-3" class="radio-label">Classic</label> | |
</div> | |
</div> | |
</div> | |
<footer> | |
<h2>About this Pen</h2> | |
<p>To test the player just click on the open (<i class="zmdi zmdi-eject"></i>) button, select your favorite audio file and see how it works.</p> | |
<p>This is one of the new features comming in the next update of Flamapop, soon you will be able to select from three themes we made for you. </p> | |
<p>Flamapop is a Google Chrome extension that allows to control the playback of the current Youtube video from any tab in your browser.</p> | |
<p class="right"> | |
<a href="https://chrome.google.com/webstore/detail/flamapop/knnlmpnmodboangkbfcghejobbbokadl" target="_blank"> | |
<img src="https://lh3.googleusercontent.com/IuTJuEcuFZ0s8CKZ4Ie6PLngqB4aq5e8TsUz0kPgKjLZ6siNYIpmEoI4S_zvxYJiVl_3ZQTxSg=w26-h26-e365" alt="flamapop-logo" /> | |
<span>See Flamapop at Chrome Store</span> | |
</a> | |
</p> | |
</footer> |
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
var audio = null, | |
analyser = null, | |
audioContext = null, | |
sourceNode = null, | |
stream = null; | |
var barsColor = '#00CCFF'; | |
var audioInput = document.getElementById('audiofile'); | |
var timeRender = document.querySelector('.time .current'); | |
var trackRender = document.querySelector('.track'); | |
var canvas, ctx; | |
// choose file | |
audioInput.addEventListener('change', function(event) { | |
stream = URL.createObjectURL(event.target.files[0]); | |
if(audio === null) { | |
audio = new Audio(); | |
audio.src = stream; | |
audio.controls = true; | |
audio.autoplay = true; | |
} | |
else { | |
audio.removeAttribute('src'); | |
audio.load(); | |
audio.setAttribute('src', stream); | |
audio.load(); | |
setTimeout(() => audio.play(), 400); | |
} | |
trackRender.textContent = event.target.files[0].name; | |
barsColor = getComputedColor('.analyser'); | |
if(audioContext === null) | |
setup(); | |
}); | |
function setup() { | |
audio.addEventListener('canplay', function () { | |
document.body.className+='loaded'; | |
document.getElementById('audio_box').appendChild(audio); | |
var AudioContext = window.AudioContext || window.webkitAudioContext; | |
audioContext = new AudioContext(); | |
analyser = (analyser || audioContext.createAnalyser()); | |
sourceNode = audioContext.createMediaElementSource(audio); | |
sourceNode.connect(analyser); | |
sourceNode.connect(audioContext.destination); | |
canvas = document.getElementById('analyser_render'); | |
ctx = canvas.getContext('2d'); | |
document.querySelector('.status').classList.add('play'); | |
document.querySelector('.duration').textContent = formatTime(audio.duration); | |
audio.play(); | |
update(); | |
}); | |
} | |
function update(){ | |
window.webkitRequestAnimationFrame(update); | |
var fbc_array = new Uint8Array(analyser.frequencyBinCount); | |
analyser.getByteFrequencyData(fbc_array); | |
ctx.clearRect(0, 0, canvas.width, canvas.height); // Clear the canvas | |
ctx.fillStyle = barsColor; // Color of the bars | |
var bars = 50; | |
for (var i = 0; i < bars; i++) { | |
var bar_x = i * 6; | |
var bar_width = 5; | |
var bar_height = -(fbc_array[i] / 2); | |
ctx.fillRect(bar_x, canvas.height, bar_width, bar_height); | |
} | |
timeRender.textContent = formatTime(audio.currentTime); | |
} | |
function formatTime(seconds) { | |
var minutes = Math.floor(seconds / 60); | |
minutes = (minutes >= 10) ? minutes : "" + minutes; | |
var seconds = Math.floor(seconds % 60); | |
seconds = (seconds >= 10) ? seconds : "0" + seconds; | |
return minutes + ":" + seconds; | |
} | |
function getComputedColor(selector) | |
{ | |
var element = document.querySelector(selector); | |
if (element.currentStyle) | |
return element.currentStyle.backgroundColor; | |
if (window.getComputedStyle) | |
{ | |
var elementStyle=window.getComputedStyle(element,""); | |
if (elementStyle) | |
return elementStyle.getPropertyValue("color"); | |
} | |
// Return 0 if both methods failed. | |
return 0; | |
} | |
document.querySelector('.play-button').addEventListener("click", e => { | |
audio.play(); | |
document.querySelector('.status').classList.add('play'); | |
}, false); | |
document.querySelector('.pause-button').addEventListener("click", e => { | |
audio.pause(); | |
document.querySelector('.status').classList.remove('play'); | |
}, false); | |
document.querySelector('.repeat-button').addEventListener("click", e => { | |
var btn = e.currentTarget; | |
if(!audio.loop) { | |
audio.loop = true; | |
btn.style.opacity = .5; | |
} | |
else { | |
audio.loop = false; | |
btn.style.opacity = .9; | |
} | |
}, false); | |
document.querySelector('.open-button').addEventListener("click", e => { | |
document.querySelector('#audiofile').click(); | |
}, false); | |
var themes = [ | |
{ | |
bg: '#222', | |
visor: '#002D3C', | |
text: '#F5F5F5', | |
bars: '#00CCFF' | |
}, | |
{ | |
bg: '#F44336', | |
visor: '#dadada', | |
text: '#F5F5F5', | |
bars: '#6b6b6b' | |
}, | |
{ | |
bg: '#333', | |
visor: '#222', | |
text: '#F5F5F5', | |
bars: '#F00' | |
} | |
] | |
function setThemeVar(name, value, unit) { | |
var rootStyles = document.styleSheets[1].cssRules[1].style; | |
rootStyles.setProperty('--' + name, value + (unit || '')); | |
} | |
var radios = document.querySelectorAll('.radio input'); | |
for(var i = 0, max = radios.length; i < max; i++) { | |
radios[i].onclick = e => { | |
var index = parseInt(e.currentTarget.value); | |
var theme = themes[index]; | |
barsColor = theme.bars; | |
setThemeVar('bg-color', theme.bg); | |
setThemeVar('visor-color', theme.visor); | |
setThemeVar('text-color', theme.text); | |
setThemeVar('bars-color', theme.bars); | |
} | |
} | |
radios[1].click(); |
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
@import url(https://fonts.googleapis.com/css?family=Lato|Roboto:100,400); | |
:root { | |
--bg-color: #322; | |
--visor-color: #002D3C; | |
--text-color: #f5f5f5; | |
--bars-color: #00CCFF; | |
--transition-config: background .8s ease; | |
} | |
body { | |
font-family: 'Lato', Helvetica; | |
padding: 0; | |
margin: 0; | |
background-color: #f5f5f5; | |
display: flex; | |
flex-direction: column; | |
} | |
div#player { | |
width:500px; | |
height:170px; | |
background: #444; | |
background:var(--bg-color); | |
padding:15px; | |
/* margin:50px auto; */ | |
margin-right: 10px; | |
font-family: 'Roboto', Helvetica; | |
color: var(--bars-color); | |
border-radius: 2px; | |
transition: var(--transition-config); | |
} | |
div#player .visor { | |
width: 100%; | |
height: 90px; | |
background: #dadada; | |
background:var(--visor-color); | |
transition: var(--transition-config); | |
} | |
div#player .visor > div { | |
display: inline-block; | |
position: relative; | |
} | |
div#player .info { | |
width: 270px; | |
padding-left: 20px; | |
height: 100%; | |
} | |
div#player .info > div { | |
height: 50%; | |
width: 100%; | |
display: flex; | |
align-items: center; | |
} | |
div#player .analyser { | |
position: relative; | |
width:200px; | |
height:70px; | |
background:#dadada; | |
background:var(--visor-color); | |
padding: 0 10px 10px; | |
transition: var(--transition-config); | |
} | |
div#player .analyser canvas { | |
width:100%; | |
height:100%; | |
background: #dadada; | |
background:var(--visor-color); | |
transition: var(--transition-config); | |
} | |
.time { | |
width: 200px; | |
position: relative; | |
left: 10px; | |
top: -5px; | |
font-size: 20px; | |
font-weight: 100; | |
} | |
.time .current { | |
font-size: 64px | |
} | |
.time .duration { | |
opacity:.3; | |
font-weight: 400 | |
} | |
.status { | |
justify-content: space-around; | |
font-size: 12px; | |
} | |
.status span:first-child:before { | |
content: '\f3a7'; | |
font: normal normal normal 14px/1 'Material-Design-Iconic-Font'; | |
} | |
.status.play span:first-child:before { | |
content: '\f3aa'; | |
} | |
.track { font-size: 14px; } | |
.controls { | |
float: right; | |
width: 260px; | |
height: 60px; | |
} | |
.controls button { | |
border: none; | |
background-color: rgba(255,255,255,.0); | |
color: #FFF; | |
color: var(--text-color); | |
border-radius: 50%; | |
font-size: 32px; | |
width: 48px; | |
height: 48px; | |
margin-right: 0px; | |
margin-top: 25px; | |
outline: none; | |
cursor: pointer; | |
opacity: .9; | |
transition: all .4s ease; | |
} | |
.controls button:hover { | |
transform: scale(1.1); | |
opacity: 1; | |
} | |
.open-button { | |
float: right; | |
} | |
.hidden { | |
display: none; | |
} | |
h2.title { | |
text-align: center; | |
margin: 45px auto; | |
color: #444; | |
} | |
.demo { | |
width: 680px; | |
margin: 0 auto; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
.demo > div { | |
display: inline-block | |
} | |
footer { | |
margin-top: 60px; | |
padding: 15px; | |
background: #444; | |
background-color: var(--bg-color); | |
color: #fff; | |
color: var(--text-color); | |
transition: all .4s ease; | |
flex-grow: 2; | |
} | |
footer { | |
h2, p { | |
max-width: 640px; | |
margin: 20px auto; | |
line-height: 1.5; | |
} | |
h2 { | |
opacity: 0.6; | |
} | |
a { | |
color: #444; | |
text-decoration: none; | |
background-color: #ddd; | |
padding: 8px 12px; | |
border-radius: 2px; | |
} | |
img { | |
vertical-align: text-bottom; | |
width: 24px; | |
position: relative; | |
top: 2px; | |
} | |
p.right { | |
text-align: right; | |
margin-top: 25px | |
} | |
} | |
/** Radio buttons **/ | |
$color1: #f4f4f4; | |
$color2: #3197EE; | |
.radio { | |
// display: inline-block; | |
margin: 0.5rem; | |
input[type="radio"] { | |
position: absolute; | |
opacity: 0; | |
+ .radio-label { | |
&:before { | |
content: ''; | |
background: $color1; | |
border-radius: 100%; | |
border: 1px solid darken($color1, 25%); | |
display: inline-block; | |
width: 1.4em; | |
height: 1.4em; | |
position: relative; | |
top: -0.2em; | |
margin-right: 1em; | |
vertical-align: top; | |
cursor: pointer; | |
text-align: center; | |
transition: all 250ms ease; | |
} | |
} | |
&:checked { | |
+ .radio-label { | |
&:before { | |
background-color: $color2; | |
box-shadow: inset 0 0 0 4px $color1; | |
} | |
} | |
} | |
&:focus { | |
+ .radio-label { | |
&:before { | |
outline: none; | |
border-color: $color2; | |
} | |
} | |
} | |
&:disabled { | |
+ .radio-label { | |
&:before { | |
box-shadow: inset 0 0 0 4px $color1; | |
border-color: darken($color1, 25%); | |
background: darken($color1, 25%); | |
} | |
} | |
} | |
+ .radio-label { | |
&:empty { | |
&:before { | |
margin-right: 0; | |
} | |
} | |
} | |
} | |
} |
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
<link href="https://cdnjs.cloudflare.com/ajax/libs/material-design-iconic-font/2.2.0/css/material-design-iconic-font.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment