github login using firebase

This commit is contained in:
Radek Stepan 2014-08-30 10:17:46 -07:00
parent c4cc413d26
commit 7eb7a29ef7
19 changed files with 789 additions and 10406 deletions

View File

@ -3,11 +3,15 @@ module.exports = (grunt) ->
pkg: grunt.file.readJSON("package.json") pkg: grunt.file.readJSON("package.json")
apps_c: apps_c:
loader:
dest: 'public/js/commonjs.js'
commonjs: commonjs:
src: [ 'src/**/*.{coffee,mustache}' ] src: [ 'src/**/*.{coffee,js,json,mustache}' ]
dest: 'build/app.js' dest: 'public/js/app.js'
options: options:
main: 'src/app.coffee' main: 'src/app.coffee'
loader: no
stylus: stylus:
compile: compile:
@ -16,22 +20,22 @@ module.exports = (grunt) ->
'src/styles/icons.styl' 'src/styles/icons.styl'
'src/styles/app.styl' 'src/styles/app.styl'
] ]
dest: 'build/app.css' dest: 'public/css/app.css'
concat: concat:
scripts: scripts:
src: [ src: [
# CommonJS loader.
'public/js/commonjs.js'
# Vendor dependencies. # Vendor dependencies.
'vendor/jquery/jquery.js'
'vendor/lodash/dist/lodash.js' 'vendor/lodash/dist/lodash.js'
'vendor/async/lib/async.js'
'vendor/ractive/ractive.js' 'vendor/ractive/ractive.js'
'vendor/firebase/lib/firebase.js' 'vendor/firebase/firebase.js'
'vendor/firebase-simple-login/firebase-simple-login.js' 'vendor/firebase-simple-login/firebase-simple-login.js'
# Our app. # Our app.
'build/app.js' 'public/js/app.js'
] ]
dest: 'build/app.bundle.js' dest: 'public/js/app.bundle.js'
options: options:
separator: ';' # for minification purposes separator: ';' # for minification purposes
@ -40,21 +44,21 @@ module.exports = (grunt) ->
# Vendor dependencies. # Vendor dependencies.
'vendor/normalize-css/normalize.css' 'vendor/normalize-css/normalize.css'
# Our style. # Our style.
'build/app.css' 'public/css/app.css'
] ]
dest: 'build/app.bundle.css' dest: 'public/css/app.bundle.css'
uglify: uglify:
scripts: scripts:
files: files:
'build/app.min.js': 'build/app.js' 'public/js/app.min.js': 'public/js/app.js'
'build/app.bundle.min.js': 'build/app.bundle.js' 'public/js/app.bundle.min.js': 'public/js/app.bundle.js'
cssmin: cssmin:
combine: combine:
files: files:
'build/app.min.css': 'build/app.css' 'public/css/app.min.css': 'public/css/app.css'
'build/app.bundle.min.css': 'build/app.bundle.css' 'public/css/app.bundle.min.css': 'public/css/app.bundle.css'
grunt.loadNpmTasks('grunt-apps-c') grunt.loadNpmTasks('grunt-apps-c')
grunt.loadNpmTasks('grunt-contrib-stylus') grunt.loadNpmTasks('grunt-contrib-stylus')

View File

@ -11,4 +11,7 @@ watch:
serve: serve:
cd public; python -m SimpleHTTPServer 8000 cd public; python -m SimpleHTTPServer 8000
deploy:
firebase deploy
.PHONY: build .PHONY: build

View File

@ -2,8 +2,6 @@
"name": "burnchart", "name": "burnchart",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"async": "0.2.5",
"jquery": "2.0.3",
"lodash": "2.3.0", "lodash": "2.3.0",
"normalize-css": "2.1.3", "normalize-css": "2.1.3",
"ractive": "~0.5.5", "ractive": "~0.5.5",

9
firebase.json Normal file
View File

@ -0,0 +1,9 @@
{
"firebase": "burnchart",
"public": "public",
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}

View File

@ -1 +0,0 @@
../build/app.bundle.css

View File

@ -1 +0,0 @@
../build/app.bundle.js

View File

@ -405,9 +405,9 @@ table {
border-spacing: 0; border-spacing: 0;
} }
@font-face{font-family:'MuseoSlab500Regular';src:url("fonts/museo-slab-500.eot");src:url("fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'),url("fonts/museo-slab-500.woff") format('woff'),url("fonts/museo-slab-500.ttf") format('truetype'),url("fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'MuseoSlab500Regular';src:url("../fonts/museo-slab-500.eot");src:url("../fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'),url("../fonts/museo-slab-500.woff") format('woff'),url("../fonts/museo-slab-500.ttf") format('truetype'),url("../fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg');font-weight:normal;font-style:normal}
@font-face{font-family:'MuseoSans500Regular';src:url("fonts/museo-sans-500.eot");src:url("fonts/museo-sans-500.eot?#iefix") format('embedded-opentype'),url("fonts/museo-sans-500.woff") format('woff'),url("fonts/museo-sans-500.ttf") format('truetype'),url("fonts/museo-sans-500.svg#MuseoSans500Regular") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'MuseoSans500Regular';src:url("../fonts/museo-sans-500.eot");src:url("../fonts/museo-sans-500.eot?#iefix") format('embedded-opentype'),url("../fonts/museo-sans-500.woff") format('woff'),url("../fonts/museo-sans-500.ttf") format('truetype'),url("../fonts/museo-sans-500.svg#MuseoSans500Regular") format('svg');font-weight:normal;font-style:normal}
@font-face{font-family:'Fontello';src:url("fonts/fontello.eot?74672344");src:url("fonts/fontello.eot?74672344#iefix") format('embedded-opentype'),url("fonts/fontello.woff?74672344") format('woff'),url("fonts/fontello.ttf?74672344") format('truetype'),url("fonts/fontello.svg?74672344#fontello") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'Fontello';src:url("../fonts/fontello.eot?74672344");src:url("../fonts/fontello.eot?74672344#iefix") format('embedded-opentype'),url("../fonts/fontello.woff?74672344") format('woff'),url("../fonts/fontello.ttf?74672344") format('truetype'),url("../fonts/fontello.svg?74672344#fontello") format('svg');font-weight:normal;font-style:normal}
.icon{vertical-align:middle;} .icon{vertical-align:middle;}
.icon:before{font-family:"Fontello";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none;line-height:1em} .icon:before{font-family:"Fontello";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none;line-height:1em}
@ -462,7 +462,7 @@ ul li{display:inline-block}
#title .milestone{font-size:16px;font-weight:bold;margin:0 20px} #title .milestone{font-size:16px;font-weight:bold;margin:0 20px}
#title .description{display:inline-block;font-family:'MuseoSlab500Regular',serif;color:#b1b6c4} #title .description{display:inline-block;font-family:'MuseoSlab500Regular',serif;color:#b1b6c4}
#content{padding:20px;margin-top:20px;} #content{padding:20px;margin-top:20px;}
#content #hero{background:url("img/hires/2.jpg") center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px;} #content #hero{background:url("../img/hires/2.jpg") center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px;}
#content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,0.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);} #content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,0.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);}
#content #hero .content h2{margin-bottom:20px;margin-left:140px} #content #hero .content h2{margin-bottom:20px;margin-left:140px}
#content #hero .content p{font-family:'MuseoSlab500Regular',serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word} #content #hero .content p{font-family:'MuseoSlab500Regular',serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word}

View File

@ -1,6 +1,6 @@
@font-face{font-family:'MuseoSlab500Regular';src:url("fonts/museo-slab-500.eot");src:url("fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'),url("fonts/museo-slab-500.woff") format('woff'),url("fonts/museo-slab-500.ttf") format('truetype'),url("fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'MuseoSlab500Regular';src:url("../fonts/museo-slab-500.eot");src:url("../fonts/museo-slab-500.eot?#iefix") format('embedded-opentype'),url("../fonts/museo-slab-500.woff") format('woff'),url("../fonts/museo-slab-500.ttf") format('truetype'),url("../fonts/museo-slab-500.svg#MuseoSlab500Regular") format('svg');font-weight:normal;font-style:normal}
@font-face{font-family:'MuseoSans500Regular';src:url("fonts/museo-sans-500.eot");src:url("fonts/museo-sans-500.eot?#iefix") format('embedded-opentype'),url("fonts/museo-sans-500.woff") format('woff'),url("fonts/museo-sans-500.ttf") format('truetype'),url("fonts/museo-sans-500.svg#MuseoSans500Regular") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'MuseoSans500Regular';src:url("../fonts/museo-sans-500.eot");src:url("../fonts/museo-sans-500.eot?#iefix") format('embedded-opentype'),url("../fonts/museo-sans-500.woff") format('woff'),url("../fonts/museo-sans-500.ttf") format('truetype'),url("../fonts/museo-sans-500.svg#MuseoSans500Regular") format('svg');font-weight:normal;font-style:normal}
@font-face{font-family:'Fontello';src:url("fonts/fontello.eot?74672344");src:url("fonts/fontello.eot?74672344#iefix") format('embedded-opentype'),url("fonts/fontello.woff?74672344") format('woff'),url("fonts/fontello.ttf?74672344") format('truetype'),url("fonts/fontello.svg?74672344#fontello") format('svg');font-weight:normal;font-style:normal} @font-face{font-family:'Fontello';src:url("../fonts/fontello.eot?74672344");src:url("../fonts/fontello.eot?74672344#iefix") format('embedded-opentype'),url("../fonts/fontello.woff?74672344") format('woff'),url("../fonts/fontello.ttf?74672344") format('truetype'),url("../fonts/fontello.svg?74672344#fontello") format('svg');font-weight:normal;font-style:normal}
.icon{vertical-align:middle;} .icon{vertical-align:middle;}
.icon:before{font-family:"Fontello";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none;line-height:1em} .icon:before{font-family:"Fontello";font-style:normal;font-weight:normal;speak:none;display:inline-block;text-decoration:inherit;text-align:center;font-variant:normal;text-transform:none;line-height:1em}
@ -55,7 +55,7 @@ ul li{display:inline-block}
#title .milestone{font-size:16px;font-weight:bold;margin:0 20px} #title .milestone{font-size:16px;font-weight:bold;margin:0 20px}
#title .description{display:inline-block;font-family:'MuseoSlab500Regular',serif;color:#b1b6c4} #title .description{display:inline-block;font-family:'MuseoSlab500Regular',serif;color:#b1b6c4}
#content{padding:20px;margin-top:20px;} #content{padding:20px;margin-top:20px;}
#content #hero{background:url("img/hires/2.jpg") center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px;} #content #hero{background:url("../img/hires/2.jpg") center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-webkit-border-radius:2px;border-radius:2px;margin-bottom:30px;}
#content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,0.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);} #content #hero .content{-webkit-border-radius:2px;border-radius:2px;color:#fff;padding:30px;background:rgba(0,0,0,0.3);-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);box-shadow:inset 0 1px 2px rgba(0,0,0,0.2);}
#content #hero .content h2{margin-bottom:20px;margin-left:140px} #content #hero .content h2{margin-bottom:20px;margin-left:140px}
#content #hero .content p{font-family:'MuseoSlab500Regular',serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word} #content #hero .content p{font-family:'MuseoSlab500Regular',serif;font-size:18px;line-height:24px;margin-left:140px;text-align:justify;text-justify:inter-word}

View File

@ -3,15 +3,14 @@
<head> <head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> <meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link rel="stylesheet" type="text/css" href="app.bundle.css"> <link rel="stylesheet" type="text/css" href="css/app.bundle.css">
<script src="app.bundle.js"></script> <script src="js/app.bundle.js"></script>
</head>
<body>
<script> <script>
$(function() {
var app = require('burnchart'); var app = require('burnchart');
app.render('body'); app.render('body');
});
</script> </script>
</head> </body>
<body></body>
</html> </html>

File diff suppressed because it is too large Load Diff

View File

@ -1,208 +1,3 @@
// A standalone CommonJS loader.
(function(root) {
/**
* Require the given path.
*
* @param {String} path
* @return {Object} exports
* @api public
*/
var require = function(path, parent, orig) {
var resolved = require.resolve(path);
// lookup failed
if (!resolved) {
orig = orig || path;
parent = parent || 'root';
var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
err.path = orig;
err.parent = parent;
err.require = true;
throw err;
}
var module = require.modules[resolved];
// perform real require()
// by invoking the module's
// registered function
if (!module._resolving && !module.exports) {
var mod = {};
mod.exports = {};
mod.client = mod.component = true;
module._resolving = true;
module.call(this, mod.exports, require.relative(resolved), mod);
delete module._resolving;
module.exports = mod.exports;
}
return module.exports;
};
/**
* Registered modules.
*/
require.modules = {};
/**
* Registered aliases.
*/
require.aliases = {};
/**
* Resolve `path`.
*
* Lookup:
*
* - PATH/index.js
* - PATH.js
* - PATH
*
* @param {String} path
* @return {String} path or null
* @api private
*/
require.resolve = function(path) {
if (path.charAt(0) === '/') path = path.slice(1);
var paths = [
path,
path + '.js',
path + '.json',
path + '/index.js',
path + '/index.json'
];
for (var i = 0; i < paths.length; i++) {
path = paths[i];
if (require.modules.hasOwnProperty(path)) return path;
if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
}
};
/**
* Normalize `path` relative to the current path.
*
* @param {String} curr
* @param {String} path
* @return {String}
* @api private
*/
require.normalize = function(curr, path) {
var segs = [];
if ('.' != path.charAt(0)) return path;
curr = curr.split('/');
path = path.split('/');
for (var i = 0; i < path.length; ++i) {
if ('..' == path[i]) {
curr.pop();
} else if ('.' !== path[i] && '' !== path[i]) {
segs.push(path[i]);
}
}
return curr.concat(segs).join('/');
};
/**
* Register module at `path` with callback `definition`.
*
* @param {String} path
* @param {Function} definition
* @api private
*/
require.register = function(path, definition) {
require.modules[path] = definition;
};
/**
* Alias a module definition.
*
* @param {String} from
* @param {String} to
* @api private
*/
require.alias = function(from, to) {
if (!require.modules.hasOwnProperty(from)) {
throw new Error('Failed to alias "' + from + '", it does not exist');
}
require.aliases[to] = from;
};
/**
* Return a require function relative to the `parent` path.
*
* @param {String} parent
* @return {Function}
* @api private
*/
require.relative = function(parent) {
var p = require.normalize(parent, '..');
/**
* lastIndexOf helper.
*/
function lastIndexOf(arr, obj) {
var i = arr.length;
while (i--) {
if (arr[i] === obj) return i;
}
return -1;
}
/**
* The relative require() itself.
*/
var localRequire = function(path) {
var resolved = localRequire.resolve(path);
return require(resolved, parent, path);
};
/**
* Resolve relative to the parent.
*/
localRequire.resolve = function(path) {
var c = path.charAt(0);
if ('/' == c) return path.slice(1);
if ('.' == c) return require.normalize(p, path);
// resolve deps by returning
// the dep in the nearest "deps"
// directory
var segs = parent.split('/');
var i = lastIndexOf(segs, 'deps') + 1;
if (!i) i = 0;
path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
return path;
};
/**
* Check if module is defined at `path`.
*/
localRequire.exists = function(path) {
return require.modules.hasOwnProperty(localRequire.resolve(path));
};
return localRequire;
};
// Do we already have require loader?
root.require = (typeof root.require !== 'undefined') ? root.require : require;
})(this);
// Concat modules and export them as an app. // Concat modules and export them as an app.
(function(root) { (function(root) {
@ -212,74 +7,100 @@
// app.coffee // app.coffee
root.require.register('burnchart/src/app.js', function(exports, require, module) { root.require.register('burnchart/src/app.js', function(exports, require, module) {
var App; var App, firebase;
firebase = require('./modules/firebase');
document.title = 'BurnChart: GitHub Burndown Chart as a Service'; document.title = 'BurnChart: GitHub Burndown Chart as a Service';
App = Ractive.extend({ App = Ractive.extend({
template: require('./templates/layout'), template: require('./templates/layout'),
init: function() {} init: function() {
return firebase.login(function(err) {
if (err) {
throw err;
}
});
}
}); });
module.exports = new App(); module.exports = new App();
}); });
// firebase.coffee // config.json
root.require.register('burnchart/src/components/firebase.js', function(exports, require, module) { root.require.register('burnchart/src/models/config.js', function(exports, require, module) {
var authCb, state, user; module.exports = {
"firebase": "burnchart",
"provider": "github"
};
});
// firebase.coffee
root.require.register('burnchart/src/modules/firebase.js', function(exports, require, module) {
var FB, authCb, config, user;
config = require('../models/config');
user = require('./user'); user = require('./user');
state = require('../modules/state');
authCb = function() {}; authCb = function() {};
module.exports = new can.Map({ FB = (function() {
setClient: function(root, success, error) { function FB() {
var client; console.log('Init Firebase');
client = new Firebase("https://" + root + ".firebaseio.com"); this.client = new Firebase("https://" + config.firebase + ".firebaseio.com");
state.load('Loading'); this.auth = new FirebaseSimpleLogin(this.client, function(err, obj) {
this.attr('auth', new FirebaseSimpleLogin(client, function(err, obj) {
if (err || !obj) { if (err || !obj) {
if (!obj) {
state.none();
}
return authCb(err); return authCb(err);
} }
user(obj); user.set(obj);
state.info("" + obj.displayName + " is logged in"); return console.log("" + obj.displayName + " is logged in");
return authCb(); });
}));
return client;
},
login: function(cb, provider) {
if (provider == null) {
provider = 'github';
} }
FB.prototype.login = function(cb) {
if (!this.client) { if (!this.client) {
return cb('Client is not setup'); return cb('Client is not setup');
} }
authCb = cb; authCb = cb;
state.load('Connecting GitHub account'); console.log('Connecting GitHub account');
return this.auth.login(provider, { return this.auth.login(config.provider, {
'rememberMe': true, 'rememberMe': true,
'scope': 'public_repo' 'scope': 'public_repo'
}); });
}, };
logout: function() {
FB.prototype.logout = function() {
var _ref; var _ref;
if ((_ref = this.auth) != null) { if ((_ref = this.auth) != null) {
_ref.logout(); _ref.logout;
}
user({});
return state.info('You have logged out');
},
signup: function(data, cb) {
console.log(data);
return cb(null);
} }
user.reset();
return console.log('You have logged out');
};
return FB;
})();
module.exports = new FB();
});
// user.coffee
root.require.register('burnchart/src/modules/user.js', function(exports, require, module) {
var user;
module.exports = user = new Ractive();
user.render();
user.observe('*', function() {
return console.log('User', arguments);
}); });
}); });

205
public/js/commonjs.js Normal file
View File

@ -0,0 +1,205 @@
// A standalone CommonJS loader.
(function(root) {
/**
* Require the given path.
*
* @param {String} path
* @return {Object} exports
* @api public
*/
var require = function(path, parent, orig) {
var resolved = require.resolve(path);
// lookup failed
if (!resolved) {
orig = orig || path;
parent = parent || 'root';
var err = new Error('Failed to require "' + orig + '" from "' + parent + '"');
err.path = orig;
err.parent = parent;
err.require = true;
throw err;
}
var module = require.modules[resolved];
// perform real require()
// by invoking the module's
// registered function
if (!module._resolving && !module.exports) {
var mod = {};
mod.exports = {};
mod.client = mod.component = true;
module._resolving = true;
module.call(this, mod.exports, require.relative(resolved), mod);
delete module._resolving;
module.exports = mod.exports;
}
return module.exports;
};
/**
* Registered modules.
*/
require.modules = {};
/**
* Registered aliases.
*/
require.aliases = {};
/**
* Resolve `path`.
*
* Lookup:
*
* - PATH/index.js
* - PATH.js
* - PATH
*
* @param {String} path
* @return {String} path or null
* @api private
*/
require.resolve = function(path) {
if (path.charAt(0) === '/') path = path.slice(1);
var paths = [
path,
path + '.js',
path + '.json',
path + '/index.js',
path + '/index.json'
];
for (var i = 0; i < paths.length; i++) {
path = paths[i];
if (require.modules.hasOwnProperty(path)) return path;
if (require.aliases.hasOwnProperty(path)) return require.aliases[path];
}
};
/**
* Normalize `path` relative to the current path.
*
* @param {String} curr
* @param {String} path
* @return {String}
* @api private
*/
require.normalize = function(curr, path) {
var segs = [];
if ('.' != path.charAt(0)) return path;
curr = curr.split('/');
path = path.split('/');
for (var i = 0; i < path.length; ++i) {
if ('..' == path[i]) {
curr.pop();
} else if ('.' !== path[i] && '' !== path[i]) {
segs.push(path[i]);
}
}
return curr.concat(segs).join('/');
};
/**
* Register module at `path` with callback `definition`.
*
* @param {String} path
* @param {Function} definition
* @api private
*/
require.register = function(path, definition) {
require.modules[path] = definition;
};
/**
* Alias a module definition.
*
* @param {String} from
* @param {String} to
* @api private
*/
require.alias = function(from, to) {
if (!require.modules.hasOwnProperty(from)) {
throw new Error('Failed to alias "' + from + '", it does not exist');
}
require.aliases[to] = from;
};
/**
* Return a require function relative to the `parent` path.
*
* @param {String} parent
* @return {Function}
* @api private
*/
require.relative = function(parent) {
var p = require.normalize(parent, '..');
/**
* lastIndexOf helper.
*/
function lastIndexOf(arr, obj) {
var i = arr.length;
while (i--) {
if (arr[i] === obj) return i;
}
return -1;
}
/**
* The relative require() itself.
*/
var localRequire = function(path) {
var resolved = localRequire.resolve(path);
return require(resolved, parent, path);
};
/**
* Resolve relative to the parent.
*/
localRequire.resolve = function(path) {
var c = path.charAt(0);
if ('/' == c) return path.slice(1);
if ('.' == c) return require.normalize(p, path);
// resolve deps by returning
// the dep in the nearest "deps"
// directory
var segs = parent.split('/');
var i = lastIndexOf(segs, 'deps') + 1;
if (!i) i = 0;
path = segs.slice(0, i + 1).join('/') + '/deps/' + path;
return path;
};
/**
* Check if module is defined at `path`.
*/
localRequire.exists = function(path) {
return require.modules.hasOwnProperty(localRequire.resolve(path));
};
return localRequire;
};
// Do we already have require loader?
root.require = (typeof root.require !== 'undefined') ? root.require : require;
})(this);

View File

@ -1,3 +1,5 @@
firebase = require './modules/firebase'
document.title = 'BurnChart: GitHub Burndown Chart as a Service' document.title = 'BurnChart: GitHub Burndown Chart as a Service'
App = Ractive.extend App = Ractive.extend
@ -5,5 +7,8 @@ App = Ractive.extend
template: require './templates/layout' template: require './templates/layout'
init: -> init: ->
# Login user.
firebase.login (err) ->
throw err if err
module.exports = new App() module.exports = new App()

View File

@ -1,3 +1,4 @@
{ {
"firebase": "burnchart-app" "firebase": "burnchart",
"provider": "github"
} }

View File

@ -1,62 +1,43 @@
config = require '../models/config' config = require '../models/config'
user = require './user' user = require './user'
state = require '../modules/state'
# Default "silent" callback for auth. # Default "silent" callback for auth.
authCb = -> authCb = ->
# New client. class FB
firebase.attr 'client', opts.firebase
module.exports = new can.Map constructor: ->
console.log 'Init Firebase'
# Ref server. # Setup a new client.
setClient: (root, success, error) -> @client = new Firebase "https://#{config.firebase}.firebaseio.com"
# Create a new instance pointing to a root.
client = new Firebase "https://#{root}.firebaseio.com"
# Check if we have a user in session. # Check if we have a user in session.
state.load 'Loading' @auth = new FirebaseSimpleLogin @client, (err, obj) ->
@attr 'auth', new FirebaseSimpleLogin client, (err, obj) ->
if err or not obj if err or not obj
do state.none unless obj
return authCb err return authCb err
# Save user in memory. # Save user.
user obj user.set obj
state.info "#{obj.displayName} is logged in" console.log "#{obj.displayName} is logged in"
# Call back.
do authCb
client
# Login a user. # Login a user.
login: (cb, provider='github') -> login: (cb) ->
return cb 'Client is not setup' unless @client return cb 'Client is not setup' unless @client
# Override the default auth callback. # Override the default auth callback.
authCb = cb authCb = cb
# Login. # Login.
state.load 'Connecting GitHub account' console.log 'Connecting GitHub account'
@auth.login provider, @auth.login config.provider,
# 30 days.
'rememberMe': yes 'rememberMe': yes
# See: http://developer.github.com/v3/oauth/#scopes
# TODO: access private repos as well
'scope': 'public_repo' 'scope': 'public_repo'
# Logout a user. # Logout a user.
logout: -> logout: ->
do @auth?.logout @auth?.logout
user {} do user.reset
# TODO: fixme console.log 'You have logged out'
state.info 'You have logged out'
# Signup a new account. module.exports = new FB()
signup: (data, cb) ->
console.log data
cb null

View File

@ -1,40 +0,0 @@
# Timeout in ms.
ms = 3e3
update = (text, type) ->
switch type
when 'load'
text += '<span class="icon spin6"></span>'
@
.attr('text', text)
.attr('type', type)
module.exports = State = new can.Map
# HTML text.
text: null
# none/load/info/warn
type: 'none'
load: _.partialRight update, 'load'
info: _.partialRight update, 'info'
warn: _.partialRight update, 'warn'
none: ->
@attr 'type', 'none'
timeout = null
# Hide in 3s unless it is an alert or we are loading.
State.bind 'type', (ev, newVal, oldVal) ->
clearTimeout timeout
# Skip?
return if newVal in [ 'warn', 'load' ]
# Hide.
setTimeout =>
@attr 'type', 'none'
, ms

View File

@ -1,7 +1,8 @@
# Currently logged-in user. # Currently logged-in user.
module.exports = user = can.compute({ }) module.exports = user = new Ractive()
user.bind 'change', (ev, obj) ->
mixpanel.people.set # Init now.
'$email': obj.email do user.render
'name': obj.displayName
mixpanel.identify obj.username user.observe '*', ->
console.log 'User', arguments

View File

@ -124,7 +124,7 @@ ul
margin-top: 20px margin-top: 20px
#hero #hero
background: url('img/hires/2.jpg') center background: url('../img/hires/2.jpg') center
background-size: cover background-size: cover
border-radius: 2px border-radius: 2px
margin-bottom: 30px margin-bottom: 30px

View File

@ -1,32 +1,32 @@
@font-face { @font-face {
font-family: 'MuseoSlab500Regular'; font-family: 'MuseoSlab500Regular';
src: url('fonts/museo-slab-500.eot'); src: url('../fonts/museo-slab-500.eot');
src: url('fonts/museo-slab-500.eot?#iefix') format('embedded-opentype'), src: url('../fonts/museo-slab-500.eot?#iefix') format('embedded-opentype'),
url('fonts/museo-slab-500.woff') format('woff'), url('../fonts/museo-slab-500.woff') format('woff'),
url('fonts/museo-slab-500.ttf') format('truetype'), url('../fonts/museo-slab-500.ttf') format('truetype'),
url('fonts/museo-slab-500.svg#MuseoSlab500Regular') format('svg'); url('../fonts/museo-slab-500.svg#MuseoSlab500Regular') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'MuseoSans500Regular'; font-family: 'MuseoSans500Regular';
src: url('fonts/museo-sans-500.eot'); src: url('../fonts/museo-sans-500.eot');
src: url('fonts/museo-sans-500.eot?#iefix') format('embedded-opentype'), src: url('../fonts/museo-sans-500.eot?#iefix') format('embedded-opentype'),
url('fonts/museo-sans-500.woff') format('woff'), url('../fonts/museo-sans-500.woff') format('woff'),
url('fonts/museo-sans-500.ttf') format('truetype'), url('../fonts/museo-sans-500.ttf') format('truetype'),
url('fonts/museo-sans-500.svg#MuseoSans500Regular') format('svg'); url('../fonts/museo-sans-500.svg#MuseoSans500Regular') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }
@font-face { @font-face {
font-family: 'Fontello'; font-family: 'Fontello';
src: url('fonts/fontello.eot?74672344'); src: url('../fonts/fontello.eot?74672344');
src: url('fonts/fontello.eot?74672344#iefix') format('embedded-opentype'), src: url('../fonts/fontello.eot?74672344#iefix') format('embedded-opentype'),
url('fonts/fontello.woff?74672344') format('woff'), url('../fonts/fontello.woff?74672344') format('woff'),
url('fonts/fontello.ttf?74672344') format('truetype'), url('../fonts/fontello.ttf?74672344') format('truetype'),
url('fonts/fontello.svg?74672344#fontello') format('svg'); url('../fonts/fontello.svg?74672344#fontello') format('svg');
font-weight: normal; font-weight: normal;
font-style: normal; font-style: normal;
} }