Enter, Trello Dojo Status Board Starter Page. This page contains everything you need to stand up a page that shows time, StatusCake,
Weather Underground, and Trello information. You may customize it as needed to fit your screen sizes and organization's needs. To learn more, check out http://leanpub.com/trellodojo
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
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>Status Board</title> | |
<script type="text/javascript"> | |
//TODO:Fill out the information below to configure your board. | |
//This page contains everything you need to stand up a page that shows time, StatusCake, | |
//Weather Underground, and Trello information. To learn more, check out http://leanpub.com/trellodojo | |
//You may customize it as needed to fit your screen sizes and organization's needs. | |
//Note that storing API Key and user information client side like this can be a security concern. Only use this approach | |
//if you are sure that the page can only be viewed on authorized machines and only over secure SSL connections. | |
window.wundergroundApiKey = ''; //Get API key and location from http://www.wunderground.com/weather/api | |
window.wundergroundApiLocation = 'MS/Jackson.json'; | |
window.trelloApiKey = ''; //Get a Trello API Key here: https://trello.com/1/appKey/generate | |
window.trelloBoardId = ''; //Get Trello board id from URL of a board. | |
window.statusCakeUser = ''; //Get StatusCake Today! https://www.statuscake.com/?aff=5780 | |
window.statusCakeApiKey = ''; //StatusCake Api Key: https://www.statuscake.com/App/APIKey.php | |
window.weatherImageUrl = 'http://radblast-aws.wunderground.com/cgi-bin/radar/WUNIDS_map?station=DGX&brand=0&num=1&delay=15&type=N0R&frame=0&scale=1.000&noclutter=1&t=1370642716&lat=32.42003632&lon=-90.12447357&label=&showstorms=0&map.x=400&map.y=240¢erx=400¢ery=240&transx=0&transy=0&showlabels=0&severe=0&rainsnow=0&lightning=0&smooth=0&'; | |
</script> | |
<link rel="stylesheet" type="text/css" href="//cdnjs.cloudflare.com/ajax/libs/font-awesome/3.1.0/css/font-awesome.min.css" /> | |
<style type="text/css"> | |
body { | |
margin: 0; | |
padding: 0; | |
background-color: #000; | |
color: #fff; | |
font-size: 50px; | |
font-family: Helvetica, Arial, sans-serif; | |
} | |
div, h1, h2, h3, h4, h5 { | |
padding: 0; | |
margin: 0; | |
} | |
h1, h2, h3, h4, h5 { | |
font-weight: normal; | |
} | |
/*1920x1080*/ | |
.bigscreen { | |
display: none; | |
border: 1px solid silver; | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 1915px; | |
height: 1080px; | |
} | |
.container { | |
width: 1915px; | |
height: 1080px; | |
/*overflow: hidden;*/ | |
} | |
.widget { | |
/*border: 1px solid silver;*/ | |
clear: none; | |
float: left; | |
margin-right: 10px; | |
margin-bottom: 10px; | |
padding: 4px; | |
background-color: #000; /* #191919;*/ | |
overflow: hidden; | |
border: 0 solid #626262; | |
} | |
.widget-1x1 { | |
height: 341px; | |
width: 363px; | |
} | |
.widget-1x2 { | |
height: 705px; | |
width: 363px; | |
} | |
.widget-4x2 { | |
height: 705px; | |
width: 1514px; | |
} | |
.rowend { | |
margin-right: 0; | |
} | |
.small-label { | |
font-size: 35px; | |
} | |
/*Widgets*/ | |
/*picture*/ | |
#picture { | |
background-repeat: no-repeat; | |
background-size: cover; | |
} | |
/*Time*/ | |
.ampm { | |
font-size: 40px; | |
} | |
#time h1 { | |
font-size: 118px; | |
width: 100%; | |
text-align: center; | |
margin-top: 25px; | |
/*margin-left: 5px;*/ | |
margin-bottom: 30px; | |
} | |
#time h3 { | |
margin-top: 10px; | |
margin-left: 30px; | |
color: #ccc; | |
font-size: 45px; | |
} | |
/*Weather*/ | |
#weather { | |
background-position: -170px -40px; | |
} | |
/*sites*/ | |
#sites { | |
position: relative; | |
background-color: #000; | |
} | |
#sites .small-label { | |
text-align: center; | |
} | |
#sitesChart { | |
position: absolute; | |
top: 0; | |
left: 0; | |
width: 363px; | |
height: 363px; | |
} | |
#sites .up { | |
margin-top: 35px; | |
} | |
#sites h1 { | |
margin-top: 90px; | |
font-size: 140px; | |
text-align: center; | |
} | |
#sites .downDesc { | |
font-size: 30px; | |
color: brown; | |
} | |
#sites .upDesc { | |
font-size: 30px; | |
color: green; | |
} | |
#sites .uptime { | |
margin-top: 20px; | |
color: #ccc; | |
} | |
#sites .uptime span { | |
font-size: 30px; | |
} | |
#sites .sitesdown { | |
font-size: 30px; | |
color: #ffffff; | |
background-color: brown; | |
display: block; | |
position: absolute; | |
bottom: 0; | |
width: 100%; | |
margin-left: -5px; | |
padding: 3px; | |
overflow: hidden; | |
} | |
/*ad*/ | |
#ad { | |
text-align: center; | |
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#263F3F), to(#000)); | |
background-image: -webkit-linear-gradient(top, #263F3F, #000); | |
background-image: -moz-linear-gradient(top, #263F3F, #000); | |
background-image: -ms-linear-gradient(top, #263F3F, #000); | |
background-image: -o-linear-gradient(top, #263F3F, #000); | |
} | |
#ad h2 { | |
padding-top: 60px; | |
} | |
#ad a { | |
text-decoration: none; | |
color: #ffffff; | |
} | |
/*chat*/ | |
#chat #messages { | |
list-style-type: none; | |
padding: 0; | |
margin: 0; | |
} | |
/*forecast*/ | |
#forecast ul { | |
list-style-type: none; | |
margin: 0; | |
padding: 0; | |
font-size: 25px; | |
color: #ccc; | |
} | |
#forecast .day { | |
font-size: 30px; | |
font-weight: bold; | |
color: #fff; | |
} | |
/*harvest*/ | |
.trello-listname { | |
font-size: 40px; | |
position: relative; | |
border-bottom: 8px solid #000; | |
text-align: right; | |
padding-right: 8px; | |
} | |
/*trello*/ | |
.trello { | |
display: none; | |
width: 371px; | |
border: 0; | |
border-bottom: 0 none; | |
background-color: #000; | |
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#263F3F), to(#000)); | |
background-image: -webkit-linear-gradient(top, #263F3F, #000); | |
background-image: -moz-linear-gradient(top, #263F3F, #000); | |
background-image: -ms-linear-gradient(top, #263F3F, #000); | |
background-image: -o-linear-gradient(top, #263F3F, #000); | |
padding: 0; | |
} | |
.trello h3 { | |
padding-left: 10px; | |
border-bottom: 10px solid black; | |
background-color: #263F3F; | |
text-align: right; | |
padding-right: 10px; | |
} | |
.trello ul { | |
list-style-type: none; | |
margin: 0; | |
padding: 0; | |
} | |
.trello ul li { | |
list-style-type: none; | |
margin: 0; | |
padding: 10px 8px; | |
border-bottom: 8px solid #000; | |
font-size: 20px; | |
font-weight: normal; | |
display: block; | |
position: relative; | |
} | |
.trello ul.colors { | |
display: block; | |
clear: both; | |
width: 100%; | |
position: absolute; | |
right: 5px; | |
top: 5px; | |
width: auto; | |
} | |
.trello .trello-listname ul.colors { | |
left: 0px; | |
top: 0px; | |
right: auto; | |
} | |
.trello ul.colors li { | |
list-style-type: none; | |
margin: 0 3px; | |
padding: 0; | |
width: 10px; | |
height: 10px; | |
float: left; | |
background-color: #fff; | |
border-bottom: 0px; | |
border-radius: 5px; | |
} | |
.trello .trello-listname ul.colors li { | |
height: 45px; | |
border-radius: 0; | |
margin: 0px; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="bigscreen"> | |
</div> | |
<div class="container"> | |
<div id="time" class="widget widget-1x1"> | |
<h1><span data-bind="text: time"></span><span class="ampm" data-bind=" text: ampm"></span></h1> | |
<h3 class="dayname" data-bind="text: dayname"></h3> | |
<h3 class="date" data-bind="text: date"></h3> | |
</div> | |
<div id="sites" class="widget widget-1x1"> | |
<h1 data-bind="text: sitesUpCount"></h1> | |
<div class="small-label">sites up. <span data-bind="visible: anySitesDown, text: sitesDownCount() + ' down'"></span></div> | |
<canvas id="sitesChart" width="363" height="363"></canvas> | |
<span class="sitesdown" data-bind="visible: anySitesDown, foreach: sitesDownNames"> | |
<i class="icon-warning-sign"></i> <span data-bind="text: $data"></span> | |
</span> | |
</div> | |
<div id="ad" class="widget widget-1x1"> | |
<h2><a href="http://leanpub.com/trellodojo">Enter Trello Dojo</a></h2> | |
</div> | |
<div id="forecast" class="widget widget-1x1"> | |
<h1><span data-bind="text: currentTemp"></span>°</h1> | |
<ul data-bind="foreach: forecast"> | |
<li><span class="day" data-bind="text: $data['date']['weekday_short']"></span> | |
<span data-bind="text: $data['high']['fahrenheit']"></span>/ | |
<span data-bind="text: $data['low']['fahrenheit']"></span> | |
<span data-bind="text: $data['conditions']"></span> | |
</li> | |
</ul> | |
</div> | |
<div id="weather" class="widget widget-1x1 rowend" data-bind="style: { backgroundImage: weatherImage }"> | |
</div> | |
<div class="widget widget-4x2" data-bind="visible: $root.isTrelloAuthorized() == false, click: updateTrelloInfo">Click to authorize Trello</div> | |
<!-- ko if:isTrelloAuthorized --> | |
<!-- ko foreach:{data:statusListNames, afterAdd:flyIn} --> | |
<div class="widget widget-1x2 trello"> | |
<div class="trello-listname"> | |
<ul class="colors" data-bind="foreach: { data: $root.labelsForList($data), as: 'color' }"> | |
<li data-bind="style: { backgroundColor: color }"></li> | |
</ul> | |
<span data-bind="text: $data.name"></span> | |
</div> | |
<ul data-bind="foreach: $root.cardsForList($data)"> | |
<li> | |
<ul class="colors" data-bind="foreach: labels"> | |
<li data-bind="style: { backgroundColor: color }"></li> | |
</ul> | |
<div data-bind="text: name"></div> | |
</li> | |
</ul> | |
</div> | |
<!-- /ko --> | |
<!-- /ko --> | |
<div id="else" class="widget widget-1x1 rowend"></div> | |
<div id="e" class="widget widget-1x1 rowend"></div> | |
</div> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.0.2/jquery.min.js"></script> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js"></script> | |
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/knockout-min.js"></script> | |
<script type="text/javascript"> | |
document.writeln(' <script type="text/javascript" src="//api.trello.com/1/client.js?key=' + window.trelloApiKey + '"></s' + 'cript>'); | |
function drawGauge(canvasId, color1, color2, lineWidth, min, max, value) { | |
var canvas = document.getElementById(canvasId); | |
var context = canvas.getContext("2d"); | |
var path = getGaugeArc(min, max, value); | |
context.beginPath(); | |
context.lineWidth = lineWidth; | |
context.strokeStyle = color1; | |
context.arc(181.5, 181.5, 130, path.startAngle, path.midAngle); | |
context.stroke(); | |
context.beginPath(); | |
context.strokeStyle = color2; | |
context.arc(181.5, 181.5, 130, path.midAngle, path.endAngle); | |
context.stroke(); | |
} | |
function getGaugeArc(min, max, value) { | |
var mid = 0; | |
if (max != value) mid = (Math.PI) + ((value / (max - min)) * Math.PI); | |
return { | |
startAngle: Math.PI, | |
midAngle: mid, | |
endAngle: 0 | |
}; | |
} | |
function ViewModel() { | |
var self = this; | |
//chat | |
this.currentMessageIndex = ko.observable(0); | |
this.messages = ko.observableArray([]); | |
this.currentMessage = ko.computed(function () { | |
if (self.messages().length == 0) return ''; | |
return self.messages()[self.currentMessageIndex()]; | |
}); | |
this.rotateMessages = function () { | |
var next = self.currentMessageIndex() + 1; | |
if (next >= self.messages().length) next = 0; | |
self.currentMessageIndex(next); | |
}; | |
//time | |
this.time = ko.observable('12:59'); | |
this.ampm = ko.observable('PM'); | |
this.dayname = ko.observable('Friday'); | |
this.date = ko.observable('12 Jun 99'); | |
this.updateTime = function () { | |
var now = moment(); | |
self.time(now.format('h:mm')); | |
self.ampm(now.format('a')); | |
self.dayname(now.format('dddd')); | |
self.date(now.format('MMM Do YYYY')); | |
}; | |
//weather | |
this.weatherImageUrl = window.weatherImageUrl; | |
this.weatherImage = ko.observable(''); | |
this.currentTemp = ko.observable(98); | |
this.forecast = ko.observableArray([]); | |
this.loTemp = ko.observable(0); | |
this.updateWeather = function () { | |
self.weatherImage('url(' + self.weatherImageUrl + new Date().getTime() + ')'); | |
if (window.wundergroundApiKey == '') return; | |
$.ajax({ | |
url: "http://api.wunderground.com/api/" + window.wundergroundApiKey + "/geolookup/conditions/q/" + window.wundergroundApiLocation, | |
dataType: "jsonp", | |
success: function (parsed_json) { | |
var temp_f = parsed_json['current_observation']['temp_f']; | |
self.currentTemp(temp_f); | |
} | |
}); | |
$.ajax({ | |
url: "http://api.wunderground.com/api/" + window.wundergroundApiKey + "/forecast/q/" + window.wundergroundApiLocation, | |
dataType: "jsonp", | |
success: function (parsed_json) { | |
var forecast = parsed_json['forecast']['simpleforecast']['forecastday']; | |
self.forecast(forecast); | |
} | |
}); | |
}; | |
//sites | |
this.sitesDownCount = ko.observable(0); | |
this.sitesUpCount = ko.observable(0); | |
this.sitesDownNames = ko.observable(['']); | |
this.anySitesDown = ko.computed(function () { | |
return self.sitesDownCount() > 0; | |
}); | |
this.updateSitesCount = function () { | |
if (window.statusCakeUser == '') return; | |
$.getJSON("http://query.yahooapis.com/v1/public/yql", | |
{ | |
q: 'select * from json where url=\"https://www.statuscake.com/API/Tests?Username=' + window.statusCakeUser + '&API=' + window.statusCakeApiKey + '\"', | |
format: "json" | |
}, | |
function(data) { | |
if (data.query.results) { | |
data = data.query.results.json.json; | |
var downSites = data.filter(function (o) { return o.Status == "Down" && o.Paused == false; }); | |
self.sitesDownCount(downSites.length); | |
self.sitesUpCount(data.filter(function (o) { return o.Status == "Up"; }).length); | |
var totalSites = self.sitesDownCount() + self.sitesUpCount(); | |
drawGauge('sitesChart', '#00ff00', '#ff0000', 70, 0, totalSites, self.sitesUpCount()); | |
var downSiteNames = []; | |
downSites.forEach(function (o) { | |
downSiteNames.push(o.WebsiteName); | |
}); | |
self.sitesDownNames(downSiteNames); | |
} | |
}); | |
}; | |
//trello | |
this.statusBoard = ko.observable({}); | |
this.statusListNames = ko.computed(function () { | |
if (self.statusBoard() == null) return []; | |
var allLists = self.statusBoard().lists; | |
if (allLists == null) return []; | |
return allLists.filter(function (o) { return o.name != 'About'; }); | |
}); | |
this.cardsForList = function (list) { | |
if (self.statusBoard() == null) return []; | |
var allCards = self.statusBoard().cards; | |
if (allCards == null) return []; | |
return allCards.filter(function (o) { return o.idList == list.id; }); | |
}; | |
this.labelsForList = function (list) { | |
if (self.statusBoard() == null) return []; | |
var cards = self.cardsForList(list); | |
if (cards == null) return []; | |
if (cards.length == 0) return []; | |
var uniqueLabels = []; | |
cards.forEach(function (e) { | |
if (e.labels == null || e.labels.length == 0) return; | |
e.labels.forEach(function (l) { | |
if (uniqueLabels.indexOf(l.color) == -1) { | |
uniqueLabels.push(l.color); | |
} | |
}); | |
}); | |
console.log(list.name + ' ' + uniqueLabels.length); | |
return uniqueLabels; | |
}; | |
this.isTrelloAuthorized = ko.observable(false); | |
this.updateTrelloInfo = function () { | |
Trello.authorize({ | |
expiration: 'never', | |
type: 'redirect', | |
name: 'Status Board', | |
persist: true, | |
success: function () { | |
self.isTrelloAuthorized(true); | |
Trello.boards.get(window.trelloBoardId, { cards: 'open', lists: 'open', list_fields: 'name' }, function (board) { | |
self.statusBoard(board); | |
}); | |
}, | |
error: function () { | |
self.isTrelloAuthorized(false); | |
} | |
}); | |
}; | |
this.flyIn = function (e) { | |
$(e).fadeIn('slow'); | |
}; | |
//common | |
this.minute = 60000; | |
this.hour = 3600000; | |
this.poll = function (func, interval) { | |
func(); | |
return window.setInterval(func, interval); | |
}; | |
//Initialize | |
this.poll(this.updateTime, this.minute); | |
this.poll(this.updateWeather, this.hour); | |
this.poll(this.updateSitesCount, this.minute * 5); | |
this.poll(this.updateTrelloInfo, this.minute * 5); | |
// this.initializeChat(); | |
this.poll(this.rotateMessages, this.minute * 0.5); | |
} | |
$(function() { | |
var model = new ViewModel(); | |
ko.applyBindings(model); | |
}); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This gist contains everything you need to stand up a page that shows time, StatusCake, Weather Underground, and Trello information. To learn more, check out http://leanpub.com/trellodojo