Skip to content

Commit

Permalink
Added node.js script to build out a site based on express that includ…
Browse files Browse the repository at this point in the history
…es the metro.css style and other niceties like less compilation etc.
  • Loading branch information
Chris Sainty committed Feb 12, 2012
1 parent a4eb952 commit 1cf19ad
Show file tree
Hide file tree
Showing 4 changed files with 371 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Original file line Diff line number Diff line change
@@ -1,2 +1,3 @@
less/*.css less/*.css
_site _site
node/node_modules
16 changes: 15 additions & 1 deletion README.md
Original file line number Original file line Diff line number Diff line change
@@ -1,3 +1,17 @@
As we'll be either pulling in parts of [Bootstrap](http://bootstrap.io) or at the very least aiming for that type of project, we're going to use [Less](http://lesscss.org/) which adds variables and other goodies into CSS. As we'll be either pulling in parts of [Bootstrap](http://bootstrap.io) or at the very least aiming for that type of project, we're going to use [Less](http://lesscss.org/) which adds variables and other goodies into CSS.


For those new to Less, it's worth checking out [SimpLESS](http://wearekiss.com/simpless) (which runs on all platforms) which watches and compiles Less into CSS. For those new to Less, it's worth checking out [SimpLESS](http://wearekiss.com/simpless) (which runs on all platforms) which watches and compiles Less into CSS.

### Node.js
Included in the `node` folder is a script for creating a template website using the metro.css theme in Node.js
With node installed on your system, run the following commands

`npm install`
`node metro <path>`
`cd <path>`
`npm install`
`node app.js`

Then point your browser at http://localhost:3000


338 changes: 338 additions & 0 deletions node/metro.js
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,338 @@
var fs = require('fs'),
os = require('os'),
mkdirp = require('mkdirp'),
ncp = require('ncp').ncp;

/**
* Framework version.
*/

var version = '0.0.1';

/**
* Usage documentation.
*/

var usage = ''
+ '\n'
+ ' Usage: node metro [options|path]\n'
+ '\n'
+ ' Options:\n'
+ ' -v, --version output framework version\n'
+ ' -h, --help output help information\n'
;

// Parse arguments

var args = process.argv.slice(2)
, path = '.';

while (args.length) {
var arg = args.shift();
switch (arg) {
case '-h':
case '--help':
abort(usage);
break;
case '-v':
case '--version':
abort(version);
break;
default:
path = arg;
}
}


/**
* End-of-line code.
*/

var eol = os.platform
? ('win32' == os.platform() ? '\r\n' : '\n')
: '\n';

/**
* Routes index template.
*/

var index = [
''
, '/*'
, ' * GET home page.'
, ' */'
, ''
, 'exports.index = function(req, res){'
, ' res.render(\'index\', { title: \'Metro.css\' })'
, '};'
].join(eol);

/**
* Jade layout template.
*/

var jadeLayout = [
'!!!'
, 'html'
, ' head'
, ' title= title'
, ' link(rel=\'stylesheet\', href=\'/css/metro.css\')'
, ' style'
, ' body { width: 800px; margin: 0 auto; }'
, ' script(type=\'text/javascript\', src=\'http://code.jquery.com/jquery-1.5.1.min.js\')'
, ' script(type=\'text/javascript\', src=\'/js/jquery.metro.js\')'
, ' body!= body'
].join(eol);

/**
* Jade index template.
*/

var jadeIndex = [
'h1= title'
, 'div.metro-pivot'
, ' div.pivot-item'
, ' h3 page one'
, ' p page one content'
, ' div.pivot-item'
, ' h3 page two'
, ' p page two content'
, ' div.pivot-item'
, ' h3 page three'
, ' p page three content'
, ' script'
, ' var defaults = {'
, ' animationDuration: 350,'
, ' headerOpacity: 0.25,'
, ' fixedHeaders: false,'
, ' headerSelector: function (item) { return item.children("h3").first(); },'
, ' itemSelector: function (item) { return item.children(".pivot-item"); },'
, ' headerItemTemplate: function () { return $("<span class=\'header\' />"); },'
, ' pivotItemTemplate: function () { return $("<div class=\'pivotItem\' />"); },'
, ' itemsTemplate: function () { return $("<div class=\'items\' />"); },'
, ' headersTemplate: function () { return $("<div class=\'headers\' />"); },'
, ' controlInitialized: undefined,'
, ' selectedItemChanged: undefined'
, ' };'
, ' $(function () {'
, ' $("div.metro-pivot").metroPivot(defaults);'
, ' });'
].join(eol);

/**
* App template.
*/

var app = [
''
, '/**'
, ' * Module dependencies.'
, ' */'
, ''
, 'var express = require(\'express\')'
, ' , routes = require(\'./routes\')'
, ' , less = require(\'less\')'
, ''
, 'var app = module.exports = express.createServer();'
, ''
, '// Hack connect.js to allow relative @import statements in less.js'
, 'express.compiler.compilers.less.compile = function(str, fn) {'
, ' try {'
, ' less.render(str, {paths: [__dirname + \'/public/css\']}, fn);'
, ' } catch (err) {'
, ' fn(err);'
, ' }'
, '};'
, ''
, '// Configuration'
, ''
, 'app.configure(function(){'
, ' app.set(\'views\', __dirname + \'/views\');'
, ' app.set(\'view engine\', \'jade\');'
, ' app.use(express.bodyParser());'
, ' app.use(express.methodOverride());'
, ' app.use(app.router);'
, ' app.use(express.compiler({ src: __dirname + \'/public\', enable: [\'less\']}));'
, ' app.use(express.static(__dirname + \'/public\'));'
, '});'
, ''
, 'app.configure(\'development\', function(){'
, ' app.use(express.errorHandler({ dumpExceptions: true, showStack: true })); '
, '});'
, ''
, 'app.configure(\'production\', function(){'
, ' app.use(express.errorHandler()); '
, '});'
, ''
, '// Routes'
, ''
, 'app.get(\'/\', routes.index);'
, ''
, 'app.listen(3000);'
, 'console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);'
, ''
].join(eol);

// Generate application

(function createApplication(path) {
emptyDirectory(path, function(empty){
if (empty) {
createApplicationAt(path);
} else {
confirm('destination is not empty, continue? ', function(ok){
if (ok) {
process.stdin.destroy();
createApplicationAt(path);
} else {
abort('aborting');
}
});
}
});
})(path);

/**
* Create application at the given directory `path`.
*
* @param {String} path
*/

function createApplicationAt(path) {
console.log();
process.on('exit', function(){
console.log();
console.log(' dont forget to install dependencies:');
console.log(' $ cd %s && npm install', path);
console.log();
});

mkdir(path, function(){
mkdir(path + '/public');
mkdir(path + '/public/js', function() {
copy('../scripts/jquery.metro.js', path + '/public/js/jquery.metro.js');
});
mkdir(path + '/public/img');
mkdir(path + '/public/css', function(){
ncp('../less', path + '/public/css', function() { });
});

mkdir(path + '/routes', function(){
write(path + '/routes/index.js', index);
});

mkdir(path + '/views', function(){
write(path + '/views/layout.jade', jadeLayout);
write(path + '/views/index.jade', jadeIndex);
});

// package.json
var json = '{' + eol;
json += ' "name": "application-name"' + eol;
json += ' , "version": "0.0.1"' + eol;
json += ' , "private": true' + eol;
json += ' , "dependencies": {' + eol;
json += ' "express": ">= 2.5.0"' + eol;
json += ' , "jade": ">= 0.20.1"' + eol;
json += ' , "less": ">= 1.2.0"' + eol;
json += ' }' + eol;
json += '}';

write(path + '/package.json', json);
write(path + '/app.js', app);
});
}

/**
* Check if the given directory `path` is empty.
*
* @param {String} path
* @param {Function} fn
*/

function emptyDirectory(path, fn) {
fs.readdir(path, function(err, files){
if (err && 'ENOENT' != err.code) throw err;
fn(!files || !files.length);
});
}

/**
* echo str > path.
*
* @param {String} path
* @param {String} str
*/

function write(path, str) {
fs.writeFile(path, str);
console.log(' \x1b[36mcreate\x1b[0m : ' + path);
}

/**
* Prompt confirmation with the given `msg`.
*
* @param {String} msg
* @param {Function} fn
*/

function confirm(msg, fn) {
prompt(msg, function(val){
fn(/^ *y(es)?/i.test(val));
});
}

/**
* Prompt input with the given `msg` and callback `fn`.
*
* @param {String} msg
* @param {Function} fn
*/

function prompt(msg, fn) {
// prompt
if (' ' == msg[msg.length - 1]) {
process.stdout.write(msg);
} else {
console.log(msg);
}

// stdin
process.stdin.setEncoding('ascii');
process.stdin.once('data', function(data){
fn(data);
}).resume();
}

/**
* Mkdir -p.
*
* @param {String} path
* @param {Function} fn
*/

function mkdir(path, fn) {
mkdirp(path, 0755, function(err){
if (err) throw err;
console.log(' \033[36mcreate\033[0m : ' + path);
fn && fn();
});
}

function copy(from, to, done) {
var fileFrom = fs.createReadStream(from);
var fileTo = fs.createWriteStream(to);
fileTo.on('end', done || function() { });
fileFrom.pipe(fileTo);
}

/**
* Exit with the given `str`.
*
* @param {String} str
*/

function abort(str) {
console.error(str);
process.exit(1);
}
16 changes: 16 additions & 0 deletions node/package.json
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "metro-css",
"description": "A website template with \"Metro\" styling.",
"version": "0.0.1",
"author": "Code 52",
"contributors": [
{ "name" : "Chris Sainty", "email": "csainty@hotmail.com" }
],
"dependencies": {
"mkdirp": ">= 0.3.0",
"ncp": ">= 0.2.4"
},
"repository": "git://github.com/Code52/metro.css.git",
"main": "metro",
"engines": { "node": ">= 0.4.1 < 0.7.0" }
}

0 comments on commit 1cf19ad

Please sign in to comment.