Skip to content

Instantly share code, notes, and snippets.

@danroot danroot/index.html
Last active Jun 1, 2016

Embed
What would you like to do?
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
<!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&centerx=400&centery=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>&nbsp<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>&deg;</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>
@danroot

This comment has been minimized.

Copy link
Owner Author

danroot commented Nov 24, 2013

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.