Defite
3/5/2014 - 2:42 PM

Gruntfile.js

<!doctype html>
<!--[if lt IE 7]>      <html class="lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]>         <html class="lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]>         <html class="lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html> <!--<![endif]-->
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <title><%= _.capitalize(blogName) %></title>
  <link rel="stylesheet" href="bower_components/showup/showup.css">
</head>
<body>
  <!--[if lt IE 7]>
    <p class="chromeframe">You are using an <strong>outdated</strong> browser. Please <a href="http://browsehappy.com/">upgrade your browser</a> or <a href="http://www.google.com/chromeframe/?redirect=true">activate Google Chrome Frame</a> to improve your experience.</p>
  <![endif]-->
  <div class="gutter"></div>
  <div class="container"></div>
  <script src="bower_components/showdown/compressed/showdown.js"></script>
  <script src="bower_components/showup/showup.js"></script>
  <script>
    Showup.init({
      posts: 'posts/',
      wordmap: 'wordmap.json',
      gutter: document.querySelector('.gutter'),
      container: document.querySelector('.container')
    });
  </script>
</body>
</html>
{
  "directory": "bower_components"
}
{
  "name": "<%= _.slugify(blogName) %>",
  "private": true,
  "devDependencies": {
    "grunt": "~0.4.1",
    "bower": "~0.9.2",
    "grunt-contrib-connect": "~0.2.0",
    "grunt-contrib-watch": "~0.4.3",
    "grunt-open": "~0.2.0",
    "matchdep": "~0.1.2",
    "connect-livereload": "~0.1.3",
    "moment": "~2.0.0"
  },
  "engines": {
    "node": ">=0.8.0"
  }
}

<%= blogName %>

Create a post!

From the terminal, pop in:

yo weblog:post

{
  "name": "<%= blogName %>"
}
{
  "name": "<%= _.slugify(blogName) %>",
  "version": "0.0.0",
  "dependencies": {
    "showup": "~0.0.2"
  }
}
// Generated on <%= (new Date).toISOString().split('T')[0] %> using <%= pkg.name %> <%= pkg.version %>
'use strict';
var moment = require('moment');

var LIVERELOAD_PORT = 35729;
var lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT});
var mountFolder = function (connect, dir) {
  return connect.static(require('path').resolve(dir));
};

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

  grunt.initConfig({
    watch: {
      options: {
        nospawn: true,
        livereload: LIVERELOAD_PORT
      },
      livereload: {
        files: [
          'index.html',
          'posts/*.md'
        ],
        tasks: ['build']
      }
    },
    connect: {
      options: {
        port: 9000,
        // change this to '0.0.0.0' to access the server from outside
        hostname: 'localhost'
      },
      livereload: {
        options: {
          middleware: function (connect) {
            return [
              lrSnippet,
              mountFolder(connect, '.')
            ];
          }
        }
      }
    },
    open: {
      server: {
        path: 'http://localhost:<%%= connect.options.port %>'
      }
    }
  });

  grunt.registerTask('server', ['build', 'connect:livereload', 'open', 'watch']);

  grunt.registerTask('build', 'Build your blog.', function () {
    var words = [];
    var posts = [];

    var ignoredWords = [
      'the', 'couldn\'t', 'you\'re', 'you\'ve', 'just', 'something', 'some',
      'thing', 'um', 'ahh', 'ah', 'uh', 'if', 'out', 'at', 'no', 'with', 'had',
      'got', 'have', 'for', 'it\'s', 'that', 'that\'s', 'from', 'in', 'a', 'of',
      'them', 'you', 'his', 'her', 'their', 'there', 'how', 'what', 'why',
      'who', 'when', 'i', 'went', 'to', 'they', 'you\'ll', 'welcome', 'are'
    ];

    var unslug = function (slug) {
      return slug.replace(/(-(\w))/g, function () { return ' ' + arguments[2].toUpperCase(); });
    };

    grunt.file.recurse('posts', function (post, root, sub, fileName) {
      if (fileName === 'index.md') {
        return;
      }

      var wordMap = {};

      posts.push(fileName.replace('.md', ''));
      words.push('id:' + fileName.replace('.md', ''));

      post = grunt.file.read(post)
        .toLowerCase()
        .trim()
        .replace(/\s+/gm, ' ');

      post.split(' ').forEach(function (word) {
        if (word.length > 5 && ignoredWords.indexOf(word) === -1) {
          if (wordMap[word]) {
            wordMap[word].count++;
          } else {
            wordMap[word] = {
              name: word,
              count: 1
            };
          }
        }
      });

      wordMap = grunt.util._.chain(wordMap).sortBy('count').reverse().value();

      var postWords = [];

      while (postWords.length < 10) {
        postWords.push(wordMap[postWords.length] && wordMap[postWords.length].name || '');
      }

      words.push(postWords);
    });

    words = grunt.util._.chain(words).flatten().reject(function (word) { return !word; }).value();

    grunt.file.write('wordmap.json', JSON.stringify(words));
    grunt.file.write('posts/index.md', function () {
      var file = '# ' + grunt.file.readJSON('config.json').name + '\n';
      var lastDate;

      posts.reverse().forEach(function (post) {
        var postDate = post.replace(/((\d*-\d*-\d*).*)/, '$2');
        var title = post.replace(postDate, '').replace(/\s+/g, ' ').trim();

        if (lastDate !== postDate) {
          file += '\n### ' + moment(postDate).format('dddd, MMMM Do, YYYY');
        }

        file += '\n#### [' + postDate + ' -' + unslug(title) + '](#' + postDate + title + ')';

        lastDate = postDate;
      });

      return file.trim();
    }());
  });
};