Task manager using Reactive Coffee

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.string/2.3.0/underscore.string.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/normalize/2.1.0/normalize.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/reactive-coffee/0.0.3/reactive-coffee.min.js"></script>

SCSS

html, body { margin: 20px; padding: 0; }
body {
  font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
  line-height: 1.4em;
  background: #eaeaea;
  color: #4d4d4d;
  width: 550px;
  margin: 0 auto;
  -webkit-font-smoothing: antialiased;
  -moz-font-smoothing: antialiased;
  -ms-font-smoothing: antialiased;
  -o-font-smoothing: antialiased;
  font-smoothing: antialiased;
}
ul { list-style: none; padding: 0; }
label { display: inline-block; width: 100px; }
.descrip { margin: 10px; }
.task a { font-size: smaller; }
.task-selected { margin-bottom: 2px; background: rgba(0,0,0,.1); }
.task-unselected { margin-bottom: 2px; }

CoffeeScript

bind = rx.bind
rxt.importTags()

# This is our application's core data model, an array of Task objects.
# `cell` and `array` are our primitive reactive data structures.  You can
# listen for (and react to) changes to their values.

class Task
  constructor: (descrip, priority, isDone) ->
    @descrip = rx.cell(descrip)
    @priority = rx.cell(priority)
    @isDone = rx.cell(isDone)

tasks = rx.array([
  new Task('Get milk', 'important', false)
  new Task('Play with Reactive Coffee', 'critical', false)
  new Task('Walk the dog', 'meh', false)
])

# Our main view: a checklist of tasks, a button to add a new task, and a
# task editor component (defined further down).
#
# `bind` (and `array.map`) are the central mechanisms by which you can
# declare cells that are always bound to the current value of some
# expression over other cells.  `z = bind -> x.get() + y.get()` says `z`
# should always reflect the sum even as `x` and `y` change.  Subscription
# management is handled automatically.

main = ->
  currentTask = rx.cell(tasks.at(0)) # "View model" of currently selected task

  $('body').append(
    div {class: 'task-manager'}, [
      h1 bind -> "#{tasks.length()} task(s) for today"
      ul {class: 'tasks'}, tasks.map (task) ->
        li {class: bind -> "task-#{if task == currentTask.get() then 'selected' else 'unselected'}"}, [
          input {type: 'checkbox', click: -> task.isDone.set(@is(':checked')); true}
          span {class: 'descrip'}, bind ->
            "#{task.descrip.get()} (#{task.priority.get()})"
          a {href: 'javascript: void 0', click: -> currentTask.set(task)}, 'Edit'
        ]
      button {click: -> tasks.push(new Task('Task', 'none', false))}, 'Add new task'
      taskEditor {
        task: bind -> currentTask.get()
        onSubmit: (descrip, priority) ->
          currentTask.get().descrip.set(descrip)
          currentTask.get().priority.set(priority)
      }
    ]
  )

# The task editor demonstrates how to define a simple...