A blog platform written in JavaScript for developers, but with normal people in mind.
Go to file
AJ ONeal 93e493acbb fix date 2015-01-11 23:22:55 -07:00
components fix date 2015-01-11 23:22:55 -07:00
lib work on create post 2015-01-11 20:59:14 -07:00
tests add api write test 2015-01-09 04:54:10 +00:00
views fix date 2015-01-11 23:22:55 -07:00
.gitignore initial commit 2015-01-05 19:23:26 +00:00
.gitmodules retrieving files and folders 2015-01-05 22:05:35 +00:00
.jshintrc began ui work 2015-01-10 00:23:15 -07:00
BUGS.md began setup wizard 2015-01-11 04:04:30 -07:00
LICENSE Initial commit 2015-01-03 12:26:23 -07:00
MIGRATE.md Update MIGRATE.md 2015-01-03 23:17:42 -07:00
README.md began setup wizard 2015-01-11 04:04:30 -07:00
app.js work on create post 2015-01-11 20:59:14 -07:00
bower.json began setup wizard 2015-01-11 04:04:30 -07:00
deardesi.js fix date 2015-01-11 23:22:55 -07:00
index.html work on create post 2015-01-11 20:59:14 -07:00
package.json hacked stylesheets, fixed base_url 2015-01-09 01:49:14 -07:00
partials.yml fix markdown, hack in style assets 2015-01-09 04:44:11 +00:00
server.js began setup wizard 2015-01-11 04:04:30 -07:00
swatches.yml began setup wizard 2015-01-11 04:04:30 -07:00

README.md

Desirae

A blog platform built for Developers, but with normal people in mind.

Desirae runs entirely in the browser, but needs a little help from Node.js for saving and retrieving files.

She can also be run from entirely headless from node.js.

Key Features

Really good use of try { ... } catch(e) ... - it won't all blow up at the slightest parse error (cough ruhoh cough jekyll)... bless me.

JavaScript - it's so stable it takes 10 years to get new any features. Won't break every time you upgrade OS X and reinstall brew (cough ruby).

Browser (optional) - using your front-end templates to build in your front-end? Imagine that!

Node (optional) - if you'd prefer to go headless, you can.

The server is very minimal and could easily be implemented in any language (such as ruby or python).

Install and Usage

If you're on OS X or Linux, it's as easy as pie to install and use Desirae.

git clone git@github.com:DearDesi/desirae.git
pushd desirae

# Downloads and installs node.js and a few other tools Desirae needs
bash setup.sh ./blog

After the initial installation you can launch Dear Desi, the Web-based configuration and build tool like so:

deardesi ./blog 65080

Or, if you prefer, you can build with desirae from the command line:

desirae build ./blog

desirae build-dev ./blog

Create a new Post

desirae post "My First Post"

Configuration

There are a few configuration files:

  • site.yml is stuff that might be unique to your site, such as (title, url, adwords id, etc)
  • authors/<<your-handle.yml>> contains information about you (name, handle, facebook, etc)
  • desirae.yml contains directives that describe how the blog should be compiled - more technical stuff.

If any of these files change, the entire site needs to be retemplated.

Widgets

All widgets should export an object with a create(widgetConf, desiState) function that returns a promise.

widgets:
  foogizmo:
    # only stuff that is intensely specific to foogizmo goes here
    # stuff like google ad and disqus ids should go in config.yml or data.yml
    config:
      foobeep: boop
      
    handle:
      - html
      - markdown
    handlers:
      post: fooposter
      page: foopager
'use strict';

module.exports.Foogizmo.create = function (foogizmoConf, desiState) {
  return new Promise(function (resolve) {

    function pager(desiPageState) {
      // Do processing

      return Promise.resolve();
    }

    function poster(desiPostState) {
      // Do processing

      desiPostState.fooembedinator = function (fooval) {
        // figure out what type of link fooval is and return iframe html
        return '<iframe src="http://embedinator.com/"' + foovalProcessed + '></iframe>'
      }
    }

    resolve({ foopager: pager, fooposter: poster });
  });
}

Overlays

For any config a widget uses, it should also check on post.fooconfig and theme.fooconfig to make sure that they don't override the foogizmo.config.fooconfig

Server

Obviously there has to be a server with some sort of storage and retrieval mechanism.

I've implemented a very simple node server using the filesystem.

GET /api/fs/walk

GET http://local.dear.desi:8080/api/fs/walk?dir=posts&dotfiles=true&extensions=md,markdown,jade,htm,html

  • dir must be supplied. returns a flat list of all files, recursively
  • dotfiles default to false. includes dotfiles when true.
  • extensions defaults to null. inclode only the supplied extensions when true.
[
  { "name": "happy-new-year.md"
  , "lastModifiedDate": "2015-01-05T18:19:30.000Z"
  , "size": 2121
  , "relativePath": "posts/2015"
  }

, { "name": "tips-for-the-ages.jade"
  , "lastModifiedDate": "2014-06-16T18:19:30.000Z"
  , "size": 389
  , "relativePath": "posts"
  }
, { "name": "my-first-post.html"
  , "lastModifiedDate": "2013-08-01T22:47:37.000Z"
  , "size": 4118
  , "relativePath": "posts/2013"
  }
]

To retrieve multiple dir listings at once:

  • for a few simple dirs without special chars just change dir to dirs and separate with commas

GET http://local.dear.desi:8080/api/fs/walk?dirs=posts/2015,posts/2013&dotfiles=true&extensions=md,markdown,jade,htm,html

  • for many dirs, or dirs with special chars, POST an object containing an array of dirs with &_method=GET appended to the url.
POST http://local.dear.desi:8080/api/fs/walk?dotfiles=true&extensions=md,markdown,jade,htm,html&_method=GET

{ "dirs": [ "old", "2013,12", "2013,11" ] }
{
  "posts/2015": [ { "name": ... }, { ... } ]
, "posts/2013": [ ... ]
}

GET /api/fs/files

GET http://local.dear.desi:8080/api/fs/files?path=posts/happy-new-year.md

{ "path": "posts/intro-to-http-with-netcat-node-connect.md"
, "lastModifiedDate": "2013-08-01T22:47:37.000Z"
, "contents": "..."
, "sha1": "6eae3a5b062c6d0d79f070c26e6d62486b40cb46"
}

To retrieve multiple files at once:

  • for a few simple files without special chars just change path to paths and separate with commas

GET http://local.dear.desi:8080/api/fs/files?paths=posts/foo.md,posts/bar.md

  • for many files, or files with special chars, POST an object containing an array of pathss with &_method=GET appended to the url.
POST http://local.dear.desi:8080/api/fs/files?dotfiles=true&extensions=md,markdown,jade,htm,html&_method=GET

{ "paths": [ "posts/foo.md", "posts/2013,11,30.md" ] }
[
  { "path": "posts/foo.md"
  , "lastModifiedDate": "2013-08-01T22:47:37.000Z"
  , "contents": "..."
  , "sha1": "6eae3a5b062c6d0d79f070c26e6d62486b40cb46"
  }
, ...
]

POST /api/fs/files

By default this should assume that you intended to write to the compiled directory and return an error if you try to write to any other directory, unless compiled=false (not yet implemented).

_method=PUT is just for funzies.

Including sha1 is optional, but recommended.

lastModifiedDate is optional and may or may not make any difference.

strict (not yet implemented) fail immediately and completely on any error

POST http://local.dear.desi:8080/api/fs/files?compiled=true&_method=PUT

{
  "files": [
    { "path": "posts/foo.md"
    , "name": "foo.md"
    , "relativePath": "posts"
    , "lastModifiedDate": "2013-08-01T22:47:37.000Z"
    , "contents": "..."
    , "sha1": "6eae3a5b062c6d0d79f070c26e6d62486b40cb46"
    , "delete": false
    }
  , ...
  ]
}

The response may include errors of all shapes and sizes.

{ "error": { message: "any top-level error", ... }
, "errors": [
    { "type": "file|directory"
    , "message": "maybe couldn't create the directory, but maybe still wrote the file. Maybe not"
    }
  , ...
  ]
}

TODO Allow rename and delete?

TODO

option for client write to a hidden .desi-revisions (as well as indexeddb) to safeguard against accidental blow-ups for people who aren't using git.