A Twitch.tv Status Tracker application. See whether users are online or not, and what they are streaming.
Created
January 26, 2016 03:42
-
-
Save Jean13/9d7823ddda47653a1d4f to your computer and use it in GitHub Desktop.
Twitch.tv Status
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
head | |
title Twitch.tv Status | |
.wrapper | |
h1 Twitch Steamer Status | |
nav.nav | |
ul.left | |
li | |
a#all.active(href='#') All | |
li | |
a#online(href='#') Online | |
li | |
a#offline(href='#') Offline | |
#activeBar.activeBar.moveLeft | |
form.search | |
i.fa.fa-search.left | |
input#search.searchbar(type='text' placeholder='Search...') | |
.bar | |
form | |
input#input(type='text' placeholder='Enter channel name...') | |
input#button(type='submit', value='Add Channel') | |
#panel.panel | |
#footer | |
#author | |
| app created by | |
a(href='http://codepen.io/Jean13') | |
| Jean González | |
a |
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
$(document).ready(function() { | |
function truncate(str, num) { | |
var newStr | |
if (str.length > num) { | |
newStr = str.slice(0, num - 3); | |
newStr += '\u2026'; | |
} else { | |
newStr = str; | |
} | |
return newStr; | |
} | |
var twitchName = [ | |
'freecodecamp', | |
'storbeck', | |
'habathcx', | |
'RobotCaleb', | |
'devwars', | |
'inostupid', | |
'yomama', | |
'Noobs2Ninjas', | |
'medrybw', | |
'sing_sing', | |
'nl_kripp', | |
'screwattack', | |
'kingdime', | |
'vgbootcamp' | |
]; | |
var twitchNameLength = twitchName.length; | |
twitchName.sort(); | |
var input = document.getElementById("input"); | |
var button = document.getElementById("button"); | |
var $nav = $('.nav'), | |
$navItems = $nav.find('ul li > a'), | |
$all = $('#all'), | |
$online = $('#online'), | |
$offline = $('#offline'), | |
$activeBar = $('#activeBar'), | |
$panel = $('#panel'), | |
$search = $('#search'), | |
$streamers; | |
var streams = [], | |
channels = [], | |
online = [], | |
offline = [], | |
count = 0; | |
function createStreamList(i) { | |
$.ajax({ | |
dataType: 'jsonp', | |
url: 'https://api.twitch.tv/kraken/streams/' + twitchName[i] | |
}).then(function(streamsData) { | |
$.ajax({ | |
dataType: 'jsonp', | |
url: 'https://api.twitch.tv/kraken/channels/' + twitchName[i] | |
}).then(function(channelsData) { | |
streams[i] = streamsData; | |
channels[i] = channelsData; | |
count++; | |
if (count === twitchNameLength) { | |
createAll(); | |
showAll(); | |
} | |
}); | |
}); | |
} | |
function createAll() { | |
for (var i = 0; i < twitchNameLength; i++) { | |
if (streams[i].stream !== null) { | |
online[i] = ( | |
'<a class="streamLink" href=' + channels[i].url + ' target="_blank">' + | |
'<div class="streamers">' + | |
'<img class="profilePicture left" src=' + channels[i].logo + '>' + | |
'<div class="group left">' + | |
'<h2 class="displayName">' + channels[i].display_name + '<i class="fa fa-circle-thin"></i></h2>' + '<p id="flw">' + channels[i].followers + '</p>' + | |
'<p class="status">' + truncate(channels[i].status, 28) + '</p>' + | |
'</div>' + | |
'</div>' + | |
'</a>' | |
); | |
} else { | |
offline[i] = ( | |
'<div class="streamers offline">' + | |
'<img class="profilePicture left" src=' + channels[i].logo + '>' + | |
'<div class="group left">' + | |
'<h2 class="displayName">' + channels[i].display_name + '</h2>' + | |
'</div>' + | |
'</div>' | |
); | |
} | |
} | |
} | |
function showAll() { | |
$(this).addClass('active'); | |
$online.removeClass('active'); | |
$offline.removeClass('active'); | |
$activeBar.removeClass().addClass('activeBar moveLeft'); | |
$panel.html(online.join('')).append(offline.join('')); | |
doAnimation(); | |
doRipple(); | |
} | |
function showOnline() { | |
$(this).addClass('active'); | |
$all.removeClass('active'); | |
$offline.removeClass('active'); | |
$activeBar.removeClass().addClass('activeBar moveCenter'); | |
$panel.html(online.join('')); | |
doAnimation(); | |
doRipple(); | |
} | |
function showOffline() { | |
$(this).addClass('active'); | |
$all.removeClass('active'); | |
$online.removeClass('active'); | |
$activeBar.removeClass().addClass('activeBar moveRight'); | |
$panel.html(offline.join('')); | |
doAnimation(); | |
doRipple(); | |
} | |
function doAnimation() { | |
$streamers = $panel.find('.streamers'); | |
$streamers.each(function(index) { | |
$(this).addClass('animate ani-' + index); | |
}); | |
} | |
function doRipple() { | |
$streamers.on('click', function(e) { | |
var width = $(this).outerWidth(); | |
var x = e.pageX; | |
var y = e.pageY; | |
var offsetX = x - $(this).offset().left; | |
var offsetY = y - $(this).offset().top; | |
var layerX = Math.round(offsetX - (width / 2)); | |
var layerY = Math.round(offsetY - (width / 2)); | |
$(this).find('span').remove(); | |
$(this).append('<span class="layer rippleStream"></span>'); | |
$('.layer').css({ | |
top: layerY + 'px', | |
left: layerX + 'px', | |
}).addClass('animateLayer'); | |
}); | |
} | |
$search.keyup(function(e) { | |
$streamers.each(function(index) { | |
var text = $(this).text().toUpperCase(); | |
var input = $search.val().toUpperCase(); | |
if (text.indexOf(input) === -1) $(this).hide(); | |
else $(this).show(); | |
}); | |
e.preventDefault(); | |
}); | |
$navItems.on('click', function(e) { | |
var width = $(this).outerWidth(); | |
var x = e.pageX; | |
var y = e.pageY; | |
var offsetX = x - $(this).offset().left; | |
var offsetY = y - $(this).offset().top; | |
var layerX = Math.round(offsetX - (width / 2)); | |
var layerY = Math.round(offsetY - (width / 2)); | |
$(this).find('span').remove(); | |
$(this).append('<span class="layer rippleNav"></span>'); | |
$('.layer').css({ | |
top: layerY + 'px', | |
left: layerX + 'px', | |
}).addClass('animateLayer'); | |
}); | |
$all.on('click', showAll); | |
$online.on('click', showOnline); | |
$offline.on('click', showOffline); | |
for (var j = 0; j < twitchNameLength; j++) { | |
createStreamList(j); | |
}; | |
button.onclick = function addTW() { | |
twitchName.unshift(input.value); | |
var twitchNameLength = twitchName.length; | |
var count = 0; | |
createStreamList(0); | |
createAll(); | |
showAll(); | |
}; | |
}); |
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
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script> | |
<script src="https://cdn.rawgit.com/Fugiman/Twitch-Channel-Status/1d74252edf89110507cbf3088f9c3eaa38fac9d3/twitch-channel-status.min.js"></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
@import "bourbon"; | |
@import url(https://fonts.googleapis.com/css?family=Cinzel|Philosopher|Kreon|Merriweather|Electrolize|Orbitron|Geo); | |
$lightPurple: #b000c5; | |
$darkPurple: #410049; | |
$somePurple: #51295c; | |
$someWhite: #f0f0f0; | |
$darkGreen: #134704; | |
$darkBlue: #0047df; | |
* {box-sizing: border-box;} | |
h1 { | |
font-family: 'Geo'; | |
font-size: 16px; | |
color: white; | |
background: orange; | |
margin-bottom: -0.1%; | |
border-radius: 2% 0 0 0; | |
text-transform: uppercase; | |
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); | |
} | |
h2, h3, h4 { | |
margin: 0; | |
padding: 0; | |
font-family: 'Geo'; | |
font-weight: 300; | |
line-height: 1.1; | |
letter-spacing: 0.025em; | |
} | |
p { | |
margin: 0; | |
font-family: 'Electrolize'; | |
font-weight: 100; | |
font-size: 16px; | |
} | |
a { | |
font-family: 'Electrolize'; | |
font-weight: 300; | |
text-decoration: none; | |
text-transform: uppercase; | |
opacity: 0.7; | |
} | |
#button { | |
border-radius: 5%; | |
background: $lightPurple; | |
color: white; | |
opacity: 0.9; | |
font-family: 'Electrolize'; | |
font-weight: 300; | |
border-color: orange; | |
} | |
input { | |
font-family: 'Electrolize'; | |
} | |
#footer { | |
} | |
#author { | |
font-family: 'Electrolize'; | |
color: green; | |
} | |
.wrapper { | |
background: white; | |
width: 325px; | |
height: 100%; | |
margin: 0 auto; | |
padding-bottom: 30px; | |
margin-bottom: 2%; | |
text-align: center; | |
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 6px 6px rgba(0,0,0,0.23); | |
} | |
.nav { | |
background: $lightPurple; | |
height: 60px; | |
width: 100%; | |
box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24); | |
position: relative; | |
} | |
.nav > ul { | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
list-style: none; | |
} | |
.nav ul li { | |
width: 33.334%; | |
height: 60px; | |
float: left; | |
overflow: hidden; | |
} | |
.nav ul li > a { | |
display: block; | |
color: white; | |
line-height: 60px; | |
border-left: 1px solid rgba(255, 255, 255, 0.3); | |
opacity: 0.7; | |
position: relative; | |
} | |
.nav ul li:first-child > a { | |
border-left: none; | |
} | |
.nav ul li > a:hover { | |
opacity: 1; | |
transition: all .15s ease; | |
} | |
.nav ul li > .active { | |
opacity: 1; | |
} | |
.activeBar { | |
background: white; | |
height: 3px; | |
width: 33.334%; | |
position: absolute; | |
bottom: 0; | |
transition: left 0.2s ease-in-out; | |
} | |
.moveLeft { | |
left: 0; | |
} | |
.moveCenter { | |
left: 109px; | |
} | |
.moveRight { | |
left: 217px; | |
} | |
.search { | |
position: relative; | |
} | |
.searchbar { | |
width: 305px; | |
height: 30px; | |
margin: 1em 0; | |
padding-left: 28px; | |
border: none; | |
box-shadow: 0 1px 0 rgba(0,0,0,0.12); | |
font: 300 1rem 'Roboto'; | |
letter-spacing: 0.025em; | |
} | |
.searchbar::-webkit-input-placeholder { opacity: 0.54; } | |
.searchbar:focus::-webkit-input-placeholder { opacity: 0.87; } | |
.searchbar::-moz-placeholder { opacity: 0.54; } | |
.searchbar:focus::-moz-placeholder { opacity: 0.87; } | |
.searchbar:focus { | |
outline: none; | |
opacity: 0.87; | |
} | |
.bar { | |
width: 305px; | |
height: 3px; | |
background: $darkPurple; | |
position: absolute; | |
bottom: 15px; | |
left: 10px; | |
transform: scaleX(0); | |
transition: transform 0.2s ease-in-out; | |
} | |
.searchbar:focus + .bar { | |
transform: scaleX(1); | |
} | |
.streamLink { | |
text-transform: none; | |
color: inherit; | |
opacity: 1; | |
} | |
.offline { | |
color: rgba(0, 0, 0, 0.38); | |
font-style: italic; | |
} | |
.streamers { | |
height: 92px; | |
border-right: #FFF; | |
position: relative; | |
overflow: hidden; | |
clear: both; | |
} | |
.streamers:after { | |
content: ''; | |
width: 233px; | |
height: 1px; | |
position: absolute; | |
bottom: 0; | |
left: 92px; | |
border-bottom: 1px solid rgba(0, 0, 0, 0.12); | |
} | |
.streamers:hover { | |
border-right: 5px solid $darkPurple; | |
transition: border-right .15s ease; | |
} | |
.profilePicture { | |
height: 60px; | |
width: 60px; | |
border-radius: 50%; | |
margin: 16px; | |
} | |
.group { | |
margin: 16px 0 0 0; | |
height: 60px; | |
position: relative; | |
width: 200px; | |
} | |
.displayName { | |
text-align: left; | |
line-height: 60px; | |
font-size: 18px; | |
width: 211px; | |
} | |
.status { | |
text-align: left; | |
font-size: 16px; | |
position: absolute; | |
bottom: 0; left: 0; | |
width: 255px; | |
opacity: 0.38; | |
} | |
.fa-search { | |
position: absolute; | |
width: 25px; | |
height: 25px; | |
top: 23px; | |
left: 10px; | |
z-index: 1; | |
opacity: 0.54; | |
} | |
.fa-circle-thin { | |
float: right; | |
line-height: 60px; | |
color: $darkBlue; | |
opacity: 0.54; | |
} | |
.left { | |
float: left; | |
} | |
.animate { transform: scale(0); animation: animate 0.25s ease-in-out forwards; } | |
@keyframes animate { 100% { transform: scale(1); } } | |
.ani-0 { animation-delay: 0ms; } | |
.ani-1 { animation-delay: 75ms; } | |
.ani-2 { animation-delay: 150ms; } | |
.ani-3 { animation-delay: 225ms; } | |
.ani-4 { animation-delay: 300ms; } | |
.ani-5 { animation-delay: 375ms; } | |
.layer { border-radius: 50%; position: absolute; transform: scale(0); } | |
.rippleStream { background: #FF80AB; width: 325px; height: 325px;} | |
.rippleNav { background: #1E88E5; width: 108px; height: 108px;} | |
.animateLayer { animation: ripple 0.5s linear; } | |
@keyframes ripple { 100% { opacity: 0; transform: scale(2.75); } } |
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/font-awesome/4.5.0/css/font-awesome.min.css" rel="stylesheet" /> | |
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet" /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment