Pretty much the final product.

This commit is contained in:
Elf M. Sternberg 2012-07-16 11:20:23 -07:00
parent 738ea5cc8d
commit f09acdbf9b
8 changed files with 580 additions and 141 deletions

BIN
assets/images/gear.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 464 B

218
assets/jquery/bootstrap-modal.js vendored Normal file
View File

@ -0,0 +1,218 @@
/* =========================================================
* bootstrap-modal.js v2.0.3
* http://twitter.github.com/bootstrap/javascript.html#modals
* =========================================================
* Copyright 2012 Twitter, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
!function ($) {
"use strict"; // jshint ;_;
/* MODAL CLASS DEFINITION
* ====================== */
var Modal = function (content, options) {
this.options = options
this.$element = $(content)
.delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
}
Modal.prototype = {
constructor: Modal
, toggle: function () {
return this[!this.isShown ? 'show' : 'hide']()
}
, show: function () {
var that = this
, e = $.Event('show')
this.$element.trigger(e)
if (this.isShown || e.isDefaultPrevented()) return
$('body').addClass('modal-open')
this.isShown = true
escape.call(this)
backdrop.call(this, function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
that.$element.appendTo(document.body) //don't move modals dom position
}
that.$element
.show()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element.addClass('in')
transition ?
that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
that.$element.trigger('shown')
})
}
, hide: function (e) {
e && e.preventDefault()
var that = this
e = $.Event('hide')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
$('body').removeClass('modal-open')
escape.call(this)
this.$element.removeClass('in')
$.support.transition && this.$element.hasClass('fade') ?
hideWithTransition.call(this) :
hideModal.call(this)
}
}
/* MODAL PRIVATE METHODS
* ===================== */
function hideWithTransition() {
var that = this
, timeout = setTimeout(function () {
that.$element.off($.support.transition.end)
hideModal.call(that)
}, 500)
this.$element.one($.support.transition.end, function () {
clearTimeout(timeout)
hideModal.call(that)
})
}
function hideModal(that) {
this.$element
.hide()
.trigger('hidden')
backdrop.call(this)
}
function backdrop(callback) {
var that = this
, animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
.appendTo(document.body)
if (this.options.backdrop != 'static') {
this.$backdrop.click($.proxy(this.hide, this))
}
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
doAnimate ?
this.$backdrop.one($.support.transition.end, callback) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
$.support.transition && this.$element.hasClass('fade')?
this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
removeBackdrop.call(this)
} else if (callback) {
callback()
}
}
function removeBackdrop() {
this.$backdrop.remove()
this.$backdrop = null
}
function escape() {
var that = this
if (this.isShown && this.options.keyboard) {
$(document).on('keyup.dismiss.modal', function ( e ) {
e.which == 27 && that.hide()
})
} else if (!this.isShown) {
$(document).off('keyup.dismiss.modal')
}
}
/* MODAL PLUGIN DEFINITION
* ======================= */
$.fn.modal = function (option) {
return this.each(function () {
var $this = $(this)
, data = $this.data('modal')
, options = $.extend({}, $.fn.modal.defaults, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option]()
else if (options.show) data.show()
})
}
$.fn.modal.defaults = {
backdrop: true
, keyboard: true
, show: true
}
$.fn.modal.Constructor = Modal
/* MODAL DATA-API
* ============== */
$(function () {
$('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
var $this = $(this), href
, $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
, option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
e.preventDefault()
$target.modal(option)
})
})
}(window.jQuery);

View File

@ -94,6 +94,7 @@ module.exports = (grunt) ->
"assets/jquery/jquery-1.7.2.js"
"assets/require.js"
"assets/lawnchair/lawnchair.js"
"assets/jquery/bootstrap-modal.js"
"assets/images/*.png"
]
dest: "dist"

View File

@ -111,7 +111,7 @@ module.exports = function(grunt) {
findNestedDependencies: true
},
install: {
src: ["assets/jquery/jquery-1.7.2.js", "assets/require.js", "assets/lawnchair/lawnchair.js", "assets/images/*.png"],
src: ["assets/jquery/jquery-1.7.2.js", "assets/require.js", "assets/lawnchair/lawnchair.js", "assets/jquery/bootstrap-modal.js", "assets/images/*.png"],
dest: "dist"
},
mocha: {

View File

@ -1,3 +1,3 @@
.edit-priority
%input.edit-priority-field(type="text" value="<%= p.name %>" data-pos="<%= p.pos %>" data-ty="<%= type %>")
%button.delete-priority-field(data-for="<%= p.pos %>")
%button.delete-priority-field(data-for="<%= p.pos %>") ×

View File

@ -12,6 +12,10 @@
%title Priority / Ignore
%body
#gear
#gearbutton
%img(src="gear.png")
#grid.container
.flow
.row-fluid
@ -22,33 +26,30 @@
%h1#ignorize(data-pos="N" data-ty="ignore") Today I Will Ignore:
#ignorities
#message(style="display:none")
%h2 How to Use
%p
#message.modal.hide.fade
.modal-header
%button.close(data-dismiss="modal" type="button") ×
%h3 Prioritize / Ignore
%p
According to the Harvard School of Business, there are <a
href="http://blogs.hbr.org/bregman/2009/05/two-lists-you-should-look-at-e.html">two
lists</a> you should look at every morning, and perhaps
every chance you get: the list of things that are important
to you, and the list of things that you should ignore.
<b>Priority / Ignore</b> is a simple project reminder. It is
not a to-do list or project manager. It's just a
<i>reminder</i>. After <a
href="https://github.com/elfsternberg/rightnow">downloading
and installing <b>Priority / Ignore!</b> locally</a>, set the
index.html file as your home page, open a new tab and click on
either header.
%p
Prioritize / Ignore is an extension of that idea: a
reminder, each and every time you open your browser, of what
is important, and what is not.
%p
%p
To use: Just click on either header. A new entry will open
up in that list for you to fill out. Empty entries will be
deleted automatically.
The idea is simple: every time you open your browser or click
"New Tab," you'll get the <b>Priority / Ignore</b> page.
Every day we should remind ourselves not only of what must be
done, but what we must put aside as trivial and distracting.
%p
All the data is stored locally using the browser's own local
storage mechanism. There is no server, and no data is ever
sent anywhere. Everything on your screen is yours, kept as
secure as you keep your physical hardware.
%p
This message will disappear as soon as you've created your
first entry. You can also <button id="preclose">Close it
now.</button>
%p
You can click on the gear icon in the lower
left-hand corner any time you like to review this page.
.model-body
.model-footer
%a.btn(href="#" data-dismiss="modal") Close

View File

@ -2,94 +2,100 @@ require.config
paths:
'jquery': 'jquery-1.7.2'
require ['jquery', 'priority_tmpl', 'edit_priority_tmpl', 'lawnchair'], ($, priority_template, edit_priority_template) ->
require ['jquery', 'lawnchair'], ($) ->
require ['priority_tmpl', 'edit_priority_tmpl', 'bootstrap-modal'], (priority_template, edit_priority_template) ->
class Prioritize
class Prioritize
constructor: (@repo) ->
@repo.get 'priorities', (p) =>
@priorities = if p? and p.priorities? then p.priorities else []
@render()
$('body').on 'click', @render
$('#prioritize').on 'click', @editPriority
$('#ignorize').on 'click', @editPriority
constructor: (@repo) ->
@repo.get 'priorities', (p) =>
@priorities = if p? and p.priorities? then p.priorities else []
@render()
$('body').on 'click', @render
$('#prioritize').on 'click', @editPriority
$('#ignorize').on 'click', @editPriority
editPriority: (ev) =>
ev.stopPropagation()
editPriority: (ev) =>
ev.stopPropagation()
# Only allow one edit-priority at a time!
return if $('.edit-priority').length > 0
# Only allow one edit-priority at a time!
return if $('.edit-priority').length > 0
tg = $(ev.currentTarget)
ty = tg.data('ty')
pos = tg.data('pos')
tg = $(ev.currentTarget)
ty = tg.data('ty')
pos = tg.data('pos')
# If the position is 'N', we're adding a new list item to
# the bottom of a list to be populated.
# If the position is 'N', we're adding a new list item to
# the bottom of a list to be populated.
if pos == 'N'
@priorities.push({name: '', cat: ty})
pos = @priorities.length - 1
(if ty == 'priority' then $('#priorities') else $('#ignorities'))
.append('<li class="priority" id="pos-' + pos + '"></li>')
if pos == 'N'
@priorities.push({name: '', cat: ty})
pos = @priorities.length - 1
(if ty == 'priority' then $('#priorities') else $('#ignorities'))
.append('<li class="priority" id="pos-' + pos + '"></li>')
# Replace the list item's contents with the editor's
# content.
li = $('#pos-' + pos)
li.html edit_priority_template
p:
name: @priorities[pos].name
pos: pos
type: ty
# Replace the list item's contents with the editor's
# content.
li = $('#pos-' + pos)
li.html edit_priority_template
p:
name: @priorities[pos].name
pos: pos
type: ty
input = $('input.edit-priority-field', li)
input = $('input.edit-priority-field', li)
maybePrioritySave = (ev) =>
prioritySave = =>
@priorities[pos] = {cat: ty, name: input.val()}
maybePrioritySave = (ev) =>
prioritySave = =>
@priorities[pos] = {cat: ty, name: input.val()}
@save()
code = if ev.keyCode then ev.keyCode else ev.which
return prioritySave() if code == 13
return @cleanAndRender() if code == 27
deletePriority = (ev) =>
ev.stopPropagation()
@priorities[pos].name = ""
@save()
code = if ev.keyCode then ev.keyCode else ev.which
return prioritySave() if code == 13
return @cleanAndRender() if code == 27
input.on 'keyup', maybePrioritySave
$('.delete-priority-field', li).on 'click', deletePriority
input.focus()
deletePriority = (ev) =>
ev.stopPropagation()
@priorities[pos].name = ""
@save()
save: ->
@clean()
@repo.save {key: 'priorities', 'priorities': @priorities}, () =>
@render()
input.on 'keyup', maybePrioritySave
$('.delete-priority-field', li).on 'click', deletePriority
input.focus()
clean: ->
@priorities = ({name: p.name, cat: p.cat} for p in @priorities when p.name.trim() != "")
save: ->
@clean()
@repo.save {key: 'priorities', 'priorities': @priorities}, () =>
@render()
save: ->
@clean()
@repo.save {key: 'priorities', 'priorities': @priorities}, =>
@render()
clean: ->
@priorities = ({name: p.name, cat: p.cat} for p in @priorities when p.name.trim() != "")
render: =>
priority_enumerate = (cat) =>
r = []
for i in [0...@priorities.length]
if @priorities[i].cat == cat
r.push({name: @priorities[i].name, cat: @priorities[i].cat, pos: i})
r
save: ->
@clean()
@repo.save {key: 'priorities', 'priorities': @priorities}, =>
@render()
$('#priorities').html(priority_template({priorities: priority_enumerate('priority'), type: 'priority'}))
$('#ignorities').html(priority_template({priorities: priority_enumerate('ignore'), type: 'ignore'}))
$('.priorityc').bind 'click', @editPriority
render: =>
priority_enumerate = (cat) =>
r = []
for i in [0...@priorities.length]
if @priorities[i].cat == cat
r.push({name: @priorities[i].name, cat: @priorities[i].cat, pos: i})
r
$ ->
prioritize = new Lawnchair {name: 'Prioritize'}, ->
handler = new Prioritize(this)
handler.render()
$('#priorities').html(priority_template({priorities: priority_enumerate('priority'), type: 'priority'}))
$('#ignorities').html(priority_template({priorities: priority_enumerate('ignore'), type: 'ignore'}))
$('.priorityc').bind 'click', @editPriority
$('#gearbutton').bind 'click', () => $('#message').modal()
$ ->
prioritize = new Lawnchair {name: 'Prioritize'}, ->
handler = new Prioritize(this)
handler.render()
this.get 'priorities', (p) ->
if not p? or not p.priorities? or p.priorities.length == 0
$('#message').modal()

View File

@ -56,6 +56,8 @@ input[type="search"]::-webkit-search-cancel-button {
body {
margin: 0;
padding: 0;
font: 13pt/190% Montserrat,Calibri,Georgia,"Lucida Bright",Lucidabright,"Bitstream Vera Serif",serif;
background-color: #fff;
}
@ -517,43 +519,22 @@ ul + p {
margin-left: 10px;
}
#newcat h1, div.category, .editcat, .addstory, li.task {
#newcat h1, div.category, .editcat, .addstory, li.priority {
cursor: pointer;
}
.edit-category, .edit-priority {
.edit-category, .edit-task {
padding: 4px 2px 0px 5px;
text-shadow: 0px 1px 0px #fff;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
border: 1px solid #ddd;
.edit-priority-field {
margin-top: 8px;
}
-webkit-box-shadow: 2px 1px 0px #efefef;
-moz-box-shadow: 2px 1px 0px #efefef;
box-shadow: 2px 1px 0px #efefef;
width: 80%;
input.edit-task-field {
width: 80%;
border: 1px solid #eee;
padding-bottom: 0;
margin-bottom: 0;
margin-left: 5px;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
}
button.delete-task-field {
margin-top: 4px;
padding: 1px 4px 3px 3px;
.delete-priority-field {
padding: 0px 4px 3px 3px;
font-weight: bold;
display: block;
float: right;
margin-right: 10px;
display: inline-block;
background-color: #ff9f00;
vertical-align: middle;
color: #333;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
@ -563,16 +544,248 @@ ul + p {
#message {
font-family: Constantina,Georgia,"Lucida Bright",Lucidabright,"Bitstream Vera Serif",serif;
display: block;
position:absolute;
top: 1.0416666%;
right: 1.0416666%;
width: 35.0416666%;
max-width: 32em;
padding: 1.0416666%;
background:#eee;
border:1px solid #ddd;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
}
#gear {
position: fixed;
bottom: 0px;
height: 20px;
width: 100%;
}
#gearbutton {
position: relative;
-webkit-border-top-left-radius: 2px;
-moz-border-radius-top-left: 2px;
border-top-left-radius: 2px;
float: right;
margin-right: 0px;
background-color: black;
height: 20px;
img {
vertical-align: top;
padding: 2px 2px 0px 2px;
}
}
@zindexDropdown: 1000;
@zindexPopover: 1010;
@zindexTooltip: 1020;
@zindexFixedNavbar: 1030;
@zindexModalBackdrop: 1040;
@zindexModal: 1050;
// Opacity
.opacity(@opacity) {
opacity: @opacity / 100;
filter: ~"alpha(opacity=@{opacity})";
}
.background-clip(@clip) {
-webkit-background-clip: @clip;
-moz-background-clip: @clip;
background-clip: @clip;
}
.modal-open {
.dropdown-menu { z-index: @zindexDropdown + @zindexModal; }
.dropdown.open { *z-index: @zindexDropdown + @zindexModal; }
.popover { z-index: @zindexPopover + @zindexModal; }
.tooltip { z-index: @zindexTooltip + @zindexModal; }
}
// Background
.modal-backdrop {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: @zindexModalBackdrop;
background-color: black;
// Fade for backdrop
&.fade { opacity: 0; }
}
.modal-backdrop,
.modal-backdrop.fade.in {
.opacity(80);
}
#gradient {
.vertical(@startColor: #555, @endColor: #333) {
background-color: mix(@startColor, @endColor, 60%);
background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+
background-image: -ms-linear-gradient(top, @startColor, @endColor); // IE10
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+
background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+
background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10
background-image: linear-gradient(top, @startColor, @endColor); // The standard
background-repeat: repeat-x;
}
}
.buttonBackground(@startColor, @endColor) {
// gradientBar will set the background to a pleasing blend of these, to support IE<=9
.gradientBar(@startColor, @endColor);
*background-color: @endColor; /* Darken IE7 buttons by default so they stand out more given they won't have borders */
// in these cases the gradient won't cover the background, so we override
&:hover, &:active, &.active, &.disabled, &[disabled] {
background-color: @endColor;
*background-color: darken(@endColor, 5%);
}
// IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves
&:active,
&.active {
background-color: darken(@endColor, 10%) e("\9");
}
}
.gradientBar(@primaryColor, @secondaryColor) {
#gradient > .vertical(@primaryColor, @secondaryColor);
border-color: @secondaryColor @secondaryColor darken(@secondaryColor, 15%);
border-color: rgba(0,0,0,.1) rgba(0,0,0,.1) fadein(rgba(0,0,0,.1), 15%);
}
@btnBackground: #fff;
@btnBackgroundHighlight: darken(#fff, 10%);
@btnBorder: #ccc;
.btn {
display: inline-block;
padding: 4px 10px 4px;
margin-bottom: 0; // For input.btn
font-size: @baseFontSize;
line-height: @baseLineHeight;
*line-height: 20px;
color: #333;
text-align: center;
text-shadow: 0 1px 1px rgba(255,255,255,.75);
vertical-align: middle;
cursor: pointer;
.buttonBackground(@btnBackground, @btnBackgroundHighlight);
border: 1px solid @btnBorder;
*border: 0; // Remove the border to prevent IE7's black border on input:focus
border-bottom-color: darken(@btnBorder, 10%);
.border-radius(4px);
.box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
}
// Hover state
.btn:hover {
color: #333;
text-decoration: none;
background-color: darken(white, 10%);
*background-color: darken(white, 15%); /* Buttons in IE7 don't get borders, so darken on hover */
background-position: 0 -15px;
// transition is only when going to hover, otherwise the background
// behind the gradient (there for IE<=9 fallback) gets mismatched
.transition(background-position .1s linear);
}
// Focus state for keyboard and accessibility
.btn:focus {
.tab-focus();
}
.tab-focus() {
// Default
outline: thin dotted #333;
// Webkit
outline: 5px auto -webkit-focus-ring-color;
outline-offset: -2px;
}
// Active state
.btn.active,
.btn:active {
background-color: darken(#fff, 10%);
background-color: darken(#fff, 15%) e("\9");
background-image: none;
outline: 0;
.box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
}
// Disabled state
.btn.disabled,
.btn[disabled] {
cursor: default;
background-color: darken(#fff, 10%);
background-image: none;
.opacity(65);
.box-shadow(none);
}
// Base modal
.modal {
position: fixed;
top: 50%;
left: 50%;
z-index: @zindexModal;
overflow: auto;
width: 560px;
margin: -250px 0 0 -280px;
background-color: white;
border: 1px solid #999;
border: 1px solid rgba(0,0,0,.3);
*border: 1px solid #999; /* IE6-7 */
.border-radius(6px);
.box-shadow(0 3px 7px rgba(0,0,0,0.3));
.background-clip(padding-box);
&.fade {
.transition(e('opacity .3s linear, top .3s ease-out'));
top: -25%;
}
&.fade.in { top: 50%; }
}
.modal-header {
padding: 9px 15px;
border-bottom: 1px solid #eee;
// Close icon
.close { margin-top: 2px; float: left }
}
// Body (where all modal content resides)
.modal-body {
overflow-y: auto;
max-height: 400px;
padding: 15px;
}
// Remove bottom margin if need be
.modal-form {
margin-bottom: 0;
}
// Footer (for actions)
.modal-footer {
padding: 14px 15px 15px;
margin-bottom: 0;
text-align: right; // right align buttons
background-color: #f5f5f5;
border-top: 1px solid #ddd;
.border-radius(0 0 6px 6px);
.box-shadow(inset 0 1px 0 white);
.clearfix(); // clear it in case folks use .pull-* classes on buttons
// Properly space out buttons
.btn + .btn {
margin-left: 5px;
margin-bottom: 0; // account for input[type="submit"] which gets the bottom margin like all other inputs
}
// but override that for button groups
.btn-group .btn + .btn {
margin-left: -1px;
}
}
.hide {
display: none;
}
.show {
display: block;
}