mirror of
https://github.com/sudoxnym/habitica.git
synced 2026-07-31 15:09:32 +00:00
Merge branch 'develop'
Conflicts: src/server/api.coffee views/static/head.html views/static/privacy.html views/static/terms.html
This commit is contained in:
commit
be305f918e
37 changed files with 1277 additions and 605 deletions
|
|
@ -1,2 +1,9 @@
|
|||
3/3/2013
|
||||
## 3/21/2013
|
||||
* New Design: https://github.com/lefnire/habitrpg/issues/585
|
||||
* Toggle helm visible: https://trello.com/card/toggle-helm-visible/50e5d3684fe3a7266b0036d6/153
|
||||
* Toggle Header: https://trello.com/card/toggle-header/50e5d3684fe3a7266b0036d6/241
|
||||
* Deletable Accounts: https://trello.com/card/deletable-accounts/50e5d3684fe3a7266b0036d6/69
|
||||
* Undo Button: https://trello.com/card/undo-button/50e5d3684fe3a7266b0036d6/20
|
||||
|
||||
## 3/3/2013
|
||||
* Add custom day start: https://trello.com/card/custom-day-start/50e5d3684fe3a7266b0036d6/15
|
||||
|
|
@ -26,8 +26,7 @@
|
|||
"superagent": "~0.12.4",
|
||||
"resolve": "~0.2.3",
|
||||
"browserify": "1.17.3",
|
||||
"expect.js": "~0.2.0",
|
||||
"webkit-devtools-agent": "*"
|
||||
"expect.js": "~0.2.0"
|
||||
},
|
||||
"private": true,
|
||||
"subdomain": "habitrpg",
|
||||
|
|
|
|||
|
|
@ -1,27 +1,17 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>HabitRPG | Gamify Your Life</title>
|
||||
<title>HabitRPG | Error</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<!-- Le styles -->
|
||||
<link href="/vendor/bootstrap/docs/assets/css/bootstrap.css" rel="stylesheet">
|
||||
<link href="/vendor/bootstrap/docs/assets/css/bootstrap-responsive.css" rel="stylesheet">
|
||||
<!-- CDN -->
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
|
||||
<link href="/vendor/bootstrap/docs/assets/css/docs.css" rel="stylesheet">
|
||||
<link href="/css/static-pages.css" rel="stylesheet">
|
||||
|
||||
<style type="text/css">
|
||||
.jumbotron {
|
||||
background-color: #1b1b1b;
|
||||
background-image: -moz-linear-gradient(top, #222222, #111111);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));
|
||||
background-image: -webkit-linear-gradient(top, #222222, #111111);
|
||||
background-image: -o-linear-gradient(top, #222222, #111111);
|
||||
background-image: linear-gradient(to bottom, #222222, #111111);
|
||||
background-repeat: repeat-x;
|
||||
border-color: #252525;
|
||||
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);
|
||||
|
||||
}
|
||||
.rotate-img {
|
||||
transform:rotate(90deg);
|
||||
-ms-transform:rotate(90deg); /* IE 9 */
|
||||
|
|
@ -37,7 +27,7 @@
|
|||
<div class='marketing'>
|
||||
<img class='rotate-img' src="/img/sprites/armor3_m.png" />
|
||||
<h2>The server is experiencing issues.</h2>
|
||||
<p><a href="/">Try again</a> in a few, the developer has been notified. The most likely culprit is <a href="https://github.com/lefnire/habitrpg/issues/165">this issue</a> which Tyler is working frantically to fix. (Any memory leak experts?)</p>
|
||||
<p><a href="/">Try again</a> in a few, the developer has been notified. The most likely culprit is <a href="https://github.com/lefnire/habitrpg/issues/165">this issue</a> which Tyler is working to fix. (Any memory leak experts?)</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 3.2 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
BIN
public/img/sprites/Mount-SpriteSheet.png
Normal file
BIN
public/img/sprites/Mount-SpriteSheet.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 4.1 KiB |
11
public/img/sprites/Mounts.css
Normal file
11
public/img/sprites/Mounts.css
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
Mount_Head_Lion, Mount_Body_Lion, Mount_Head_PolarBear, Mount_Body_PolarBear, Mount_Head_Panda, Mount_Body_Panda, Mount_Head_Tiger, Mount_Body_Tiger, Mount_Head_Bear, Mount_Body_Bear {background: url(Mount-SpriteSheet.png) no-repeat}
|
||||
Mount_Head_Lion {background-position: 0 0; width: 105px; height: 123px}
|
||||
Mount_Body_Lion {background-position: -105 0; width: 105px; height: 123px}
|
||||
Mount_Head_PolarBear {background-position: -210 0; width: 105px; height: 123px}
|
||||
Mount_Body_PolarBear {background-position: -315 0; width: 105px; height: 123px}
|
||||
Mount_Head_Panda {background-position: -420 0; width: 105px; height: 123px}
|
||||
Mount_Body_Panda {background-position: -525 0; width: 105px; height: 123px}
|
||||
Mount_Head_Tiger {background-position: -630 0; width: 105px; height: 123px}
|
||||
Mount_Body_Tiger {background-position: -735 0; width: 105px; height: 123px}
|
||||
Mount_Head_Bear {background-position: -840 0; width: 105px; height: 123px}
|
||||
Mount_Body_Bear {background-position: -945 0; width: 105px; height: 123px}
|
||||
|
|
@ -1,17 +1,10 @@
|
|||
#PetEggs {
|
||||
/* egg sprite size */
|
||||
width: 48px;
|
||||
height: 51px;
|
||||
/* link to sprite sheet image */
|
||||
background-image: url(Egg_Sprite_Sheet.png);
|
||||
}
|
||||
/* defines where in the sheet the eggs are */
|
||||
.WolfEgg{background-position: 0px 0px;}
|
||||
.TigerEgg{background-position: 0px -51px;}
|
||||
.PolarBearEgg{background-position: 0px -102px;}
|
||||
.PandaEgg{background-position: 0px -153px;}
|
||||
.LionEgg{background-position: 0px -204px;}
|
||||
.FlyingPigEgg{background-position: 0px -255px;}
|
||||
.DrakeEgg{background-position: 0px -306px;}
|
||||
.CactusEgg{background-position: 0px -357px;}
|
||||
.BearEgg{background-position: 0px -408px;}
|
||||
Pet_Egg_Wolf, Pet_Egg_Tiger, Pet_Egg_PolarBear, Pet_Egg_Panda, Pet_Egg_Lion, Pet_Egg_FlyingPig, Pet_Egg_Drake, Pet_Egg_Cactus, Pet_Egg_Bear {background: url(Egg_Sprite_Sheet.png) no-repeat}
|
||||
Pet_Egg_Wolf {background-position: 0 0; width: 48px; height: 51px}
|
||||
Pet_Egg_Tiger {background-position: 0 -51; width: 48px; height: 51px}
|
||||
Pet_Egg_PolarBear{background-position: 0 -102; width: 48px; height: 51px}
|
||||
Pet_Egg_Panda {background-position: 0 -153; width: 48px; height: 51px}
|
||||
Pet_Egg_Lion {background-position: 0 -204; width: 48px; height: 51px}
|
||||
Pet_Egg_FlyingPig {background-position: 0 -255; width: 48px; height: 51px}
|
||||
Pet_Egg_Drake {background-position: 0 -306; width: 48px; height: 51px}
|
||||
Pet_Egg_Cactus {background-position: 0 -357; width: 48px; height: 51px}
|
||||
Pet_Egg_Bear {background-position: 0 -408; width: 48px; height: 51px}
|
||||
|
|
@ -10,41 +10,27 @@ restoreRefs = module.exports.restoreRefs = (model) ->
|
|||
|
||||
###
|
||||
Loads JavaScript files from (1) public/js/* and (2) external sources
|
||||
We use this file (instead of <Scripts:> or <Tail:> inside .html) so we can utilize require() to concatinate for
|
||||
faster page load, and $.getScript for asyncronous external script loading
|
||||
If a library is available in a CDN, we put it in <Scripts:> (index.html) for better caching. If not, we use
|
||||
this function to utilize require() to concatinate for faster page load, and $.getScript for asyncronous external script loading
|
||||
###
|
||||
loadJavaScripts = (model) ->
|
||||
|
||||
require '../../public/vendor/jquery-ui/jquery-1.9.1'
|
||||
unless model.get('_view.mobileDevice')
|
||||
require '../../public/vendor/jquery-ui/ui/jquery.ui.core'
|
||||
require '../../public/vendor/jquery-ui/ui/jquery.ui.widget'
|
||||
require '../../public/vendor/jquery-ui/ui/jquery.ui.mouse'
|
||||
require '../../public/vendor/jquery-ui/ui/jquery.ui.sortable'
|
||||
|
||||
# Bootstrap
|
||||
require '../../public/vendor/bootstrap/docs/assets/js/bootstrap'
|
||||
# require '../../public/vendor/bootstrap/js/bootstrap-tooltip'
|
||||
# require '../../public/vendor/bootstrap/js/bootstrap-tab'
|
||||
# require '../../public/vendor/bootstrap/js/bootstrap-popover'
|
||||
# require '../../public/vendor/bootstrap/js/bootstrap-modal'
|
||||
# require '../../public/vendor/bootstrap/js/bootstrap-dropdown'
|
||||
|
||||
|
||||
require '../../public/vendor/jquery-cookie/jquery.cookie'
|
||||
require '../../public/vendor/bootstrap-tour/bootstrap-tour'
|
||||
require '../../public/vendor/bootstrap-datepicker/js/bootstrap-datepicker'
|
||||
require '../../public/vendor/bootstrap-growl/jquery.bootstrap-growl.min'
|
||||
|
||||
|
||||
# JS files not needed right away (google charts) or entirely optional (analytics)
|
||||
# Each file getsload asyncronously via $.getScript, so it doesn't bog page-load
|
||||
unless model.get('_view.mobileDevice')
|
||||
|
||||
$.getScript("https://s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire");
|
||||
$.getScript("//s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire");
|
||||
|
||||
# Google Charts
|
||||
$.getScript "https://www.google.com/jsapi", ->
|
||||
$.getScript "//www.google.com/jsapi", ->
|
||||
# Specifying callback in options param is vital! Otherwise you get blank screen, see http://stackoverflow.com/a/12200566/362790
|
||||
google.load "visualization", "1", {packages:["corechart"], callback: ->}
|
||||
|
||||
|
|
@ -61,7 +47,6 @@ setupSortable = (model) ->
|
|||
dropOnEmpty: false
|
||||
cursor: "move"
|
||||
items: "li"
|
||||
opacity: 0.4
|
||||
scroll: true
|
||||
axis: 'y'
|
||||
update: (e, ui) ->
|
||||
|
|
@ -195,8 +180,8 @@ setupGrowlNotifications = (model) ->
|
|||
|
||||
|
||||
module.exports.resetDom = (model) ->
|
||||
window.DERBY.app.dom.clear()
|
||||
window.DERBY.app.view.render(model)
|
||||
DERBY.app.dom.clear()
|
||||
DERBY.app.view.render(model, DERBY.app.view._lastRender.ns, DERBY.app.view._lastRender.context);
|
||||
|
||||
module.exports.app = (appExports, model, app) ->
|
||||
loadJavaScripts(model)
|
||||
|
|
|
|||
|
|
@ -61,14 +61,8 @@ module.exports.app = (appExports, model) ->
|
|||
batch.commit()
|
||||
browser.resetDom(model)
|
||||
|
||||
appExports.closeAlgosNotification = (e, el) ->
|
||||
user.set('flags.algosNotification', 'hide')
|
||||
|
||||
appExports.closeOnliesNotification = (e, el) ->
|
||||
user.set('flags.onliesNotification', 'hide')
|
||||
|
||||
appExports.closePriorityNotification = (e, el) ->
|
||||
user.set('flags.priorityNotification', 'hide')
|
||||
appExports.closeNewStuff = (e, el) ->
|
||||
user.set('flags.newStuff', 'hide')
|
||||
|
||||
appExports.customizeGender = (e, el) ->
|
||||
user.set 'preferences.gender', $(el).attr('data-value')
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
moment = require('moment')
|
||||
moment = require 'moment'
|
||||
_ = require 'underscore'
|
||||
|
||||
# Absolute diff between two dates
|
||||
module.exports.daysBetween = (yesterday, now, dayStart) ->
|
||||
|
|
@ -37,4 +38,8 @@ module.exports.viewHelpers = (view) ->
|
|||
loc = window?.location.host or process.env.BASE_URL
|
||||
encodeURIComponent "http://#{loc}/v1/users/#{uid}/calendar.ics?apiToken=#{apiToken}"
|
||||
|
||||
view.fn "notEqual", (a, b) -> (a != b)
|
||||
view.fn "and", -> _.reduce arguments, (cumm, curr) -> cumm && curr
|
||||
view.fn "or", -> _.reduce arguments, (cumm, curr) -> cumm || curr
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,6 @@ module.exports.app = (appExports, model) ->
|
|||
appExports.profileChangeActive = (e, el) ->
|
||||
uid = $(el).attr('data-uid')
|
||||
model.ref '_profileActive', model.at("users.#{uid}")
|
||||
model.set '_profileActiveMain', model.get('_user.id') == uid
|
||||
model.set '_profileActiveMain', user.get('id') is uid
|
||||
model.set '_profileActiveUsername', character.username model.get('_profileActive.auth')
|
||||
|
||||
|
|
|
|||
|
|
@ -2,17 +2,21 @@ scoring = require './scoring'
|
|||
helpers = require './helpers'
|
||||
_ = require 'underscore'
|
||||
moment = require 'moment'
|
||||
character = require './character'
|
||||
|
||||
module.exports.view = (view) ->
|
||||
view.fn 'taskClasses', (type, completed, value, repeat) ->
|
||||
#TODO figure out how to just pass in the task model, so i can access all these properties from one object
|
||||
view.fn 'taskClasses', (task) ->
|
||||
return unless task
|
||||
{type, completed, value, repeat} = task
|
||||
|
||||
classes = type
|
||||
|
||||
# show as completed if completed (naturally) or not required for today
|
||||
if completed or (repeat and repeat[helpers.dayMapping[moment().day()]]==false)
|
||||
classes += " completed"
|
||||
else
|
||||
classes += " uncompleted"
|
||||
if type in ['todo', 'daily']
|
||||
if completed or (repeat and repeat[helpers.dayMapping[moment().day()]]==false)
|
||||
classes += " completed"
|
||||
else
|
||||
classes += " uncompleted"
|
||||
|
||||
if value < -20
|
||||
classes += ' color-worst'
|
||||
|
|
@ -33,17 +37,6 @@ module.exports.view = (view) ->
|
|||
module.exports.app = (appExports, model) ->
|
||||
user = model.at('_user')
|
||||
|
||||
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
||||
return if passed? && passed.cron # Don't do this stuff on cron
|
||||
direction = () ->
|
||||
return 'up' if completed==true and previous == false
|
||||
return 'down' if completed==false and previous == true
|
||||
throw new Error("Direction neither 'up' nor 'down' on checkbox set.")
|
||||
|
||||
# Score the user based on todo task
|
||||
task = user.at("tasks.#{i}")
|
||||
scoring.score(model, i, direction())
|
||||
|
||||
appExports.addTask = (e, el, next) ->
|
||||
type = $(el).attr('data-task-type')
|
||||
list = model.at "_#{type}List"
|
||||
|
|
@ -75,7 +68,7 @@ module.exports.app = (appExports, model) ->
|
|||
|
||||
appExports.del = (e, el) ->
|
||||
# Derby extends model.at to support creation from DOM nodes
|
||||
task = model.at(e.target)
|
||||
task = e.at()
|
||||
id = task.get('id')
|
||||
|
||||
history = task.get('history')
|
||||
|
|
@ -123,8 +116,8 @@ module.exports.app = (appExports, model) ->
|
|||
appExports.toggleTaskEdit = (e, el) ->
|
||||
hideId = $(el).attr('data-hide-id')
|
||||
toggleId = $(el).attr('data-toggle-id')
|
||||
$(document.getElementById(hideId)).hide()
|
||||
$(document.getElementById(toggleId)).toggle()
|
||||
$(document.getElementById(hideId)).addClass('visuallyhidden')
|
||||
$(document.getElementById(toggleId)).toggleClass('visuallyhidden')
|
||||
|
||||
appExports.toggleChart = (e, el) ->
|
||||
hideSelector = $(el).attr('data-hide-id')
|
||||
|
|
@ -172,15 +165,63 @@ module.exports.app = (appExports, model) ->
|
|||
target.removeClass(oldContext)
|
||||
target.addClass(newContext)
|
||||
|
||||
appExports.score = (e, el, next) ->
|
||||
|
||||
setUndo = (stats, task) ->
|
||||
previousUndo = model.get('_undo')
|
||||
clearTimeout(previousUndo.timeoutId) if previousUndo?.timeoutId
|
||||
timeoutId = setTimeout (-> model.del('_undo')), 10000
|
||||
model.set '_undo', {stats:stats, task:task, timeoutId: timeoutId}
|
||||
|
||||
|
||||
###
|
||||
Call scoring functions for habits & rewards (todos & dailies handled below)
|
||||
###
|
||||
appExports.score = (e, el) ->
|
||||
task= model.at $(el).parents('li')[0]
|
||||
taskObj = task.get()
|
||||
direction = $(el).attr('data-direction')
|
||||
direction = 'up' if direction == 'true/'
|
||||
direction = 'down' if direction == 'false/'
|
||||
task = model.at $(el).parents('li')[0]
|
||||
scoring.score(model, task.get('id'), direction)
|
||||
|
||||
# set previous state for undo
|
||||
setUndo _.clone(user.get('stats')), _.clone(taskObj)
|
||||
|
||||
scoring.score(model, taskObj.id, direction)
|
||||
|
||||
###
|
||||
This is how we handle appExports.score for todos & dailies. Due to Derby's special handling of `checked={:task.completd}`,
|
||||
the above function doesn't work so we need a listener here
|
||||
###
|
||||
user.on 'set', 'tasks.*.completed', (i, completed, previous, isLocal, passed) ->
|
||||
return if passed? && passed.cron # Don't do this stuff on cron
|
||||
direction = if completed then 'up' else 'down'
|
||||
|
||||
# set previous state for undo
|
||||
taskObj = _.clone user.get("tasks.#{i}")
|
||||
taskObj.completed = previous
|
||||
setUndo _.clone(user.get('stats')), taskObj
|
||||
|
||||
scoring.score(model, i, direction)
|
||||
|
||||
###
|
||||
Undo
|
||||
###
|
||||
appExports.undo = () ->
|
||||
undo = model.get '_undo'
|
||||
clearTimeout(undo.timeoutId) if undo?.timeoutId
|
||||
batch = character.BatchUpdate(model)
|
||||
batch.startTransaction()
|
||||
model.del '_undo'
|
||||
_.each undo.stats, (val, key) -> batch.set "stats.#{key}", val
|
||||
taskPath = "tasks.#{undo.task.id}"
|
||||
_.each undo.task, (val, key) ->
|
||||
return if key in ['id', 'type'] # strange bugs in this world: https://workflowy.com/shared/a53582ea-43d6-bcce-c719-e134f9bf71fd/
|
||||
if key is 'completed'
|
||||
user.pass({cron:true}).set("#{taskPath}.completed",val)
|
||||
else
|
||||
batch.set "#{taskPath}.#{key}", val
|
||||
batch.commit()
|
||||
|
||||
appExports.tasksToggleAdvanced = (e, el) ->
|
||||
$(el).next('.advanced').toggle()
|
||||
$(el).next('.advanced-option').toggleClass('visuallyhidden')
|
||||
|
||||
appExports.tasksSaveAndClose = ->
|
||||
# When they update their notes, re-establish tooltip & popover
|
||||
|
|
|
|||
|
|
@ -20,9 +20,15 @@ NO_USER_FOUND = err: "No user found."
|
|||
$ mocha test/api.mocha.coffee
|
||||
###
|
||||
|
||||
###
|
||||
API Status
|
||||
###
|
||||
router.get '/status', (req, res) ->
|
||||
res.json status: 'up'
|
||||
|
||||
###
|
||||
beforeEach auth interceptor
|
||||
###
|
||||
auth = (req, res, next) ->
|
||||
uid = req.headers['x-api-user']
|
||||
token = req.headers['x-api-key']
|
||||
|
|
@ -38,7 +44,9 @@ auth = (req, res, next) ->
|
|||
return res.json 401, NO_USER_FOUND if !req.userObj || _.isEmpty(req.userObj)
|
||||
req._isServer = true
|
||||
next()
|
||||
|
||||
###
|
||||
GET /user
|
||||
###
|
||||
router.get '/user', auth, (req, res) ->
|
||||
user = req.userObj
|
||||
|
||||
|
|
@ -46,17 +54,24 @@ router.get '/user', auth, (req, res) ->
|
|||
user.stats.maxHealth = 50
|
||||
|
||||
delete user.apiToken
|
||||
delete user.auth.hashed_password
|
||||
delete user.auth.salt
|
||||
if user.auth
|
||||
delete user.auth.hashed_password
|
||||
delete user.auth.salt
|
||||
|
||||
res.json user
|
||||
|
||||
###
|
||||
GET /user/task/:id
|
||||
###
|
||||
router.get '/user/task/:id', auth, (req, res) ->
|
||||
task = req.userObj.tasks[req.params.id]
|
||||
return res.json 400, err: "No task found." if !task || _.isEmpty(task)
|
||||
|
||||
res.json 200, task
|
||||
|
||||
###
|
||||
validate task
|
||||
###
|
||||
validateTask = (req, res, next) ->
|
||||
task = {}
|
||||
newTask = { type, text, notes, value, up, down, completed } = req.body
|
||||
|
|
@ -87,11 +102,17 @@ validateTask = (req, res, next) ->
|
|||
req.task = task
|
||||
next()
|
||||
|
||||
###
|
||||
PUT /user/task/:id
|
||||
###
|
||||
router.put '/user/task/:id', auth, validateTask, (req, res) ->
|
||||
req.user.set "tasks.#{req.task.id}", req.task
|
||||
|
||||
res.json 200, req.task
|
||||
|
||||
###
|
||||
DELETE /user/task/:id
|
||||
###
|
||||
router.delete '/user/task/:id', auth, validateTask, (req, res) ->
|
||||
taskIds = req.user.get "#{req.task.type}Ids"
|
||||
|
||||
|
|
@ -101,6 +122,9 @@ router.delete '/user/task/:id', auth, validateTask, (req, res) ->
|
|||
|
||||
res.send 204
|
||||
|
||||
###
|
||||
POST /user/task/
|
||||
###
|
||||
router.post '/user/task', auth, validateTask, (req, res) ->
|
||||
task = req.task
|
||||
type = task.type
|
||||
|
|
@ -112,6 +136,9 @@ router.post '/user/task', auth, validateTask, (req, res) ->
|
|||
|
||||
res.json 201, task
|
||||
|
||||
###
|
||||
GET /user/tasks
|
||||
###
|
||||
router.get '/user/tasks', auth, (req, res) ->
|
||||
user = req.userObj
|
||||
return res.json 400, NO_USER_FOUND if !user || _.isEmpty(user)
|
||||
|
|
@ -160,8 +187,12 @@ scoreTask = (req, res, next) ->
|
|||
delta = scoring.score(model, taskId, direction)
|
||||
result = model.get ('_user.stats')
|
||||
result.delta = delta
|
||||
res.send(result)
|
||||
res.json result
|
||||
|
||||
###
|
||||
POST /user/tasks/:taskId/:direction
|
||||
###
|
||||
router.post '/user/task/:taskId/:direction', auth, scoreTask
|
||||
router.post '/user/tasks/:taskId/:direction', auth, scoreTask
|
||||
|
||||
module.exports = router
|
||||
|
|
|
|||
|
|
@ -1,3 +1,19 @@
|
|||
.new-stuff
|
||||
position: fixed
|
||||
text-align: center
|
||||
top: 0
|
||||
left: 0
|
||||
width: 100%
|
||||
height: 0
|
||||
z-index: 1010
|
||||
|
||||
.new-stuff> .alert
|
||||
border-top: 0
|
||||
border-radius: 0 0 4px 4px
|
||||
padding-right: 14px
|
||||
display: inline-block
|
||||
|
||||
|
||||
// variables
|
||||
|
||||
gpColor = #FBEFC0
|
||||
|
|
@ -60,4 +76,10 @@ borderDarken = 20%
|
|||
background-position: center center
|
||||
background-size: 14px
|
||||
width: 14px
|
||||
height: 14px
|
||||
height: 14px
|
||||
|
||||
|
||||
.undo-button
|
||||
position:absolute
|
||||
left:5px
|
||||
top:5px
|
||||
32
styles/app/helpers.styl
Normal file
32
styles/app/helpers.styl
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
// Hide from both screenreaders and browsers: h5bp.com/u
|
||||
.hidden
|
||||
display: none !important
|
||||
visibility: hidden
|
||||
|
||||
|
||||
// Hide only visually, but have it available for screenreaders: h5bp.com/v
|
||||
.visuallyhidden
|
||||
border: 0
|
||||
clip: rect(0 0 0 0)
|
||||
height: 1px
|
||||
margin: -1px
|
||||
overflow: hidden
|
||||
padding: 0
|
||||
position: absolute
|
||||
width: 1px
|
||||
|
||||
|
||||
// Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p
|
||||
.visuallyhidden.focusable:active,
|
||||
.visuallyhidden.focusable:focus
|
||||
clip: auto
|
||||
height: auto
|
||||
margin: 0
|
||||
overflow: visible
|
||||
position: static
|
||||
width: auto
|
||||
|
||||
|
||||
// Hide visually and from screenreaders, but maintain layout
|
||||
.invisible
|
||||
visibility: hidden
|
||||
|
|
@ -12,14 +12,33 @@
|
|||
@import "./customizer.styl";
|
||||
@import "./items.styl";
|
||||
@import "./alerts.styl";
|
||||
@import "./helpers.styl";
|
||||
@import "./responsive.styl";
|
||||
|
||||
@import "./scrollbars.styl";
|
||||
|
||||
|
||||
@import "../../public/vendor/bootstrap-datepicker/css/datepicker.css";
|
||||
|
||||
// fix exploding to very wide for some reason
|
||||
.datepicker
|
||||
width: 210px
|
||||
|
||||
html,body,p,h1,ul,li,table,tr,th,td
|
||||
margin: 0
|
||||
padding: 0
|
||||
|
||||
*
|
||||
-webkit-box-sizing: border-box
|
||||
-moz-box-sizing: border-box
|
||||
box-sizing: border-box
|
||||
|
||||
hr
|
||||
border-top: 0
|
||||
border-bottom: 1px solid #ddd
|
||||
border-color: rgba(0,0,0,0.1)
|
||||
|
||||
|
||||
/* Header
|
||||
-------------------------------------------------- */
|
||||
|
||||
|
|
@ -40,7 +59,7 @@ html,body,p,h1,ul,li,table,tr,th,td
|
|||
box-sizing: border-box
|
||||
z-index: 1000
|
||||
|
||||
@media (max-width: 480px) {
|
||||
@media (max-width: 600px) {
|
||||
#head {
|
||||
position: static;
|
||||
}
|
||||
|
|
@ -127,7 +146,7 @@ html,body,p,h1,ul,li,table,tr,th,td
|
|||
/*overflow:auto;*/
|
||||
padding-bottom: 250px; /* don't know why this works, sticky footers are weird */
|
||||
|
||||
@media (max-width: 480px) {
|
||||
@media (max-width: 600px) {
|
||||
#wrap {
|
||||
margin-top: 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,83 @@
|
|||
/* ----- Items, Weapons, Armor -----*/
|
||||
.item-store-popover img
|
||||
float:left
|
||||
padding-right:7px;
|
||||
// money styles
|
||||
.money
|
||||
display: inline-block
|
||||
line-height: 1.5em
|
||||
padding-left: 0.75em
|
||||
|
||||
.item .task-text img
|
||||
max-height: 16px
|
||||
[class^="shop_"]
|
||||
vertical-align: top
|
||||
display: inline-block
|
||||
|
||||
.buy-link, .item-buy-link
|
||||
background-color: #DEE5F2
|
||||
padding: 2px
|
||||
margin-right: 10px
|
||||
border-radius: 5px
|
||||
.btn-buy
|
||||
width: 4.5em
|
||||
height: 3em
|
||||
padding: 0.75em 0 0
|
||||
text-align: center
|
||||
vertical-align: top
|
||||
background-color: $better
|
||||
|
||||
img
|
||||
height:20px
|
||||
color: #555
|
||||
&:hover, &:focus
|
||||
background-color: $bad
|
||||
text-decoration: none
|
||||
|
||||
.item-buy-link
|
||||
background-color: #ccffcc
|
||||
.rewards
|
||||
margin-bottom: 1.5em
|
||||
padding-bottom: 1.5em
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1)
|
||||
|
||||
.item
|
||||
position:relative
|
||||
.reward-item
|
||||
background: white
|
||||
|
||||
.shop-table
|
||||
position:absolute
|
||||
top: 0
|
||||
left: 50px
|
||||
.reward-cost
|
||||
display: inline
|
||||
|
||||
#money
|
||||
position:relative
|
||||
.shop_gold, .shop_silver, .shop_copper
|
||||
float:right
|
||||
.money-table
|
||||
position:absolute
|
||||
top: 0
|
||||
|
||||
.shop-pet
|
||||
mouse: pointer
|
||||
.shop-pet-owned-check
|
||||
position:absolute
|
||||
right:0px
|
||||
bottom:0px
|
||||
// store items
|
||||
.btn-reroll
|
||||
background-color: $better
|
||||
cursor: pointer
|
||||
box-shadow: inset -1px -1px 0 rgba(0,0,0,0.1)
|
||||
&:hover, &:focus
|
||||
background-color: $bad
|
||||
|
||||
.item-img
|
||||
display: inline-block
|
||||
vertical-align: top
|
||||
// background-color: $bad
|
||||
height: 3em
|
||||
margin-left: -0.5em
|
||||
margin-right: 0.5em
|
||||
// border: 1px solid rgba(0,0,0,0.1)
|
||||
border-top: 0
|
||||
border-bottom: 0
|
||||
|
||||
.token-wallet
|
||||
cursor: pointer
|
||||
.tile
|
||||
background-color: darken($neutral, 10%)
|
||||
.add-token-btn
|
||||
opacity: 0
|
||||
&:hover, &:focus
|
||||
.add-token-btn
|
||||
opacity: 1
|
||||
background-color: $good
|
||||
.tile
|
||||
opacity: 1
|
||||
|
||||
|
||||
// pets (this will all change when pet system is overhauled)
|
||||
.pet-grid
|
||||
padding-top: 1.5em
|
||||
border-top: rgba(0,0,0,0.1)
|
||||
table
|
||||
width: 100%
|
||||
td
|
||||
padding: 0.5em
|
||||
width: 25%
|
||||
&.active-pet
|
||||
background-color: $bad
|
||||
outline: 1px solid rgba(0,0,0,0.1)
|
||||
outline-offset: -1px
|
||||
&:hover, &:focus
|
||||
background-color: darken($better, 10%)
|
||||
61
styles/app/responsive.styl
Normal file
61
styles/app/responsive.styl
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// widths
|
||||
.full
|
||||
width: 100%;
|
||||
.half
|
||||
width: 50%;
|
||||
.third
|
||||
width: 33.3333%;
|
||||
.two-thirds
|
||||
width: 66.6666%;
|
||||
.quarter
|
||||
width: 25%;
|
||||
.three-quarters
|
||||
width: 75%;
|
||||
.fifth
|
||||
width: 20%;
|
||||
.two-fifths
|
||||
width: 40%;
|
||||
.three-fifths
|
||||
width: 60%;
|
||||
.four-fifths
|
||||
width: 80%;
|
||||
.sixth
|
||||
width: 16.6667%;
|
||||
.eighth
|
||||
width: 12.5%;
|
||||
.tenth
|
||||
width: 10%;
|
||||
.twelfth
|
||||
width: 8.3333%;
|
||||
|
||||
.grid
|
||||
padding: 0 1.5em 1.5em 0
|
||||
letter-spacing: -4px
|
||||
|
||||
.module
|
||||
display: inline-block
|
||||
letter-spacing: normal
|
||||
vertical-align: top
|
||||
width: 25%
|
||||
padding: 0 0 1.5em 1.5em
|
||||
-moz-box-sizing: border-box
|
||||
box-sizing: border-box
|
||||
|
||||
// at 960px when 4 columns really starts to break
|
||||
@media (max-width: 60em)
|
||||
.module
|
||||
width: 50%
|
||||
.task-column
|
||||
max-height: 18em
|
||||
overflow-y: scroll
|
||||
|
||||
// at 600px when 2col starts breaking
|
||||
@media (max-width: 37.5em)
|
||||
.grid
|
||||
padding-right: 0
|
||||
.module
|
||||
width: 100%
|
||||
padding-left: 0
|
||||
.task-column
|
||||
max-height: none
|
||||
overflow: visible
|
||||
82
styles/app/scrollbars.styl
Normal file
82
styles/app/scrollbars.styl
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* Gmail style scrollbar */
|
||||
.task-column::-webkit-scrollbar {
|
||||
width: 12px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb {
|
||||
border-width: 1px 1px 1px 2px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track {
|
||||
border-width: 0
|
||||
}
|
||||
.task-column::-webkit-scrollbar {
|
||||
height: 16px;
|
||||
overflow: visible;
|
||||
width: 16px;
|
||||
}
|
||||
.task-column::-webkit-scrollbar-button {
|
||||
height: 0;
|
||||
width: 0;
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track {
|
||||
background-clip: padding-box;
|
||||
border: solid transparent;
|
||||
border-width: 0 0 0 4px;
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:horizontal {
|
||||
border-width: 4px 0 0
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:hover {
|
||||
background-color: rgba(150,150,150,.05);
|
||||
box-shadow: inset 1px 0 0 rgba(150,150,150,.1);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:horizontal:hover {
|
||||
box-shadow: inset 0 1px 0 rgba(150,150,150,.1)
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:active {
|
||||
background-color: rgba(150,150,150,.05);
|
||||
box-shadow: inset 1px 0 0 rgba(150,150,150,.14),inset -1px 0 0 rgba(150,150,150,.07);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:horizontal:active {
|
||||
box-shadow: inset 0 1px 0 rgba(150,150,150,.14),inset 0 -1px 0 rgba(150,150,150,.07)
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb {
|
||||
background-color: rgba(150,150,150,.2);
|
||||
background-clip: padding-box;
|
||||
border: solid transparent;
|
||||
border-width: 1px 1px 1px 6px;
|
||||
min-height: 28px;
|
||||
padding: 100px 0 0;
|
||||
box-shadow: inset 1px 1px 0 rgba(150,150,150,.1),inset 0 -1px 0 rgba(150,150,150,.07);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb:horizontal {
|
||||
border-width: 6px 1px 1px;
|
||||
padding: 0 0 0 100px;
|
||||
box-shadow: inset 1px 1px 0 rgba(150,150,150,.1),inset -1px 0 0 rgba(150,150,150,.07);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb:hover {
|
||||
background-color: rgba(150,150,150,.4);
|
||||
box-shadow: inset 1px 1px 1px rgba(150,150,150,.25);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb:active {
|
||||
background-color: rgba(150,150,150,0.5);
|
||||
box-shadow: inset 1px 1px 3px rgba(150,150,150,0.35);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track {
|
||||
border-width: 0 1px 0 6px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:horizontal {
|
||||
border-width: 6px 0 1px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-track:hover {
|
||||
background-color: rgba(150,150,150,.035);
|
||||
box-shadow: inset 1px 1px 0 rgba(150,150,150,.14),inset -1px -1px 0 rgba(150,150,150,.07);
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb {
|
||||
border-width: 0 1px 0 6px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-thumb:horizontal {
|
||||
border-width: 6px 0 1px
|
||||
}
|
||||
.task-column::-webkit-scrollbar-corner {
|
||||
background: transparent
|
||||
}
|
||||
|
|
@ -49,6 +49,6 @@
|
|||
.shop_armor_1 {background-position: -800px 0; width: 40px; height: 40px}
|
||||
.shop_reroll {background-position: -840px 0; width: 40px; height: 40px}
|
||||
.shop_potion {background-position: -880px 0; width: 40px; height: 40px}
|
||||
.shop_copper {background-position: -920px 0; width: 40px; height: 40px}
|
||||
.shop_silver {background-position: -960px 0; width: 40px; height: 40px}
|
||||
.shop_gold {background-position: -1000px 0; width: 40px; height: 40px}
|
||||
.shop_copper {background-position: -923px -8px; width: 32px; height: 22px}
|
||||
.shop_silver {background-position: -963px -8px; width: 32px; height: 22px}
|
||||
.shop_gold {background-position: -1003px -8px; width: 32px; height: 22px}
|
||||
|
|
|
|||
|
|
@ -1,42 +1,361 @@
|
|||
.color-worst pre
|
||||
background-color: rgb(230, 184, 175)
|
||||
.color-worse pre
|
||||
background-color: rgb(244, 204, 204)
|
||||
.color-bad pre
|
||||
background-color: rgb(252, 229, 205)
|
||||
.color-neutral pre
|
||||
background-color: rgb(255, 242, 204)
|
||||
.color-good pre
|
||||
background-color: rgb(217, 234, 211)
|
||||
.color-better pre
|
||||
background-color: rgb(208, 224, 227)
|
||||
.color-best pre
|
||||
background-color: rgb(201, 218, 248)
|
||||
.completed pre
|
||||
background-color: rgb(217, 217, 217)
|
||||
color: rgb(153, 153, 153)
|
||||
.reward pre
|
||||
// 1. Set up color classes
|
||||
// ========================
|
||||
|
||||
// color variables
|
||||
$worst = rgb(230, 184, 175)
|
||||
$worse = rgb(244, 204, 204)
|
||||
$bad = rgb(252, 229, 205)
|
||||
$neutral = rgb(255, 242, 204)
|
||||
$good = rgb(217, 234, 211)
|
||||
$better = rgb(208, 224, 227)
|
||||
$best = rgb(201, 218, 248)
|
||||
$completed = rgb(217, 217, 217)
|
||||
|
||||
// array of keywords and their associated color vars
|
||||
$stages = (worst $worst) (worse $worse) (bad $bad) (neutral $neutral) (good $good) (better $better) (best $best)
|
||||
|
||||
// for each color stage, generate a named class w/ the appropriate color
|
||||
for $stage in $stages
|
||||
.color-{$stage[0]}
|
||||
background-color: $stage[1]
|
||||
.action-yesno label,
|
||||
.task-action-btn
|
||||
background-color: darken($stage[1], 30%)
|
||||
&:hover, &:focus
|
||||
background-color: darken($stage[1], 40%)
|
||||
|
||||
// completed has to be outside the loop to override the color class
|
||||
.completed
|
||||
background-color: $completed
|
||||
color: #999
|
||||
.task-checker label
|
||||
background-color: darken($completed, 30%)
|
||||
.task-action-btn
|
||||
background-color: darken($completed, 30%)
|
||||
|
||||
.reward
|
||||
background-color: white
|
||||
|
||||
label.checkbox.inline{
|
||||
width: 40px
|
||||
|
||||
|
||||
// 2. Columns & Tasks
|
||||
// ===================
|
||||
|
||||
// main columns
|
||||
// ------------
|
||||
.task-column
|
||||
padding: 1.5em
|
||||
background: #f5f5f5
|
||||
border: 1px solid #ccc
|
||||
font-family: 'Lato', sans-serif
|
||||
|
||||
.task-column_title
|
||||
margin: 0 0 0.5em
|
||||
padding: 0
|
||||
|
||||
|
||||
// add new task form
|
||||
// -----------------
|
||||
.addtask-form
|
||||
margin-bottom: 0.75em
|
||||
outline: 1px solid rgba(0,0,0,0.15)
|
||||
outline-offset: -1px
|
||||
background-color: white
|
||||
// box-shadow: 0 0 3px rgba(0,0,0,0.15)
|
||||
position: relative
|
||||
|
||||
// the input field
|
||||
.addtask-field
|
||||
display: block
|
||||
width: 100%
|
||||
input
|
||||
font-family: 'Lato', sans-serif
|
||||
border: 0
|
||||
outline: 0
|
||||
border-radius: 0
|
||||
box-shadow: none
|
||||
background-color: white
|
||||
height: 3em
|
||||
padding: 0 0 0 0.5em
|
||||
width: 100%
|
||||
&:focus
|
||||
box-shadow: inset 0 0 3px darken($best, 20%),inset -1px 0 1px darken($best, 30%)
|
||||
|
||||
// the button
|
||||
.addtask-btn
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 0
|
||||
// important for overriding bootstrap, remove later
|
||||
width: 1.81818em !important
|
||||
height: 1.88em
|
||||
padding: 0
|
||||
font-size: 1.61em
|
||||
line-height: 1.7
|
||||
outline: 0
|
||||
border: 0
|
||||
border-radius: 0 //required to nuke BB-playbook user agent styles
|
||||
background-color: darken($best, 15%)
|
||||
&:hover,
|
||||
&:focus
|
||||
// opacity: 1
|
||||
background-color: darken($best, 20%)
|
||||
&:active
|
||||
background-color: darken($best, 30%)
|
||||
// opacity: 1
|
||||
|
||||
|
||||
// an individual task entry
|
||||
// ------------------------
|
||||
.task
|
||||
overflow: hidden
|
||||
list-style: none
|
||||
clear: both
|
||||
padding: 0 0.5em 0 0.5em
|
||||
min-height: 3em
|
||||
line-height: 3
|
||||
margin-bottom: 0.75em
|
||||
outline: 1px solid rgba(0,0,0,0.1)
|
||||
outline-offset: -1px
|
||||
&:hover
|
||||
cursor: move
|
||||
&:last-child
|
||||
margin-bottom: 0
|
||||
|
||||
// task content
|
||||
.task-text
|
||||
display: inline
|
||||
|
||||
// when a task is being dragged
|
||||
.task.ui-sortable-helper {
|
||||
box-shadow: 0 0 3px rgba(0,0,0,0.15), 0 0 5px rgba(0,0,0,0.1)
|
||||
transform: scale(1.05)
|
||||
outline: 1px solid rgba(0,0,0,0.2)
|
||||
}
|
||||
|
||||
.todos
|
||||
.nav-pills > .active > a, .nav-pills > .active > a:hover
|
||||
color: #005580
|
||||
background-color: #DEE5F2
|
||||
// primary task commands
|
||||
// ----------------------
|
||||
.task-controls
|
||||
display: inline
|
||||
margin-left: -0.5em
|
||||
margin-right: 0.5em
|
||||
|
||||
.dailys
|
||||
.repeat-days > .btn:not(.active)
|
||||
background-color: #aaa;
|
||||
background-image: -moz-linear-gradient(top, #eee, #aaa);
|
||||
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eee), to(#aaa));
|
||||
background-image: -webkit-linear-gradient(top, #eee, #aaa);
|
||||
background-image: -o-linear-gradient(top, #eee, #aaa);
|
||||
background-image: linear-gradient(to bottom, #eee, #aaa);
|
||||
background-repeat: repeat-x;
|
||||
// plus/minus commands
|
||||
.task-action-btn
|
||||
display: inline-block
|
||||
width: 2.12765em
|
||||
height: 2.12765em
|
||||
padding: 0
|
||||
font-size: 1.41em
|
||||
line-height: 2.12765
|
||||
text-align: center
|
||||
color: #222
|
||||
vertical-align: top
|
||||
border-right: 1px solid rgba(0,0,0,0.25)
|
||||
&:last-child
|
||||
border: 0
|
||||
&:hover, &:focus
|
||||
color: #222
|
||||
text-decoration: none
|
||||
|
||||
// checkbox
|
||||
.task-checker input[type=checkbox]
|
||||
margin: 0
|
||||
padding: 0
|
||||
visibility: hidden
|
||||
|
||||
.task-checker label
|
||||
display: inline-block
|
||||
width: 3em
|
||||
height: 3em
|
||||
margin: 0
|
||||
vertical-align: top
|
||||
cursor: pointer
|
||||
|
||||
// plus/minus checkbox
|
||||
.action-plusminus
|
||||
label
|
||||
margin-right: 1.5em
|
||||
label:after
|
||||
font-size: 1.41em
|
||||
width: 2.12765em
|
||||
height: 2.12765em
|
||||
line-height: 2.12765
|
||||
text-align: center
|
||||
display: inline-block
|
||||
vertical-align top
|
||||
opacity: 0.3
|
||||
background-color: #ddd
|
||||
outline: 1px solid rgba(0,0,0,0.5)
|
||||
color: #222
|
||||
label[for$="plus"]:after
|
||||
content: '+'
|
||||
label[for$="minus"]:after
|
||||
content: '−'
|
||||
|
||||
&.select-toggle input[type=checkbox]:checked + label:after
|
||||
opacity: 1
|
||||
|
||||
// yes/no checkbox
|
||||
.action-yesno
|
||||
position: relative
|
||||
// uncompleted icon
|
||||
label:after, label:before
|
||||
// content: '◯'
|
||||
content: ''
|
||||
display: block
|
||||
height: 1.714285714em
|
||||
width: 1.714285714em
|
||||
font-size: 1.75em
|
||||
line-height: 1.714285714em
|
||||
text-align: center
|
||||
color: black
|
||||
opacity: 0.2
|
||||
|
||||
label:after
|
||||
content: '▨'
|
||||
label:before
|
||||
position: absolute
|
||||
left: 0
|
||||
// hint at completed icon
|
||||
label:hover:before,
|
||||
label:focus:before
|
||||
content: ''
|
||||
label:hover:after,
|
||||
label:focus:after
|
||||
content: '¬'
|
||||
font-size: 3.2em
|
||||
line-height: 0.9375em
|
||||
height: 0.9375em
|
||||
width: 1.15em
|
||||
text-align: center
|
||||
transform: rotate(135deg)
|
||||
opacity: 0.5 !important
|
||||
label:active:after
|
||||
opacity: 0.75 !important
|
||||
|
||||
// completed icon
|
||||
input[type=checkbox]:checked + label:after
|
||||
content: '¬'
|
||||
font-size: 3.2em
|
||||
line-height: 0.9375em
|
||||
height: 0.9375em
|
||||
width: 1.15em
|
||||
text-align: center
|
||||
transform: rotate(135deg)
|
||||
opacity: 0.75
|
||||
|
||||
|
||||
// secondary task commands
|
||||
// -----------------------
|
||||
.task-meta-controls
|
||||
float: right
|
||||
margin-left: 0.25em
|
||||
opacity: 0.25
|
||||
a > i
|
||||
margin-left: 0.125em
|
||||
.task-notes
|
||||
margin-left: 0.125em
|
||||
|
||||
.task:hover .task-meta-controls
|
||||
opacity: 1
|
||||
|
||||
|
||||
// task editing
|
||||
// ------------
|
||||
[class$="-options"]
|
||||
padding: 0 0.5em
|
||||
margin-top: 1.25em
|
||||
color: #333
|
||||
|
||||
.option-group
|
||||
border-bottom: 1px solid rgba(0,0,0,0.1)
|
||||
padding: 0 0 1em
|
||||
margin-bottom: 1em
|
||||
|
||||
.option-title
|
||||
font-size: 1em
|
||||
margin: 0 0 0.5em
|
||||
line-height: 1.5
|
||||
border: 0
|
||||
padding: 0
|
||||
color: #333
|
||||
font-style: italic
|
||||
&:not(.mega):after
|
||||
content: ':'
|
||||
&.mega
|
||||
cursor: pointer
|
||||
font-style: normal
|
||||
font-weight: bold
|
||||
text-decoration: underline
|
||||
|
||||
.option-content
|
||||
height: 2.5em
|
||||
width: 100%
|
||||
margin: 0 0 1em
|
||||
padding: 0 0 0 0.5em
|
||||
outline: 0
|
||||
border: 1px solid rgba(0,0,0,0.2)
|
||||
box-shadow: none
|
||||
border-radius: 0
|
||||
font-family: 'Lato', sans-serif //bootstrap override
|
||||
|
||||
textarea.option-content
|
||||
height: 5em
|
||||
padding-top: 0.25em
|
||||
resize: none
|
||||
margin-bottom: 0
|
||||
|
||||
.option-short
|
||||
.option-content
|
||||
width: 3em
|
||||
display: inline-block
|
||||
.input-suffix
|
||||
vertical-align: 20%
|
||||
padding-left: 0.25em
|
||||
|
||||
// button-group
|
||||
.task-controls.tile-group
|
||||
display: block
|
||||
text-align: center
|
||||
margin: 0
|
||||
|
||||
.task-action-btn.tile
|
||||
border: 0
|
||||
font-size: 1.15em
|
||||
font-weight: 300
|
||||
outline: 1px solid rgba(0,0,0,0.2)
|
||||
outline-offset: -1px
|
||||
margin: 0 0 0 3px
|
||||
font-family: 'Lato', sans-serif
|
||||
text-align: inherit
|
||||
opacity: 0.5
|
||||
width: auto
|
||||
padding: 0 0.5em
|
||||
&.active
|
||||
opacity: 1
|
||||
|
||||
.tile.spacious
|
||||
margin: 0.75em 0
|
||||
font-size: 1.5em
|
||||
opacity: 1
|
||||
.tile.bright
|
||||
background-color: lighten($best, 20%)
|
||||
&:hover, &:focus
|
||||
background-color: lighten($best, 40%)
|
||||
.tile.flush
|
||||
margin-left: 0
|
||||
border: 1px solid rgba(0,0,0,0.2)
|
||||
outline: 0
|
||||
line-height: 2em
|
||||
&:first-child
|
||||
border-right: 0
|
||||
|
||||
|
||||
// todos ui
|
||||
// --------
|
||||
|
||||
// context switching
|
||||
.context-enabled
|
||||
.display-context-dependant,
|
||||
.task-list li
|
||||
|
|
@ -50,39 +369,19 @@ label.checkbox.inline{
|
|||
.show-for-uncompleted, .uncompleted
|
||||
display: block
|
||||
|
||||
.help-icon
|
||||
float:right;
|
||||
|
||||
.task:hover
|
||||
cursor: move
|
||||
|
||||
li:hover .task-meta-controls .hover-show
|
||||
display: inline
|
||||
|
||||
.task
|
||||
list-style:none
|
||||
|
||||
pre
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif
|
||||
font-size: 13px
|
||||
line-height: 18px
|
||||
color: black
|
||||
word-break: normal
|
||||
|
||||
.task-meta-controls
|
||||
float:right
|
||||
i
|
||||
margin-left:5px
|
||||
|
||||
.task-controls,.task-text
|
||||
display:inline
|
||||
margin-right:10px
|
||||
|
||||
.task-meta-controls .hover-show
|
||||
display: none;
|
||||
|
||||
.vote-up, .vote-down
|
||||
text-decoration:none;
|
||||
|
||||
.new-task-form
|
||||
margin-bottom:5px;
|
||||
// nav tabs
|
||||
.nav-tabs
|
||||
margin-top: 1.5em
|
||||
.nav-tabs > li
|
||||
&.active > a
|
||||
color: #333
|
||||
&:hover
|
||||
margin-top: 1px
|
||||
> a
|
||||
border-radius: 0 !important
|
||||
margin-top: 1px
|
||||
color: #333
|
||||
&:hover
|
||||
border-top: 0
|
||||
margin-top: 2px
|
||||
|
|
@ -271,3 +271,16 @@ describe 'API', ->
|
|||
expect(res.statusCode).to.be 400
|
||||
expect(res.body.err).to.be 'No task found.'
|
||||
done()
|
||||
|
||||
it 'POST /api/v1/user/task/:id/up', (done) ->
|
||||
tid = currentUser.habitIds[0]
|
||||
request.post("#{baseURL}/user/task/#{tid}/up")
|
||||
.set('Accept', 'application/json')
|
||||
.set('X-API-User', currentUser.id)
|
||||
.set('X-API-Key', currentUser.apiToken)
|
||||
.send({})
|
||||
.end (res) ->
|
||||
expect(res.body.err).to.be undefined
|
||||
expect(res.statusCode).to.be 200
|
||||
expect(res.body).to.eql { gp: 1, exp: 7.5, lvl: 1, hp: 50, delta: 1 }
|
||||
done()
|
||||
|
|
|
|||
|
|
@ -1,32 +1,16 @@
|
|||
<alerts:>
|
||||
<newStuff:>
|
||||
{#if equal(_user.flags.newStuff,'show')}
|
||||
<div class='new-stuff'>
|
||||
<p class='alert alert-success'>
|
||||
<a href="https://github.com/lefnire/habitrpg/blob/develop/CHANGELOG.md#3212013" target="_blank">New Stuff!</a> <a x-bind="click:closeNewStuff"><i class='icon-remove'></i></a>
|
||||
</p>
|
||||
|
||||
</div>
|
||||
{/}
|
||||
|
||||
<flash:>
|
||||
{#if _flash.error}
|
||||
<ul class="unstyled alert alert-error">
|
||||
{#each _flash.error as :error}<li>{:error}</li>{/}
|
||||
</ul>
|
||||
{/}
|
||||
|
||||
{#if equal(_user.flags.algosNotification,'show')}
|
||||
<div class='alert alert-success'>
|
||||
<a x-bind="click:closeAlgosNotification" class=pull-right>[x]</a>
|
||||
<p>New features! Custom day start, new and better algorithms, authentication enhancements. See <a target="_blank" href="http://habitrpg.tumblr.com/post/44468869138/custom-day-start-better-algorithms-auth-enhancements">details here.</a>
|
||||
"Hey, I had more Exp before this roll-out!" <a data-target="#restore-modal" data-toggle=modal>Restore your Exp here.</a></p>
|
||||
</div>
|
||||
{/}
|
||||
|
||||
{#if equal(_user.flags.onliesNotification, 'show')}
|
||||
<div class='alert alert-success'>
|
||||
<a x-bind="click:closeOnliesNotification " class=pull-right>[x]</a>
|
||||
<p>
|
||||
"Onlies" now gain / lose value just like other habits, and are reset back to 0 at the beginning of each day.
|
||||
See <a target="_blank" href="https://trello.com/card/shading-onlies/50e5d3684fe3a7266b0036d6/67">details here</a>, and
|
||||
chime in with your recommendations on this mechanic.
|
||||
</p>
|
||||
</div>
|
||||
{/}
|
||||
|
||||
{#if equal(_user.flags.priorityNotification, 'show')}
|
||||
<div class='alert alert-success'>
|
||||
<a x-bind="click:closePriorityNotification" class=pull-right>[x]</a>
|
||||
<p>New Feature: Priority Multiplier! You can now multiply "more important" tasks on a 1x, 1.5x, or 2x scale. <a target="_blank" href="https://trello.com/card/priority-multiplier/50e5d3684fe3a7266b0036d6/17">See details</a>.</p>
|
||||
</div>
|
||||
{/}
|
||||
|
|
@ -1,20 +1,18 @@
|
|||
<modals:>
|
||||
<app:modals:modal modalId="avatar-modal">
|
||||
{#if _profileActiveMain}
|
||||
{#with _user.preferences}
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a data-toggle='tab' href="#profileCustomize">Avatar</a></li>
|
||||
<li><a data-toggle='tab' href="#profileEdit">Profile</a></li>
|
||||
</ul>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a data-toggle='tab' href="#profileCustomize">Avatar</a></li>
|
||||
<li><a data-toggle='tab' href="#profileEdit">Profile</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="profileCustomize">
|
||||
<app:avatar:customize />
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="profileEdit"><app:avatar:profile user="{_user}" main="true" /></div>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="profileCustomize">
|
||||
<app:avatar:customize />
|
||||
</div>
|
||||
{/}
|
||||
|
||||
<div class="tab-pane" id="profileEdit"><app:avatar:profile user="{_user}" main="true" /></div>
|
||||
</div>
|
||||
{else}
|
||||
<app:avatar:profile profile={_profileActive} />
|
||||
{/}
|
||||
|
|
@ -25,23 +23,28 @@
|
|||
|
||||
<avatar:>
|
||||
<div class="avatar {{#if @main}}main-avatar{{/}} {{#if @party}}party-avatar{{/}}" data-toggle='modal' data-target='#avatar-modal' data-uid="{@profile.id}" x-bind="click:profileChangeActive">
|
||||
{#unless @minimal}{#if @profile.items.pet}<img src='img/sprites/{@profile.items.pet.icon}' />{/}{/}
|
||||
<div class='character-sprites'>
|
||||
{#with @profile.preferences as :p}
|
||||
<span class='{:p.gender}_skin_{:p.skin}'></span>
|
||||
<span class='{:p.gender}_hair_{:p.hair}'></span>
|
||||
<span class="{equipped(@profile, 'armor')}"></span>
|
||||
{#if :p.showHelm}
|
||||
<span class="{equipped(@profile, 'head')}"></span>
|
||||
{else}
|
||||
<span class="{:p.gender}_head_0"></span>
|
||||
{/}
|
||||
<span class='{:p.gender}_shield_{@profile.items.shield}'></span>
|
||||
<span class='{:p.gender}_weapon_{@profile.items.weapon}'></span>
|
||||
{/}
|
||||
</div>
|
||||
|
||||
{#if and(@profile.items.pet, not(@minimal))}
|
||||
<img src='/img/sprites/{@profile.items.pet.icon}' />
|
||||
{/}
|
||||
|
||||
{#with @profile.preferences as :p}
|
||||
<div class='character-sprites'>
|
||||
<span class='{:p.gender}_skin_{:p.skin}'></span>
|
||||
<span class='{:p.gender}_hair_{:p.hair}'></span>
|
||||
<span class="{equipped(@profile, 'armor')}"></span>
|
||||
{#if :p.showHelm}
|
||||
<span class="{equipped(@profile, 'head')}"></span>
|
||||
{else}
|
||||
<span class="{:p.gender}_head_0"></span>
|
||||
{/}
|
||||
<span class='{:p.gender}_shield_{@profile.items.shield}'></span>
|
||||
<span class='{:p.gender}_weapon_{@profile.items.weapon}'></span>
|
||||
</div>
|
||||
{/}
|
||||
|
||||
{{#unless @minimal}}
|
||||
<div class="lvl"><span class="badge badge-info">Lvl {@profile.stats.lvl}</span></div>
|
||||
<div class="lvl"><span class="badge badge-info">Lvl {@profile.stats.lvl}</span></div>
|
||||
{{/}}
|
||||
</div>
|
||||
|
||||
|
|
@ -53,101 +56,103 @@
|
|||
</figure>
|
||||
|
||||
<!-- customization options -->
|
||||
<menu type="list">
|
||||
<!-- gender -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Head">
|
||||
<button type="button" class="m_head_0 customize-option" data-value="m" x-bind="click:customizeGender"></button>
|
||||
<button type="button" class="f_head_0 customize-option" data-value="f" x-bind="click:customizeGender"></button>
|
||||
</menu>
|
||||
<label class="checkbox">
|
||||
<input type=checkbox checked="{_user.preferences.showHelm}" /> Show Helm
|
||||
</label>
|
||||
|
||||
</li>
|
||||
|
||||
<!-- hair -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Hair">
|
||||
<button type="button" class="{.gender}_hair_blond customize-option" data-value="blond" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{.gender}_hair_black customize-option" data-value="black" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{.gender}_hair_brown customize-option" data-value="brown" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{.gender}_hair_white customize-option" data-value="white" x-bind="click:customizeHair"></button>
|
||||
</menu>
|
||||
</li>
|
||||
|
||||
<!-- skin -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Skin">
|
||||
<button type="button" class='{.gender}_skin_dead customize-option' data-value="dead" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{.gender}_skin_orc customize-option' data-value="orc" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{.gender}_skin_asian customize-option' data-value="asian" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{.gender}_skin_black customize-option' data-value="black" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{.gender}_skin_white customize-option' data-value="white" x-bind="click:customizeSkin"></button>
|
||||
</menu>
|
||||
</li>
|
||||
</menu>
|
||||
|
||||
{#if equal(_user.preferences.gender, 'f')} <!-- Sorry boys -->
|
||||
{#with _user.preferences as :p}
|
||||
<menu type="list">
|
||||
<!-- gender -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Clothing">
|
||||
<button type="button" class="f_armor_0_v1 customize-option" data-value="v1" x-bind="click:customizeArmorSet"></button>
|
||||
<button type="button" class="f_armor_0_v2 customize-option" data-value="v2" x-bind="click:customizeArmorSet"></button>
|
||||
<menu label="Head">
|
||||
<button type="button" class="m_head_0 customize-option" data-value="m" x-bind="click:customizeGender"></button>
|
||||
<button type="button" class="f_head_0 customize-option" data-value="f" x-bind="click:customizeGender"></button>
|
||||
</menu>
|
||||
<label class="checkbox">
|
||||
<input type=checkbox checked="{_user.preferences.showHelm}" /> Show Helm
|
||||
</label>
|
||||
|
||||
</li>
|
||||
|
||||
<!-- hair -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Hair">
|
||||
<button type="button" class="{:p.gender}_hair_blond customize-option" data-value="blond" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{:p.gender}_hair_black customize-option" data-value="black" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{:p.gender}_hair_brown customize-option" data-value="brown" x-bind="click:customizeHair"></button>
|
||||
<button type="button" class="{:p.gender}_hair_white customize-option" data-value="white" x-bind="click:customizeHair"></button>
|
||||
</menu>
|
||||
</li>
|
||||
|
||||
<!-- skin -->
|
||||
<li class="customize-menu">
|
||||
<menu label="Skin">
|
||||
<button type="button" class='{:p.gender}_skin_dead customize-option' data-value="dead" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{:p.gender}_skin_orc customize-option' data-value="orc" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{:p.gender}_skin_asian customize-option' data-value="asian" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{:p.gender}_skin_black customize-option' data-value="black" x-bind="click:customizeSkin"></button>
|
||||
<button type="button" class='{:p.gender}_skin_white customize-option' data-value="white" x-bind="click:customizeSkin"></button>
|
||||
</menu>
|
||||
</li>
|
||||
</menu>
|
||||
|
||||
{#if equal(_user.preferences.gender, 'f')} <!-- Sorry boys -->
|
||||
<menu type="list">
|
||||
<li class="customize-menu">
|
||||
<menu label="Clothing">
|
||||
<button type="button" class="f_armor_0_v1 customize-option" data-value="v1" x-bind="click:customizeArmorSet"></button>
|
||||
<button type="button" class="f_armor_0_v2 customize-option" data-value="v2" x-bind="click:customizeArmorSet"></button>
|
||||
</menu>
|
||||
</li>
|
||||
</menu>
|
||||
{/}
|
||||
{/}
|
||||
|
||||
<profile:>
|
||||
<div class='row-fluid'>
|
||||
<div class='span6 well'>
|
||||
{#if _profileEditing}
|
||||
{#if _profileActiveMain}
|
||||
<a class='btn btn-success' x-bind="click:profileSave">Save</a>
|
||||
<!-- TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileImageUrl">Photo Url</label>
|
||||
<div class="controls">
|
||||
<input type="url" id="profileImageUrl" value="{_user.profile.imageUrl}" placeholder="Image Url"/>
|
||||
</div>
|
||||
{#if and(_profileEditing, _profileActiveMain)}
|
||||
<a class='btn btn-success' x-bind="click:profileSave">Save</a>
|
||||
<!-- TODO use photo-upload instead: https://groups.google.com/forum/?fromgroups=#!topic/derbyjs/xMmADvxBOak -->
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileImageUrl">Photo Url</label>
|
||||
<div class="controls">
|
||||
<input type="url" id="profileImageUrl" value="{_user.profile.imageUrl}" placeholder="Image Url"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileFullName">Full Name</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="profileFullName" placeholder="Full Name" value="{_user.profile.name}" />
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileFullName">Full Name</label>
|
||||
<div class="controls">
|
||||
<input type="text" id="profileFullName" placeholder="Full Name" value="{_user.profile.name}" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileBlurb">Blurb</label>
|
||||
<div class="controls">
|
||||
<textarea id="profileBlurb" placeholder="Blurb" >{_user.profile.blurb}</textarea>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileBlurb">Blurb</label>
|
||||
<div class="controls">
|
||||
<textarea id="profileBlurb" placeholder="Blurb" >{_user.profile.blurb}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileWebsite">Websites</label>
|
||||
<div class="controls">
|
||||
<form x-bind="submit:profileAddWebsite">
|
||||
<input type="url" id="profileWebsite" value="{_newProfileWebsite}" placeholder="Add Website"/>
|
||||
</form>
|
||||
</div>
|
||||
<ul>
|
||||
{#each _user.profile.websites as :website}
|
||||
<!-- would prefer if there were and index in #each, instead using data-website to search with indexOf -->
|
||||
<li>{:website} <a data-website="{:website}" x-bind="click:profileRemoveWebsite"><i class='icon-remove'></i></a></li>
|
||||
{/}
|
||||
</ul>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label" for="profileWebsite">Websites</label>
|
||||
<div class="controls">
|
||||
<form x-bind="submit:profileAddWebsite">
|
||||
<input type="url" id="profileWebsite" value="{_newProfileWebsite}" placeholder="Add Website"/>
|
||||
</form>
|
||||
</div>
|
||||
<a class='btn btn-success' x-bind="click:profileSave">Save</a>
|
||||
{/}
|
||||
<ul>
|
||||
{#each _user.profile.websites as :website}
|
||||
<!-- would prefer if there were and index in #each, instead using data-website to search with indexOf -->
|
||||
<li>{:website} <a data-website="{:website}" x-bind="click:profileRemoveWebsite"><i class='icon-remove'></i></a></li>
|
||||
{/}
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<a class='btn btn-success' x-bind="click:profileSave">Save</a>
|
||||
{else}
|
||||
<h3>
|
||||
{#if _profileActive.profile.name}{_profileActive.profile.name}
|
||||
{else}{username(_profileActive.auth)}
|
||||
{#if _profileActive.profile.name}
|
||||
{_profileActive.profile.name}
|
||||
{else}
|
||||
{username(_profileActive.auth)}
|
||||
{/}
|
||||
{#if _profileActiveMain}<a class='btn pull-right' x-bind="click:profileEdit">Edit</a>{/}
|
||||
</h3>
|
||||
|
|
@ -160,7 +165,7 @@
|
|||
{#if _profileActive.profile.websites}
|
||||
<ul>
|
||||
{#each _profileActive.profile.websites as :website}
|
||||
<li>{:website}</li>
|
||||
<li>{:website}</li>
|
||||
{/}
|
||||
</ul>
|
||||
{/}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
<!-- party -->
|
||||
{{#each _partyMembers as :member}}
|
||||
<!-- #each requires an element, so #if / #unless blocks nested immediately inside cause issues if they return false -->
|
||||
<!-- see https://github.com/codeparty/derby/issues/215 -->
|
||||
<span>
|
||||
{{#unless equal(:member.id, _userId)}}
|
||||
<figure class="party-avatar-wrap" rel="popover" data-title="{{username(:member.auth)}}" data-placement="bottom" data-trigger="hover" data-html="true" data-content="
|
||||
<div>
|
||||
|
|
@ -27,6 +30,7 @@
|
|||
<app:avatar:avatar profile={{:member}} party="true" />
|
||||
</figure>
|
||||
{{/}}
|
||||
</span>
|
||||
{{/}}
|
||||
|
||||
<!-- progress bars -->
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<import: src="modals">
|
||||
<import: src="tasks" ns="">
|
||||
<import: src="tasks">
|
||||
<import: src="header">
|
||||
<import: src="alerts">
|
||||
<import: src="avatar">
|
||||
<import: src="rewards" ns="">
|
||||
<import: src="rewards">
|
||||
<import: src="footer">
|
||||
<import: src="settings">
|
||||
<import: src="party">
|
||||
|
|
@ -12,13 +12,24 @@
|
|||
HabitRPG | Gamify Your Life
|
||||
|
||||
<Head:>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||
|
||||
<!-- webfonts -->
|
||||
<link href='//fonts.googleapis.com/css?family=Lato:300,400,700,400italic,700italic' rel='stylesheet' type='text/css'>
|
||||
|
||||
<!-- CDN -->
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
|
||||
<Header:>
|
||||
<app:modals:modals />
|
||||
<ui:connectionAlert>
|
||||
<app:alerts:newStuff />
|
||||
<div id="head" class="container-fluid">
|
||||
|
||||
{#if _undo}<a x-bind="click:undo" class='label undo-button'>Undo</a>{/}
|
||||
|
||||
<app:settings:menu />
|
||||
<app:header:header />
|
||||
</div>
|
||||
|
|
@ -26,18 +37,27 @@
|
|||
<Body:>
|
||||
<br/>
|
||||
<div id="notification-area"></div>
|
||||
<div id=wrap class="container-fluid">
|
||||
<app:alerts:alerts />
|
||||
<div id=main class="row-fluid">
|
||||
<app:taskLists />
|
||||
<div id="wrap">
|
||||
<app:alerts:flash />
|
||||
<div id=main class="grid">
|
||||
<app:tasks:taskLists />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app:footer:footer />
|
||||
|
||||
<Scripts:>
|
||||
<!-- scripts go in /src/app/browser.coffee, that way we can get min/concat -->
|
||||
<!-- only the ones that are remote and can't be done async are here -->
|
||||
<!-- we load as many CDN-available javascript files here as possible. For the rest,
|
||||
we use /src/app/browser.coffee -> loadJavaScripts() which concats/minifies /public/vendor javascript libraries,
|
||||
as well as runs async loads -->
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.3.1/jquery.cookie.min.js"></script>
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-growl/1.0.0/jquery.bootstrap-growl.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.0.0/js/bootstrap-datepicker.min.js"></script>
|
||||
|
||||
<script src="https://checkout.stripe.com/v2/checkout.js"></script>
|
||||
|
||||
{#if equal(_view.nodeEnv,"production")}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
<!-- Re-Roll modal -->
|
||||
<app:modals:modal modalId='reroll-modal' header="Reset Your Tasks">
|
||||
<app:userTokens/>
|
||||
<app:rewards:userTokens/>
|
||||
<p>Highly discouraged because red tasks provide good incentive to improve (<a target="_blank" href="https://github.com/lefnire/habitrpg#all-my-tasks-are-red-im-dying-too-fast">read more</a>). However, this becomes necessary after long bouts of bad habits.</p>
|
||||
<@footer>
|
||||
{#if lt(_user.balance,1)}
|
||||
|
|
@ -30,7 +30,7 @@
|
|||
|
||||
<!-- Buy more tokens modal -->
|
||||
<app:modals:modal modalId='more-tokens-modal' header="Out Of Tokens">
|
||||
<app:userTokens/>
|
||||
<app:rewards:userTokens/>
|
||||
<p>You're out of tokens, which are used to buy pets and mounts.</p>
|
||||
<@footer>
|
||||
<a data-dismiss="modal" x-bind="click:showStripe" class="btn btn-success btn-large">Buy More Tokens</a><span class='token-cost'>Not enough tokens</span>
|
||||
|
|
|
|||
|
|
@ -1,65 +1,142 @@
|
|||
<rewardsColumn:>
|
||||
<div class="module">
|
||||
<div class="task-column rewards">
|
||||
<!-- cash or tokens -->
|
||||
<span class='option-box pull-right wallet'>
|
||||
{#unless _view.activeTabPets}
|
||||
<div class="money">
|
||||
{gold(_user.stats.gp)}
|
||||
<span class='shop_gold' rel='tooltip' title='Gold'></span>
|
||||
</div>
|
||||
<div class="money">
|
||||
{silver(_user.stats.gp)}
|
||||
<span class='shop_silver' rel='tooltip' title='Silver'></span>
|
||||
</div>
|
||||
<!-- <div class="money">
|
||||
{copper(_user.stats.gp)}
|
||||
<span class='shop_copper' rel='tooltip' title='Copper'></span>
|
||||
</div> -->
|
||||
{else}
|
||||
<app:rewards:userTokens />
|
||||
{/}
|
||||
</span>
|
||||
<h2 class="task-column_title">Rewards</h2>
|
||||
|
||||
<!-- if pets are enabled, make tabs -->
|
||||
{#if equal(_user.flags.petsEnabled,true)}
|
||||
<div class='tabbable tabs-below'>
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="rewards-tab">
|
||||
<app:rewards:rewardsTab />
|
||||
</div>
|
||||
|
||||
<!-- pets pane -->
|
||||
<div class="tab-pane pet-grid" id="pets-tab">
|
||||
{#with _view.items.pets as :pets}
|
||||
<table>
|
||||
<tr>
|
||||
{#with :pets[0]}<app:rewards:pet />{/}
|
||||
{#with :pets[1]}<app:rewards:pet />{/}
|
||||
{#with :pets[2]}<app:rewards:pet />{/}
|
||||
{#with :pets[3]}<app:rewards:pet />{/}
|
||||
</tr>
|
||||
<tr>
|
||||
{#with :pets[4]}<app:rewards:pet />{/}
|
||||
{#with :pets[5]}<app:rewards:pet />{/}
|
||||
{#with :pets[6]}<app:rewards:pet />{/}
|
||||
{#with :pets[7]}<app:rewards:pet />{/}
|
||||
</tr>
|
||||
<tr>
|
||||
{#with :pets[8]}<app:rewards:pet />{/}
|
||||
{#with :pets[9]}<app:rewards:pet />{/}
|
||||
{#with :pets[10]}<app:rewards:pet />{/}
|
||||
{#with :pets[11]}<app:rewards:pet />{/}
|
||||
</tr>
|
||||
<tr>
|
||||
{#with :pets[12]}<app:rewards:pet />{/}
|
||||
{#with :pets[13]}<app:rewards:pet />{/}
|
||||
{#with :pets[14]}<app:rewards:pet />{/}
|
||||
{#with :pets[15]}<app:rewards:pet />{/}
|
||||
</tr>
|
||||
<tr>
|
||||
{#with :pets[16]}<app:rewards:pet />{/}
|
||||
</tr>
|
||||
</table>
|
||||
{/}
|
||||
</div>
|
||||
<!--<div class="tab-pane" id="mounts-tab">...</div>-->
|
||||
</div>
|
||||
|
||||
<ul class="nav nav-tabs" id="rewardsTabs">
|
||||
<li class="active"><a href="#rewards-tab" data-toggle="tab" x-bind="click:activateRewardsTab">Rewards</a></li>
|
||||
<li><a href="#pets-tab" data-toggle="tab" x-bind='click:activatePetsTab'>Pets</a></li>
|
||||
<!--<li><a href="#mounts-tab" data-toggle="tab">Mounts</a></li>-->
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<!-- if pets are disabled, just do rewards tab -->
|
||||
{else}
|
||||
<app:rewards:rewardsTab />
|
||||
{/}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<rewardsTab:>
|
||||
<!-- add new reward -->
|
||||
<app:tasks:newTask type="reward" inputValue="{_newReward}" placeHolder="New Reward" />
|
||||
|
||||
{#if _rewardList}
|
||||
<ul class='rewards'>
|
||||
{#each _rewardList as :task}<app:task />{/}
|
||||
{#each _rewardList as :task}<app:tasks:task />{/}
|
||||
</ul>
|
||||
{/}
|
||||
|
||||
|
||||
{#if _user.flags.itemsEnabled}
|
||||
<ul class='items'>
|
||||
{#with _view.items.weapon as :item}<app:item />{/}
|
||||
{#with _view.items.armor as :item}<app:item />{/}
|
||||
{#with _view.items.head as :item}<app:item />{/}
|
||||
{#with _view.items.shield as :item}<app:item />{/}
|
||||
{#with _view.items.potion as :item}<app:item />{/}
|
||||
{#with _view.items.reroll as :item}<app:item reroll=true />{/}
|
||||
{#with _view.items.weapon as :item}<app:rewards:item />{/}
|
||||
{#with _view.items.armor as :item}<app:rewards:item />{/}
|
||||
{#with _view.items.head as :item}<app:rewards:item />{/}
|
||||
{#with _view.items.shield as :item}<app:rewards:item />{/}
|
||||
{#with _view.items.potion as :item}<app:rewards:item />{/}
|
||||
{#with _view.items.reroll as :item}<app:rewards:item reroll=true />{/}
|
||||
</ul>
|
||||
{/}
|
||||
|
||||
<pet:>
|
||||
<div class="span3 shop-pet" rel=tooltip title="{.text} - {.value} Tokens">
|
||||
<div style='position:relative'>
|
||||
{#if _user.items.pets[.name]}<i class='icon-ok shop-pet-owned-check'></i>{/}
|
||||
<img x-bind="click:selectPet" data-pet='{.name}' src='img/sprites/{.icon}'/>
|
||||
</div>
|
||||
</div>
|
||||
<td class="{#if _user.items.pets[.name]}active-pet{/}">
|
||||
<img rel=tooltip title="{.text} - {.value} Tokens" x-bind="click:selectPet" data-pet='{.name}' src='img/sprites/{.icon}'/>
|
||||
</td>
|
||||
|
||||
|
||||
<userTokens:>
|
||||
<div class="pull-right">
|
||||
<div class="input-append">
|
||||
<span class="uneditable-input" style="width:auto;">{tokens(_user.balance)}</span>
|
||||
<span class="add-on">Tokens</span>
|
||||
</div>
|
||||
</div>
|
||||
<!--<span class="well pull-right">Tokens: {tokens(_user.balance)}</span>-->
|
||||
<a class="pull-right token-wallet">
|
||||
<span class="task-action-btn tile flush bright add-token-btn">+</span>
|
||||
<span class="task-action-btn tile flush neutral">{tokens(_user.balance)} Tokens</span>
|
||||
</a>
|
||||
|
||||
|
||||
|
||||
<item:>
|
||||
{#unless :item.hide}
|
||||
<li class="task reward item">
|
||||
<pre>
|
||||
<div class="task-meta-controls">
|
||||
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:item.notes}" data-original-title="{:item.text}" class='task-notes'><i class="icon-comment"></i></span>
|
||||
</div>
|
||||
<div class="task-controls">
|
||||
{#if @reroll}
|
||||
<a href="#" data-toggle="modal" data-target="#reroll-modal" class="item-buy-link" style='cursor:pointer'><i class=icon-retweet></i></a>
|
||||
{else}
|
||||
<a x-bind=click:buyItem class="item-buy-link" data-type={:item.type} data-value={:item.value} data-index={:item.index}>{:item.value}<img src="/img/coin_single_gold.png"/></a>
|
||||
{/}
|
||||
</div>
|
||||
<div class="task-text">
|
||||
{#if :item.icon}
|
||||
<img src="/img/sprites/{:item.icon}" /> {:item.text}
|
||||
{else}
|
||||
<table class='shop-table'><tr>
|
||||
<td><div class="shop_{:item.classes} shop-sprite"></div></td>
|
||||
<td>{:item.text}</td>
|
||||
</tr></table>
|
||||
{/}
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
</li>
|
||||
{/}
|
||||
<li class="task reward-item {#if :item.hide}hide{/}">
|
||||
<!-- right-hand side control buttons -->
|
||||
<div class="task-meta-controls">
|
||||
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:item.notes}" data-original-title="{:item.text}" class='task-notes'><i class="icon-comment"></i></span>
|
||||
</div>
|
||||
|
||||
<!-- left-hand size commands -->
|
||||
<div class="task-controls">
|
||||
{#if @reroll}
|
||||
<a class="task-action-btn btn-reroll" data-toggle="modal" data-target="#reroll-modal">⟲</a>
|
||||
{else}
|
||||
<a class="money btn-buy item-btn" x-bind=click:buyItem data-type={:item.type} data-value={:item.value} data-index={:item.index}>
|
||||
<span class="reward-cost">{:item.value}</span>
|
||||
<span class='shop_gold'></span>
|
||||
</a>
|
||||
{/}
|
||||
</div>
|
||||
<!-- main content -->
|
||||
<span class="shop_{:item.classes} shop-sprite item-img"></span>
|
||||
<p class="task-text">{:item.text}</p>
|
||||
</li>
|
||||
|
|
@ -7,11 +7,11 @@
|
|||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="settings-settings">
|
||||
<div class="tab-pane active personal-options" id="settings-settings">
|
||||
<h4>Custom Day Start</h4>
|
||||
<div class="input-append">
|
||||
<input class="span2" type="number" min=0 max=24 value={_user.preferences.dayStart} />
|
||||
<span class="add-on">:00 (24h)</span>
|
||||
<div class="option-group option-short">
|
||||
<input class="option-content option-time" type="number" min=0 max=24 value={_user.preferences.dayStart}>
|
||||
<span class="input-suffix">:00 (24h clock)</span>
|
||||
</div>
|
||||
<div>
|
||||
<small>Habit defaults to check and reset your dailies at midnight each day. You can customize that here (Enter number between 0 and 24).</small>
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
<hr/>
|
||||
<h4>Misc</h4>
|
||||
<button x-bind="click:toggleHeader">{#if _user.preferences.hideHeader}Show Header{else}Hide Header{/}</button>
|
||||
<button x-bind="click:toggleHeader" class="btn">{#if _user.preferences.hideHeader}Show Header{else}Hide Header{/}</button>
|
||||
{#unless _user.flags.partyEnabled} <button x-bind="click:manuallyUnlockParties" data-dismiss='modal' rel=tooltip title="Parties are unlocked automatically for usability reasons, but you can override that here.">Enable Parties</button>{/}
|
||||
|
||||
{{#if _user.auth.local}}
|
||||
|
|
@ -157,4 +157,4 @@
|
|||
</ul>
|
||||
</div>
|
||||
{/}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,235 +1,191 @@
|
|||
<taskLists:>
|
||||
<!--helpTitle & helpContent moved to tour -->
|
||||
<div class="span3 well habits">
|
||||
<h2>Habits</h2>
|
||||
<app:newTask type="habit" inputValue="{_newHabit}" placeHolder="New Habit" />
|
||||
<ul class="habits">{#each _habitList as :task}<app:task />{/}</ul>
|
||||
|
||||
<!-- Habits Column -->
|
||||
<div class="module">
|
||||
<div class="task-column habits">
|
||||
<h2 class="task-column_title">Habits</h2>
|
||||
<app:tasks:newTask type="habit" inputValue="{_newHabit}" placeHolder="New Habit" />
|
||||
<ul class="habits">{#each _habitList as :task}<app:tasks:task />{/}</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="span3 well dailys">
|
||||
<h2>Daily</h2>
|
||||
<app:newTask type="daily" inputValue="{_newDaily}" placeHolder="New Daily" />
|
||||
<ul class='dailys'>{#each _dailyList as :task}<app:task />{/}</ul>
|
||||
<!-- Dailys Column -->
|
||||
<div class="module">
|
||||
<div class="task-column dailys">
|
||||
<h2 class="task-column_title">Daily</h2>
|
||||
<app:tasks:newTask type="daily" inputValue="{_newDaily}" placeHolder="New Daily" />
|
||||
<ul class='dailys'>{#each _dailyList as :task}<app:tasks:task />{/}</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="span3 well todos context-enabled context-uncompleted tabbable tabs-below" id="todo-well">
|
||||
<h2>Todos</h2>
|
||||
<div class="display-context-dependant show-for-uncompleted">
|
||||
<app:newTask type="todo" inputValue="{_newTodo}" placeHolder="New Todo" />
|
||||
</div>
|
||||
<ul class='todos task-list'>
|
||||
{#each _todoList as :task}<app:task />{/}
|
||||
</ul>
|
||||
<div class="display-context-dependant show-for-completed">
|
||||
<a class='btn' x-bind=click:clearCompleted>Clear Completed</a>
|
||||
<p> </p>
|
||||
</div>
|
||||
<span class='pull-right'>
|
||||
<!-- Todos Column -->
|
||||
<div class="module">
|
||||
<div class="task-column todos context-enabled context-uncompleted tabbable tabs-below" id="todo-well">
|
||||
<!-- todo export/graph options -->
|
||||
<span class='option-box pull-right'>
|
||||
{#if _user.history.todos}
|
||||
<a x-bind=click:toggleChart data-toggle-id="todos-chart" data-history-path="_user.history.todos" rel=tooltip title="Progress"><i class=icon-signal></i></a>
|
||||
<a class="option-action" x-bind=click:toggleChart data-toggle-id="todos-chart" data-history-path="_user.history.todos" rel=tooltip title="Progress"><i class=icon-signal></i></a>
|
||||
{/}
|
||||
<a href="/v1/users/{{_user.id}}/calendar.ics?apiToken={{_user.apiToken}}"><img src='/img/calendar_ical.png' title="iCal" alt="iCal" rel=tooltip /></a>
|
||||
<!-- <a target="_blank" href="https://www.google.com/calendar/render?cid={{encodeiCalLink(_user.id, _user.apiToken)}}"><img src='/img/calendar_google.png' title="Google Calendar" alt="Google Calendar" rel=tooltip /></a>-->
|
||||
<a class="option-action" href="/v1/users/{{_user.id}}/calendar.ics?apiToken={{_user.apiToken}}" rel=tooltip title="iCal"><i class=icon-calendar></i></a>
|
||||
<!-- <a href="https://www.google.com/calendar/render?cid={{encodeiCalLink(_user.id, _user.apiToken)}}" rel=tooltip title="Google Calendar"><i class=icon-calendar></i></a> -->
|
||||
</span>
|
||||
<div id="todos-chart" style="display:none;"></div>
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a x-bind=click:changeContext data-target="#todo-well" data-context="context-uncompleted">Remaining</a></li>
|
||||
<li><a x-bind=click:changeContext data-target="#todo-well" data-context="context-completed">Complete</a></li>
|
||||
</ul>
|
||||
<h2 class="task-column_title">Todos</h2>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="span3 well rewards">
|
||||
|
||||
<!--Title -->
|
||||
<div class="row-fluid">
|
||||
<div class="span6"><h2>Rewards</h2></div>
|
||||
<div class="span6">
|
||||
{#unless _view.activeTabPets}
|
||||
<table><tr>
|
||||
<td>{gold(_user.stats.gp)} </td>
|
||||
<td><div class='shop_gold' rel='tooltip' title='Gold'></div></td>
|
||||
<td>{silver(_user.stats.gp)} </td>
|
||||
<td><div class='shop_silver' rel='tooltip' title='Silver'></div></td>
|
||||
<!--<td>{copper(_user.stats.gp)} </td>
|
||||
<td><div class='shop_copper' rel='tooltip' title='shop_copper'></div></td>-->
|
||||
</tr></table>
|
||||
{else}
|
||||
<app:userTokens />
|
||||
{/}
|
||||
</div>
|
||||
</div>
|
||||
<app:newTask type="reward" inputValue="{_newReward}" placeHolder="New Reward" />
|
||||
|
||||
{#if equal(_user.flags.petsEnabled,true)}
|
||||
<div class='tabbable tabs-below'>
|
||||
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane active" id="rewards-tab">
|
||||
<app:rewardsTab />
|
||||
</div>
|
||||
|
||||
<div class="tab-pane" id="pets-tab">
|
||||
{#with _view.items.pets as :pets}
|
||||
|
||||
<div class="row-fluid">
|
||||
{#with :pets[0]}<app:pet />{/}
|
||||
{#with :pets[1]}<app:pet />{/}
|
||||
{#with :pets[2]}<app:pet />{/}
|
||||
{#with :pets[3]}<app:pet />{/}
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
{#with :pets[4]}<app:pet />{/}
|
||||
{#with :pets[5]}<app:pet />{/}
|
||||
{#with :pets[6]}<app:pet />{/}
|
||||
{#with :pets[7]}<app:pet />{/}
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
{#with :pets[8]}<app:pet />{/}
|
||||
{#with :pets[9]}<app:pet />{/}
|
||||
{#with :pets[10]}<app:pet />{/}
|
||||
{#with :pets[11]}<app:pet />{/}
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
{#with :pets[12]}<app:pet />{/}
|
||||
{#with :pets[13]}<app:pet />{/}
|
||||
{#with :pets[14]}<app:pet />{/}
|
||||
{#with :pets[15]}<app:pet />{/}
|
||||
</div>
|
||||
|
||||
<div class="row-fluid">
|
||||
{#with :pets[16]}<app:pet />{/}
|
||||
</div>
|
||||
|
||||
|
||||
{/}
|
||||
</div>
|
||||
<!--<div class="tab-pane" id="mounts-tab">...</div>-->
|
||||
<!-- create new todo -->
|
||||
<div class="display-context-dependant show-for-uncompleted">
|
||||
<app:tasks:newTask type="todo" inputValue="{_newTodo}" placeHolder="New Todo" />
|
||||
</div>
|
||||
|
||||
|
||||
<ul class="nav nav-tabs" id="rewardsTabs">
|
||||
<li class="active"><a href="#rewards-tab" data-toggle="tab" x-bind="click:activateRewardsTab">Rewards</a></li>
|
||||
<li><a href="#pets-tab" id='pets-tab' data-toggle="tab" x-bind='click:activatePetsTab'>Pets</a></li>
|
||||
<!--<li><a href="#mounts-tab" data-toggle="tab">Mounts</a></li>-->
|
||||
<!-- list of all the todos -->
|
||||
<ul class='todos task-list'>
|
||||
{#each _todoList as :task}<app:tasks:task />{/}
|
||||
</ul>
|
||||
|
||||
<button class='task-action-btn tile spacious bright display-context-dependant show-for-completed' x-bind=click:clearCompleted>Clear Completed</button>
|
||||
<div id="todos-chart" style="display:none;"></div>
|
||||
|
||||
<!-- remaining/completed tabs -->
|
||||
<ul class="todo-status-toggler nav nav-tabs">
|
||||
<li class="active"><a x-bind=click:changeContext data-target="#todo-well" data-context="context-uncompleted">Remaining</a></li>
|
||||
<li><a x-bind=click:changeContext data-target="#todo-well" data-context="context-completed">Complete</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{else}
|
||||
<app:rewardsTab />
|
||||
{/}
|
||||
</div>
|
||||
|
||||
<!-- Rewards Column -->
|
||||
<app:rewards:rewardsColumn />
|
||||
|
||||
|
||||
<!-- Templates -->
|
||||
<newTask:>
|
||||
<form class="form-inline new-task-form" id="new-{@type}" data-task-type="{@type}" x-bind="submit:addTask">
|
||||
<input value="{@inputValue}" type="text" name="new-task" placeholder="{@placeHolder}"/>
|
||||
<input class="btn" type="submit" value="Add" />
|
||||
<form class="addtask-form form-inline new-task-form" id="new-{@type}" data-task-type="{@type}" x-bind="submit:addTask">
|
||||
<span class="addtask-field"><input value="{@inputValue}" type="text" name="new-task" placeholder="{@placeHolder}"/></span>
|
||||
<input class="addtask-btn" type="submit" value="+">
|
||||
</form>
|
||||
<hr>
|
||||
|
||||
<!-- all the parts of a single task -->
|
||||
<task:>
|
||||
<li data-id={{:task.id}} class="task {taskClasses(:task.type, :task.completed, :task.value, :task.repeat)}">
|
||||
<pre>
|
||||
<div class="task-meta-controls">
|
||||
<li data-id={{:task.id}} class="task {taskClasses(:task)}">
|
||||
|
||||
<!-- right-hand side control buttons -->
|
||||
<div class="task-meta-controls">
|
||||
<!-- edit -->
|
||||
<a x-bind=click:toggleTaskEdit data-hide-id="{{:task.id}}-chart" data-toggle-id="{{:task.id}}-edit" rel=tooltip title="Edit"><i class="icon-pencil"></i></a>
|
||||
<!-- delete -->
|
||||
<a x-bind=click:del rel=tooltip title="Delete"><i class="icon-trash"></i></a>
|
||||
<!-- chart -->
|
||||
<!-- removing for now cuz it's broken -->
|
||||
{#if :task.history}
|
||||
<!-- <a x-bind=click:toggleChart data-toggle-id="{{:task.id}}-chart" data-hide-id="{{:task.id}}-edit" data-history-path="_user.tasks.{{:task.id}}.history" rel="tooltip" title="Progress"><i class="icon-signal"></i></a> -->
|
||||
{/}
|
||||
<!-- notes -->
|
||||
{#if :task.notes}
|
||||
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:task.notes}" data-original-title="{:task.text}" class='task-notes'><i class="icon-comment"></i></span>
|
||||
{/}
|
||||
</div>
|
||||
|
||||
<div class="hover-show">
|
||||
<a x-bind=click:toggleTaskEdit data-hide-id="{{:task.id}}-chart" data-toggle-id="{{:task.id}}-edit" rel=tooltip title="Edit"><i class="icon-pencil"></i></a>
|
||||
<a x-bind=click:del rel=tooltip title="Delete"><i class="icon-trash"></i></a>
|
||||
{#if :task.history}
|
||||
<a x-bind=click:toggleChart data-toggle-id="{{:task.id}}-chart" data-hide-id="{{:task.id}}-edit" data-history-path="_user.tasks.{{:task.id}}.history" rel="tooltip" title="Progress">
|
||||
<i class="icon-signal"></i>
|
||||
</a>
|
||||
{/}
|
||||
</div>
|
||||
<!-- left-hand side checkbox -->
|
||||
<div class="task-controls">
|
||||
<!-- Habits -->
|
||||
{#if equal(:task.type, 'habit')}
|
||||
{#if :task.up}<a class="task-action-btn" data-direction=up x-bind=click:score>+</a>{/}
|
||||
{#if :task.down}<a class="task-action-btn" data-direction=down x-bind=click:score>−</a>{/}
|
||||
|
||||
<!-- Rewards -->
|
||||
{else if equal(:task.type, 'reward')}
|
||||
<a class="money btn-buy" x-bind=click:score data-direction=down>
|
||||
<span class="reward-cost">{:task.value}</span>
|
||||
<span class='shop_gold'></span>
|
||||
</a>
|
||||
|
||||
<!-- Daily & Todos -->
|
||||
{else}
|
||||
<span class="task-checker action-yesno">
|
||||
<input type=checkbox id="box-{{:task.id}}" class="visuallyhidden focusable" checked="{:task.completed}">
|
||||
<label for="box-{{:task.id}}"></label>
|
||||
</span>
|
||||
{/}
|
||||
</div>
|
||||
|
||||
{#if :task.notes}
|
||||
<span rel="popover" data-trigger="hover" data-placement="left" data-content="{:task.notes}" data-original-title="{:task.text}" class='task-notes'><i class="icon-comment"></i></span>
|
||||
{/}
|
||||
</div>
|
||||
<!-- main content -->
|
||||
<p class="task-text">{:task.text}</p>
|
||||
|
||||
<div class="task-controls">
|
||||
<!-- Habits -->
|
||||
{#if equal(:task.type, 'habit')}
|
||||
{#if :task.up}<a data-direction=up x-bind=click:score><img src="/img/add.png" /></a>{/}
|
||||
{#if :task.down}<a data-direction=down x-bind=click:score><img src="/img/remove.png" /></a>{/}
|
||||
<!-- Rewards -->
|
||||
{else if equal(:task.type, 'reward')}
|
||||
<a x-bind=click:score class="buy-link" data-direction=down>{:task.value}<img src="/img/coin_single_gold.png"/></a>
|
||||
<!-- Daily & Todos -->
|
||||
{else}
|
||||
<input type=checkbox checked="{:task.completed}"/>
|
||||
{/}
|
||||
</div>
|
||||
<div class="task-text">{:task.text}</div>
|
||||
|
||||
<app:taskMeta />
|
||||
</pre>
|
||||
<!-- edit/options dialog -->
|
||||
<app:tasks:taskMeta />
|
||||
</li>
|
||||
|
||||
<!-- task edit/options -->
|
||||
<taskMeta:>
|
||||
<div style="display:none;" id={{:task.id}}-edit>
|
||||
<hr/>
|
||||
<div id="{{:task.id}}-edit" class="task-options visuallyhidden">
|
||||
<form x-bind=submit:toggleTaskEdit data-toggle-id="{{:task.id}}-edit">
|
||||
<div class=control-group>
|
||||
<label>Text</label><input type=text value={:task.text} />
|
||||
<label>Notes</label><textarea rows=3>{:task.notes}</textarea>
|
||||
</div>
|
||||
<!-- text & notes -->
|
||||
<fieldset class="option-group">
|
||||
<label class="option-title">Text</label><input class="option-content" type=text value={:task.text}>
|
||||
<label class="option-title">Extra Notes</label><textarea class="option-content" rows=3>{:task.notes}</textarea>
|
||||
</fieldset>
|
||||
|
||||
<!-- if Habit, plus/minus command options -->
|
||||
{#if equal(:task.type, 'habit')}
|
||||
<hr/>
|
||||
<label>Direction</label>
|
||||
<div class="control-group">
|
||||
<label class="checkbox inline"><input type=checkbox checked={:task.up}>Up</label>
|
||||
<label class="checkbox inline"><input type=checkbox checked={:task.down}>Down</label>
|
||||
</div>
|
||||
<fieldset class="option-group">
|
||||
<legend class="option-title">Direction/Actions</legend>
|
||||
<span class="task-checker action-plusminus select-toggle">
|
||||
<input class="visuallyhidden focusable" type=checkbox id="{{:task.id}}-option-plus" checked={:task.up}>
|
||||
<label for="{{:task.id}}-option-plus"></label>
|
||||
</span>
|
||||
<span class="task-checker action-plusminus select-toggle">
|
||||
<input class="visuallyhidden focusable" type=checkbox id="{{:task.id}}-option-minus" checked={:task.down}>
|
||||
<label for="{{:task.id}}-option-minus"></label>
|
||||
</span>
|
||||
</fieldset>
|
||||
|
||||
<!-- if Daily, calendar -->
|
||||
{else if equal(:task.type, 'daily')}
|
||||
<hr/>
|
||||
<label>Repeat</label>
|
||||
<div class="control-group btn-group repeat-days">
|
||||
<!-- note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding -->
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.su}active{/}" data-day='su' x-bind=click:toggleDay>Su</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.m}active{/}" data-day='m' x-bind=click:toggleDay>M</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.t}active{/}" data-day='t' x-bind=click:toggleDay>T</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.w}active{/}" data-day='w' x-bind=click:toggleDay>W</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.th}active{/}" data-day='th' x-bind=click:toggleDay>Th</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.f}active{/}" data-day='f' x-bind=click:toggleDay>F</button>
|
||||
<button type="button" class="btn btn-info {#if :task.repeat.s}active{/}" data-day='s' x-bind=click:toggleDay>S</button>
|
||||
</div>
|
||||
<fieldset class="option-group">
|
||||
<legend class="option-title">Repeat</legend>
|
||||
<div class="task-controls tile-group repeat-days">
|
||||
<!-- note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding -->
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.su}active{/}" data-day='su' x-bind=click:toggleDay>Su</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.m}active{/}" data-day='m' x-bind=click:toggleDay>M</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.t}active{/}" data-day='t' x-bind=click:toggleDay>T</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.w}active{/}" data-day='w' x-bind=click:toggleDay>W</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.th}active{/}" data-day='th' x-bind=click:toggleDay>Th</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.f}active{/}" data-day='f' x-bind=click:toggleDay>F</button>
|
||||
<button type="button" class="task-action-btn tile {#if :task.repeat.s}active{/}" data-day='s' x-bind=click:toggleDay>S</button>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<!-- if Reward, pricing -->
|
||||
{else if equal(:task.type, 'reward')}
|
||||
<hr/>
|
||||
<div class=control-group>
|
||||
<label>Price</label>
|
||||
<div class="input-append">
|
||||
<input class="span5" size="16" type="number" min="0" value={:task.value}><span class="add-on">Gold</span>
|
||||
</div>
|
||||
<fieldset class="option-group option-short">
|
||||
<legend class="option-title">Price</legend>
|
||||
<input class="option-content" size="16" type="number" min="0" value={:task.value}>
|
||||
<div class="money input-suffix"><span class='shop_gold'></span></div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
</div>
|
||||
<!-- if Todo, the due date -->
|
||||
{else if equal(:task.type, 'todo')}
|
||||
<hr/>
|
||||
<div class=control-group>
|
||||
<label>Due Date</label>
|
||||
<input type="text" value="{:task.date}" data-date-format="mm/dd/yyyy" class="datepicker" />
|
||||
<div><small>Enter as date, eg 02/19/2013 or 02-19-2013</small></div>
|
||||
</div>
|
||||
<fieldset class="option-group">
|
||||
<legend class="option-title">Due Date</legend>
|
||||
<input class="option-content datepicker" type="text" value="{:task.date}" data-date-format="mm/dd/yyyy">
|
||||
</fieldset>
|
||||
{/}
|
||||
|
||||
<hr/>
|
||||
|
||||
<!-- Advanced Options -->
|
||||
{#unless equal(:task.type, 'reward')}
|
||||
<div>
|
||||
<a x-bind="click:tasksToggleAdvanced">Advanced</a>
|
||||
<div class='advanced hide'>
|
||||
|
||||
<label>Difficulty <a class='priority-multiplier-help' href="https://trello.com/card/priority-multiplier/50e5d3684fe3a7266b0036d6/17" target="_blank"><i class='icon-question-sign'></i></a></label>
|
||||
<div class="control-group btn-group priority-multiplier" data-id="{{:task.id}}">
|
||||
<button type="button" class="btn btn-info {#if equal(:task.priority,'!')}active{/}{#unless :task.priority}active{/}" data-priority='!' x-bind=click:tasksSetPriority>Easy</button>
|
||||
<button type="button" class="btn btn-info {#if equal(:task.priority,'!!')}active{/}" data-priority='!!' x-bind=click:tasksSetPriority>Medium</button>
|
||||
<button type="button" class="btn btn-info {#if equal(:task.priority,'!!!')}active{/}" data-priority='!!!' x-bind=click:tasksSetPriority>Hard</button>
|
||||
</div>
|
||||
<p x-bind="click:tasksToggleAdvanced" class="option-title mega">Advanced Options</p>
|
||||
<fieldset class="option-group advanced-option visuallyhidden">
|
||||
<legend class="option-title"><a class='priority-multiplier-help' href="https://trello.com/card/priority-multiplier/50e5d3684fe3a7266b0036d6/17" target="_blank"><i class='icon-question-sign'></i></a> Difficulty</legend>
|
||||
<div class="task-controls tile-group priority-multiplier" data-id="{{:task.id}}">
|
||||
<button type="button" class="task-action-btn tile {#if equal(:task.priority,'!')}active{/}{#unless :task.priority}active{/}" data-priority='!' x-bind=click:tasksSetPriority>Easy</button>
|
||||
<button type="button" class="task-action-btn tile {#if equal(:task.priority,'!!')}active{/}" data-priority='!!' x-bind=click:tasksSetPriority>Medium</button>
|
||||
<button type="button" class="task-action-btn tile {#if equal(:task.priority,'!!!')}active{/}" data-priority='!!!' x-bind=click:tasksSetPriority>Hard</button>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
</fieldset>
|
||||
{/}
|
||||
<button type=submit class="btn" x-bind="click:tasksSaveAndClose">Save & Close</button>
|
||||
<button type=submit class="task-action-btn tile spacious" x-bind="click:tasksSaveAndClose">Save & Close</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,16 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
<!-- CDN -->
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css" rel="stylesheet">
|
||||
|
||||
<link href="/vendor/bootstrap/docs/assets/css/docs.css" rel="stylesheet">
|
||||
<link href="/css/static-pages.css" rel="stylesheet">
|
||||
<link href="/css/footer.css" rel="stylesheet">
|
||||
|
||||
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="//netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
|
||||
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/2.3.1/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
$.getScript("//s7.addthis.com/js/250/addthis_widget.js#pubid=lefnire");
|
||||
</script>
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
<import: src="../app/footer">
|
||||
|
||||
<Title:>
|
||||
HabitRPG | About
|
||||
HabitRPG | Privacy
|
||||
|
||||
<Head:>
|
||||
<app:head:head active="about"/>
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<import: src="../app/footer">
|
||||
|
||||
<Title:>
|
||||
HabitRPG | About
|
||||
HabitRPG | Terms
|
||||
|
||||
<Head:>
|
||||
<app:head:head active="about"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue