yarr, fix all teh bugs

This commit is contained in:
Daniel Saewitz 2013-03-16 16:30:45 -04:00
commit 7083e7a103
27 changed files with 1071 additions and 439 deletions

View file

@ -4,7 +4,7 @@
"version": "0.0.0-150", "version": "0.0.0-150",
"main": "./server.js", "main": "./server.js",
"dependencies": { "dependencies": {
"derby": "git://github.com/lefnire/derby#habitrpg", "derby": "git://github.com/Unroll-Me/derby#master",
"racer": "git://github.com/lefnire/racer#habitrpg", "racer": "git://github.com/lefnire/racer#habitrpg",
"racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#habitrpg", "racer-db-mongo": "git://github.com/lefnire/racer-db-mongo#habitrpg",
"derby-ui-boot": "git://github.com/codeparty/derby-ui-boot#master", "derby-ui-boot": "git://github.com/codeparty/derby-ui-boot#master",
@ -26,8 +26,7 @@
"superagent": "~0.12.4", "superagent": "~0.12.4",
"resolve": "~0.2.3", "resolve": "~0.2.3",
"browserify": "1.17.3", "browserify": "1.17.3",
"expect.js": "~0.2.0", "expect.js": "~0.2.0"
"webkit-devtools-agent": "*"
}, },
"private": true, "private": true,
"subdomain": "habitrpg", "subdomain": "habitrpg",

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -0,0 +1,17 @@
#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;}

View file

@ -4,16 +4,6 @@ moment = require 'moment'
restoreRefs = module.exports.restoreRefs = (model) -> restoreRefs = module.exports.restoreRefs = (model) ->
# tnl function
model.fn '_tnl', '_user.stats.lvl', (lvl) ->
# see https://github.com/lefnire/habitrpg/issues/4
# also update in scoring.coffee. TODO create a function accessible in both locations
#TODO find a method of calling algos.tnl()
if lvl==100
0
else
Math.round(((Math.pow(lvl,2)*0.25)+(10 * lvl) + 139.75)/10)*10
#refLists #refLists
_.each ['habit', 'daily', 'todo', 'reward'], (type) -> _.each ['habit', 'daily', 'todo', 'reward'], (type) ->
model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids" model.refList "_#{type}List", "_user.tasks", "_user.#{type}Ids"
@ -71,7 +61,6 @@ setupSortable = (model) ->
dropOnEmpty: false dropOnEmpty: false
cursor: "move" cursor: "move"
items: "li" items: "li"
opacity: 0.4
scroll: true scroll: true
axis: 'y' axis: 'y'
update: (e, ui) -> update: (e, ui) ->

View file

@ -1,6 +1,7 @@
character = require './character' character = require './character'
browser = require './browser' browser = require './browser'
items = require './items' items = require './items'
algos = require './algos'
moment = require 'moment' moment = require 'moment'
_ = require 'underscore' _ = require 'underscore'
@ -21,6 +22,9 @@ module.exports.username = username = (auth) ->
module.exports.view = (view) -> module.exports.view = (view) ->
view.fn "username", (auth) -> username(auth) view.fn "username", (auth) -> username(auth)
view.fn "tnl", algos.tnl
module.exports.app = (appExports, model) -> module.exports.app = (appExports, model) ->
user = model.at '_user' user = model.at '_user'
@ -78,27 +82,6 @@ module.exports.app = (appExports, model) ->
appExports.customizeArmorSet = (e, el) -> appExports.customizeArmorSet = (e, el) ->
user.set 'preferences.armorSet', $(el).attr('data-value') user.set 'preferences.armorSet', $(el).attr('data-value')
appExports.chooseEgg = (e, el) ->
egg = model.at el
model.ref '_feedEgg', egg
appExports.feedEgg = (e, el) ->
food = $(el).children('select').val()
foods = user.get 'items.food'
egg = model.get '_feedEgg'
eggs = user.get 'items.eggs'
foodIdx = foods.indexOf food
eggIdx = eggs.indexOf egg
return alert "You don't own that food :\\" if foodIdx is -1
return alert "You don't own that egg :\\" if eggIdx is -1
user.push 'items.pets', egg.text + '-' + food
user.remove 'items.food', foodIdx, 1
user.remove 'items.eggs', eggIdx, 1
appExports.restoreSave = (e, el) -> appExports.restoreSave = (e, el) ->
batch = new BatchUpdate(model) batch = new BatchUpdate(model)
batch.startTransaction() batch.startTransaction()
@ -106,6 +89,13 @@ module.exports.app = (appExports, model) ->
batch.set $(this).attr('data-for'), parseInt($(this).val() || 1) batch.set $(this).attr('data-for'), parseInt($(this).val() || 1)
batch.commit() batch.commit()
appExports.toggleHeader = (e, el) ->
user.set 'preferences.hideHeader', !user.get('preferences.hideHeader')
appExports.deleteAccount = (e, el) ->
model.del "users.#{user.get('id')}", ->
window.location.href = "/logout"
user.on 'set', 'flags.customizationsNotification', (captures, args) -> user.on 'set', 'flags.customizationsNotification', (captures, args) ->
return unless captures == true return unless captures == true
$('.main-avatar').popover('destroy') #remove previous popovers $('.main-avatar').popover('destroy') #remove previous popovers
@ -125,7 +115,7 @@ userSchema =
stats: { gp: 0, exp: 0, lvl: 1, hp: 50 } stats: { gp: 0, exp: 0, lvl: 1, hp: 50 }
party: { current: null, invitation: null } party: { current: null, invitation: null }
items: { weapon: 0, armor: 0, head: 0, shield: 0 } items: { weapon: 0, armor: 0, head: 0, shield: 0 }
preferences: { gender: 'm', skin: 'white', hair: 'blond', armorSet: 'v1', dayStart:0 } preferences: { gender: 'm', skin: 'white', hair: 'blond', armorSet: 'v1', dayStart:0, showHelm: true }
habitIds: [] habitIds: []
dailyIds: [] dailyIds: []
todoIds: [] todoIds: []

View file

@ -1,4 +1,5 @@
moment = require 'moment' moment = require 'moment'
algos = require './algos'
module.exports.app = (appExports, model) -> module.exports.app = (appExports, model) ->
user = model.at('_user') user = model.at('_user')
@ -14,7 +15,7 @@ module.exports.app = (appExports, model) ->
window.location.reload() window.location.reload()
appExports.cheat = -> appExports.cheat = ->
user.incr 'stats.exp', model.get '_tnl' user.incr 'stats.exp', algos.tnl(user.get('stats.lvl'))
user.incr 'stats.gp', 1000 user.incr 'stats.gp', 1000
appExports.reset = -> appExports.reset = ->

View file

@ -1,7 +1,7 @@
derby = require 'derby' derby = require 'derby'
app = derby.createApp module app = derby.createApp module
{get, view, ready} = app {get, view, ready} = app
derby.use require('derby-ui-boot'), {styles: ['bootstrap', 'responsive']} derby.use require('derby-ui-boot'), {styles: ['bootstrap']}
derby.use require '../../ui' derby.use require '../../ui'
derby.use require 'derby-auth/components' derby.use require 'derby-auth/components'

View file

@ -59,8 +59,8 @@ items = module.exports.items =
{text: 'Red', name: 'Red', notes: 'Turns your animal into a Red.', value: 3} {text: 'Red', name: 'Red', notes: 'Turns your animal into a Red.', value: 3}
{text: 'Golden', name: 'Golden', notes: 'Turns your animal into a Golden.', value: 3} {text: 'Golden', name: 'Golden', notes: 'Turns your animal into a Golden.', value: 3}
{text: 'Desert', name: 'Desert', notes: 'Turns your animal into a Desert.', value: 3} {text: 'Desert', name: 'Desert', notes: 'Turns your animal into a Desert.', value: 3}
{text: 'CottonCandyPink', name: 'CottonCandyPink', notes: 'Turns your animal into a CottonCandyPink.', value: 3} {text: 'Cotton Candy Pink', name: 'CottonCandyPink', notes: 'Turns your animal into a CottonCandyPink.', value: 3}
{text: 'CottonCandyBlue', name: 'CottonCandyBlue', notes: 'Turns your animal into a CottonCandyBlue.', value: 3} {text: 'Cotton Candy Blue', name: 'CottonCandyBlue', notes: 'Turns your animal into a CottonCandyBlue.', value: 3}
] ]
# add "type" to each item, so we can reference that as "weapon" or "armor" in the html # add "type" to each item, so we can reference that as "weapon" or "armor" in the html
@ -201,6 +201,7 @@ module.exports.updateStore = updateStore = (model) ->
model.set '_view.items.potion', items.potion model.set '_view.items.potion', items.potion
model.set '_view.items.reroll', items.reroll model.set '_view.items.reroll', items.reroll
model.set '_view.items.pets', items.pets model.set '_view.items.pets', items.pets
model.set '_view.items.food', items.food

View file

@ -71,8 +71,7 @@ module.exports.partySubscribe = partySubscribe = (page, model, params, next, cb)
module.exports.app = (appExports, model) -> module.exports.app = (appExports, model) ->
user = model.at('_user') user = model.at('_user')
user.on 'set', 'flags.partyEnabled', (captures, args) -> unlockPartiesNotification = ->
return unless captures == true
$('.main-avatar').popover('destroy') #remove previous popovers $('.main-avatar').popover('destroy') #remove previous popovers
html = """ html = """
<div class='party-system-popover'> <div class='party-system-popover'>
@ -89,6 +88,14 @@ module.exports.app = (appExports, model) ->
content: html content: html
$('.main-avatar').popover 'show' $('.main-avatar').popover 'show'
appExports.manuallyUnlockParties = ->
$("#settings-modal").modal("hide")
user.set('flags.partyEnabled', true)
unlockPartiesNotification()
user.on 'set', 'flags.partyEnabled', (captures, args) ->
unlockPartiesNotification() if captures == true
#TODO implement this when we have unsubscribe working properly #TODO implement this when we have unsubscribe working properly
model.on 'set', '_user.party.invitation', (after, before) -> model.on 'set', '_user.party.invitation', (after, before) ->
if !before? and after? # they just got invited if !before? and after? # they just got invited

View file

@ -21,6 +21,27 @@ module.exports.app = (appExports, model) ->
$('#drops-enabled-modal').modal 'show' $('#drops-enabled-modal').modal 'show'
appExports.chooseEgg = (e, el) ->
egg = model.at el
model.ref '_feedEgg', egg
appExports.feedEgg = (e, el) ->
foodName = $(el).children('select').val()
myFood = user.get 'items.food'
egg = model.get '_feedEgg'
eggs = user.get 'items.eggs'
foodIdx = myFood.indexOf foodName
eggIdx = eggs.indexOf egg
return alert "You don't own that food :\\" if foodIdx is -1
return alert "You don't own that egg :\\" if eggIdx is -1
user.push 'items.pets', egg.text + '-' + foodName
user.remove 'items.food', foodIdx, 1
user.remove 'items.eggs', eggIdx, 1
appExports.choosePet = (e, el) -> appExports.choosePet = (e, el) ->
petArray = $(el).attr('data-pet').split '-' petArray = $(el).attr('data-pet').split '-'
text = petArray[0] text = petArray[0]
@ -44,3 +65,14 @@ module.exports.app = (appExports, model) ->
user.set 'balance', (tokens - pet.value)/4 user.set 'balance', (tokens - pet.value)/4
else else
$('#more-tokens-modal').modal 'show' $('#more-tokens-modal').modal 'show'
appExports.buyFood = (e, el) ->
name = $(el).attr 'data-food'
newFood = _.findWhere food, name: name
tokens = user.get('balance') * 4
if tokens > newFood.value
if confirm "Buy this food with #{newFood.value} of your #{tokens} tokens?"
user.push 'items.food', newFood.text
user.set 'balance', (tokens - newFood.value) / 4
else
$('#more-tokens-modal').modal 'show'

View file

@ -153,7 +153,7 @@ updateStats = (model, newStats, batch) ->
obj.stats.hp = newStats.hp obj.stats.hp = newStats.hp
if newStats.exp? if newStats.exp?
tnl = model.get '_tnl' tnl = algos.tnl(obj.stats.lvl)
#silent = false #silent = false
# if we're at level 100, turn xp to gold # if we're at level 100, turn xp to gold
if obj.stats.lvl >= 100 if obj.stats.lvl >= 100

View file

@ -123,8 +123,8 @@ module.exports.app = (appExports, model) ->
appExports.toggleTaskEdit = (e, el) -> appExports.toggleTaskEdit = (e, el) ->
hideId = $(el).attr('data-hide-id') hideId = $(el).attr('data-hide-id')
toggleId = $(el).attr('data-toggle-id') toggleId = $(el).attr('data-toggle-id')
$(document.getElementById(hideId)).hide() $(document.getElementById(hideId)).addClass('visuallyhidden')
$(document.getElementById(toggleId)).toggle() $(document.getElementById(toggleId)).toggleClass('visuallyhidden')
appExports.toggleChart = (e, el) -> appExports.toggleChart = (e, el) ->
hideSelector = $(el).attr('data-hide-id') hideSelector = $(el).attr('data-hide-id')
@ -180,7 +180,7 @@ module.exports.app = (appExports, model) ->
scoring.score(model, task.get('id'), direction) scoring.score(model, task.get('id'), direction)
appExports.tasksToggleAdvanced = (e, el) -> appExports.tasksToggleAdvanced = (e, el) ->
$(el).next('.advanced').toggle() $(el).next('.advanced-option').toggleClass('visuallyhidden')
appExports.tasksSaveAndClose = -> appExports.tasksSaveAndClose = ->
# When they update their notes, re-establish tooltip & popover # When they update their notes, re-establish tooltip & popover

View file

@ -20,9 +20,15 @@ NO_USER_FOUND = err: "No user found."
$ mocha test/api.mocha.coffee $ mocha test/api.mocha.coffee
### ###
###
API Status
###
router.get '/status', (req, res) -> router.get '/status', (req, res) ->
res.json status: 'up' res.json status: 'up'
###
beforeEach auth interceptor
###
auth = (req, res, next) -> auth = (req, res, next) ->
uid = req.headers['x-api-user'] uid = req.headers['x-api-user']
token = req.headers['x-api-key'] 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) return res.json 401, NO_USER_FOUND if !req.userObj || _.isEmpty(req.userObj)
req._isServer = true req._isServer = true
next() next()
###
GET /user
###
router.get '/user', auth, (req, res) -> router.get '/user', auth, (req, res) ->
user = req.userObj user = req.userObj
@ -49,12 +57,18 @@ router.get '/user', auth, (req, res) ->
res.json user res.json user
###
GET /user/task/:id
###
router.get '/user/task/:id', auth, (req, res) -> router.get '/user/task/:id', auth, (req, res) ->
task = req.userObj.tasks[req.params.id] task = req.userObj.tasks[req.params.id]
return res.json 400, err: "No task found." if !task || _.isEmpty(task) return res.json 400, err: "No task found." if !task || _.isEmpty(task)
res.json 200, task res.json 200, task
###
validate task
###
validateTask = (req, res, next) -> validateTask = (req, res, next) ->
task = {} task = {}
newTask = { type, text, notes, value, up, down, completed } = req.body newTask = { type, text, notes, value, up, down, completed } = req.body
@ -85,11 +99,17 @@ validateTask = (req, res, next) ->
req.task = task req.task = task
next() next()
###
PUT /user/task/:id
###
router.put '/user/task/:id', auth, validateTask, (req, res) -> router.put '/user/task/:id', auth, validateTask, (req, res) ->
req.user.set "tasks.#{req.task.id}", req.task req.user.set "tasks.#{req.task.id}", req.task
res.json 200, req.task res.json 200, req.task
###
DELETE /user/task/:id
###
router.delete '/user/task/:id', auth, validateTask, (req, res) -> router.delete '/user/task/:id', auth, validateTask, (req, res) ->
taskIds = req.user.get "#{req.task.type}Ids" taskIds = req.user.get "#{req.task.type}Ids"
@ -99,6 +119,9 @@ router.delete '/user/task/:id', auth, validateTask, (req, res) ->
res.send 204 res.send 204
###
POST /user/task/
###
router.post '/user/task', auth, validateTask, (req, res) -> router.post '/user/task', auth, validateTask, (req, res) ->
task = req.task task = req.task
type = task.type type = task.type
@ -110,6 +133,9 @@ router.post '/user/task', auth, validateTask, (req, res) ->
res.json 201, task res.json 201, task
###
GET /user/tasks
###
router.get '/user/tasks', auth, (req, res) -> router.get '/user/tasks', auth, (req, res) ->
user = req.userObj user = req.userObj
return res.json 400, NO_USER_FOUND if !user || _.isEmpty(user) return res.json 400, NO_USER_FOUND if !user || _.isEmpty(user)

32
styles/app/helpers.styl Normal file
View 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

View file

@ -8,13 +8,31 @@
@import "./items.styl"; @import "./items.styl";
@import "./alerts.styl"; @import "./alerts.styl";
@import "../../public/img/sprites/pet_sprites.css"; @import "../../public/img/sprites/pet_sprites.css";
@import "./helpers.styl";
@import "./responsive.styl";
@import "./scrollbars.styl";
@import "../../public/vendor/bootstrap-datepicker/css/datepicker.css"; @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 html,body,p,h1,ul,li,table,tr,th,td
margin: 0 margin: 0
padding: 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 /* Header
-------------------------------------------------- */ -------------------------------------------------- */
@ -35,7 +53,7 @@ html,body,p,h1,ul,li,table,tr,th,td
box-sizing: border-box box-sizing: border-box
z-index: 1000 z-index: 1000
@media (max-width: 480px) { @media (max-width: 600px) {
#head { #head {
position: static; position: static;
} }
@ -132,7 +150,7 @@ html,body,p,h1,ul,li,table,tr,th,td
/*overflow:auto;*/ /*overflow:auto;*/
padding-bottom: 250px; /* don't know why this works, sticky footers are weird */ padding-bottom: 250px; /* don't know why this works, sticky footers are weird */
@media (max-width: 480px) { @media (max-width: 600px) {
#wrap { #wrap {
margin-top: 0 margin-top: 0
} }

View file

@ -1,42 +1,83 @@
/* ----- Items, Weapons, Armor -----*/ // money styles
.item-store-popover img .money
float:left display: inline-block
padding-right:7px; line-height: 1.5em
padding-left: 0.75em
.item .task-text img [class^="shop_"]
max-height: 16px vertical-align: top
display: inline-block
.buy-link, .item-buy-link .btn-buy
background-color: #DEE5F2 width: 4.5em
padding: 2px height: 3em
margin-right: 10px padding: 0.75em 0 0
border-radius: 5px text-align: center
vertical-align: top
background-color: $better
img color: #555
height:20px &:hover, &:focus
background-color: $bad
text-decoration: none
.item-buy-link .rewards
background-color: #ccffcc margin-bottom: 1.5em
padding-bottom: 1.5em
border-bottom: 1px solid rgba(0,0,0,0.1)
.item .reward-item
position:relative background: white
.shop-table .reward-cost
position:absolute display: inline
top: 0
left: 50px
#money
position:relative
.shop_gold, .shop_silver, .shop_copper
float:right
.money-table
position:absolute
top: 0
.shop-pet // store items
mouse: pointer .btn-reroll
.shop-pet-owned-check background-color: $better
position:absolute cursor: pointer
right:0px box-shadow: inset -1px -1px 0 rgba(0,0,0,0.1)
bottom:0px &: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%)

View file

@ -0,0 +1,31 @@
.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

View 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
}

View file

@ -49,6 +49,6 @@
.shop_armor_1 {background-position: -800px 0; width: 40px; height: 40px} .shop_armor_1 {background-position: -800px 0; width: 40px; height: 40px}
.shop_reroll {background-position: -840px 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_potion {background-position: -880px 0; width: 40px; height: 40px}
.shop_copper {background-position: -920px 0; width: 40px; height: 40px} .shop_copper {background-position: -923px -8px; width: 32px; height: 22px}
.shop_silver {background-position: -960px 0; width: 40px; height: 40px} .shop_silver {background-position: -963px -8px; width: 32px; height: 22px}
.shop_gold {background-position: -1000px 0; width: 40px; height: 40px} .shop_gold {background-position: -1003px -8px; width: 32px; height: 22px}

View file

@ -1,42 +1,354 @@
.color-worst pre // 1. Set up color classes
background-color: rgb(230, 184, 175) // ========================
.color-worse pre
background-color: rgb(244, 204, 204) // color variables
.color-bad pre $worst = rgb(230, 184, 175)
background-color: rgb(252, 229, 205) $worse = rgb(244, 204, 204)
.color-neutral pre $bad = rgb(252, 229, 205)
background-color: rgb(255, 242, 204) $neutral = rgb(255, 242, 204)
.color-good pre $good = rgb(217, 234, 211)
background-color: rgb(217, 234, 211) $better = rgb(208, 224, 227)
.color-better pre $best = rgb(201, 218, 248)
background-color: rgb(208, 224, 227) $completed = rgb(217, 217, 217)
.color-best pre
background-color: rgb(201, 218, 248) // array of keywords and their associated color vars
.completed pre $stages = (worst $worst) (worse $worse) (bad $bad) (neutral $neutral) (good $good) (better $better) (best $best)
background-color: rgb(217, 217, 217)
color: rgb(153, 153, 153) // for each color stage, generate a named class w/ the appropriate color
.reward pre 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 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, 20%)
opacity: 0.75
&: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 // primary task commands
.nav-pills > .active > a, .nav-pills > .active > a:hover // ----------------------
color: #005580 .task-controls
background-color: #DEE5F2 display: inline
margin-left: -0.5em
margin-right: 0.5em
.dailys // plus/minus commands
.repeat-days > .btn:not(.active) .task-action-btn
background-color: #aaa; display: inline-block
background-image: -moz-linear-gradient(top, #eee, #aaa); width: 2.12765em
background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eee), to(#aaa)); height: 2.12765em
background-image: -webkit-linear-gradient(top, #eee, #aaa); padding: 0
background-image: -o-linear-gradient(top, #eee, #aaa); font-size: 1.41em
background-image: linear-gradient(to bottom, #eee, #aaa); line-height: 2.12765
background-repeat: repeat-x; 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
// ------------
.task-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
// 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 .context-enabled
.display-context-dependant, .display-context-dependant,
.task-list li .task-list li
@ -50,39 +362,19 @@ label.checkbox.inline{
.show-for-uncompleted, .uncompleted .show-for-uncompleted, .uncompleted
display: block display: block
.help-icon
float:right;
.task:hover // nav tabs
cursor: move .nav-tabs
margin-top: 1.5em
li:hover .task-meta-controls .hover-show .nav-tabs > li
display: inline &.active > a
color: #333
.task &:hover
list-style:none margin-top: 1px
> a
pre border-radius: 0 !important
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif margin-top: 1px
font-size: 13px color: #333
line-height: 18px &:hover
color: black border-top: 0
word-break: normal margin-top: 2px
.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;

View file

@ -46,7 +46,11 @@
<span class='{:p.gender}_skin_{:p.skin}'></span> <span class='{:p.gender}_skin_{:p.skin}'></span>
<span class='{:p.gender}_hair_{:p.hair}'></span> <span class='{:p.gender}_hair_{:p.hair}'></span>
<span class="{equipped(@profile, 'armor')}"></span> <span class="{equipped(@profile, 'armor')}"></span>
{#if :p.showHelm}
<span class="{equipped(@profile, 'head')}"></span> <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}_shield_{@profile.items.shield}'></span>
<span class='{:p.gender}_weapon_{@profile.items.weapon}'></span> <span class='{:p.gender}_weapon_{@profile.items.weapon}'></span>
{/} {/}
@ -67,10 +71,14 @@
<menu type="list"> <menu type="list">
<!-- gender --> <!-- gender -->
<li class="customize-menu"> <li class="customize-menu">
<menu label="Gender"> <menu label="Head">
<button type="button" class="m_head_0 customize-option" data-value="m" x-bind="click:customizeGender"></button> <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> <button type="button" class="f_head_0 customize-option" data-value="f" x-bind="click:customizeGender"></button>
</menu> </menu>
<label class="checkbox">
<input type=checkbox checked="{_user.preferences.showHelm}" /> Show Helm
</label>
</li> </li>
<!-- hair --> <!-- hair -->

View file

@ -1,4 +1,5 @@
<header:> <header:>
{#unless _user.preferences.hideHeader}
<div class="row-fluid"> <div class="row-fluid">
<div class='char-status {#if gt(_partyMembers.length,1)}span8 offset2 has-party{else}span6 offset3{/}'> <div class='char-status {#if gt(_partyMembers.length,1)}span8 offset2 has-party{else}span6 offset3{/}'>
@ -8,13 +9,25 @@
</figure> </figure>
<!-- party --> <!-- party -->
{#each _partyMembers as :member} {{#each _partyMembers as :member}}
{#unless equal(:member.id, _userId)} {{#unless equal(:member.id, _userId)}}
<figure class="party-avatar-wrap" rel="tooltip" title="{username(:member.auth)}" data-placement="bottom"> <figure class="party-avatar-wrap" rel="popover" data-title="{{username(:member.auth)}}" data-placement="bottom" data-trigger="hover" data-html="true" data-content="
<app:avatar:avatar profile={:member} party="true" /> <div>
<div class='progress progress-danger' style='height:5px;'>
<div class='bar' style='height: 5px; width: {percent(:member.stats.hp, 50)}%;'></div>
</div>
<div class='progress progress-warning' style='height:5px;'>
<div class='bar' style='height: 5px; width: {percent(:member.stats.exp, tnl(:member.stats.lvl))}%;'></div>
</div>
<div>GP: {{floor(:member.stats.gp)}}</div>
</div>
">
<!-- Would be way cleaner as a Derby template `data-content="<app:party:member-stats profile={{:member}} />"`, but it was just printing HTML as text -->
<app:avatar:avatar profile={{:member}} party="true" />
</figure> </figure>
{/} {{/}}
{/} {{/}}
<!-- progress bars --> <!-- progress bars -->
<div class="progress-bars"> <div class="progress-bars">
@ -24,12 +37,12 @@
</div> </div>
<div class="progress progress-warning" rel=tooltip data-placement=bottom title="Experience"> <div class="progress progress-warning" rel=tooltip data-placement=bottom title="Experience">
<div class="bar" style="width: {percent(_user.stats.exp,_tnl)}%;"></div> <div class="bar" style="width: {percent(_user.stats.exp,tnl(_user.stats.lvl))}%;"></div>
<span class="progress-text"> <span class="progress-text">
{#if _user.history.exp} {#if _user.history.exp}
<a x-bind=click:toggleChart data-toggle-id="exp-chart" data-history-path="_user.history.exp" rel=tooltip title="Progress"><i class=icon-signal></i></a>&nbsp; <a x-bind=click:toggleChart data-toggle-id="exp-chart" data-history-path="_user.history.exp" rel=tooltip title="Progress"><i class=icon-signal></i></a>&nbsp;
{/} {/}
<i class=icon-star></i> {floor(_user.stats.exp)} / {_tnl} <i class=icon-star></i> {floor(_user.stats.exp)} / {tnl(_user.stats.lvl)}
</span> </span>
</div> </div>
<div id="exp-chart" style="display:none;"></div> <div id="exp-chart" style="display:none;"></div>
@ -38,3 +51,4 @@
</div> </div>
<!-- end .row-fluid --> <!-- end .row-fluid -->
</div> </div>
{/}

View file

@ -13,8 +13,10 @@
HabitRPG | Gamify Your Life HabitRPG | Gamify Your Life
<Head:> <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"> <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'>
<Header:> <Header:>
<app:modals:modals /> <app:modals:modals />
@ -27,9 +29,9 @@
<Body:> <Body:>
<br/> <br/>
<div id="notification-area"></div> <div id="notification-area"></div>
<div id=wrap class="container-fluid"> <div id="wrap">
<app:alerts:alerts /> <app:alerts:alerts />
<div id=main class="row-fluid"> <div id=main class="grid">
<app:taskLists /> <app:taskLists />
</div> </div>
</div> </div>
@ -39,11 +41,13 @@
<!-- scripts go in /src/app/browser.coffee, that way we can get min/concat --> <!-- 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 --> <!-- only the ones that are remote and can't be done async are here -->
<script src="https://checkout.stripe.com/v2/checkout.js"></script> <script src="https://checkout.stripe.com/v2/checkout.js"></script>
{#if equal(_view.nodeEnv,"production")} {#if equal(_view.nodeEnv,"production")}
<!-- Google Analytics --> <!-- Google Analytics -->
<script type="text/javascript"> <script type="text/javascript">
var _gaq = _gaq || []; var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-33510635-1']); _gaq.push(['_setAccount', 'UA-33510635-1']);
_gaq.push(['_setDomainName', 'habitrpg.com']);
_gaq.push(['_trackPageview']); _gaq.push(['_trackPageview']);
(function() { (function() {

View file

@ -1,7 +1,12 @@
<rewardsTab:> <rewardsTab:>
<!-- add new reward -->
<app:newTask type="reward" inputValue="{_newReward}" placeHolder="New Reward" />
{#if _rewardList}
<ul class='rewards'> <ul class='rewards'>
{#each _rewardList as :task}<app:task />{/} {#each _rewardList as :task}<app:task />{/}
</ul> </ul>
{/}
{#if _user.flags.itemsEnabled} {#if _user.flags.itemsEnabled}
@ -16,50 +21,44 @@
{/} {/}
<pet:> <pet:>
<div class="span3 shop-pet" rel=tooltip title="{.text} - {.value} Tokens"> <td class="{{#if _user.items.pets[.name]}}active-pet{{/}}">
<div style='position:relative'> <img rel=tooltip title="{.text} - {.value} Tokens" x-bind="click:selectPet" data-pet='{.name}' src='img/sprites/{.icon}'/>
{#if _user.items.pets[.name]}<i class='icon-ok shop-pet-owned-check'></i>{/} </td>
<img x-bind="click:selectPet" data-pet='{.name}' src='img/sprites/{.icon}'/>
</div>
</div>
<food:>
<td class="active-food">
<div rel=tooltip class="{.name}" title="{.text} - {.value} Tokens" x-bind="click:buyFood" data-food='{.name}'>{.text}</div>
</td>
<userTokens:> <userTokens:>
<div class="pull-right"> <a class="pull-right token-wallet">
<div class="input-append"> <span class="task-action-btn tile flush bright add-token-btn"></span>
<span class="uneditable-input" style="width:auto;">{tokens(_user.balance)}</span> <span class="task-action-btn tile flush neutral">{tokens(_user.balance)} Tokens</span>
<span class="add-on">Tokens</span> </a>
</div>
</div>
<!--<span class="well pull-right">Tokens: {tokens(_user.balance)}</span>-->
<item:> <item:>
{#unless :item.hide} {#unless :item.hide}
<li class="task reward item"> <li class="task reward-item">
<pre> <!-- right-hand side control buttons -->
<div class="task-meta-controls"> <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> <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>
<!-- left-hand size commands -->
<div class="task-controls"> <div class="task-controls">
{#if @reroll} {#if @reroll}
<a href="#" data-toggle="modal" data-target="#reroll-modal" class="item-buy-link" style='cursor:pointer'><i class=icon-retweet></i></a> <a class="task-action-btn btn-reroll" data-toggle="modal" data-target="#reroll-modal"></a>
{else} {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> <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> </div>
<div class="task-text"> <!-- main content -->
{#if :item.icon} <span class="shop_{:item.classes} shop-sprite item-img"></span>
<img src="/img/sprites/{:item.icon}" /> {:item.text} <p class="task-text">{:item.text}</p>
{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>
{/} {/}

View file

@ -1,15 +1,13 @@
<modals:> <modals:>
{{#if _loggedIn}} {{#if _loggedIn}}
<app:modals:modal modalId="settings-modal" header="Settings"> <app:modals:modal modalId="settings-modal" header="Settings">
<h4>API</h4> <ul class="nav nav-tabs">
<small>Copy these for use in third party applications.</small> <li class="active"><a data-toggle="tab" href="#" data-target="#settings-settings">General</a></li>
<h6>User ID</h6> <li><a data-toggle="tab" href="#" data-target="#settings-api">API</a></li>
<pre class=prettyprint>{_user.id}</pre> </ul>
<h6>API Token</h6> <div class="tab-content">
<pre class=prettyprint>{_user.apiToken}</pre> <div class="tab-pane active" id="settings-settings">
<hr/>
<h4>Custom Day Start</h4> <h4>Custom Day Start</h4>
<div class="input-append"> <div class="input-append">
<input class="span2" type="number" min=0 max=24 value={_user.preferences.dayStart} /> <input class="span2" type="number" min=0 max=24 value={_user.preferences.dayStart} />
@ -19,6 +17,11 @@
<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> <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>
</div> </div>
<hr/>
<h4>Misc</h4>
<button x-bind="click:toggleHeader">{#if _user.preferences.hideHeader}Show Header{else}Hide Header{/}</button>
{#unless _user.flags.partyEnabled}&nbsp;<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}} {{#if _user.auth.local}}
<hr/> <hr/>
<h4>Change Password</h4> <h4>Change Password</h4>
@ -26,8 +29,20 @@
{{/}} {{/}}
<hr/> <hr/>
<h4>Danger Zone</h4>
<a class='btn btn-danger' data-target="#reset-modal" data-toggle="modal" rel=tooltip title="Resets your entire account (dangerous).">Reset</a> <a class='btn btn-danger' data-target="#reset-modal" data-toggle="modal" rel=tooltip title="Resets your entire account (dangerous).">Reset</a>
&nbsp;<a class='btn btn-danger' data-target="#restore-modal" data-toggle="modal" rel=tooltip title="Restores attributes to your character.">Restore</a> &nbsp;<a class='btn btn-danger' data-target="#restore-modal" data-toggle="modal" rel=tooltip title="Restores attributes to your character.">Restore</a>
&nbsp;<a class='btn btn-danger' data-target="#delete-modal" data-toggle="modal" rel=tooltip title="Delete your account.">Delete</a>
</div>
<div class="tab-pane" id="settings-api">
<small>Copy these for use in third party applications.</small>
<h6>User ID</h6>
<pre class=prettyprint>{_user.id}</pre>
<h6>API Token</h6>
<pre class=prettyprint>{_user.apiToken}</pre>
</div>
</div>
<@footer> <@footer>
<button class="btn" data-dismiss="modal" aria-hidden="true">Close</button> <button class="btn" data-dismiss="modal" aria-hidden="true">Close</button>
@ -92,6 +107,15 @@
</@footer> </@footer>
</app:modals:modal> </app:modals:modal>
<app:modals:modal modalId="delete-modal" header="Delete Account">
<p>Woa woa woa! Are you sure? This will seriously delete your account forever, and it can never be restored. If you're absolutely certain, type <strong>DELETE</strong> into the text-box below.</p>
<p><input type="text" value="{_deleteAccount}" /></p>
<@footer>
<button class="btn btn-large" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button data-dismiss="modal" x-bind="click:deleteAccount" class="btn btn-danger btn-small {#unless equal(_deleteAccount,'DELETE')}disabled{/}">Delete Account</button>
</@footer>
</app:modals:modal>
{{else}} {{else}}
<app:modals:modal modalId="login-modal" header="Login / Register"> <app:modals:modal modalId="login-modal" header="Login / Register">
<a href="/auth/facebook"><img src='/img/facebook-login-register.jpeg' alt="Login / Register With Facebook"/></a> <a href="/auth/facebook"><img src='/img/facebook-login-register.jpeg' alt="Login / Register With Facebook"/></a>

View file

@ -1,235 +1,260 @@
<taskLists:> <taskLists:>
<!--helpTitle & helpContent moved to tour --> <!--helpTitle & helpContent moved to tour -->
<div class="span3 well habits">
<h2>Habits</h2> <!-- Habits Column -->
<div class="module">
<div class="task-column habits">
<h2 class="task-column_title">Habits</h2>
<app:newTask type="habit" inputValue="{_newHabit}" placeHolder="New Habit" /> <app:newTask type="habit" inputValue="{_newHabit}" placeHolder="New Habit" />
<ul class="habits">{#each _habitList as :task}<app:task />{/}</ul> <ul class="habits">{#each _habitList as :task}<app:task />{/}</ul>
</div> </div>
</div>
<div class="span3 well dailys"> <!-- Dailys Column -->
<h2>Daily</h2> <div class="module">
<div class="task-column dailys">
<h2 class="task-column_title">Daily</h2>
<app:newTask type="daily" inputValue="{_newDaily}" placeHolder="New Daily" /> <app:newTask type="daily" inputValue="{_newDaily}" placeHolder="New Daily" />
<ul class='dailys'>{#each _dailyList as :task}<app:task />{/}</ul> <ul class='dailys'>{#each _dailyList as :task}<app:task />{/}</ul>
</div> </div>
</div>
<div class="span3 well todos context-enabled context-uncompleted tabbable tabs-below" id="todo-well"> <!-- Todos Column -->
<h2>Todos</h2> <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 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 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>
<h2 class="task-column_title">Todos</h2>
<!-- create new todo -->
<div class="display-context-dependant show-for-uncompleted"> <div class="display-context-dependant show-for-uncompleted">
<app:newTask type="todo" inputValue="{_newTodo}" placeHolder="New Todo" /> <app:newTask type="todo" inputValue="{_newTodo}" placeHolder="New Todo" />
</div> </div>
<!-- list of all the todos -->
<ul class='todos task-list'> <ul class='todos task-list'>
{#each _todoList as :task}<app:task />{/} {#each _todoList as :task}<app:task />{/}
</ul> </ul>
<div class="display-context-dependant show-for-completed">
<a class='btn' x-bind=click:clearCompleted>Clear Completed</a> <button class='task-action-btn tile spacious bright display-context-dependant show-for-completed' x-bind=click:clearCompleted>Clear Completed</button>
<p>&nbsp;</p>
</div>
<span class='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>
{/}
&nbsp;<a href="/v1/users/{{_user.id}}/calendar.ics?apiToken={{_user.apiToken}}"><img src='/img/calendar_ical.png' title="iCal" alt="iCal" rel=tooltip /></a>
<!--&nbsp;<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>-->
</span>
<div id="todos-chart" style="display:none;"></div> <div id="todos-chart" style="display:none;"></div>
<ul class="nav nav-tabs">
<!-- 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 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> <li><a x-bind=click:changeContext data-target="#todo-well" data-context="context-completed">Complete</a></li>
</ul> </ul>
</div>
</div> </div>
<div class="span3 well rewards"> <!-- Rewards Column -->
<div class="module">
<!--Title --> <div class="task-column rewards">
<div class="row-fluid"> <!-- cash or tokens -->
<div class="span6"><h2>Rewards</h2></div> <span class='option-box pull-right wallet'>
<div class="span6">
{#unless _view.activeTabPets} {#unless _view.activeTabPets}
<table><tr> <div class="money">
<td>{gold(_user.stats.gp)} </td> {gold(_user.stats.gp)}
<td><div class='shop_gold' rel='tooltip' title='Gold'></div></td> <span class='shop_gold' rel='tooltip' title='Gold'></span>
<td>{silver(_user.stats.gp)} </td> </div>
<td><div class='shop_silver' rel='tooltip' title='Silver'></div></td> <div class="money">
<!--<td>{copper(_user.stats.gp)} </td> {silver(_user.stats.gp)}
<td><div class='shop_copper' rel='tooltip' title='shop_copper'></div></td>--> <span class='shop_silver' rel='tooltip' title='Silver'></span>
</tr></table> </div>
<!-- <div class="money">
{copper(_user.stats.gp)}
<span class='shop_copper' rel='tooltip' title='Copper'></span>
</div> -->
{else} {else}
<app:userTokens /> <app:userTokens />
{/} {/}
</div> </span>
</div> <h2 class="task-column_title">Rewards</h2>
<app:newTask type="reward" inputValue="{_newReward}" placeHolder="New Reward" />
{#if equal(_user.flags.petsEnabled,true)} <!-- if pets are enabled, make tabs -->
{#if equal(_user.flags.dropsEnabled,true)}
<div class='tabbable tabs-below'> <div class='tabbable tabs-below'>
<div class="tab-content"> <div class="tab-content">
<div class="tab-pane active" id="rewards-tab"> <div class="tab-pane active" id="rewards-tab">
<app:rewardsTab /> <app:rewardsTab />
</div> </div>
<div class="tab-pane" id="pets-tab"> <!-- pets pane -->
{#with _view.items.pets as :pets} <div class="tab-pane pet-grid" id="market-tab">
<h4>Welcome to the market</h4>
<div class="row-fluid"> {#with _view.items.food as :food}
{#with :pets[0]}<app:pet />{/} <table>
{#with :pets[1]}<app:pet />{/} <tr>
{#with :pets[2]}<app:pet />{/} {#with :food[0]}<app:food />{/}
{#with :pets[3]}<app:pet />{/} {#with :food[1]}<app:food />{/}
</div> {#with :food[2]}<app:food />{/}
{#with :food[3]}<app:food />{/}
<div class="row-fluid"> </tr>
{#with :pets[4]}<app:pet />{/} <tr>
{#with :pets[5]}<app:pet />{/} {#with :food[4]}<app:food />{/}
{#with :pets[6]}<app:pet />{/} {#with :food[5]}<app:food />{/}
{#with :pets[7]}<app:pet />{/} {#with :food[6]}<app:food />{/}
</div> {#with :food[7]}<app:food />{/}
</tr>
<div class="row-fluid"> <tr>
{#with :pets[8]}<app:pet />{/} {#with :food[8]}<app:food />{/}
{#with :pets[9]}<app:pet />{/} {#with :food[9]}<app:food />{/}
{#with :pets[10]}<app:pet />{/} </tr>
{#with :pets[11]}<app:pet />{/} </table>
</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>
<!--<div class="tab-pane" id="mounts-tab">...</div>--> <!--<div class="tab-pane" id="mounts-tab">...</div>-->
</div> </div>
<ul class="nav nav-tabs" id="rewardsTabs"> <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 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="#market-tab" id='market-tab' data-toggle="tab" x-bind='click:activatePetsTab'>Market</a></li>
<!--<li><a href="#mounts-tab" data-toggle="tab">Mounts</a></li>--> <!--<li><a href="#mounts-tab" data-toggle="tab">Mounts</a></li>-->
</ul> </ul>
</div> </div>
<!-- if pets are disabled, just do rewards tab -->
{else} {else}
<app:rewardsTab /> <app:rewardsTab />
{/} {/}
</div> </div>
<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>
<task:>
<li data-id={{:task.id}} class="task {taskClasses(:task.type, :task.completed, :task.value, :task.repeat)}">
<pre>
<div class="task-meta-controls">
<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> </div>
<!-- Templates -->
<newTask:>
<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)}">
<!-- 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} {#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> <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>
<!-- left-hand side checkbox -->
<div class="task-controls"> <div class="task-controls">
<!-- Habits --> <!-- Habits -->
{#if equal(:task.type, 'habit')} {#if equal(:task.type, 'habit')}
{#if :task.up}<a data-direction=up x-bind=click:score><img src="/img/add.png" /></a>{/} {#if :task.up}<a class="task-action-btn" data-direction=up x-bind=click:score></a>{/}
{#if :task.down}<a data-direction=down x-bind=click:score><img src="/img/remove.png" /></a>{/} {#if :task.down}<a class="task-action-btn" data-direction=down x-bind=click:score></a>{/}
<!-- Rewards --> <!-- Rewards -->
{else if equal(:task.type, 'reward')} {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> <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 --> <!-- Daily & Todos -->
{else} {else}
<input type=checkbox checked="{:task.completed}"/> <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> </div>
<div class="task-text">{:task.text}</div>
<!-- main content -->
<p class="task-text">{:task.text}</p>
<!-- edit/options dialog -->
<app:taskMeta /> <app:taskMeta />
</pre>
</li> </li>
<!-- task edit/options -->
<taskMeta:> <taskMeta:>
<div style="display:none;" id={{:task.id}}-edit> <div id="{{:task.id}}-edit" class="task-options visuallyhidden">
<hr/>
<form x-bind=submit:toggleTaskEdit data-toggle-id="{{:task.id}}-edit"> <form x-bind=submit:toggleTaskEdit data-toggle-id="{{:task.id}}-edit">
<div class=control-group> <!-- text & notes -->
<label>Text</label><input type=text value={:task.text} /> <fieldset class="option-group">
<label>Notes</label><textarea rows=3>{:task.notes}</textarea> <label class="option-title">Text</label><input class="option-content" type=text value={:task.text}>
</div> <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')} {#if equal(:task.type, 'habit')}
<hr/> <fieldset class="option-group">
<label>Direction</label> <legend class="option-title">Direction/Actions</legend>
<div class="control-group"> <span class="task-checker action-plusminus select-toggle">
<label class="checkbox inline"><input type=checkbox checked={:task.up}>Up</label> <input class="visuallyhidden focusable" type=checkbox id="{{:task.id}}-option-plus" checked={:task.up}>
<label class="checkbox inline"><input type=checkbox checked={:task.down}>Down</label> <label for="{{:task.id}}-option-plus"></label>
</div> </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')} {else if equal(:task.type, 'daily')}
<hr/> <fieldset class="option-group">
<label>Repeat</label> <legend class="option-title">Repeat</legend>
<div class="control-group btn-group repeat-days"> <div class="task-controls tile-group repeat-days">
<!-- note, does not use data-toggle="buttons-checkbox" - it would interfere with our own click binding --> <!-- 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="task-action-btn tile {#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="task-action-btn tile {#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="task-action-btn tile {#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="task-action-btn tile {#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="task-action-btn tile {#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="task-action-btn tile {#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> <button type="button" class="task-action-btn tile {#if :task.repeat.s}active{/}" data-day='s' x-bind=click:toggleDay>S</button>
</div> </div>
</fieldset>
<!-- if Reward, pricing -->
{else if equal(:task.type, 'reward')} {else if equal(:task.type, 'reward')}
<hr/>
<div class=control-group> <div class=control-group>
<label>Price</label> <label>Price</label>
<div class="input-append"> <div class="input-append">
<input class="span5" size="16" type="number" min="0" value={:task.value}><span class="add-on">Gold</span> <input class="span5" size="16" type="number" min="0" value={:task.value}><span class="add-on">Gold</span>
</div> </div>
</div> </div>
<!-- if Todo, the due date -->
{else if equal(:task.type, 'todo')} {else if equal(:task.type, 'todo')}
<hr/> <fieldset class="option-group">
<div class=control-group> <legend class="option-title">Due Date</legend>
<label>Due Date</label> <input class="option-content datepicker" type="text" value="{:task.date}" data-date-format="mm/dd/yyyy">
<input type="text" value="{:task.date}" data-date-format="mm/dd/yyyy" class="datepicker" /> </fieldset>
<div><small>Enter as date, eg 02/19/2013 or 02-19-2013</small></div>
</div>
{/} {/}
<hr/> <!-- Advanced Options -->
{#unless equal(:task.type, 'reward')} {#unless equal(:task.type, 'reward')}
<div> <p x-bind="click:tasksToggleAdvanced" class="option-title mega">Advanced Options</p>
<a x-bind="click:tasksToggleAdvanced">Advanced</a> <fieldset class="option-group advanced-option visuallyhidden">
<div class='advanced hide'> <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}}">
<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> <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>
<div class="control-group btn-group priority-multiplier" data-id="{{:task.id}}"> <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="btn btn-info {#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>Hard</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> </div>
</div> </fieldset>
</div>
<br/>
{/} {/}
<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> </form>
</div> </div>